# JSON Lines export v1

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

```js
import assert from 'node:assert/strict';
import { previewJsonLinesExport } from './json-lines-export.mjs';
const input = JSON.stringify([
  { id: '001', note: 'line\nnext' },
  { id: '002', empty: '' },
]);
const result = previewJsonLinesExport(input);
assert.equal(result.records, 2);
assert.equal(result.jsonLines, '{"id":"001","note":"line\\nnext"}\n{"id":"002","empty":""}');
assert.deepEqual(result.jsonLines.split('\n').map(line => JSON.parse(line)), JSON.parse(input));
console.log('JSON Lines export example passed.');
```

## Contract

`previewJsonLinesExport(input)` returns `{ records, jsonLines }`.
Supply a nonempty JSON array of flat objects with string values only.
Each output record is compact JSON on one physical line, joined with LF and
no terminal newline. `records` counts objects. Field sets may differ; missing
fields are not filled. Empty objects and empty or whitespace-only field names
are accepted. JSON property ordering follows JSON.parse and JSON.stringify;
the original JSON formatting is not retained.

Empty input, invalid JSON, non-array roots, empty arrays, non-object records,
numbers, booleans, null, arrays and nested object field values reject.
Record validation errors identify the one-based array position without echoing
input. A failure stops the whole conversion; no records are silently dropped.

Exact 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 output. Formulas are not
evaluated. 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 object and
300,000 output characters including LF separators, measured as JavaScript
string length. The union of field names may exceed 50. Lone Unicode surrogates
are escaped by JSON.stringify and count toward the output limit.
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-export.ts` core with
`node scripts/build-json-lines-export-source.mjs`; use `--check` to verify bytes.
Tests compare runtime results/errors at input/output bounds 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.
