# JSON string-field sort v1

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

```js
import assert from 'node:assert/strict';
import { sortJsonRecords } from './json-sort.mjs';
const input = '[{"rank":"b","id":"001"},{"rank":"a","id":"002"},{"rank":"b","id":"003"}]';
const ascending = sortJsonRecords(input, 'rank', 'asc');
assert.equal(ascending.records, 3);
assert.equal(ascending.fields, 2);
assert.equal(ascending.output, '[{"rank":"a","id":"002"},{"rank":"b","id":"001"},{"rank":"b","id":"003"}]');
const descending = sortJsonRecords(input, 'rank', 'desc');
assert.deepEqual(JSON.parse(descending.output).map(record => record.id), ['001', '003', '002']);
assert.deepEqual(JSON.parse(sortJsonRecords('[{"rank":"2"},{"rank":"10"}]', 'rank', 'asc').output), [{rank:'10'}, {rank:'2'}]);
console.log('JSON string-field sort example passed.');
```

## Contract

`sortJsonRecords(input, field, direction)` returns `{ output, records, fields }`.
`fields` counts fields in the first input record; other records may have different
fields. Supply a nonempty JSON array of flat objects with string values only,
an explicit nonempty exact field name and direction `'asc'` or `'desc'`.
Names and values are never trimmed or normalized. Whitespace-only names and
embedded controls are literal. Every record must contain the selected field
as an own property. All fields in every record are validated before sorting.

Ordering is UTF-16 lexical string comparison, with no numeric conversion,
locale collation, case folding or Unicode normalization. For example, `"10"`
precedes `"2"`, and `"A"` precedes `"a"` in ascending order. Equal values retain
their original record order in both directions. Empty strings are valid values.
Complete records are preserved. The helper never sorts field names.

Invalid JSON, non-array roots, empty arrays, non-object records, missing sort
fields, and numbers, booleans, null, arrays or nested objects reject the entire
operation. Failure produces no partial output. Errors never echo field names
or values. Output is compact JSON without a terminal newline; input is unchanged.
Special names such as `__proto__`, `constructor` and `toString` remain inert own
properties. JSON.parse resolves duplicate input keys using the last value;
validation applies after resolution. JavaScript standard property enumeration
applies to integer index-like field names.

Limits: 100,000 input characters, 100,000 field-name characters, 499 records,
50 fields per record and 300,000 output characters, measured as JavaScript
string length. Escaped lone Unicode surrogates count toward the output limit.
Leading zeros, empty strings, spaces, formula text, Unicode and escaped tabs,
CR and newlines are preserved. Formulas are not evaluated. Browser field boxes
normalize CR and CRLF to LF; this source accepts exact CR and CRLF field names.
The helper performs no requests, file writes or type coercion. Native export
plus a local script is an alternative; no measured advantage or demand is claimed.

## Source parity

Generated from the browser's exact `site/lib/json-sort.ts` core with
`node scripts/build-json-sort-source.mjs`; use `--check` to verify bytes.
Tests compare runtime results/errors at input/output bounds and execute this
example. Downloading does not demonstrate independent local execution.
Input, output, field names and direction values 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.
