# JSON Lines string records v1

Save `json-lines.mjs` beside `json-lines-example.mjs` containing this example.
Run `node json-lines-example.mjs` with Node 18+; no runtime dependencies or network.

```js
import assert from 'node:assert/strict';
import { jsonLinesToArray } from './json-lines.mjs';
const input = '{"id":"001","note":"line\\nnext"}\r\n{"id":"002","empty":""}\r\n';
const result = jsonLinesToArray(input);
assert.deepEqual(JSON.parse(result.json), [
  { id: '001', note: 'line\nnext' },
  { id: '002', empty: '' },
]);
assert.equal(result.rows, 2);
assert.equal(result.columns, 3);
console.log('JSON Lines example passed.');
```

## Contract

`jsonLinesToArray(input)` returns `{ json, report, rows, columns }`.
Supply one complete, flat JSON object per physical line, with string values
only. The output is a JSON array with two-space indentation and no terminal
newline. `rows` counts records; `columns` counts distinct field names across
all records. Field sets may differ. Missing fields are not added or filled.
Empty objects and empty or whitespace-only field names are accepted.

LF and CRLF line endings are accepted, including mixed endings. Exactly one
final LF or CRLF terminator is ignored. Empty input, blank lines (including
interior or additional terminal blank lines), bare CR line endings, invalid
JSON, multiline objects and concatenated records reject. Each record error
reports its original physical line number without echoing the input. A
failure stops the whole conversion; no records are silently dropped.

String values and literal key spacing preserve leading zeros, spaces, empty
strings, formula text, Unicode and escaped tabs, CR and newlines. Controls
remain inside strings and are escaped in the JSON output. Formulas are not
evaluated. Numbers, booleans, null, arrays and nested objects reject.
Special keys such as `__proto__`, `constructor` and `toString` remain inert
own properties. JSON.parse resolves duplicate object keys using the last
value; earlier duplicate values cannot be recovered. Limits and type checks
apply to the parsed object after that resolution.

Limits: 100,000 input characters, 499 records, 50 fields per record, and
300,000 output JSON characters. The union of field names can exceed 50.
This helper performs no file writes, requests or formula evaluation.
Native export plus a local script is an alternative; no measured advantage
or user demand is claimed.

## Source parity

Generated from the browser's exact `site/lib/json-lines.ts` core with
`node scripts/build-json-lines.mjs`; use `--check` to verify bytes. Tests
compare runtime results/errors and execute this example. A download is not
evidence of independent local execution. Input and output are not sent in
analytics.

## License

MIT License

Copyright (c) 2026 QuasiLife

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
