@helpers4/json 3.1.2-alpha.0 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +14 -14
- package/lib/index.js +7 -7
- package/lib/index.js.map +1 -1
- package/llms.txt +1 -1
- package/meta/api.json +12 -12
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* }`) // => { outDir: 'dist' }
|
|
50
50
|
* @example
|
|
51
51
|
* parse("{ name: 'app', retries: 0x3, ratio: .5, }") // => { name: 'app', retries: 3, ratio: 0.5 }
|
|
52
|
-
* @since
|
|
52
|
+
* @since 3.1.3
|
|
53
53
|
*/
|
|
54
54
|
declare function parse<T = unknown>(text: string): T;
|
|
55
55
|
|
|
@@ -60,7 +60,7 @@ declare function parse<T = unknown>(text: string): T;
|
|
|
60
60
|
*/
|
|
61
61
|
/**
|
|
62
62
|
* Options for {@link parseLines} and {@link safeParseLines}.
|
|
63
|
-
* @since
|
|
63
|
+
* @since 3.1.3
|
|
64
64
|
*/
|
|
65
65
|
interface ParseLinesOptions {
|
|
66
66
|
/**
|
|
@@ -109,7 +109,7 @@ interface ParseLinesOptions {
|
|
|
109
109
|
* parseLines('{"id":1}\n{"id":2}\n') // => [{ id: 1 }, { id: 2 }]
|
|
110
110
|
* @example
|
|
111
111
|
* parseLines('{"id":1}\n{"id":', { invalidLines: 'skip' }) // => [{ id: 1 }]
|
|
112
|
-
* @since
|
|
112
|
+
* @since 3.1.3
|
|
113
113
|
*/
|
|
114
114
|
declare function parseLines<T = unknown>(text: string, options?: ParseLinesOptions): T[];
|
|
115
115
|
|
|
@@ -120,7 +120,7 @@ declare function parseLines<T = unknown>(text: string, options?: ParseLinesOptio
|
|
|
120
120
|
*/
|
|
121
121
|
/**
|
|
122
122
|
* Options for {@link parseSequence} and {@link safeParseSequence}.
|
|
123
|
-
* @since
|
|
123
|
+
* @since 3.1.3
|
|
124
124
|
*/
|
|
125
125
|
interface ParseSequenceOptions {
|
|
126
126
|
/**
|
|
@@ -163,7 +163,7 @@ interface ParseSequenceOptions {
|
|
|
163
163
|
* @example
|
|
164
164
|
* // A crash cut the last record: skip it, as RFC 7464 recommends
|
|
165
165
|
* parseSequence('\u001E{"id":1}\n\u001E{"id', { invalidRecords: 'skip' }) // => [{ id: 1 }]
|
|
166
|
-
* @since
|
|
166
|
+
* @since 3.1.3
|
|
167
167
|
*/
|
|
168
168
|
declare function parseSequence<T = unknown>(text: string, options?: ParseSequenceOptions): T[];
|
|
169
169
|
|
|
@@ -196,7 +196,7 @@ declare function parseSequence<T = unknown>(text: string, options?: ParseSequenc
|
|
|
196
196
|
* @example
|
|
197
197
|
* parseStrict<{ a: number }>('{"a":1}') // => { a: 1 }
|
|
198
198
|
* parseStrict('{"a":1,}') // throws SyntaxError (trailing comma)
|
|
199
|
-
* @since
|
|
199
|
+
* @since 3.1.3
|
|
200
200
|
*/
|
|
201
201
|
declare function parseStrict<T = unknown>(text: string): T;
|
|
202
202
|
|
|
@@ -225,7 +225,7 @@ declare function parseStrict<T = unknown>(text: string): T;
|
|
|
225
225
|
* safeParse("{ a: 'x' }") // => { a: 'x' } (JSON5)
|
|
226
226
|
* safeParse('not json') // => null
|
|
227
227
|
* safeParse('not json', {}) // => {}
|
|
228
|
-
* @since
|
|
228
|
+
* @since 3.1.3
|
|
229
229
|
*/
|
|
230
230
|
declare function safeParse<T = unknown>(text: string): T | null;
|
|
231
231
|
declare function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F;
|
|
@@ -257,7 +257,7 @@ declare function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F
|
|
|
257
257
|
* safeParseLines('{"id":1}\n{"id":2}') // => [{ id: 1 }, { id: 2 }]
|
|
258
258
|
* safeParseLines('{"id":1}\n{"id":') // => null
|
|
259
259
|
* safeParseLines('{"id":1}\n\n', null, { blankLines: 'fail' }) // => null
|
|
260
|
-
* @since
|
|
260
|
+
* @since 3.1.3
|
|
261
261
|
*/
|
|
262
262
|
declare function safeParseLines<T = unknown>(text: string): T[] | null;
|
|
263
263
|
declare function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseLinesOptions): T[] | F;
|
|
@@ -289,7 +289,7 @@ declare function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F,
|
|
|
289
289
|
* safeParseSequence('\u001E{"id":1}\n') // => [{ id: 1 }]
|
|
290
290
|
* safeParseSequence('\u001E{"id"\n') // => null
|
|
291
291
|
* safeParseSequence('\u001E{"id"\n', []) // => []
|
|
292
|
-
* @since
|
|
292
|
+
* @since 3.1.3
|
|
293
293
|
*/
|
|
294
294
|
declare function safeParseSequence<T = unknown>(text: string): T[] | null;
|
|
295
295
|
declare function safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseSequenceOptions): T[] | F;
|
|
@@ -318,7 +318,7 @@ declare function safeParseSequence<T = unknown, F = T[]>(text: string, fallback:
|
|
|
318
318
|
* safeParseStrict<{ a: number }>('{"a":1}') // => { a: 1 }
|
|
319
319
|
* safeParseStrict('{"a":1,}') // => null
|
|
320
320
|
* safeParseStrict('oops', {}) // => {}
|
|
321
|
-
* @since
|
|
321
|
+
* @since 3.1.3
|
|
322
322
|
*/
|
|
323
323
|
declare function safeParseStrict<T = unknown>(text: string): T | null;
|
|
324
324
|
declare function safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F;
|
|
@@ -332,7 +332,7 @@ declare function safeParseStrict<T = unknown, F = T>(text: string, fallback: F):
|
|
|
332
332
|
* How {@link stringify} lays out its output:
|
|
333
333
|
* - `{ indent }` — pretty-printed with `indent` spaces per level (`0` for a compact single line)
|
|
334
334
|
* - `'canonical'` — canonical JSON (RFC 8785), byte-for-byte reproducible
|
|
335
|
-
* @since
|
|
335
|
+
* @since 3.1.3
|
|
336
336
|
*/
|
|
337
337
|
type StringifyFormatting = 'canonical' | {
|
|
338
338
|
indent?: number;
|
|
@@ -377,7 +377,7 @@ type StringifyFormatting = 'canonical' | {
|
|
|
377
377
|
* @example
|
|
378
378
|
* stringify({ b: 1, a: [true] }, { indent: 0 }) // => '{"b":1,"a":[true]}'
|
|
379
379
|
* stringify({ b: 1, a: [true] }, 'canonical') // => '{"a":[true],"b":1}'
|
|
380
|
-
* @since
|
|
380
|
+
* @since 3.1.3
|
|
381
381
|
*/
|
|
382
382
|
declare function stringify(value: unknown, formatting?: StringifyFormatting): string;
|
|
383
383
|
|
|
@@ -418,7 +418,7 @@ declare function stringify(value: unknown, formatting?: StringifyFormatting): st
|
|
|
418
418
|
* stringifyLines([{ id: 1 }, { id: 2 }]) // => '{"id":1}\n{"id":2}\n'
|
|
419
419
|
* @example
|
|
420
420
|
* stringifyLines([{ b: 1, a: 2 }], 'canonical') // => '{"a":2,"b":1}\n'
|
|
421
|
-
* @since
|
|
421
|
+
* @since 3.1.3
|
|
422
422
|
*/
|
|
423
423
|
declare function stringifyLines(values: readonly unknown[], formatting?: 'canonical'): string;
|
|
424
424
|
|
|
@@ -455,7 +455,7 @@ declare function stringifyLines(values: readonly unknown[], formatting?: 'canoni
|
|
|
455
455
|
* @see {@link stringifyLines} — newline-delimited JSON (NDJSON, JSON Lines)
|
|
456
456
|
* @example
|
|
457
457
|
* stringifySequence([{ id: 1 }, 2]) // => '\u001E{"id":1}\n\u001E2\n'
|
|
458
|
-
* @since
|
|
458
|
+
* @since 3.1.3
|
|
459
459
|
*/
|
|
460
460
|
declare function stringifySequence(values: readonly unknown[], formatting?: 'canonical'): string;
|
|
461
461
|
|
package/lib/index.js
CHANGED
|
@@ -442,7 +442,7 @@ function stripJsonComments(input) {
|
|
|
442
442
|
* }`) // => { outDir: 'dist' }
|
|
443
443
|
* @example
|
|
444
444
|
* parse("{ name: 'app', retries: 0x3, ratio: .5, }") // => { name: 'app', retries: 3, ratio: 0.5 }
|
|
445
|
-
* @since
|
|
445
|
+
* @since 3.1.3
|
|
446
446
|
*/
|
|
447
447
|
function parse(text) {
|
|
448
448
|
const input = text.startsWith("") ? text.slice(1) : text;
|
|
@@ -489,7 +489,7 @@ var LINE_FEED = "\n";
|
|
|
489
489
|
* parseLines('{"id":1}\n{"id":2}\n') // => [{ id: 1 }, { id: 2 }]
|
|
490
490
|
* @example
|
|
491
491
|
* parseLines('{"id":1}\n{"id":', { invalidLines: 'skip' }) // => [{ id: 1 }]
|
|
492
|
-
* @since
|
|
492
|
+
* @since 3.1.3
|
|
493
493
|
*/
|
|
494
494
|
function parseLines(text, options = {}) {
|
|
495
495
|
const { blankLines = "skip", invalidLines = "fail" } = options;
|
|
@@ -552,7 +552,7 @@ var TRAILING_JSON_WHITESPACE = /[ \t\n\r]$/;
|
|
|
552
552
|
* @example
|
|
553
553
|
* // A crash cut the last record: skip it, as RFC 7464 recommends
|
|
554
554
|
* parseSequence('\u001E{"id":1}\n\u001E{"id', { invalidRecords: 'skip' }) // => [{ id: 1 }]
|
|
555
|
-
* @since
|
|
555
|
+
* @since 3.1.3
|
|
556
556
|
*/
|
|
557
557
|
function parseSequence(text, options = {}) {
|
|
558
558
|
const { invalidRecords = "fail" } = options;
|
|
@@ -611,7 +611,7 @@ function parseSequence(text, options = {}) {
|
|
|
611
611
|
* @example
|
|
612
612
|
* parseStrict<{ a: number }>('{"a":1}') // => { a: 1 }
|
|
613
613
|
* parseStrict('{"a":1,}') // throws SyntaxError (trailing comma)
|
|
614
|
-
* @since
|
|
614
|
+
* @since 3.1.3
|
|
615
615
|
*/
|
|
616
616
|
function parseStrict(text) {
|
|
617
617
|
return JSON.parse(text);
|
|
@@ -801,7 +801,7 @@ var MAX_INDENT = 10;
|
|
|
801
801
|
* @example
|
|
802
802
|
* stringify({ b: 1, a: [true] }, { indent: 0 }) // => '{"b":1,"a":[true]}'
|
|
803
803
|
* stringify({ b: 1, a: [true] }, 'canonical') // => '{"a":[true],"b":1}'
|
|
804
|
-
* @since
|
|
804
|
+
* @since 3.1.3
|
|
805
805
|
*/
|
|
806
806
|
function stringify(value, formatting = {}) {
|
|
807
807
|
let text;
|
|
@@ -877,7 +877,7 @@ function serializeRecords(caller, values, formatting) {
|
|
|
877
877
|
* stringifyLines([{ id: 1 }, { id: 2 }]) // => '{"id":1}\n{"id":2}\n'
|
|
878
878
|
* @example
|
|
879
879
|
* stringifyLines([{ b: 1, a: 2 }], 'canonical') // => '{"a":2,"b":1}\n'
|
|
880
|
-
* @since
|
|
880
|
+
* @since 3.1.3
|
|
881
881
|
*/
|
|
882
882
|
function stringifyLines(values, formatting) {
|
|
883
883
|
return serializeRecords("stringifyLines", values, formatting).map((line) => `${line}\n`).join("");
|
|
@@ -917,7 +917,7 @@ function stringifyLines(values, formatting) {
|
|
|
917
917
|
* @see {@link stringifyLines} — newline-delimited JSON (NDJSON, JSON Lines)
|
|
918
918
|
* @example
|
|
919
919
|
* stringifySequence([{ id: 1 }, 2]) // => '\u001E{"id":1}\n\u001E2\n'
|
|
920
|
-
* @since
|
|
920
|
+
* @since 3.1.3
|
|
921
921
|
*/
|
|
922
922
|
function stringifySequence(values, formatting) {
|
|
923
923
|
return serializeRecords("stringifySequence", values, formatting).map((text) => `\u001E${text}\n`).join("");
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../helpers/_shared/_jsonReader.ts","../../../helpers/_shared/_stripJsonComments.ts","../../../helpers/json/parse.ts","../../../helpers/json/parseLines.ts","../../../helpers/json/parseSequence.ts","../../../helpers/json/parseStrict.ts","../../../helpers/json/safeParse.ts","../../../helpers/json/safeParseLines.ts","../../../helpers/json/safeParseSequence.ts","../../../helpers/json/safeParseStrict.ts","../../../helpers/json/_canonical.ts","../../../helpers/json/stringify.ts","../../../helpers/json/_serializeRecords.ts","../../../helpers/json/stringifyLines.ts","../../../helpers/json/stringifySequence.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal JSON / JSON5 reader shared by `json/parse` (JSON5) and the `guard/isJson5` and\n * `guard/isIJson` guards. Written from the JSON5 1.0.0 specification (https://spec.json5.org)\n * and RFC 7493 (I-JSON), not from any existing implementation. Not exported from any package\n * barrel — tests live in _jsonReader.test.ts.\n */\n\n/**\n * Which grammar {@link readJson} reads:\n * - `'json5'` — JSON5 1.0.0, a superset of JSON (and of JSONC)\n * - `'json'` — strict JSON (RFC 8259), exactly what `JSON.parse` accepts\n * @ignore\n */\nexport type JsonDialect = 'json5' | 'json';\n\n/** @ignore */\nexport interface ReadJsonOptions {\n dialect: JsonDialect;\n /**\n * Also enforce I-JSON (RFC 7493) on top of the grammar: no duplicate object keys, no lone\n * surrogate or noncharacter in strings, and no number beyond what a double holds exactly.\n */\n iJson?: boolean;\n}\n\n/** JSON5 whitespace: JSON's four, plus VT, FF, NBSP, LS, PS, BOM and every Unicode space separator. @ignore */\nconst JSON5_SPACE = /[\\t\\n\\v\\f\\r \\u00A0\\u2028\\u2029\\uFEFF\\p{Zs}]/u;\n/** @ignore */\nconst LINE_TERMINATOR = /[\\n\\r\\u2028\\u2029]/;\n/** First character of an unquoted JSON5 key (ECMAScript IdentifierStart). @ignore */\nconst IDENTIFIER_START = /[\\p{ID_Start}$_]/u;\n/** Any later character of an unquoted JSON5 key (ECMAScript IdentifierPart). @ignore */\nconst IDENTIFIER_PART = /[\\p{ID_Continue}$\\u200C\\u200D]/u;\n/** @ignore */\nconst HEX_DIGIT = /[0-9A-Fa-f]/;\n/** A lone surrogate or a Unicode noncharacter, which I-JSON forbids in strings. @ignore */\nconst I_JSON_FORBIDDEN =\n /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]|[\\uFDD0-\\uFDEF\\uFFFE\\uFFFF]|[\\uD83F\\uD87F\\uD8BF\\uD8FF\\uD93F\\uD97F\\uD9BF\\uD9FF\\uDA3F\\uDA7F\\uDABF\\uDAFF\\uDB3F\\uDB7F\\uDBBF\\uDBFF][\\uDFFE\\uDFFF]/;\n/** A double has 15 to 17 significant decimal digits; more than 17 expresses precision it can't hold. @ignore */\nconst MAX_SIGNIFICANT_DIGITS = 17;\n\n/** @ignore */\nfunction isDigit(char: string | undefined): boolean {\n return char !== undefined && char >= '0' && char <= '9';\n}\n\n/** 1-based line and column of `index` in `text`; `\\r\\n` counts as one line break. @ignore */\nfunction position(text: string, index: number): string {\n let line = 1;\n let lineStart = 0;\n for (let k = 0; k < index; k++) {\n const char = text[k];\n if (char === '\\n' || char === '\\u2028' || char === '\\u2029' || (char === '\\r' && text[k + 1] !== '\\n')) {\n line++;\n lineStart = k + 1;\n }\n }\n return `line ${line}, column ${index - lineStart + 1}`;\n}\n\n/** Defines `key` like `JSON.parse` does: `__proto__` becomes an own property, never the prototype. @ignore */\nfunction define(object: Record<string, unknown>, key: string, value: unknown): void {\n if (key === '__proto__') {\n Object.defineProperty(object, key, { value, writable: true, enumerable: true, configurable: true });\n } else {\n object[key] = value;\n }\n}\n\n/**\n * Reads one JSON or JSON5 value from `text`, the whole of it, and throws a `SyntaxError` naming\n * the line and column of the first problem otherwise. Builds values the way `JSON.parse` does\n * (same numbers, `__proto__` as an own property, the last of duplicate keys wins unless `iJson`).\n * @ignore\n */\nexport function readJson(text: string, { dialect, iJson = false }: ReadJsonOptions): unknown {\n const json5 = dialect === 'json5';\n let i = 0;\n\n const fail = (message: string, at: number = i): never => {\n throw new SyntaxError(`parse: ${message} at ${position(text, at)}`);\n };\n const unexpected = (): never =>\n i >= text.length ? fail('unexpected end of input') : fail(`unexpected character ${JSON.stringify(text[i])}`);\n\n const isSpace = (char: string): boolean =>\n json5 ? JSON5_SPACE.test(char) : char === ' ' || char === '\\t' || char === '\\n' || char === '\\r';\n\n const skipSpace = (): void => {\n while (i < text.length) {\n const char = text[i]!;\n if (isSpace(char)) {\n i++;\n } else if (json5 && char === '/' && text[i + 1] === '/') {\n i += 2;\n while (i < text.length && !LINE_TERMINATOR.test(text[i]!)) i++;\n } else if (json5 && char === '/' && text[i + 1] === '*') {\n const end = text.indexOf('*/', i + 2);\n if (end === -1) fail('unterminated block comment');\n i = end + 2;\n } else {\n return;\n }\n }\n };\n\n const hexDigits = (count: number): number => {\n const start = i;\n for (let k = 0; k < count; k++) {\n if (!HEX_DIGIT.test(text[i] ?? '')) unexpected();\n i++;\n }\n return Number.parseInt(text.slice(start, i), 16);\n };\n\n const literal = <T>(word: string, result: T): T => {\n for (const expected of word) {\n if (text[i] !== expected) unexpected();\n i++;\n }\n return result;\n };\n\n const checkIJsonNumber = (raw: string, parsed: number, at: number): void => {\n if (!Number.isFinite(parsed)) fail(`number ${raw} is beyond the range of a double (I-JSON)`, at);\n const mantissa = raw.replace(/^[+-]/, '').split(/[eE]/)[0]!.replace('.', '');\n const significant = mantissa.replace(/^0+/, '').replace(/0+$/, '');\n if (significant.length > MAX_SIGNIFICANT_DIGITS || (parsed === 0 && significant !== '')) {\n fail(`number ${raw} is more precise than a double holds (I-JSON)`, at);\n }\n if (/^-?\\d+$/.test(raw) && !Number.isSafeInteger(parsed)) {\n fail(`integer ${raw} is outside the exact range of a double (I-JSON)`, at);\n }\n };\n\n const number = (): number => {\n const start = i;\n let sign = 1;\n if (text[i] === '-' || (json5 && text[i] === '+')) {\n if (text[i] === '-') sign = -1;\n i++;\n }\n if (json5) {\n if (text.startsWith('Infinity', i)) return sign * literal('Infinity', Infinity);\n if (text.startsWith('NaN', i)) return literal('NaN', Number.NaN);\n if (text[i] === '0' && (text[i + 1] === 'x' || text[i + 1] === 'X')) {\n i += 2;\n const digitsStart = i;\n while (HEX_DIGIT.test(text[i] ?? '')) i++;\n if (i === digitsStart) unexpected();\n return sign * Number.parseInt(text.slice(digitsStart, i), 16);\n }\n }\n\n const integerStart = i;\n if (text[i] === '0') {\n i++;\n } else {\n while (isDigit(text[i])) i++;\n }\n const hasInteger = i > integerStart;\n if (!hasInteger && !(json5 && text[i] === '.')) unexpected();\n if (text[i] === '.') {\n i++;\n const fractionStart = i;\n while (isDigit(text[i])) i++;\n // JSON needs digits after the dot; JSON5 also allows \"1.\" but not a bare \".\".\n if (i === fractionStart && (!json5 || !hasInteger)) unexpected();\n }\n if (text[i] === 'e' || text[i] === 'E') {\n i++;\n if (text[i] === '+' || text[i] === '-') i++;\n const exponentStart = i;\n while (isDigit(text[i])) i++;\n if (i === exponentStart) unexpected();\n }\n const raw = text.slice(start, i);\n const parsed = Number(raw.replace(/^\\+/, ''));\n if (iJson) checkIJsonNumber(raw, parsed, start);\n return parsed;\n };\n\n const escape = (): string => {\n i++; // the backslash\n const char = text[i];\n switch (char) {\n case '\"':\n case '\\\\':\n case '/':\n i++;\n return char;\n case 'b':\n i++;\n return '\\b';\n case 'f':\n i++;\n return '\\f';\n case 'n':\n i++;\n return '\\n';\n case 'r':\n i++;\n return '\\r';\n case 't':\n i++;\n return '\\t';\n case 'u':\n i++;\n return String.fromCharCode(hexDigits(4));\n }\n if (!json5 || char === undefined || (isDigit(char) && char !== '0')) return unexpected();\n i++;\n switch (char) {\n case 'v':\n return '\\v';\n case '0':\n if (isDigit(text[i])) unexpected();\n return '\\0';\n case 'x':\n return String.fromCharCode(hexDigits(2));\n case '\\r':\n if (text[i] === '\\n') i++;\n return '';\n case '\\n':\n case '\\u2028':\n case '\\u2029':\n return '';\n default:\n // JSON5 NonEscapeCharacter: any other character stands for itself (`\\'`, `\\a`, …).\n return char;\n }\n };\n\n const string = (quote: string): string => {\n const start = i;\n i++;\n let result = '';\n for (;;) {\n const char = text[i];\n if (char === undefined) fail('unterminated string', start);\n if (char === quote) break;\n if (char === '\\\\') {\n result += escape();\n } else {\n // JSON forbids every raw control character; JSON5 only forbids the line breaks.\n if (char === '\\n' || char === '\\r' || (!json5 && char! < ' ')) unexpected();\n result += char;\n i++;\n }\n }\n i++;\n if (iJson && I_JSON_FORBIDDEN.test(result)) {\n fail('string holds a lone surrogate or a noncharacter (I-JSON)', start);\n }\n return result;\n };\n\n const identifier = (): string => {\n let name = '';\n for (;;) {\n const pattern = name === '' ? IDENTIFIER_START : IDENTIFIER_PART;\n if (text[i] === '\\\\') {\n const at = i;\n i++;\n if (text[i] !== 'u') unexpected();\n i++;\n const char = String.fromCharCode(hexDigits(4));\n if (!pattern.test(char)) fail(`invalid key character ${JSON.stringify(char)}`, at);\n name += char;\n } else {\n const codePoint = text.codePointAt(i);\n const char = codePoint === undefined ? '' : String.fromCodePoint(codePoint);\n if (char === '' || !pattern.test(char)) break;\n name += char;\n i += char.length;\n }\n }\n if (name === '') unexpected();\n return name;\n };\n\n const key = (): string => {\n if (text[i] === '\"') return string('\"');\n if (!json5) return unexpected();\n return text[i] === \"'\" ? string(\"'\") : identifier();\n };\n\n // `value` and the two container readers call each other, so they're hoisted declarations.\n function object(): Record<string, unknown> {\n i++;\n const result: Record<string, unknown> = {};\n const seen = iJson ? new Set<string>() : undefined;\n skipSpace();\n if (text[i] === '}') {\n i++;\n return result;\n }\n for (;;) {\n const keyStart = i;\n const name = key();\n if (seen) {\n if (seen.has(name)) fail(`duplicate key ${JSON.stringify(name)} (I-JSON)`, keyStart);\n seen.add(name);\n }\n skipSpace();\n if (text[i] !== ':') unexpected();\n i++;\n skipSpace();\n define(result, name, value());\n skipSpace();\n if (text[i] === ',') {\n i++;\n skipSpace();\n if (json5 && text[i] === '}') break;\n } else if (text[i] === '}') {\n break;\n } else {\n unexpected();\n }\n }\n i++;\n return result;\n }\n\n function array(): unknown[] {\n i++;\n const result: unknown[] = [];\n skipSpace();\n if (text[i] === ']') {\n i++;\n return result;\n }\n for (;;) {\n result.push(value());\n skipSpace();\n if (text[i] === ',') {\n i++;\n skipSpace();\n if (json5 && text[i] === ']') break;\n } else if (text[i] === ']') {\n break;\n } else {\n unexpected();\n }\n }\n i++;\n return result;\n }\n\n function value(): unknown {\n switch (text[i]) {\n case '{':\n return object();\n case '[':\n return array();\n case '\"':\n return string('\"');\n case \"'\":\n return json5 ? string(\"'\") : unexpected();\n case 't':\n return literal('true', true);\n case 'f':\n return literal('false', false);\n case 'n':\n return literal('null', null);\n default:\n return number();\n }\n }\n\n skipSpace();\n if (i >= text.length) unexpected();\n const result = value();\n skipSpace();\n if (i < text.length) unexpected();\n return result;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal helper used by `node/safeReadJsonFile` and `json/parse` to support JSONC (JSON with\n * line and block comments, plus trailing commas) — the dialect used by tsconfig.json, VS Code's\n * settings.json, etc. Not exported from any package barrel — tests live in\n * _stripJsonComments.test.ts.\n */\n\n/**\n * Blanks out line comments (starting with two slashes), block comments (slash-star ... star-slash),\n * and trailing commas (before `}` or `]`) in a JSONC string, so the result can be passed to\n * `JSON.parse`. String literals are tracked so a comment-like or comma character occurring\n * *inside* a JSON string (e.g. a URL) is left untouched — this is a string-boundary-aware pass,\n * not a naive regex strip.\n *\n * Everything removed is replaced by spaces (line breaks inside a block comment are kept), so the\n * output has exactly the same length and line layout as the input: a position `JSON.parse`\n * reports in an error on the output points at the same place in the original JSONC text.\n * @ignore\n */\nexport function stripJsonComments(input: string): string {\n let output = '';\n let inString = false;\n // A comma seen outside a string is held back instead of emitted immediately:\n // if the next significant token turns out to be `}`/`]`, it was a trailing\n // comma and gets blanked; otherwise it (and any whitespace/comments held\n // alongside it) is flushed once a real token confirms it wasn't trailing.\n let pendingComma = '';\n const flushPendingComma = () => {\n output += pendingComma;\n pendingComma = '';\n };\n // Whitespace and blanked-out comments don't resolve a pending comma either way, so they're\n // buffered alongside it to keep the output in the original order.\n const emitFiller = (text: string) => {\n if (pendingComma) {\n pendingComma += text;\n } else {\n output += text;\n }\n };\n\n let i = 0;\n while (i < input.length) {\n const char = input[i];\n\n if (inString) {\n output += char;\n if (char === '\\\\') {\n // Copy the escaped character as-is (whatever it is) so an escaped\n // quote (`\\\"`) doesn't get mistaken for the string's end.\n i++;\n if (i < input.length) output += input[i];\n } else if (char === '\"') {\n inString = false;\n }\n i++;\n continue;\n }\n\n if (char === '\"') {\n flushPendingComma();\n inString = true;\n output += char;\n i++;\n continue;\n }\n\n if (char === '/' && input[i + 1] === '/') {\n const start = i;\n i += 2;\n // Stop at any line-ending character, not just \\n — a bare \\r (classic\n // Mac line endings, or a lone \\r before a later \\n) also ends the line,\n // otherwise everything up to the next \\n (or EOF) gets silently eaten.\n while (i < input.length && input[i] !== '\\n' && input[i] !== '\\r') i++;\n emitFiller(' '.repeat(i - start));\n continue;\n }\n\n if (char === '/' && input[i + 1] === '*') {\n const start = i;\n i += 2;\n while (i < input.length && !(input[i] === '*' && input[i + 1] === '/')) i++;\n // An unterminated block comment runs to the end of the input.\n i = Math.min(i + 2, input.length);\n emitFiller(input.slice(start, i).replace(/[^\\r\\n]/g, ' '));\n continue;\n }\n\n if (char === ',') {\n flushPendingComma();\n pendingComma = char;\n i++;\n continue;\n }\n\n if (char === '}' || char === ']') {\n // Blank the comma — it was trailing — but keep what was buffered after it.\n output += pendingComma.replace(',', ' ');\n pendingComma = '';\n output += char;\n i++;\n continue;\n }\n\n if (char === ' ' || char === '\\t' || char === '\\n' || char === '\\r') {\n emitFiller(char);\n i++;\n continue;\n }\n\n flushPendingComma();\n output += char;\n i++;\n }\n\n flushPendingComma();\n return output;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { readJson } from '../_shared/_jsonReader';\nimport { stripJsonComments } from '../_shared/_stripJsonComments';\n\n/**\n * Parses JSON permissively: strict JSON, JSONC (the dialect of `tsconfig.json` and VS Code's\n * `settings.json`, also known as HuJSON or JWCC) and JSON5 — each a superset of the one before.\n *\n * **Accepts:**\n * - everything {@link parseStrict} accepts (strict JSON, RFC 8259)\n * - comments: `// …` to the end of the line, and `/* … *\\/`\n * - one trailing comma after the last item of an object or array\n * - object keys without quotes, when they are ECMAScript identifiers (`{ name: 1 }`, `{ $id: 1 }`)\n * - strings in single quotes, and in either quote: the escapes `\\'`, `\\v`, `\\0` and `\\xHH`, any\n * other escaped character standing for itself, and a backslash before a line break to continue\n * the string on the next line\n * - numbers with a leading `+`, a leading or trailing dot (`.5`, `5.`), in hexadecimal (`0x1F`),\n * and `Infinity`, `-Infinity` and `NaN`\n * - any Unicode whitespace between tokens, including a leading byte order mark (U+FEFF)\n *\n * **Rejects:** more than one trailing comma in a row, leading zeros (`01`), octal or binary\n * numbers, unquoted keys that aren't identifiers (`{ my-key: 1 }`), raw line breaks inside a\n * string, an unterminated comment or string, `undefined`, and more than one value.\n *\n * **On invalid input:** throws a `SyntaxError` naming the line and column of the first problem.\n *\n * Strict JSON goes straight to the native `JSON.parse`, and JSONC to `JSON.parse` after its\n * comments are blanked out; only text that is neither goes through the JSON5 reader (written for\n * helpers4 from the JSON5 1.0.0 specification), so the common cases cost nothing extra.\n *\n * Values are built as `JSON.parse` builds them: the last of duplicate keys wins, and a\n * `__proto__` key is an own property, never the prototype. `NaN` and `Infinity` have no JSON\n * representation — {@link stringify} writes them as `null`.\n *\n * @param text - The JSON, JSONC or JSON5 text to parse\n * @returns The parsed value, typed as `T`\n * @throws {SyntaxError} When `text` isn't JSON5 (and so neither JSONC nor JSON)\n * @see {@link safeParse} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link parseStrict} — strict JSON only, e.g. to validate an API payload\n * @see {@link parseLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link parseSequence} — JSON text sequences (RFC 7464)\n * @example\n * parse('{\"a\":1}') // => { a: 1 }\n * @example\n * parse(`{\n * // the output directory\n * \"outDir\": \"dist\",\n * }`) // => { outDir: 'dist' }\n * @example\n * parse(\"{ name: 'app', retries: 0x3, ratio: .5, }\") // => { name: 'app', retries: 3, ratio: 0.5 }\n * @since next\n */\nexport function parse<T = unknown>(text: string): T {\n const input = text.startsWith('\\ufeff') ? text.slice(1) : text;\n try {\n return JSON.parse(input) as T;\n } catch {\n try {\n return JSON.parse(stripJsonComments(input)) as T;\n } catch {\n return readJson(input, { dialect: 'json5' }) as T;\n }\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link parseLines} and {@link safeParseLines}.\n * @since next\n */\nexport interface ParseLinesOptions {\n /**\n * What to do with a blank (empty or whitespace-only) line:\n * - `'skip'` (default) — ignore it, as NDJSON allows\n * - `'fail'` — treat it as invalid, as JSON Lines requires (*\"a blank line is not\"* a valid value)\n *\n * A single line break at the very end of the text is a terminator, not a blank line, and is\n * always accepted.\n */\n blankLines?: 'skip' | 'fail';\n /**\n * What to do with a line that isn't valid JSON:\n * - `'fail'` (default) — the whole parse fails, as NDJSON says a parser should\n * - `'skip'` — drop that line and keep the others, e.g. for a log whose last line was\n * truncated by a crash\n */\n invalidLines?: 'fail' | 'skip';\n}\n\n/** @ignore */\nconst LINE_FEED = '\\n';\n\n/**\n * Parses newline-delimited JSON — one JSON value per line. Covers both NDJSON\n * (`application/x-ndjson`, `.ndjson`) and JSON Lines (`.jsonl`), which are the same format.\n *\n * **Accepts:**\n * - one strict JSON value per line (each line is read like {@link parseStrict})\n * - `\\n` and `\\r\\n` line endings\n * - a trailing line break after the last value, or none\n * - blank lines, skipped by default (see {@link ParseLinesOptions.blankLines})\n * - an empty text, which holds zero values\n *\n * **Rejects:** comments, trailing commas and any other non-strict JSON on a line, a value spread\n * over several lines, and a leading byte order mark (JSON Lines forbids it).\n *\n * **On invalid input:** throws a `SyntaxError` naming the 1-based line number, with the\n * original parse error as its `cause` — unless `invalidLines`/`blankLines` say to skip it.\n *\n * @param text - The newline-delimited JSON text\n * @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}\n * @returns The parsed values, in line order, typed as `T[]`\n * @throws {SyntaxError} When a line isn't valid JSON (or is blank with `blankLines: 'fail'`)\n * @see {@link safeParseLines} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link stringifyLines} — the reverse operation\n * @see {@link parseSequence} — JSON text sequences (RFC 7464), the record-separator variant\n * @see {@link parse} — a single JSON or JSONC value\n * @example\n * parseLines('{\"id\":1}\\n{\"id\":2}\\n') // => [{ id: 1 }, { id: 2 }]\n * @example\n * parseLines('{\"id\":1}\\n{\"id\":', { invalidLines: 'skip' }) // => [{ id: 1 }]\n * @since next\n */\nexport function parseLines<T = unknown>(text: string, options: ParseLinesOptions = {}): T[] {\n const { blankLines = 'skip', invalidLines = 'fail' } = options;\n if (text === '') return [];\n\n const lines = text.split(LINE_FEED);\n // A line break after the last value terminates it; it doesn't open an empty last line.\n if (text.endsWith(LINE_FEED)) lines.pop();\n\n const values: T[] = [];\n lines.forEach((line, index) => {\n const lineNumber = index + 1;\n if (line.trim() === '') {\n if (blankLines === 'fail') {\n throw new SyntaxError(`parseLines: line ${lineNumber} is blank`);\n }\n return;\n }\n try {\n values.push(JSON.parse(line) as T);\n } catch (error) {\n if (invalidLines === 'fail') {\n throw new SyntaxError(`parseLines: line ${lineNumber}: ${(error as Error).message}`, { cause: error });\n }\n }\n });\n return values;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link parseSequence} and {@link safeParseSequence}.\n * @since next\n */\nexport interface ParseSequenceOptions {\n /**\n * What to do with a record that isn't a valid, complete JSON text:\n * - `'fail'` (default) — the whole parse fails, like every other `parse*` helper\n * - `'skip'` — drop that record and keep the others. RFC 7464 recommends this (*\"parsers should\n * not abort when an octet string contains a malformed JSON text\"*), for logs whose records\n * may have been truncated by a crash.\n */\n invalidRecords?: 'fail' | 'skip';\n}\n\n/** The ASCII record separator that starts every record of a JSON text sequence. @ignore */\nconst RECORD_SEPARATOR = '\\u001E';\n\n/**\n * JSON whitespace, the only thing that can end a top-level number, `true`, `false` or `null` —\n * without it, RFC 7464 §2.4 says such a record may have been truncated (`123` cut from `1234`).\n * @ignore\n */\nconst TRAILING_JSON_WHITESPACE = /[ \\t\\n\\r]$/;\n\n/**\n * Parses a JSON text sequence (RFC 7464, `application/json-seq`): records that each start with\n * the ASCII record separator (RS, U+001E) and hold one JSON text, as written by `jq --seq`.\n *\n * **Accepts:**\n * - one strict JSON value per record (each record is read like {@link parseStrict})\n * - JSON values spread over several lines inside a record — unlike {@link parseLines}\n * - several RS in a row (empty records are ignored, as the RFC's grammar allows)\n * - an empty text, which holds zero records\n *\n * **Rejects (as invalid records):**\n * - anything before the first RS\n * - a record that isn't strict JSON, or holds only whitespace\n * - a top-level number, `true`, `false` or `null` not followed by whitespace — RFC 7464 §2.4\n * requires dropping it, since it may have been truncated\n *\n * **On invalid input:** throws a `SyntaxError` naming the 1-based record number, with the\n * original parse error (if any) as its `cause` — unless `invalidRecords: 'skip'` says to drop it.\n *\n * @param text - The JSON text sequence\n * @param options - How to handle invalid records — see {@link ParseSequenceOptions}\n * @returns The parsed values, in record order, typed as `T[]`\n * @throws {SyntaxError} When a record is invalid and `invalidRecords` is `'fail'`\n * @see {@link safeParseSequence} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link stringifySequence} — the reverse operation\n * @see {@link parseLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * parseSequence('\\u001E{\"id\":1}\\n\\u001E{\"id\":2}\\n') // => [{ id: 1 }, { id: 2 }]\n * @example\n * // A crash cut the last record: skip it, as RFC 7464 recommends\n * parseSequence('\\u001E{\"id\":1}\\n\\u001E{\"id', { invalidRecords: 'skip' }) // => [{ id: 1 }]\n * @since next\n */\nexport function parseSequence<T = unknown>(text: string, options: ParseSequenceOptions = {}): T[] {\n const { invalidRecords = 'fail' } = options;\n const [beforeFirst, ...records] = text.split(RECORD_SEPARATOR);\n\n const invalid = (where: string, reason: string, cause?: unknown): void => {\n if (invalidRecords === 'fail') {\n throw new SyntaxError(`parseSequence: ${where}: ${reason}`, cause === undefined ? undefined : { cause });\n }\n };\n\n // `split` always returns at least one element, so `beforeFirst` is always a string.\n if (beforeFirst!.trim() !== '') invalid('before the first record', 'text outside any record (missing record separator)');\n\n const values: T[] = [];\n records.forEach((record, index) => {\n const where = `record ${index + 1}`;\n if (record === '') return;\n let value: unknown;\n try {\n value = JSON.parse(record);\n } catch (error) {\n invalid(where, (error as Error).message, error);\n return;\n }\n const selfDelimited = (typeof value === 'object' && value !== null) || typeof value === 'string';\n if (!selfDelimited && !TRAILING_JSON_WHITESPACE.test(record)) {\n invalid(where, `top-level ${JSON.stringify(value)} is not followed by whitespace and may be truncated`);\n return;\n }\n values.push(value as T);\n });\n return values;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Parses strict JSON (RFC 8259) — exactly what `JSON.parse` accepts, nothing more.\n *\n * **Accepts:** standard JSON only — double-quoted strings and keys, finite decimal numbers,\n * `true`/`false`/`null`, objects and arrays, surrounding whitespace.\n *\n * **Rejects:** comments, trailing commas, single quotes, unquoted keys, hexadecimal numbers,\n * `NaN`/`Infinity`, a leading byte order mark (U+FEFF), and anything else that isn't strict JSON.\n *\n * **On invalid input:** throws the native `SyntaxError` from `JSON.parse`.\n *\n * Use it to validate input that must be strict JSON, e.g. an API payload. To also read config\n * files with comments or JSON5, use {@link parse}. To never throw, use {@link safeParseStrict}.\n *\n * @param text - The JSON text to parse\n * @returns The parsed value, typed as `T`\n * @throws {SyntaxError} When `text` isn't strict JSON\n * @see {@link safeParseStrict} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link parse} — also accepts JSONC and JSON5\n * @see {@link parseLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link parseSequence} — JSON text sequences (RFC 7464)\n * @example\n * parseStrict<{ a: number }>('{\"a\":1}') // => { a: 1 }\n * parseStrict('{\"a\":1,}') // throws SyntaxError (trailing comma)\n * @since next\n */\nexport function parseStrict<T = unknown>(text: string): T {\n return JSON.parse(text) as T;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { parse } from './parse';\n\n/**\n * Parses JSON permissively like {@link parse} — strict JSON, JSONC (HuJSON, JWCC) and JSON5 —\n * but returns `null` (or `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parse} does — see there for the full list.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws.\n *\n * @param text - The JSON, JSONC or JSON5 text to parse\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @see {@link parse} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseStrict} — strict JSON only\n * @see {@link safeParseLines} — one value per line (NDJSON, JSON Lines)\n * @example\n * safeParse('{\"a\":1, /* note *\\/}') // => { a: 1 }\n * safeParse(\"{ a: 'x' }\") // => { a: 'x' } (JSON5)\n * safeParse('not json') // => null\n * safeParse('not json', {}) // => {}\n * @since next\n */\nexport function safeParse<T = unknown>(text: string): T | null;\nexport function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F;\nexport function safeParse<T, F>(text: string, fallback?: F): T | F | null {\n try {\n return parse<T>(text);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { type ParseLinesOptions, parseLines } from './parseLines';\n\n/**\n * Parses newline-delimited JSON (NDJSON, JSON Lines) like {@link parseLines}, but returns `null`\n * (or `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseLines} does, with the same\n * {@link ParseLinesOptions}.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\n * a fallback, pass `null` as the fallback.\n *\n * @param text - The newline-delimited JSON text\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}\n * @returns The parsed values typed as `T[]`, or `fallback` on invalid input\n * @see {@link parseLines} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseSequence} — JSON text sequences (RFC 7464)\n * @example\n * safeParseLines('{\"id\":1}\\n{\"id\":2}') // => [{ id: 1 }, { id: 2 }]\n * safeParseLines('{\"id\":1}\\n{\"id\":') // => null\n * safeParseLines('{\"id\":1}\\n\\n', null, { blankLines: 'fail' }) // => null\n * @since next\n */\nexport function safeParseLines<T = unknown>(text: string): T[] | null;\nexport function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseLinesOptions): T[] | F;\nexport function safeParseLines<T, F>(text: string, fallback?: F, options?: ParseLinesOptions): T[] | F | null {\n try {\n return parseLines<T>(text, options);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { type ParseSequenceOptions, parseSequence } from './parseSequence';\n\n/**\n * Parses a JSON text sequence (RFC 7464) like {@link parseSequence}, but returns `null` (or\n * `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseSequence} does, with the same\n * {@link ParseSequenceOptions}.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\n * a fallback, pass `null` as the fallback.\n *\n * @param text - The JSON text sequence\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @param options - How to handle invalid records — see {@link ParseSequenceOptions}\n * @returns The parsed values typed as `T[]`, or `fallback` on invalid input\n * @see {@link parseSequence} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * safeParseSequence('\\u001E{\"id\":1}\\n') // => [{ id: 1 }]\n * safeParseSequence('\\u001E{\"id\"\\n') // => null\n * safeParseSequence('\\u001E{\"id\"\\n', []) // => []\n * @since next\n */\nexport function safeParseSequence<T = unknown>(text: string): T[] | null;\nexport function safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseSequenceOptions): T[] | F;\nexport function safeParseSequence<T, F>(text: string, fallback?: F, options?: ParseSequenceOptions): T[] | F | null {\n try {\n return parseSequence<T>(text, options);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { parseStrict } from './parseStrict';\n\n/**\n * Parses strict JSON like {@link parseStrict}, but returns `null` (or `fallback`) instead of\n * throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseStrict} does — standard JSON only, no comments,\n * no trailing commas, no JSON5 syntax, no leading byte order mark.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws.\n *\n * @param text - The JSON text to parse\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @see {@link parseStrict} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParse} — also accepts JSONC and JSON5\n * @example\n * safeParseStrict<{ a: number }>('{\"a\":1}') // => { a: 1 }\n * safeParseStrict('{\"a\":1,}') // => null\n * safeParseStrict('oops', {}) // => {}\n * @since next\n */\nexport function safeParseStrict<T = unknown>(text: string): T | null;\nexport function safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F;\nexport function safeParseStrict<T, F>(text: string, fallback?: F): T | F | null {\n try {\n return parseStrict<T>(text);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal canonical JSON serializer (RFC 8785, JSON Canonicalization Scheme) shared by\n * stringify.ts, stringifyLines.ts and stringifySequence.ts. Not exported from the package\n * barrel — tests live in _canonical.test.ts.\n */\n\n/** A lone UTF-16 surrogate, which I-JSON (and so RFC 8785) forbids in strings and keys. @ignore */\nconst LONE_SURROGATE = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/** @ignore */\nfunction serializeString(value: string): string {\n if (LONE_SURROGATE.test(value)) {\n throw new RangeError(`stringify: canonical JSON can't hold a string with a lone surrogate: ${JSON.stringify(value)}`);\n }\n return JSON.stringify(value);\n}\n\n/**\n * Serializes `holder[key]` the way `JSON.stringify` would — same `toJSON` calls, same\n * unwrapping of `Number`/`String`/`Boolean` objects, same dropping of `undefined`, functions and\n * symbols — but with the RFC 8785 rules on top: object keys sorted by UTF-16 code units, no\n * whitespace, and an error instead of a silent `null` for `NaN`/`Infinity`. Numbers already\n * follow the RFC as is: it reuses ECMAScript's own number-to-string algorithm.\n *\n * Returns `undefined` for a value `JSON.stringify` would skip (so an object member is dropped\n * and an array item becomes `null`, as it would there).\n * @ignore\n */\nfunction serialize(holder: Record<string, unknown>, key: string, ancestors: unknown[]): string | undefined {\n let value: unknown = holder[key];\n if ((typeof value === 'object' && value !== null) || typeof value === 'bigint') {\n const toJSON = (value as { toJSON?: unknown }).toJSON;\n if (typeof toJSON === 'function') value = toJSON.call(value, key);\n }\n if (typeof value === 'object' && value !== null) {\n // Realm-safe check for a Number/String/Boolean wrapper object, which JSON.stringify unwraps.\n const tag = Object.prototype.toString.call(value);\n if (tag === '[object Number]') value = Number(value);\n else if (tag === '[object String]') value = String(value);\n else if (tag === '[object Boolean]') value = Boolean.prototype.valueOf.call(value);\n }\n\n switch (typeof value) {\n case 'boolean':\n return String(value);\n case 'number':\n if (!Number.isFinite(value)) {\n throw new RangeError(`stringify: canonical JSON can't hold ${value}`);\n }\n return JSON.stringify(value);\n case 'string':\n return serializeString(value);\n case 'bigint':\n throw new TypeError('stringify: a BigInt has no JSON representation');\n case 'object':\n break;\n default:\n // undefined, function, symbol\n return undefined;\n }\n if (value === null) return 'null';\n\n if (ancestors.includes(value)) {\n throw new TypeError('stringify: converting a circular structure to JSON');\n }\n ancestors.push(value);\n let result: string;\n if (Array.isArray(value)) {\n const items = value as unknown as Record<string, unknown>;\n result = `[${value.map((_, index) => serialize(items, String(index), ancestors) ?? 'null').join(',')}]`;\n } else {\n const object = value as Record<string, unknown>;\n const members: string[] = [];\n for (const member of Object.keys(object).toSorted()) {\n const serialized = serialize(object, member, ancestors);\n if (serialized !== undefined) members.push(`${serializeString(member)}:${serialized}`);\n }\n result = `{${members.join(',')}}`;\n }\n ancestors.pop();\n return result;\n}\n\n/**\n * Serializes `value` as canonical JSON (RFC 8785), or returns `undefined` when `JSON.stringify`\n * would (a top-level `undefined`, function or symbol).\n * @ignore\n */\nexport function stringifyCanonical(value: unknown): string | undefined {\n return serialize({ '': value }, '', []);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { stringifyCanonical } from './_canonical';\n\n/**\n * How {@link stringify} lays out its output:\n * - `{ indent }` — pretty-printed with `indent` spaces per level (`0` for a compact single line)\n * - `'canonical'` — canonical JSON (RFC 8785), byte-for-byte reproducible\n * @since next\n */\nexport type StringifyFormatting = 'canonical' | { indent?: number };\n\n/** @ignore */\nconst DEFAULT_INDENT = 2;\n/** @ignore */\nconst MAX_INDENT = 10;\n\n/**\n * Serializes a value to JSON text — pretty-printed with 2 spaces by default, or canonical.\n *\n * **Formatting:**\n * - default — indented with 2 spaces, like a hand-written config file\n * - `{ indent: n }` — indented with `n` spaces (an integer from 0 to 10); `{ indent: 0 }` gives a\n * compact single line, the same as `JSON.stringify(value)`\n * - `'canonical'` — canonical JSON (RFC 8785, JSON Canonicalization Scheme): object keys sorted\n * by UTF-16 code units, no whitespace at all, numbers in their shortest ECMAScript form. Two\n * equal values always give the same bytes, so the output can be hashed, signed or compared.\n * Canonical output can't be indented — the RFC fixes every byte.\n *\n * **Same as `JSON.stringify`:** `toJSON()` is called (a `Date` becomes its ISO string),\n * `undefined`, functions and symbols are dropped from objects and become `null` in arrays, and\n * `Number`/`String`/`Boolean` objects are unwrapped. Outside `'canonical'`, `NaN` and `±Infinity`\n * silently become `null`, as there.\n *\n * **Throws** instead of returning `undefined` or dropping data silently:\n * - a `TypeError` when `value` itself is `undefined`, a function or a symbol\n * - a `TypeError` on a circular structure or a `BigInt` (like `JSON.stringify`)\n * - with `'canonical'`, a `RangeError` on `NaN`, `±Infinity` or a string with a lone surrogate,\n * which canonical JSON can't hold\n * - a `RangeError` when `indent` isn't an integer from 0 to 10\n *\n * The output is strict JSON, so it is also valid JSONC and JSON5.\n *\n * @param value - The value to serialize\n * @param formatting - `{ indent }` (default `{ indent: 2 }`) or `'canonical'` — see {@link StringifyFormatting}\n * @returns The JSON text\n * @throws {TypeError} When `value` can't be represented as JSON\n * @throws {RangeError} On an invalid `indent`, or a value canonical JSON can't hold\n * @see {@link parse} / {@link parseStrict} — the reverse operation\n * @see {@link stringifyLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link stringifySequence} — JSON text sequences (RFC 7464)\n * @example\n * stringify({ b: 1, a: [true] })\n * // => '{\\n \"b\": 1,\\n \"a\": [\\n true\\n ]\\n}'\n * @example\n * stringify({ b: 1, a: [true] }, { indent: 0 }) // => '{\"b\":1,\"a\":[true]}'\n * stringify({ b: 1, a: [true] }, 'canonical') // => '{\"a\":[true],\"b\":1}'\n * @since next\n */\nexport function stringify(value: unknown, formatting: StringifyFormatting = {}): string {\n let text: string | undefined;\n if (formatting === 'canonical') {\n text = stringifyCanonical(value);\n } else {\n const { indent = DEFAULT_INDENT } = formatting;\n if (!Number.isInteger(indent) || indent < 0 || indent > MAX_INDENT) {\n throw new RangeError(`stringify: indent must be an integer from 0 to ${MAX_INDENT}, got ${indent}`);\n }\n text = JSON.stringify(value, null, indent);\n }\n if (text === undefined) {\n throw new TypeError(`stringify: ${typeof value} has no JSON representation`);\n }\n return text;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal helper shared by stringifyLines.ts and stringifySequence.ts. Not exported from the\n * package barrel — tests live in _serializeRecords.test.ts.\n */\n\nimport { stringifyCanonical } from './_canonical';\n\n/**\n * Serializes each value as one compact (or canonical) JSON text, for a format that holds one\n * value per record. Throws on a value with no JSON representation rather than writing a record\n * that would read back as something else.\n * @ignore\n */\nexport function serializeRecords(caller: string, values: readonly unknown[], formatting: 'canonical' | undefined): string[] {\n if (!Array.isArray(values)) {\n throw new TypeError(`${caller}: expected an array of values, got ${values === null ? 'null' : typeof values}`);\n }\n return values.map((value, index) => {\n const text = formatting === 'canonical' ? stringifyCanonical(value) : JSON.stringify(value);\n if (text === undefined) {\n throw new TypeError(`${caller}: the value at index ${index} (${typeof value}) has no JSON representation`);\n }\n return text;\n });\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { serializeRecords } from './_serializeRecords';\n\n/**\n * Serializes values as newline-delimited JSON — one compact JSON value per line, each followed\n * by `\\n`. The output is both NDJSON and JSON Lines (`.jsonl`), which are the same format.\n *\n * **Formatting:**\n * - default — each value compact, like `JSON.stringify(value)`\n * - `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes, for\n * hashing or diffing logs line by line\n *\n * Indentation isn't available: a line break inside a value would split it across lines. String\n * values can't break a line either — `JSON.stringify` escapes `\\n` and `\\r` inside them.\n *\n * **Output:** every value is followed by `\\n`, including the last one (NDJSON requires it, and\n * JSON Lines recommends it, so files can be concatenated). An empty array gives `''`.\n *\n * **Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\n * representation (`undefined`, a function, a symbol, a `BigInt`, a circular structure) — rather\n * than writing a line that would read back as something else. With `'canonical'`, also a\n * `RangeError` on `NaN`, `±Infinity` or a lone surrogate (see {@link stringify}).\n *\n * @param values - The values to write, one per line\n * @param formatting - `'canonical'` for canonical JSON lines; compact JSON by default\n * @returns The newline-delimited JSON text\n * @throws {TypeError} When `values` isn't an array, or a value has no JSON representation\n * @throws {RangeError} With `'canonical'`, on a value canonical JSON can't hold\n * @see {@link parseLines} — the reverse operation\n * @see {@link stringifySequence} — JSON text sequences (RFC 7464)\n * @see {@link stringify} — a single, possibly indented, JSON value\n * @example\n * stringifyLines([{ id: 1 }, { id: 2 }]) // => '{\"id\":1}\\n{\"id\":2}\\n'\n * @example\n * stringifyLines([{ b: 1, a: 2 }], 'canonical') // => '{\"a\":2,\"b\":1}\\n'\n * @since next\n */\nexport function stringifyLines(values: readonly unknown[], formatting?: 'canonical'): string {\n return serializeRecords('stringifyLines', values, formatting).map((line) => `${line}\\n`).join('');\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { serializeRecords } from './_serializeRecords';\n\n/**\n * Serializes values as a JSON text sequence (RFC 7464, `application/json-seq`): each value is\n * written as the ASCII record separator (RS, U+001E), the compact JSON text, then `\\n` — the\n * exact framing the RFC requires of encoders, as `jq --seq` writes it.\n *\n * **Formatting:**\n * - default — each value compact, like `JSON.stringify(value)`\n * - `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes\n *\n * Indentation isn't offered, for symmetry with {@link stringifyLines}: the trailing `\\n` is what\n * lets a reader detect a truncated top-level number, `true`, `false` or `null` (RFC 7464 §2.4).\n *\n * **Output:** an empty array gives `''`.\n *\n * **Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\n * representation (`undefined`, a function, a symbol, a `BigInt`, a circular structure). With\n * `'canonical'`, also a `RangeError` on `NaN`, `±Infinity` or a lone surrogate (see\n * {@link stringify}).\n *\n * @param values - The values to write, one per record\n * @param formatting - `'canonical'` for canonical JSON records; compact JSON by default\n * @returns The JSON text sequence\n * @throws {TypeError} When `values` isn't an array, or a value has no JSON representation\n * @throws {RangeError} With `'canonical'`, on a value canonical JSON can't hold\n * @see {@link parseSequence} — the reverse operation\n * @see {@link stringifyLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * stringifySequence([{ id: 1 }, 2]) // => '\\u001E{\"id\":1}\\n\\u001E2\\n'\n * @since next\n */\nexport function stringifySequence(values: readonly unknown[], formatting?: 'canonical'): string {\n return serializeRecords('stringifySequence', values, formatting).map((text) => `\\u001E${text}\\n`).join('');\n}\n"],"mappings":";;AA8BA,IAAM,cAAc;;AAEpB,IAAM,kBAAkB;;AAExB,IAAM,mBAAmB;;AAEzB,IAAM,kBAAkB;;AAExB,IAAM,YAAY;;AAElB,IAAM,mBACJ;;AAEF,IAAM,yBAAyB;;AAG/B,SAAS,QAAQ,MAAmC;CAClD,OAAO,SAAS,KAAA,KAAa,QAAQ,OAAO,QAAQ;AACtD;;AAGA,SAAS,SAAS,MAAc,OAAuB;CACrD,IAAI,OAAO;CACX,IAAI,YAAY;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;EAC9B,MAAM,OAAO,KAAK;EAClB,IAAI,SAAS,QAAQ,SAAS,YAAY,SAAS,YAAa,SAAS,QAAQ,KAAK,IAAI,OAAO,MAAO;GACtG;GACA,YAAY,IAAI;EAClB;CACF;CACA,OAAO,QAAQ,KAAK,WAAW,QAAQ,YAAY;AACrD;;AAGA,SAAS,OAAO,QAAiC,KAAa,OAAsB;CAClF,IAAI,QAAQ,aACV,OAAO,eAAe,QAAQ,KAAK;EAAE;EAAO,UAAU;EAAM,YAAY;EAAM,cAAc;CAAK,CAAC;MAElG,OAAO,OAAO;AAElB;;;;;;;AAQA,SAAgB,SAAS,MAAc,EAAE,SAAS,QAAQ,SAAmC;CAC3F,MAAM,QAAQ,YAAY;CAC1B,IAAI,IAAI;CAER,MAAM,QAAQ,SAAiB,KAAa,MAAa;EACvD,MAAM,IAAI,YAAY,UAAU,QAAQ,MAAM,SAAS,MAAM,EAAE,GAAG;CACpE;CACA,MAAM,mBACJ,KAAK,KAAK,SAAS,KAAK,yBAAyB,IAAI,KAAK,wBAAwB,KAAK,UAAU,KAAK,EAAE,GAAG;CAE7G,MAAM,WAAW,SACf,QAAQ,YAAY,KAAK,IAAI,IAAI,SAAS,OAAO,SAAS,OAAQ,SAAS,QAAQ,SAAS;CAE9F,MAAM,kBAAwB;EAC5B,OAAO,IAAI,KAAK,QAAQ;GACtB,MAAM,OAAO,KAAK;GAClB,IAAI,QAAQ,IAAI,GACd;QACK,IAAI,SAAS,SAAS,OAAO,KAAK,IAAI,OAAO,KAAK;IACvD,KAAK;IACL,OAAO,IAAI,KAAK,UAAU,CAAC,gBAAgB,KAAK,KAAK,EAAG,GAAG;GAC7D,OAAO,IAAI,SAAS,SAAS,OAAO,KAAK,IAAI,OAAO,KAAK;IACvD,MAAM,MAAM,KAAK,QAAQ,MAAM,IAAI,CAAC;IACpC,IAAI,QAAQ,IAAI,KAAK,4BAA4B;IACjD,IAAI,MAAM;GACZ,OACE;EAEJ;CACF;CAEA,MAAM,aAAa,UAA0B;EAC3C,MAAM,QAAQ;EACd,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK;GAC9B,IAAI,CAAC,UAAU,KAAK,KAAK,MAAM,EAAE,GAAG,WAAW;GAC/C;EACF;EACA,OAAO,OAAO,SAAS,KAAK,MAAM,OAAO,CAAC,GAAG,EAAE;CACjD;CAEA,MAAM,WAAc,MAAc,WAAiB;EACjD,KAAK,MAAM,YAAY,MAAM;GAC3B,IAAI,KAAK,OAAO,UAAU,WAAW;GACrC;EACF;EACA,OAAO;CACT;CAEA,MAAM,oBAAoB,KAAa,QAAgB,OAAqB;EAC1E,IAAI,CAAC,OAAO,SAAS,MAAM,GAAG,KAAK,UAAU,IAAI,4CAA4C,EAAE;EAE/F,MAAM,cADW,IAAI,QAAQ,SAAS,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,EAAE,CAAE,QAAQ,KAAK,EACrD,CAAA,CAAS,QAAQ,OAAO,EAAE,CAAC,CAAC,QAAQ,OAAO,EAAE;EACjE,IAAI,YAAY,SAAS,0BAA2B,WAAW,KAAK,gBAAgB,IAClF,KAAK,UAAU,IAAI,gDAAgD,EAAE;EAEvE,IAAI,UAAU,KAAK,GAAG,KAAK,CAAC,OAAO,cAAc,MAAM,GACrD,KAAK,WAAW,IAAI,mDAAmD,EAAE;CAE7E;CAEA,MAAM,eAAuB;EAC3B,MAAM,QAAQ;EACd,IAAI,OAAO;EACX,IAAI,KAAK,OAAO,OAAQ,SAAS,KAAK,OAAO,KAAM;GACjD,IAAI,KAAK,OAAO,KAAK,OAAO;GAC5B;EACF;EACA,IAAI,OAAO;GACT,IAAI,KAAK,WAAW,YAAY,CAAC,GAAG,OAAO,OAAO,QAAQ,YAAY,QAAQ;GAC9E,IAAI,KAAK,WAAW,OAAO,CAAC,GAAG,OAAO,QAAQ,OAAO,GAAU;GAC/D,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,OAAO,OAAO,KAAK,IAAI,OAAO,MAAM;IACnE,KAAK;IACL,MAAM,cAAc;IACpB,OAAO,UAAU,KAAK,KAAK,MAAM,EAAE,GAAG;IACtC,IAAI,MAAM,aAAa,WAAW;IAClC,OAAO,OAAO,OAAO,SAAS,KAAK,MAAM,aAAa,CAAC,GAAG,EAAE;GAC9D;EACF;EAEA,MAAM,eAAe;EACrB,IAAI,KAAK,OAAO,KACd;OAEA,OAAO,QAAQ,KAAK,EAAE,GAAG;EAE3B,MAAM,aAAa,IAAI;EACvB,IAAI,CAAC,cAAc,EAAE,SAAS,KAAK,OAAO,MAAM,WAAW;EAC3D,IAAI,KAAK,OAAO,KAAK;GACnB;GACA,MAAM,gBAAgB;GACtB,OAAO,QAAQ,KAAK,EAAE,GAAG;GAEzB,IAAI,MAAM,kBAAkB,CAAC,SAAS,CAAC,aAAa,WAAW;EACjE;EACA,IAAI,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK;GACtC;GACA,IAAI,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK;GACxC,MAAM,gBAAgB;GACtB,OAAO,QAAQ,KAAK,EAAE,GAAG;GACzB,IAAI,MAAM,eAAe,WAAW;EACtC;EACA,MAAM,MAAM,KAAK,MAAM,OAAO,CAAC;EAC/B,MAAM,SAAS,OAAO,IAAI,QAAQ,OAAO,EAAE,CAAC;EAC5C,IAAI,OAAO,iBAAiB,KAAK,QAAQ,KAAK;EAC9C,OAAO;CACT;CAEA,MAAM,eAAuB;EAC3B;EACA,MAAM,OAAO,KAAK;EAClB,QAAQ,MAAR;GACE,KAAK;GACL,KAAK;GACL,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO;GACT,KAAK;IACH;IACA,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC;EAC3C;EACA,IAAI,CAAC,SAAS,SAAS,KAAA,KAAc,QAAQ,IAAI,KAAK,SAAS,KAAM,OAAO,WAAW;EACvF;EACA,QAAQ,MAAR;GACE,KAAK,KACH,OAAO;GACT,KAAK;IACH,IAAI,QAAQ,KAAK,EAAE,GAAG,WAAW;IACjC,OAAO;GACT,KAAK,KACH,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC;GACzC,KAAK;IACH,IAAI,KAAK,OAAO,MAAM;IACtB,OAAO;GACT,KAAK;GACL,KAAK;GACL,KAAK,UACH,OAAO;GACT,SAEE,OAAO;EACX;CACF;CAEA,MAAM,UAAU,UAA0B;EACxC,MAAM,QAAQ;EACd;EACA,IAAI,SAAS;EACb,SAAS;GACP,MAAM,OAAO,KAAK;GAClB,IAAI,SAAS,KAAA,GAAW,KAAK,uBAAuB,KAAK;GACzD,IAAI,SAAS,OAAO;GACpB,IAAI,SAAS,MACX,UAAU,OAAO;QACZ;IAEL,IAAI,SAAS,QAAQ,SAAS,QAAS,CAAC,SAAS,OAAQ,KAAM,WAAW;IAC1E,UAAU;IACV;GACF;EACF;EACA;EACA,IAAI,SAAS,iBAAiB,KAAK,MAAM,GACvC,KAAK,4DAA4D,KAAK;EAExE,OAAO;CACT;CAEA,MAAM,mBAA2B;EAC/B,IAAI,OAAO;EACX,SAAS;GACP,MAAM,UAAU,SAAS,KAAK,mBAAmB;GACjD,IAAI,KAAK,OAAO,MAAM;IACpB,MAAM,KAAK;IACX;IACA,IAAI,KAAK,OAAO,KAAK,WAAW;IAChC;IACA,MAAM,OAAO,OAAO,aAAa,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,KAAK,IAAI,GAAG,KAAK,yBAAyB,KAAK,UAAU,IAAI,KAAK,EAAE;IACjF,QAAQ;GACV,OAAO;IACL,MAAM,YAAY,KAAK,YAAY,CAAC;IACpC,MAAM,OAAO,cAAc,KAAA,IAAY,KAAK,OAAO,cAAc,SAAS;IAC1E,IAAI,SAAS,MAAM,CAAC,QAAQ,KAAK,IAAI,GAAG;IACxC,QAAQ;IACR,KAAK,KAAK;GACZ;EACF;EACA,IAAI,SAAS,IAAI,WAAW;EAC5B,OAAO;CACT;CAEA,MAAM,YAAoB;EACxB,IAAI,KAAK,OAAO,MAAK,OAAO,OAAO,IAAG;EACtC,IAAI,CAAC,OAAO,OAAO,WAAW;EAC9B,OAAO,KAAK,OAAO,MAAM,OAAO,GAAG,IAAI,WAAW;CACpD;CAGA,SAAS,SAAkC;EACzC;EACA,MAAM,SAAkC,CAAC;EACzC,MAAM,OAAO,wBAAQ,IAAI,IAAY,IAAI,KAAA;EACzC,UAAU;EACV,IAAI,KAAK,OAAO,KAAK;GACnB;GACA,OAAO;EACT;EACA,SAAS;GACP,MAAM,WAAW;GACjB,MAAM,OAAO,IAAI;GACjB,IAAI,MAAM;IACR,IAAI,KAAK,IAAI,IAAI,GAAG,KAAK,iBAAiB,KAAK,UAAU,IAAI,EAAE,YAAY,QAAQ;IACnF,KAAK,IAAI,IAAI;GACf;GACA,UAAU;GACV,IAAI,KAAK,OAAO,KAAK,WAAW;GAChC;GACA,UAAU;GACV,OAAO,QAAQ,MAAM,MAAM,CAAC;GAC5B,UAAU;GACV,IAAI,KAAK,OAAO,KAAK;IACnB;IACA,UAAU;IACV,IAAI,SAAS,KAAK,OAAO,KAAK;GAChC,OAAO,IAAI,KAAK,OAAO,KACrB;QAEA,WAAW;EAEf;EACA;EACA,OAAO;CACT;CAEA,SAAS,QAAmB;EAC1B;EACA,MAAM,SAAoB,CAAC;EAC3B,UAAU;EACV,IAAI,KAAK,OAAO,KAAK;GACnB;GACA,OAAO;EACT;EACA,SAAS;GACP,OAAO,KAAK,MAAM,CAAC;GACnB,UAAU;GACV,IAAI,KAAK,OAAO,KAAK;IACnB;IACA,UAAU;IACV,IAAI,SAAS,KAAK,OAAO,KAAK;GAChC,OAAO,IAAI,KAAK,OAAO,KACrB;QAEA,WAAW;EAEf;EACA;EACA,OAAO;CACT;CAEA,SAAS,QAAiB;EACxB,QAAQ,KAAK,IAAb;GACE,KAAK,KACH,OAAO,OAAO;GAChB,KAAK,KACH,OAAO,MAAM;GACf,KAAK,MACH,OAAO,OAAO,IAAG;GACnB,KAAK,KACH,OAAO,QAAQ,OAAO,GAAG,IAAI,WAAW;GAC1C,KAAK,KACH,OAAO,QAAQ,QAAQ,IAAI;GAC7B,KAAK,KACH,OAAO,QAAQ,SAAS,KAAK;GAC/B,KAAK,KACH,OAAO,QAAQ,QAAQ,IAAI;GAC7B,SACE,OAAO,OAAO;EAClB;CACF;CAEA,UAAU;CACV,IAAI,KAAK,KAAK,QAAQ,WAAW;CACjC,MAAM,SAAS,MAAM;CACrB,UAAU;CACV,IAAI,IAAI,KAAK,QAAQ,WAAW;CAChC,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;ACrWA,SAAgB,kBAAkB,OAAuB;CACvD,IAAI,SAAS;CACb,IAAI,WAAW;CAKf,IAAI,eAAe;CACnB,MAAM,0BAA0B;EAC9B,UAAU;EACV,eAAe;CACjB;CAGA,MAAM,cAAc,SAAiB;EACnC,IAAI,cACF,gBAAgB;OAEhB,UAAU;CAEd;CAEA,IAAI,IAAI;CACR,OAAO,IAAI,MAAM,QAAQ;EACvB,MAAM,OAAO,MAAM;EAEnB,IAAI,UAAU;GACZ,UAAU;GACV,IAAI,SAAS,MAAM;IAGjB;IACA,IAAI,IAAI,MAAM,QAAQ,UAAU,MAAM;GACxC,OAAO,IAAI,SAAS,MAClB,WAAW;GAEb;GACA;EACF;EAEA,IAAI,SAAS,MAAK;GAChB,kBAAkB;GAClB,WAAW;GACX,UAAU;GACV;GACA;EACF;EAEA,IAAI,SAAS,OAAO,MAAM,IAAI,OAAO,KAAK;GACxC,MAAM,QAAQ;GACd,KAAK;GAIL,OAAO,IAAI,MAAM,UAAU,MAAM,OAAO,QAAQ,MAAM,OAAO,MAAM;GACnE,WAAW,IAAI,OAAO,IAAI,KAAK,CAAC;GAChC;EACF;EAEA,IAAI,SAAS,OAAO,MAAM,IAAI,OAAO,KAAK;GACxC,MAAM,QAAQ;GACd,KAAK;GACL,OAAO,IAAI,MAAM,UAAU,EAAE,MAAM,OAAO,OAAO,MAAM,IAAI,OAAO,MAAM;GAExE,IAAI,KAAK,IAAI,IAAI,GAAG,MAAM,MAAM;GAChC,WAAW,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,QAAQ,YAAY,GAAG,CAAC;GACzD;EACF;EAEA,IAAI,SAAS,KAAK;GAChB,kBAAkB;GAClB,eAAe;GACf;GACA;EACF;EAEA,IAAI,SAAS,OAAO,SAAS,KAAK;GAEhC,UAAU,aAAa,QAAQ,KAAK,GAAG;GACvC,eAAe;GACf,UAAU;GACV;GACA;EACF;EAEA,IAAI,SAAS,OAAO,SAAS,OAAQ,SAAS,QAAQ,SAAS,MAAM;GACnE,WAAW,IAAI;GACf;GACA;EACF;EAEA,kBAAkB;EAClB,UAAU;EACV;CACF;CAEA,kBAAkB;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA,SAAgB,MAAmB,MAAiB;CAClD,MAAM,QAAQ,KAAK,WAAW,GAAQ,IAAI,KAAK,MAAM,CAAC,IAAI;CAC1D,IAAI;EACF,OAAO,KAAK,MAAM,KAAK;CACzB,QAAQ;EACN,IAAI;GACF,OAAO,KAAK,MAAM,kBAAkB,KAAK,CAAC;EAC5C,QAAQ;GACN,OAAO,SAAS,OAAO,EAAE,SAAS,QAAQ,CAAC;EAC7C;CACF;AACF;;;;ACtCA,IAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiClB,SAAgB,WAAwB,MAAc,UAA6B,CAAC,GAAQ;CAC1F,MAAM,EAAE,aAAa,QAAQ,eAAe,WAAW;CACvD,IAAI,SAAS,IAAI,OAAO,CAAC;CAEzB,MAAM,QAAQ,KAAK,MAAM,SAAS;CAElC,IAAI,KAAK,SAAS,SAAS,GAAG,MAAM,IAAI;CAExC,MAAM,SAAc,CAAC;CACrB,MAAM,SAAS,MAAM,UAAU;EAC7B,MAAM,aAAa,QAAQ;EAC3B,IAAI,KAAK,KAAK,MAAM,IAAI;GACtB,IAAI,eAAe,QACjB,MAAM,IAAI,YAAY,oBAAoB,WAAW,UAAU;GAEjE;EACF;EACA,IAAI;GACF,OAAO,KAAK,KAAK,MAAM,IAAI,CAAM;EACnC,SAAS,OAAO;GACd,IAAI,iBAAiB,QACnB,MAAM,IAAI,YAAY,oBAAoB,WAAW,IAAK,MAAgB,WAAW,EAAE,OAAO,MAAM,CAAC;EAEzG;CACF,CAAC;CACD,OAAO;AACT;;;;ACnEA,IAAM,mBAAmB;;;;;;AAOzB,IAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCjC,SAAgB,cAA2B,MAAc,UAAgC,CAAC,GAAQ;CAChG,MAAM,EAAE,iBAAiB,WAAW;CACpC,MAAM,CAAC,aAAa,GAAG,WAAW,KAAK,MAAM,gBAAgB;CAE7D,MAAM,WAAW,OAAe,QAAgB,UAA0B;EACxE,IAAI,mBAAmB,QACrB,MAAM,IAAI,YAAY,kBAAkB,MAAM,IAAI,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;CAE3G;CAGA,IAAI,YAAa,KAAK,MAAM,IAAI,QAAQ,2BAA2B,oDAAoD;CAEvH,MAAM,SAAc,CAAC;CACrB,QAAQ,SAAS,QAAQ,UAAU;EACjC,MAAM,QAAQ,UAAU,QAAQ;EAChC,IAAI,WAAW,IAAI;EACnB,IAAI;EACJ,IAAI;GACF,QAAQ,KAAK,MAAM,MAAM;EAC3B,SAAS,OAAO;GACd,QAAQ,OAAQ,MAAgB,SAAS,KAAK;GAC9C;EACF;EAEA,IAAI,EADmB,OAAO,UAAU,YAAY,UAAU,QAAS,OAAO,UAAU,aAClE,CAAC,yBAAyB,KAAK,MAAM,GAAG;GAC5D,QAAQ,OAAO,aAAa,KAAK,UAAU,KAAK,EAAE,oDAAoD;GACtG;EACF;EACA,OAAO,KAAK,KAAU;CACxB,CAAC;CACD,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA,SAAgB,YAAyB,MAAiB;CACxD,OAAO,KAAK,MAAM,IAAI;AACxB;;;;;;;;ACFA,SAAgB,UAAgB,MAAc,UAA4B;CACxE,IAAI;EACF,OAAO,MAAS,IAAI;CACtB,QAAQ;EACN,OAAO,UAAU,SAAS,IAAI,OAAQ;CACxC;AACF;;;;;;;;ACLA,SAAgB,eAAqB,MAAc,UAAc,SAA6C;CAC5G,IAAI;EACF,OAAO,WAAc,MAAM,OAAO;CACpC,QAAQ;EACN,OAAO,UAAU,SAAS,IAAI,OAAQ;CACxC;AACF;;;;;;;;ACNA,SAAgB,kBAAwB,MAAc,UAAc,SAAgD;CAClH,IAAI;EACF,OAAO,cAAiB,MAAM,OAAO;CACvC,QAAQ;EACN,OAAO,UAAU,SAAS,IAAI,OAAQ;CACxC;AACF;;;;;;;;ACRA,SAAgB,gBAAsB,MAAc,UAA4B;CAC9E,IAAI;EACF,OAAO,YAAe,IAAI;CAC5B,QAAQ;EACN,OAAO,UAAU,SAAS,IAAI,OAAQ;CACxC;AACF;;;;;;;;;;;;;AC1BA,IAAM,iBAAiB;;AAGvB,SAAS,gBAAgB,OAAuB;CAC9C,IAAI,eAAe,KAAK,KAAK,GAC3B,MAAM,IAAI,WAAW,wEAAwE,KAAK,UAAU,KAAK,GAAG;CAEtH,OAAO,KAAK,UAAU,KAAK;AAC7B;;;;;;;;;;;;AAaA,SAAS,UAAU,QAAiC,KAAa,WAA0C;CACzG,IAAI,QAAiB,OAAO;CAC5B,IAAK,OAAO,UAAU,YAAY,UAAU,QAAS,OAAO,UAAU,UAAU;EAC9E,MAAM,SAAU,MAA+B;EAC/C,IAAI,OAAO,WAAW,YAAY,QAAQ,OAAO,KAAK,OAAO,GAAG;CAClE;CACA,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAE/C,MAAM,MAAM,OAAO,UAAU,SAAS,KAAK,KAAK;EAChD,IAAI,QAAQ,mBAAmB,QAAQ,OAAO,KAAK;OAC9C,IAAI,QAAQ,mBAAmB,QAAQ,OAAO,KAAK;OACnD,IAAI,QAAQ,oBAAoB,QAAQ,QAAQ,UAAU,QAAQ,KAAK,KAAK;CACnF;CAEA,QAAQ,OAAO,OAAf;EACE,KAAK,WACH,OAAO,OAAO,KAAK;EACrB,KAAK;GACH,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,MAAM,IAAI,WAAW,wCAAwC,OAAO;GAEtE,OAAO,KAAK,UAAU,KAAK;EAC7B,KAAK,UACH,OAAO,gBAAgB,KAAK;EAC9B,KAAK,UACH,MAAM,IAAI,UAAU,gDAAgD;EACtE,KAAK,UACH;EACF,SAEE;CACJ;CACA,IAAI,UAAU,MAAM,OAAO;CAE3B,IAAI,UAAU,SAAS,KAAK,GAC1B,MAAM,IAAI,UAAU,oDAAoD;CAE1E,UAAU,KAAK,KAAK;CACpB,IAAI;CACJ,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxB,MAAM,QAAQ;EACd,SAAS,IAAI,MAAM,KAAK,GAAG,UAAU,UAAU,OAAO,OAAO,KAAK,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG,EAAE;CACvG,OAAO;EACL,MAAM,SAAS;EACf,MAAM,UAAoB,CAAC;EAC3B,KAAK,MAAM,UAAU,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG;GACnD,MAAM,aAAa,UAAU,QAAQ,QAAQ,SAAS;GACtD,IAAI,eAAe,KAAA,GAAW,QAAQ,KAAK,GAAG,gBAAgB,MAAM,EAAE,GAAG,YAAY;EACvF;EACA,SAAS,IAAI,QAAQ,KAAK,GAAG,EAAE;CACjC;CACA,UAAU,IAAI;CACd,OAAO;AACT;;;;;;AAOA,SAAgB,mBAAmB,OAAoC;CACrE,OAAO,UAAU,EAAE,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC;AACxC;;;;;;;;;AC7EA,IAAM,iBAAiB;;AAEvB,IAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CnB,SAAgB,UAAU,OAAgB,aAAkC,CAAC,GAAW;CACtF,IAAI;CACJ,IAAI,eAAe,aACjB,OAAO,mBAAmB,KAAK;MAC1B;EACL,MAAM,EAAE,SAAS,mBAAmB;EACpC,IAAI,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,KAAK,SAAS,YACtD,MAAM,IAAI,WAAW,kDAAkD,WAAW,QAAQ,QAAQ;EAEpG,OAAO,KAAK,UAAU,OAAO,MAAM,MAAM;CAC3C;CACA,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,UAAU,cAAc,OAAO,MAAM,4BAA4B;CAE7E,OAAO;AACT;;;;;;;;;;;;;;;;;AC7DA,SAAgB,iBAAiB,QAAgB,QAA4B,YAA+C;CAC1H,IAAI,CAAC,MAAM,QAAQ,MAAM,GACvB,MAAM,IAAI,UAAU,GAAG,OAAO,qCAAqC,WAAW,OAAO,SAAS,OAAO,QAAQ;CAE/G,OAAO,OAAO,KAAK,OAAO,UAAU;EAClC,MAAM,OAAO,eAAe,cAAc,mBAAmB,KAAK,IAAI,KAAK,UAAU,KAAK;EAC1F,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,UAAU,GAAG,OAAO,uBAAuB,MAAM,IAAI,OAAO,MAAM,6BAA6B;EAE3G,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACcA,SAAgB,eAAe,QAA4B,YAAkC;CAC3F,OAAO,iBAAiB,kBAAkB,QAAQ,UAAU,CAAC,CAAC,KAAK,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE;AAClG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA,SAAgB,kBAAkB,QAA4B,YAAkC;CAC9F,OAAO,iBAAiB,qBAAqB,QAAQ,UAAU,CAAC,CAAC,KAAK,SAAS,SAAS,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE;AAC3G"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../helpers/_shared/_jsonReader.ts","../../../helpers/_shared/_stripJsonComments.ts","../../../helpers/json/parse.ts","../../../helpers/json/parseLines.ts","../../../helpers/json/parseSequence.ts","../../../helpers/json/parseStrict.ts","../../../helpers/json/safeParse.ts","../../../helpers/json/safeParseLines.ts","../../../helpers/json/safeParseSequence.ts","../../../helpers/json/safeParseStrict.ts","../../../helpers/json/_canonical.ts","../../../helpers/json/stringify.ts","../../../helpers/json/_serializeRecords.ts","../../../helpers/json/stringifyLines.ts","../../../helpers/json/stringifySequence.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal JSON / JSON5 reader shared by `json/parse` (JSON5) and the `guard/isJson5` and\n * `guard/isIJson` guards. Written from the JSON5 1.0.0 specification (https://spec.json5.org)\n * and RFC 7493 (I-JSON), not from any existing implementation. Not exported from any package\n * barrel — tests live in _jsonReader.test.ts.\n */\n\n/**\n * Which grammar {@link readJson} reads:\n * - `'json5'` — JSON5 1.0.0, a superset of JSON (and of JSONC)\n * - `'json'` — strict JSON (RFC 8259), exactly what `JSON.parse` accepts\n * @ignore\n */\nexport type JsonDialect = 'json5' | 'json';\n\n/** @ignore */\nexport interface ReadJsonOptions {\n dialect: JsonDialect;\n /**\n * Also enforce I-JSON (RFC 7493) on top of the grammar: no duplicate object keys, no lone\n * surrogate or noncharacter in strings, and no number beyond what a double holds exactly.\n */\n iJson?: boolean;\n}\n\n/** JSON5 whitespace: JSON's four, plus VT, FF, NBSP, LS, PS, BOM and every Unicode space separator. @ignore */\nconst JSON5_SPACE = /[\\t\\n\\v\\f\\r \\u00A0\\u2028\\u2029\\uFEFF\\p{Zs}]/u;\n/** @ignore */\nconst LINE_TERMINATOR = /[\\n\\r\\u2028\\u2029]/;\n/** First character of an unquoted JSON5 key (ECMAScript IdentifierStart). @ignore */\nconst IDENTIFIER_START = /[\\p{ID_Start}$_]/u;\n/** Any later character of an unquoted JSON5 key (ECMAScript IdentifierPart). @ignore */\nconst IDENTIFIER_PART = /[\\p{ID_Continue}$\\u200C\\u200D]/u;\n/** @ignore */\nconst HEX_DIGIT = /[0-9A-Fa-f]/;\n/** A lone surrogate or a Unicode noncharacter, which I-JSON forbids in strings. @ignore */\nconst I_JSON_FORBIDDEN =\n /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]|[\\uFDD0-\\uFDEF\\uFFFE\\uFFFF]|[\\uD83F\\uD87F\\uD8BF\\uD8FF\\uD93F\\uD97F\\uD9BF\\uD9FF\\uDA3F\\uDA7F\\uDABF\\uDAFF\\uDB3F\\uDB7F\\uDBBF\\uDBFF][\\uDFFE\\uDFFF]/;\n/** A double has 15 to 17 significant decimal digits; more than 17 expresses precision it can't hold. @ignore */\nconst MAX_SIGNIFICANT_DIGITS = 17;\n\n/** @ignore */\nfunction isDigit(char: string | undefined): boolean {\n return char !== undefined && char >= '0' && char <= '9';\n}\n\n/** 1-based line and column of `index` in `text`; `\\r\\n` counts as one line break. @ignore */\nfunction position(text: string, index: number): string {\n let line = 1;\n let lineStart = 0;\n for (let k = 0; k < index; k++) {\n const char = text[k];\n if (char === '\\n' || char === '\\u2028' || char === '\\u2029' || (char === '\\r' && text[k + 1] !== '\\n')) {\n line++;\n lineStart = k + 1;\n }\n }\n return `line ${line}, column ${index - lineStart + 1}`;\n}\n\n/** Defines `key` like `JSON.parse` does: `__proto__` becomes an own property, never the prototype. @ignore */\nfunction define(object: Record<string, unknown>, key: string, value: unknown): void {\n if (key === '__proto__') {\n Object.defineProperty(object, key, { value, writable: true, enumerable: true, configurable: true });\n } else {\n object[key] = value;\n }\n}\n\n/**\n * Reads one JSON or JSON5 value from `text`, the whole of it, and throws a `SyntaxError` naming\n * the line and column of the first problem otherwise. Builds values the way `JSON.parse` does\n * (same numbers, `__proto__` as an own property, the last of duplicate keys wins unless `iJson`).\n * @ignore\n */\nexport function readJson(text: string, { dialect, iJson = false }: ReadJsonOptions): unknown {\n const json5 = dialect === 'json5';\n let i = 0;\n\n const fail = (message: string, at: number = i): never => {\n throw new SyntaxError(`parse: ${message} at ${position(text, at)}`);\n };\n const unexpected = (): never =>\n i >= text.length ? fail('unexpected end of input') : fail(`unexpected character ${JSON.stringify(text[i])}`);\n\n const isSpace = (char: string): boolean =>\n json5 ? JSON5_SPACE.test(char) : char === ' ' || char === '\\t' || char === '\\n' || char === '\\r';\n\n const skipSpace = (): void => {\n while (i < text.length) {\n const char = text[i]!;\n if (isSpace(char)) {\n i++;\n } else if (json5 && char === '/' && text[i + 1] === '/') {\n i += 2;\n while (i < text.length && !LINE_TERMINATOR.test(text[i]!)) i++;\n } else if (json5 && char === '/' && text[i + 1] === '*') {\n const end = text.indexOf('*/', i + 2);\n if (end === -1) fail('unterminated block comment');\n i = end + 2;\n } else {\n return;\n }\n }\n };\n\n const hexDigits = (count: number): number => {\n const start = i;\n for (let k = 0; k < count; k++) {\n if (!HEX_DIGIT.test(text[i] ?? '')) unexpected();\n i++;\n }\n return Number.parseInt(text.slice(start, i), 16);\n };\n\n const literal = <T>(word: string, result: T): T => {\n for (const expected of word) {\n if (text[i] !== expected) unexpected();\n i++;\n }\n return result;\n };\n\n const checkIJsonNumber = (raw: string, parsed: number, at: number): void => {\n if (!Number.isFinite(parsed)) fail(`number ${raw} is beyond the range of a double (I-JSON)`, at);\n const mantissa = raw.replace(/^[+-]/, '').split(/[eE]/)[0]!.replace('.', '');\n const significant = mantissa.replace(/^0+/, '').replace(/0+$/, '');\n if (significant.length > MAX_SIGNIFICANT_DIGITS || (parsed === 0 && significant !== '')) {\n fail(`number ${raw} is more precise than a double holds (I-JSON)`, at);\n }\n if (/^-?\\d+$/.test(raw) && !Number.isSafeInteger(parsed)) {\n fail(`integer ${raw} is outside the exact range of a double (I-JSON)`, at);\n }\n };\n\n const number = (): number => {\n const start = i;\n let sign = 1;\n if (text[i] === '-' || (json5 && text[i] === '+')) {\n if (text[i] === '-') sign = -1;\n i++;\n }\n if (json5) {\n if (text.startsWith('Infinity', i)) return sign * literal('Infinity', Infinity);\n if (text.startsWith('NaN', i)) return literal('NaN', Number.NaN);\n if (text[i] === '0' && (text[i + 1] === 'x' || text[i + 1] === 'X')) {\n i += 2;\n const digitsStart = i;\n while (HEX_DIGIT.test(text[i] ?? '')) i++;\n if (i === digitsStart) unexpected();\n return sign * Number.parseInt(text.slice(digitsStart, i), 16);\n }\n }\n\n const integerStart = i;\n if (text[i] === '0') {\n i++;\n } else {\n while (isDigit(text[i])) i++;\n }\n const hasInteger = i > integerStart;\n if (!hasInteger && !(json5 && text[i] === '.')) unexpected();\n if (text[i] === '.') {\n i++;\n const fractionStart = i;\n while (isDigit(text[i])) i++;\n // JSON needs digits after the dot; JSON5 also allows \"1.\" but not a bare \".\".\n if (i === fractionStart && (!json5 || !hasInteger)) unexpected();\n }\n if (text[i] === 'e' || text[i] === 'E') {\n i++;\n if (text[i] === '+' || text[i] === '-') i++;\n const exponentStart = i;\n while (isDigit(text[i])) i++;\n if (i === exponentStart) unexpected();\n }\n const raw = text.slice(start, i);\n const parsed = Number(raw.replace(/^\\+/, ''));\n if (iJson) checkIJsonNumber(raw, parsed, start);\n return parsed;\n };\n\n const escape = (): string => {\n i++; // the backslash\n const char = text[i];\n switch (char) {\n case '\"':\n case '\\\\':\n case '/':\n i++;\n return char;\n case 'b':\n i++;\n return '\\b';\n case 'f':\n i++;\n return '\\f';\n case 'n':\n i++;\n return '\\n';\n case 'r':\n i++;\n return '\\r';\n case 't':\n i++;\n return '\\t';\n case 'u':\n i++;\n return String.fromCharCode(hexDigits(4));\n }\n if (!json5 || char === undefined || (isDigit(char) && char !== '0')) return unexpected();\n i++;\n switch (char) {\n case 'v':\n return '\\v';\n case '0':\n if (isDigit(text[i])) unexpected();\n return '\\0';\n case 'x':\n return String.fromCharCode(hexDigits(2));\n case '\\r':\n if (text[i] === '\\n') i++;\n return '';\n case '\\n':\n case '\\u2028':\n case '\\u2029':\n return '';\n default:\n // JSON5 NonEscapeCharacter: any other character stands for itself (`\\'`, `\\a`, …).\n return char;\n }\n };\n\n const string = (quote: string): string => {\n const start = i;\n i++;\n let result = '';\n for (;;) {\n const char = text[i];\n if (char === undefined) fail('unterminated string', start);\n if (char === quote) break;\n if (char === '\\\\') {\n result += escape();\n } else {\n // JSON forbids every raw control character; JSON5 only forbids the line breaks.\n if (char === '\\n' || char === '\\r' || (!json5 && char! < ' ')) unexpected();\n result += char;\n i++;\n }\n }\n i++;\n if (iJson && I_JSON_FORBIDDEN.test(result)) {\n fail('string holds a lone surrogate or a noncharacter (I-JSON)', start);\n }\n return result;\n };\n\n const identifier = (): string => {\n let name = '';\n for (;;) {\n const pattern = name === '' ? IDENTIFIER_START : IDENTIFIER_PART;\n if (text[i] === '\\\\') {\n const at = i;\n i++;\n if (text[i] !== 'u') unexpected();\n i++;\n const char = String.fromCharCode(hexDigits(4));\n if (!pattern.test(char)) fail(`invalid key character ${JSON.stringify(char)}`, at);\n name += char;\n } else {\n const codePoint = text.codePointAt(i);\n const char = codePoint === undefined ? '' : String.fromCodePoint(codePoint);\n if (char === '' || !pattern.test(char)) break;\n name += char;\n i += char.length;\n }\n }\n if (name === '') unexpected();\n return name;\n };\n\n const key = (): string => {\n if (text[i] === '\"') return string('\"');\n if (!json5) return unexpected();\n return text[i] === \"'\" ? string(\"'\") : identifier();\n };\n\n // `value` and the two container readers call each other, so they're hoisted declarations.\n function object(): Record<string, unknown> {\n i++;\n const result: Record<string, unknown> = {};\n const seen = iJson ? new Set<string>() : undefined;\n skipSpace();\n if (text[i] === '}') {\n i++;\n return result;\n }\n for (;;) {\n const keyStart = i;\n const name = key();\n if (seen) {\n if (seen.has(name)) fail(`duplicate key ${JSON.stringify(name)} (I-JSON)`, keyStart);\n seen.add(name);\n }\n skipSpace();\n if (text[i] !== ':') unexpected();\n i++;\n skipSpace();\n define(result, name, value());\n skipSpace();\n if (text[i] === ',') {\n i++;\n skipSpace();\n if (json5 && text[i] === '}') break;\n } else if (text[i] === '}') {\n break;\n } else {\n unexpected();\n }\n }\n i++;\n return result;\n }\n\n function array(): unknown[] {\n i++;\n const result: unknown[] = [];\n skipSpace();\n if (text[i] === ']') {\n i++;\n return result;\n }\n for (;;) {\n result.push(value());\n skipSpace();\n if (text[i] === ',') {\n i++;\n skipSpace();\n if (json5 && text[i] === ']') break;\n } else if (text[i] === ']') {\n break;\n } else {\n unexpected();\n }\n }\n i++;\n return result;\n }\n\n function value(): unknown {\n switch (text[i]) {\n case '{':\n return object();\n case '[':\n return array();\n case '\"':\n return string('\"');\n case \"'\":\n return json5 ? string(\"'\") : unexpected();\n case 't':\n return literal('true', true);\n case 'f':\n return literal('false', false);\n case 'n':\n return literal('null', null);\n default:\n return number();\n }\n }\n\n skipSpace();\n if (i >= text.length) unexpected();\n const result = value();\n skipSpace();\n if (i < text.length) unexpected();\n return result;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal helper used by `node/safeReadJsonFile` and `json/parse` to support JSONC (JSON with\n * line and block comments, plus trailing commas) — the dialect used by tsconfig.json, VS Code's\n * settings.json, etc. Not exported from any package barrel — tests live in\n * _stripJsonComments.test.ts.\n */\n\n/**\n * Blanks out line comments (starting with two slashes), block comments (slash-star ... star-slash),\n * and trailing commas (before `}` or `]`) in a JSONC string, so the result can be passed to\n * `JSON.parse`. String literals are tracked so a comment-like or comma character occurring\n * *inside* a JSON string (e.g. a URL) is left untouched — this is a string-boundary-aware pass,\n * not a naive regex strip.\n *\n * Everything removed is replaced by spaces (line breaks inside a block comment are kept), so the\n * output has exactly the same length and line layout as the input: a position `JSON.parse`\n * reports in an error on the output points at the same place in the original JSONC text.\n * @ignore\n */\nexport function stripJsonComments(input: string): string {\n let output = '';\n let inString = false;\n // A comma seen outside a string is held back instead of emitted immediately:\n // if the next significant token turns out to be `}`/`]`, it was a trailing\n // comma and gets blanked; otherwise it (and any whitespace/comments held\n // alongside it) is flushed once a real token confirms it wasn't trailing.\n let pendingComma = '';\n const flushPendingComma = () => {\n output += pendingComma;\n pendingComma = '';\n };\n // Whitespace and blanked-out comments don't resolve a pending comma either way, so they're\n // buffered alongside it to keep the output in the original order.\n const emitFiller = (text: string) => {\n if (pendingComma) {\n pendingComma += text;\n } else {\n output += text;\n }\n };\n\n let i = 0;\n while (i < input.length) {\n const char = input[i];\n\n if (inString) {\n output += char;\n if (char === '\\\\') {\n // Copy the escaped character as-is (whatever it is) so an escaped\n // quote (`\\\"`) doesn't get mistaken for the string's end.\n i++;\n if (i < input.length) output += input[i];\n } else if (char === '\"') {\n inString = false;\n }\n i++;\n continue;\n }\n\n if (char === '\"') {\n flushPendingComma();\n inString = true;\n output += char;\n i++;\n continue;\n }\n\n if (char === '/' && input[i + 1] === '/') {\n const start = i;\n i += 2;\n // Stop at any line-ending character, not just \\n — a bare \\r (classic\n // Mac line endings, or a lone \\r before a later \\n) also ends the line,\n // otherwise everything up to the next \\n (or EOF) gets silently eaten.\n while (i < input.length && input[i] !== '\\n' && input[i] !== '\\r') i++;\n emitFiller(' '.repeat(i - start));\n continue;\n }\n\n if (char === '/' && input[i + 1] === '*') {\n const start = i;\n i += 2;\n while (i < input.length && !(input[i] === '*' && input[i + 1] === '/')) i++;\n // An unterminated block comment runs to the end of the input.\n i = Math.min(i + 2, input.length);\n emitFiller(input.slice(start, i).replace(/[^\\r\\n]/g, ' '));\n continue;\n }\n\n if (char === ',') {\n flushPendingComma();\n pendingComma = char;\n i++;\n continue;\n }\n\n if (char === '}' || char === ']') {\n // Blank the comma — it was trailing — but keep what was buffered after it.\n output += pendingComma.replace(',', ' ');\n pendingComma = '';\n output += char;\n i++;\n continue;\n }\n\n if (char === ' ' || char === '\\t' || char === '\\n' || char === '\\r') {\n emitFiller(char);\n i++;\n continue;\n }\n\n flushPendingComma();\n output += char;\n i++;\n }\n\n flushPendingComma();\n return output;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { readJson } from '../_shared/_jsonReader';\nimport { stripJsonComments } from '../_shared/_stripJsonComments';\n\n/**\n * Parses JSON permissively: strict JSON, JSONC (the dialect of `tsconfig.json` and VS Code's\n * `settings.json`, also known as HuJSON or JWCC) and JSON5 — each a superset of the one before.\n *\n * **Accepts:**\n * - everything {@link parseStrict} accepts (strict JSON, RFC 8259)\n * - comments: `// …` to the end of the line, and `/* … *\\/`\n * - one trailing comma after the last item of an object or array\n * - object keys without quotes, when they are ECMAScript identifiers (`{ name: 1 }`, `{ $id: 1 }`)\n * - strings in single quotes, and in either quote: the escapes `\\'`, `\\v`, `\\0` and `\\xHH`, any\n * other escaped character standing for itself, and a backslash before a line break to continue\n * the string on the next line\n * - numbers with a leading `+`, a leading or trailing dot (`.5`, `5.`), in hexadecimal (`0x1F`),\n * and `Infinity`, `-Infinity` and `NaN`\n * - any Unicode whitespace between tokens, including a leading byte order mark (U+FEFF)\n *\n * **Rejects:** more than one trailing comma in a row, leading zeros (`01`), octal or binary\n * numbers, unquoted keys that aren't identifiers (`{ my-key: 1 }`), raw line breaks inside a\n * string, an unterminated comment or string, `undefined`, and more than one value.\n *\n * **On invalid input:** throws a `SyntaxError` naming the line and column of the first problem.\n *\n * Strict JSON goes straight to the native `JSON.parse`, and JSONC to `JSON.parse` after its\n * comments are blanked out; only text that is neither goes through the JSON5 reader (written for\n * helpers4 from the JSON5 1.0.0 specification), so the common cases cost nothing extra.\n *\n * Values are built as `JSON.parse` builds them: the last of duplicate keys wins, and a\n * `__proto__` key is an own property, never the prototype. `NaN` and `Infinity` have no JSON\n * representation — {@link stringify} writes them as `null`.\n *\n * @param text - The JSON, JSONC or JSON5 text to parse\n * @returns The parsed value, typed as `T`\n * @throws {SyntaxError} When `text` isn't JSON5 (and so neither JSONC nor JSON)\n * @see {@link safeParse} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link parseStrict} — strict JSON only, e.g. to validate an API payload\n * @see {@link parseLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link parseSequence} — JSON text sequences (RFC 7464)\n * @example\n * parse('{\"a\":1}') // => { a: 1 }\n * @example\n * parse(`{\n * // the output directory\n * \"outDir\": \"dist\",\n * }`) // => { outDir: 'dist' }\n * @example\n * parse(\"{ name: 'app', retries: 0x3, ratio: .5, }\") // => { name: 'app', retries: 3, ratio: 0.5 }\n * @since 3.1.3\n */\nexport function parse<T = unknown>(text: string): T {\n const input = text.startsWith('\\ufeff') ? text.slice(1) : text;\n try {\n return JSON.parse(input) as T;\n } catch {\n try {\n return JSON.parse(stripJsonComments(input)) as T;\n } catch {\n return readJson(input, { dialect: 'json5' }) as T;\n }\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link parseLines} and {@link safeParseLines}.\n * @since 3.1.3\n */\nexport interface ParseLinesOptions {\n /**\n * What to do with a blank (empty or whitespace-only) line:\n * - `'skip'` (default) — ignore it, as NDJSON allows\n * - `'fail'` — treat it as invalid, as JSON Lines requires (*\"a blank line is not\"* a valid value)\n *\n * A single line break at the very end of the text is a terminator, not a blank line, and is\n * always accepted.\n */\n blankLines?: 'skip' | 'fail';\n /**\n * What to do with a line that isn't valid JSON:\n * - `'fail'` (default) — the whole parse fails, as NDJSON says a parser should\n * - `'skip'` — drop that line and keep the others, e.g. for a log whose last line was\n * truncated by a crash\n */\n invalidLines?: 'fail' | 'skip';\n}\n\n/** @ignore */\nconst LINE_FEED = '\\n';\n\n/**\n * Parses newline-delimited JSON — one JSON value per line. Covers both NDJSON\n * (`application/x-ndjson`, `.ndjson`) and JSON Lines (`.jsonl`), which are the same format.\n *\n * **Accepts:**\n * - one strict JSON value per line (each line is read like {@link parseStrict})\n * - `\\n` and `\\r\\n` line endings\n * - a trailing line break after the last value, or none\n * - blank lines, skipped by default (see {@link ParseLinesOptions.blankLines})\n * - an empty text, which holds zero values\n *\n * **Rejects:** comments, trailing commas and any other non-strict JSON on a line, a value spread\n * over several lines, and a leading byte order mark (JSON Lines forbids it).\n *\n * **On invalid input:** throws a `SyntaxError` naming the 1-based line number, with the\n * original parse error as its `cause` — unless `invalidLines`/`blankLines` say to skip it.\n *\n * @param text - The newline-delimited JSON text\n * @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}\n * @returns The parsed values, in line order, typed as `T[]`\n * @throws {SyntaxError} When a line isn't valid JSON (or is blank with `blankLines: 'fail'`)\n * @see {@link safeParseLines} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link stringifyLines} — the reverse operation\n * @see {@link parseSequence} — JSON text sequences (RFC 7464), the record-separator variant\n * @see {@link parse} — a single JSON or JSONC value\n * @example\n * parseLines('{\"id\":1}\\n{\"id\":2}\\n') // => [{ id: 1 }, { id: 2 }]\n * @example\n * parseLines('{\"id\":1}\\n{\"id\":', { invalidLines: 'skip' }) // => [{ id: 1 }]\n * @since 3.1.3\n */\nexport function parseLines<T = unknown>(text: string, options: ParseLinesOptions = {}): T[] {\n const { blankLines = 'skip', invalidLines = 'fail' } = options;\n if (text === '') return [];\n\n const lines = text.split(LINE_FEED);\n // A line break after the last value terminates it; it doesn't open an empty last line.\n if (text.endsWith(LINE_FEED)) lines.pop();\n\n const values: T[] = [];\n lines.forEach((line, index) => {\n const lineNumber = index + 1;\n if (line.trim() === '') {\n if (blankLines === 'fail') {\n throw new SyntaxError(`parseLines: line ${lineNumber} is blank`);\n }\n return;\n }\n try {\n values.push(JSON.parse(line) as T);\n } catch (error) {\n if (invalidLines === 'fail') {\n throw new SyntaxError(`parseLines: line ${lineNumber}: ${(error as Error).message}`, { cause: error });\n }\n }\n });\n return values;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Options for {@link parseSequence} and {@link safeParseSequence}.\n * @since 3.1.3\n */\nexport interface ParseSequenceOptions {\n /**\n * What to do with a record that isn't a valid, complete JSON text:\n * - `'fail'` (default) — the whole parse fails, like every other `parse*` helper\n * - `'skip'` — drop that record and keep the others. RFC 7464 recommends this (*\"parsers should\n * not abort when an octet string contains a malformed JSON text\"*), for logs whose records\n * may have been truncated by a crash.\n */\n invalidRecords?: 'fail' | 'skip';\n}\n\n/** The ASCII record separator that starts every record of a JSON text sequence. @ignore */\nconst RECORD_SEPARATOR = '\\u001E';\n\n/**\n * JSON whitespace, the only thing that can end a top-level number, `true`, `false` or `null` —\n * without it, RFC 7464 §2.4 says such a record may have been truncated (`123` cut from `1234`).\n * @ignore\n */\nconst TRAILING_JSON_WHITESPACE = /[ \\t\\n\\r]$/;\n\n/**\n * Parses a JSON text sequence (RFC 7464, `application/json-seq`): records that each start with\n * the ASCII record separator (RS, U+001E) and hold one JSON text, as written by `jq --seq`.\n *\n * **Accepts:**\n * - one strict JSON value per record (each record is read like {@link parseStrict})\n * - JSON values spread over several lines inside a record — unlike {@link parseLines}\n * - several RS in a row (empty records are ignored, as the RFC's grammar allows)\n * - an empty text, which holds zero records\n *\n * **Rejects (as invalid records):**\n * - anything before the first RS\n * - a record that isn't strict JSON, or holds only whitespace\n * - a top-level number, `true`, `false` or `null` not followed by whitespace — RFC 7464 §2.4\n * requires dropping it, since it may have been truncated\n *\n * **On invalid input:** throws a `SyntaxError` naming the 1-based record number, with the\n * original parse error (if any) as its `cause` — unless `invalidRecords: 'skip'` says to drop it.\n *\n * @param text - The JSON text sequence\n * @param options - How to handle invalid records — see {@link ParseSequenceOptions}\n * @returns The parsed values, in record order, typed as `T[]`\n * @throws {SyntaxError} When a record is invalid and `invalidRecords` is `'fail'`\n * @see {@link safeParseSequence} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link stringifySequence} — the reverse operation\n * @see {@link parseLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * parseSequence('\\u001E{\"id\":1}\\n\\u001E{\"id\":2}\\n') // => [{ id: 1 }, { id: 2 }]\n * @example\n * // A crash cut the last record: skip it, as RFC 7464 recommends\n * parseSequence('\\u001E{\"id\":1}\\n\\u001E{\"id', { invalidRecords: 'skip' }) // => [{ id: 1 }]\n * @since 3.1.3\n */\nexport function parseSequence<T = unknown>(text: string, options: ParseSequenceOptions = {}): T[] {\n const { invalidRecords = 'fail' } = options;\n const [beforeFirst, ...records] = text.split(RECORD_SEPARATOR);\n\n const invalid = (where: string, reason: string, cause?: unknown): void => {\n if (invalidRecords === 'fail') {\n throw new SyntaxError(`parseSequence: ${where}: ${reason}`, cause === undefined ? undefined : { cause });\n }\n };\n\n // `split` always returns at least one element, so `beforeFirst` is always a string.\n if (beforeFirst!.trim() !== '') invalid('before the first record', 'text outside any record (missing record separator)');\n\n const values: T[] = [];\n records.forEach((record, index) => {\n const where = `record ${index + 1}`;\n if (record === '') return;\n let value: unknown;\n try {\n value = JSON.parse(record);\n } catch (error) {\n invalid(where, (error as Error).message, error);\n return;\n }\n const selfDelimited = (typeof value === 'object' && value !== null) || typeof value === 'string';\n if (!selfDelimited && !TRAILING_JSON_WHITESPACE.test(record)) {\n invalid(where, `top-level ${JSON.stringify(value)} is not followed by whitespace and may be truncated`);\n return;\n }\n values.push(value as T);\n });\n return values;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Parses strict JSON (RFC 8259) — exactly what `JSON.parse` accepts, nothing more.\n *\n * **Accepts:** standard JSON only — double-quoted strings and keys, finite decimal numbers,\n * `true`/`false`/`null`, objects and arrays, surrounding whitespace.\n *\n * **Rejects:** comments, trailing commas, single quotes, unquoted keys, hexadecimal numbers,\n * `NaN`/`Infinity`, a leading byte order mark (U+FEFF), and anything else that isn't strict JSON.\n *\n * **On invalid input:** throws the native `SyntaxError` from `JSON.parse`.\n *\n * Use it to validate input that must be strict JSON, e.g. an API payload. To also read config\n * files with comments or JSON5, use {@link parse}. To never throw, use {@link safeParseStrict}.\n *\n * @param text - The JSON text to parse\n * @returns The parsed value, typed as `T`\n * @throws {SyntaxError} When `text` isn't strict JSON\n * @see {@link safeParseStrict} — same parsing, returns `null` or a fallback instead of throwing\n * @see {@link parse} — also accepts JSONC and JSON5\n * @see {@link parseLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link parseSequence} — JSON text sequences (RFC 7464)\n * @example\n * parseStrict<{ a: number }>('{\"a\":1}') // => { a: 1 }\n * parseStrict('{\"a\":1,}') // throws SyntaxError (trailing comma)\n * @since 3.1.3\n */\nexport function parseStrict<T = unknown>(text: string): T {\n return JSON.parse(text) as T;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { parse } from './parse';\n\n/**\n * Parses JSON permissively like {@link parse} — strict JSON, JSONC (HuJSON, JWCC) and JSON5 —\n * but returns `null` (or `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parse} does — see there for the full list.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws.\n *\n * @param text - The JSON, JSONC or JSON5 text to parse\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @see {@link parse} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseStrict} — strict JSON only\n * @see {@link safeParseLines} — one value per line (NDJSON, JSON Lines)\n * @example\n * safeParse('{\"a\":1, /* note *\\/}') // => { a: 1 }\n * safeParse(\"{ a: 'x' }\") // => { a: 'x' } (JSON5)\n * safeParse('not json') // => null\n * safeParse('not json', {}) // => {}\n * @since 3.1.3\n */\nexport function safeParse<T = unknown>(text: string): T | null;\nexport function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F;\nexport function safeParse<T, F>(text: string, fallback?: F): T | F | null {\n try {\n return parse<T>(text);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { type ParseLinesOptions, parseLines } from './parseLines';\n\n/**\n * Parses newline-delimited JSON (NDJSON, JSON Lines) like {@link parseLines}, but returns `null`\n * (or `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseLines} does, with the same\n * {@link ParseLinesOptions}.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\n * a fallback, pass `null` as the fallback.\n *\n * @param text - The newline-delimited JSON text\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}\n * @returns The parsed values typed as `T[]`, or `fallback` on invalid input\n * @see {@link parseLines} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseSequence} — JSON text sequences (RFC 7464)\n * @example\n * safeParseLines('{\"id\":1}\\n{\"id\":2}') // => [{ id: 1 }, { id: 2 }]\n * safeParseLines('{\"id\":1}\\n{\"id\":') // => null\n * safeParseLines('{\"id\":1}\\n\\n', null, { blankLines: 'fail' }) // => null\n * @since 3.1.3\n */\nexport function safeParseLines<T = unknown>(text: string): T[] | null;\nexport function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseLinesOptions): T[] | F;\nexport function safeParseLines<T, F>(text: string, fallback?: F, options?: ParseLinesOptions): T[] | F | null {\n try {\n return parseLines<T>(text, options);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { type ParseSequenceOptions, parseSequence } from './parseSequence';\n\n/**\n * Parses a JSON text sequence (RFC 7464) like {@link parseSequence}, but returns `null` (or\n * `fallback`) instead of throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseSequence} does, with the same\n * {@link ParseSequenceOptions}.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\n * a fallback, pass `null` as the fallback.\n *\n * @param text - The JSON text sequence\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @param options - How to handle invalid records — see {@link ParseSequenceOptions}\n * @returns The parsed values typed as `T[]`, or `fallback` on invalid input\n * @see {@link parseSequence} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParseLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * safeParseSequence('\\u001E{\"id\":1}\\n') // => [{ id: 1 }]\n * safeParseSequence('\\u001E{\"id\"\\n') // => null\n * safeParseSequence('\\u001E{\"id\"\\n', []) // => []\n * @since 3.1.3\n */\nexport function safeParseSequence<T = unknown>(text: string): T[] | null;\nexport function safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseSequenceOptions): T[] | F;\nexport function safeParseSequence<T, F>(text: string, fallback?: F, options?: ParseSequenceOptions): T[] | F | null {\n try {\n return parseSequence<T>(text, options);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { parseStrict } from './parseStrict';\n\n/**\n * Parses strict JSON like {@link parseStrict}, but returns `null` (or `fallback`) instead of\n * throwing on invalid input.\n *\n * **Accepts / rejects:** exactly what {@link parseStrict} does — standard JSON only, no comments,\n * no trailing commas, no JSON5 syntax, no leading byte order mark.\n *\n * **On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\n * apart from an omitted argument — and `null` otherwise. Never throws.\n *\n * @param text - The JSON text to parse\n * @param fallback - Value returned on invalid input. Defaults to `null` when omitted.\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @see {@link parseStrict} — same parsing, throws a `SyntaxError` instead\n * @see {@link safeParse} — also accepts JSONC and JSON5\n * @example\n * safeParseStrict<{ a: number }>('{\"a\":1}') // => { a: 1 }\n * safeParseStrict('{\"a\":1,}') // => null\n * safeParseStrict('oops', {}) // => {}\n * @since 3.1.3\n */\nexport function safeParseStrict<T = unknown>(text: string): T | null;\nexport function safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F;\nexport function safeParseStrict<T, F>(text: string, fallback?: F): T | F | null {\n try {\n return parseStrict<T>(text);\n } catch {\n return arguments.length < 2 ? null : (fallback as F);\n }\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal canonical JSON serializer (RFC 8785, JSON Canonicalization Scheme) shared by\n * stringify.ts, stringifyLines.ts and stringifySequence.ts. Not exported from the package\n * barrel — tests live in _canonical.test.ts.\n */\n\n/** A lone UTF-16 surrogate, which I-JSON (and so RFC 8785) forbids in strings and keys. @ignore */\nconst LONE_SURROGATE = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/;\n\n/** @ignore */\nfunction serializeString(value: string): string {\n if (LONE_SURROGATE.test(value)) {\n throw new RangeError(`stringify: canonical JSON can't hold a string with a lone surrogate: ${JSON.stringify(value)}`);\n }\n return JSON.stringify(value);\n}\n\n/**\n * Serializes `holder[key]` the way `JSON.stringify` would — same `toJSON` calls, same\n * unwrapping of `Number`/`String`/`Boolean` objects, same dropping of `undefined`, functions and\n * symbols — but with the RFC 8785 rules on top: object keys sorted by UTF-16 code units, no\n * whitespace, and an error instead of a silent `null` for `NaN`/`Infinity`. Numbers already\n * follow the RFC as is: it reuses ECMAScript's own number-to-string algorithm.\n *\n * Returns `undefined` for a value `JSON.stringify` would skip (so an object member is dropped\n * and an array item becomes `null`, as it would there).\n * @ignore\n */\nfunction serialize(holder: Record<string, unknown>, key: string, ancestors: unknown[]): string | undefined {\n let value: unknown = holder[key];\n if ((typeof value === 'object' && value !== null) || typeof value === 'bigint') {\n const toJSON = (value as { toJSON?: unknown }).toJSON;\n if (typeof toJSON === 'function') value = toJSON.call(value, key);\n }\n if (typeof value === 'object' && value !== null) {\n // Realm-safe check for a Number/String/Boolean wrapper object, which JSON.stringify unwraps.\n const tag = Object.prototype.toString.call(value);\n if (tag === '[object Number]') value = Number(value);\n else if (tag === '[object String]') value = String(value);\n else if (tag === '[object Boolean]') value = Boolean.prototype.valueOf.call(value);\n }\n\n switch (typeof value) {\n case 'boolean':\n return String(value);\n case 'number':\n if (!Number.isFinite(value)) {\n throw new RangeError(`stringify: canonical JSON can't hold ${value}`);\n }\n return JSON.stringify(value);\n case 'string':\n return serializeString(value);\n case 'bigint':\n throw new TypeError('stringify: a BigInt has no JSON representation');\n case 'object':\n break;\n default:\n // undefined, function, symbol\n return undefined;\n }\n if (value === null) return 'null';\n\n if (ancestors.includes(value)) {\n throw new TypeError('stringify: converting a circular structure to JSON');\n }\n ancestors.push(value);\n let result: string;\n if (Array.isArray(value)) {\n const items = value as unknown as Record<string, unknown>;\n result = `[${value.map((_, index) => serialize(items, String(index), ancestors) ?? 'null').join(',')}]`;\n } else {\n const object = value as Record<string, unknown>;\n const members: string[] = [];\n for (const member of Object.keys(object).toSorted()) {\n const serialized = serialize(object, member, ancestors);\n if (serialized !== undefined) members.push(`${serializeString(member)}:${serialized}`);\n }\n result = `{${members.join(',')}}`;\n }\n ancestors.pop();\n return result;\n}\n\n/**\n * Serializes `value` as canonical JSON (RFC 8785), or returns `undefined` when `JSON.stringify`\n * would (a top-level `undefined`, function or symbol).\n * @ignore\n */\nexport function stringifyCanonical(value: unknown): string | undefined {\n return serialize({ '': value }, '', []);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { stringifyCanonical } from './_canonical';\n\n/**\n * How {@link stringify} lays out its output:\n * - `{ indent }` — pretty-printed with `indent` spaces per level (`0` for a compact single line)\n * - `'canonical'` — canonical JSON (RFC 8785), byte-for-byte reproducible\n * @since 3.1.3\n */\nexport type StringifyFormatting = 'canonical' | { indent?: number };\n\n/** @ignore */\nconst DEFAULT_INDENT = 2;\n/** @ignore */\nconst MAX_INDENT = 10;\n\n/**\n * Serializes a value to JSON text — pretty-printed with 2 spaces by default, or canonical.\n *\n * **Formatting:**\n * - default — indented with 2 spaces, like a hand-written config file\n * - `{ indent: n }` — indented with `n` spaces (an integer from 0 to 10); `{ indent: 0 }` gives a\n * compact single line, the same as `JSON.stringify(value)`\n * - `'canonical'` — canonical JSON (RFC 8785, JSON Canonicalization Scheme): object keys sorted\n * by UTF-16 code units, no whitespace at all, numbers in their shortest ECMAScript form. Two\n * equal values always give the same bytes, so the output can be hashed, signed or compared.\n * Canonical output can't be indented — the RFC fixes every byte.\n *\n * **Same as `JSON.stringify`:** `toJSON()` is called (a `Date` becomes its ISO string),\n * `undefined`, functions and symbols are dropped from objects and become `null` in arrays, and\n * `Number`/`String`/`Boolean` objects are unwrapped. Outside `'canonical'`, `NaN` and `±Infinity`\n * silently become `null`, as there.\n *\n * **Throws** instead of returning `undefined` or dropping data silently:\n * - a `TypeError` when `value` itself is `undefined`, a function or a symbol\n * - a `TypeError` on a circular structure or a `BigInt` (like `JSON.stringify`)\n * - with `'canonical'`, a `RangeError` on `NaN`, `±Infinity` or a string with a lone surrogate,\n * which canonical JSON can't hold\n * - a `RangeError` when `indent` isn't an integer from 0 to 10\n *\n * The output is strict JSON, so it is also valid JSONC and JSON5.\n *\n * @param value - The value to serialize\n * @param formatting - `{ indent }` (default `{ indent: 2 }`) or `'canonical'` — see {@link StringifyFormatting}\n * @returns The JSON text\n * @throws {TypeError} When `value` can't be represented as JSON\n * @throws {RangeError} On an invalid `indent`, or a value canonical JSON can't hold\n * @see {@link parse} / {@link parseStrict} — the reverse operation\n * @see {@link stringifyLines} — one value per line (NDJSON, JSON Lines)\n * @see {@link stringifySequence} — JSON text sequences (RFC 7464)\n * @example\n * stringify({ b: 1, a: [true] })\n * // => '{\\n \"b\": 1,\\n \"a\": [\\n true\\n ]\\n}'\n * @example\n * stringify({ b: 1, a: [true] }, { indent: 0 }) // => '{\"b\":1,\"a\":[true]}'\n * stringify({ b: 1, a: [true] }, 'canonical') // => '{\"a\":[true],\"b\":1}'\n * @since 3.1.3\n */\nexport function stringify(value: unknown, formatting: StringifyFormatting = {}): string {\n let text: string | undefined;\n if (formatting === 'canonical') {\n text = stringifyCanonical(value);\n } else {\n const { indent = DEFAULT_INDENT } = formatting;\n if (!Number.isInteger(indent) || indent < 0 || indent > MAX_INDENT) {\n throw new RangeError(`stringify: indent must be an integer from 0 to ${MAX_INDENT}, got ${indent}`);\n }\n text = JSON.stringify(value, null, indent);\n }\n if (text === undefined) {\n throw new TypeError(`stringify: ${typeof value} has no JSON representation`);\n }\n return text;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n *\n * Internal helper shared by stringifyLines.ts and stringifySequence.ts. Not exported from the\n * package barrel — tests live in _serializeRecords.test.ts.\n */\n\nimport { stringifyCanonical } from './_canonical';\n\n/**\n * Serializes each value as one compact (or canonical) JSON text, for a format that holds one\n * value per record. Throws on a value with no JSON representation rather than writing a record\n * that would read back as something else.\n * @ignore\n */\nexport function serializeRecords(caller: string, values: readonly unknown[], formatting: 'canonical' | undefined): string[] {\n if (!Array.isArray(values)) {\n throw new TypeError(`${caller}: expected an array of values, got ${values === null ? 'null' : typeof values}`);\n }\n return values.map((value, index) => {\n const text = formatting === 'canonical' ? stringifyCanonical(value) : JSON.stringify(value);\n if (text === undefined) {\n throw new TypeError(`${caller}: the value at index ${index} (${typeof value}) has no JSON representation`);\n }\n return text;\n });\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { serializeRecords } from './_serializeRecords';\n\n/**\n * Serializes values as newline-delimited JSON — one compact JSON value per line, each followed\n * by `\\n`. The output is both NDJSON and JSON Lines (`.jsonl`), which are the same format.\n *\n * **Formatting:**\n * - default — each value compact, like `JSON.stringify(value)`\n * - `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes, for\n * hashing or diffing logs line by line\n *\n * Indentation isn't available: a line break inside a value would split it across lines. String\n * values can't break a line either — `JSON.stringify` escapes `\\n` and `\\r` inside them.\n *\n * **Output:** every value is followed by `\\n`, including the last one (NDJSON requires it, and\n * JSON Lines recommends it, so files can be concatenated). An empty array gives `''`.\n *\n * **Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\n * representation (`undefined`, a function, a symbol, a `BigInt`, a circular structure) — rather\n * than writing a line that would read back as something else. With `'canonical'`, also a\n * `RangeError` on `NaN`, `±Infinity` or a lone surrogate (see {@link stringify}).\n *\n * @param values - The values to write, one per line\n * @param formatting - `'canonical'` for canonical JSON lines; compact JSON by default\n * @returns The newline-delimited JSON text\n * @throws {TypeError} When `values` isn't an array, or a value has no JSON representation\n * @throws {RangeError} With `'canonical'`, on a value canonical JSON can't hold\n * @see {@link parseLines} — the reverse operation\n * @see {@link stringifySequence} — JSON text sequences (RFC 7464)\n * @see {@link stringify} — a single, possibly indented, JSON value\n * @example\n * stringifyLines([{ id: 1 }, { id: 2 }]) // => '{\"id\":1}\\n{\"id\":2}\\n'\n * @example\n * stringifyLines([{ b: 1, a: 2 }], 'canonical') // => '{\"a\":2,\"b\":1}\\n'\n * @since 3.1.3\n */\nexport function stringifyLines(values: readonly unknown[], formatting?: 'canonical'): string {\n return serializeRecords('stringifyLines', values, formatting).map((line) => `${line}\\n`).join('');\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { serializeRecords } from './_serializeRecords';\n\n/**\n * Serializes values as a JSON text sequence (RFC 7464, `application/json-seq`): each value is\n * written as the ASCII record separator (RS, U+001E), the compact JSON text, then `\\n` — the\n * exact framing the RFC requires of encoders, as `jq --seq` writes it.\n *\n * **Formatting:**\n * - default — each value compact, like `JSON.stringify(value)`\n * - `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes\n *\n * Indentation isn't offered, for symmetry with {@link stringifyLines}: the trailing `\\n` is what\n * lets a reader detect a truncated top-level number, `true`, `false` or `null` (RFC 7464 §2.4).\n *\n * **Output:** an empty array gives `''`.\n *\n * **Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\n * representation (`undefined`, a function, a symbol, a `BigInt`, a circular structure). With\n * `'canonical'`, also a `RangeError` on `NaN`, `±Infinity` or a lone surrogate (see\n * {@link stringify}).\n *\n * @param values - The values to write, one per record\n * @param formatting - `'canonical'` for canonical JSON records; compact JSON by default\n * @returns The JSON text sequence\n * @throws {TypeError} When `values` isn't an array, or a value has no JSON representation\n * @throws {RangeError} With `'canonical'`, on a value canonical JSON can't hold\n * @see {@link parseSequence} — the reverse operation\n * @see {@link stringifyLines} — newline-delimited JSON (NDJSON, JSON Lines)\n * @example\n * stringifySequence([{ id: 1 }, 2]) // => '\\u001E{\"id\":1}\\n\\u001E2\\n'\n * @since 3.1.3\n */\nexport function stringifySequence(values: readonly unknown[], formatting?: 'canonical'): string {\n return serializeRecords('stringifySequence', values, formatting).map((text) => `\\u001E${text}\\n`).join('');\n}\n"],"mappings":"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"}
|
package/llms.txt
CHANGED
package/meta/api.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"category": "json",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"functions": [
|
|
5
5
|
{
|
|
6
6
|
"name": "parse",
|
|
7
7
|
"kind": "function",
|
|
8
8
|
"description": "Parses JSON permissively: strict JSON, JSONC (the dialect of `tsconfig.json` and VS Code's\n`settings.json`, also known as HuJSON or JWCC) and JSON5 — each a superset of the one before.\n\n**Accepts:**\n- everything parseStrict accepts (strict JSON, RFC 8259)\n- comments: `// …` to the end of the line, and `/* … */`\n- one trailing comma after the last item of an object or array\n- object keys without quotes, when they are ECMAScript identifiers (`{ name: 1 }`, `{ $id: 1 }`)\n- strings in single quotes, and in either quote: the escapes `\\'`, `\\v`, `\\0` and `\\xHH`, any\n other escaped character standing for itself, and a backslash before a line break to continue\n the string on the next line\n- numbers with a leading `+`, a leading or trailing dot (`.5`, `5.`), in hexadecimal (`0x1F`),\n and `Infinity`, `-Infinity` and `NaN`\n- any Unicode whitespace between tokens, including a leading byte order mark (U+FEFF)\n\n**Rejects:** more than one trailing comma in a row, leading zeros (`01`), octal or binary\nnumbers, unquoted keys that aren't identifiers (`{ my-key: 1 }`), raw line breaks inside a\nstring, an unterminated comment or string, `undefined`, and more than one value.\n\n**On invalid input:** throws a `SyntaxError` naming the line and column of the first problem.\n\nStrict JSON goes straight to the native `JSON.parse`, and JSONC to `JSON.parse` after its\ncomments are blanked out; only text that is neither goes through the JSON5 reader (written for\nhelpers4 from the JSON5 1.0.0 specification), so the common cases cost nothing extra.\n\nValues are built as `JSON.parse` builds them: the last of duplicate keys wins, and a\n`__proto__` key is an own property, never the prototype. `NaN` and `Infinity` have no JSON\nrepresentation — stringify writes them as `null`.",
|
|
9
|
-
"since": "
|
|
9
|
+
"since": "3.1.3",
|
|
10
10
|
"signatures": [
|
|
11
11
|
{
|
|
12
12
|
"signature": "parse<T = unknown>(text: string): T",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"name": "parseLines",
|
|
54
54
|
"kind": "function",
|
|
55
55
|
"description": "Parses newline-delimited JSON — one JSON value per line. Covers both NDJSON\n(`application/x-ndjson`, `.ndjson`) and JSON Lines (`.jsonl`), which are the same format.\n\n**Accepts:**\n- one strict JSON value per line (each line is read like parseStrict)\n- `\\n` and `\\r\\n` line endings\n- a trailing line break after the last value, or none\n- blank lines, skipped by default (see ParseLinesOptions.blankLines)\n- an empty text, which holds zero values\n\n**Rejects:** comments, trailing commas and any other non-strict JSON on a line, a value spread\nover several lines, and a leading byte order mark (JSON Lines forbids it).\n\n**On invalid input:** throws a `SyntaxError` naming the 1-based line number, with the\noriginal parse error as its `cause` — unless `invalidLines`/`blankLines` say to skip it.",
|
|
56
|
-
"since": "
|
|
56
|
+
"since": "3.1.3",
|
|
57
57
|
"signatures": [
|
|
58
58
|
{
|
|
59
59
|
"signature": "parseLines<T = unknown>(text: string, options: ParseLinesOptions): T[]",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"name": "parseSequence",
|
|
114
114
|
"kind": "function",
|
|
115
115
|
"description": "Parses a JSON text sequence (RFC 7464, `application/json-seq`): records that each start with\nthe ASCII record separator (RS, U+001E) and hold one JSON text, as written by `jq --seq`.\n\n**Accepts:**\n- one strict JSON value per record (each record is read like parseStrict)\n- JSON values spread over several lines inside a record — unlike parseLines\n- several RS in a row (empty records are ignored, as the RFC's grammar allows)\n- an empty text, which holds zero records\n\n**Rejects (as invalid records):**\n- anything before the first RS\n- a record that isn't strict JSON, or holds only whitespace\n- a top-level number, `true`, `false` or `null` not followed by whitespace — RFC 7464 §2.4\n requires dropping it, since it may have been truncated\n\n**On invalid input:** throws a `SyntaxError` naming the 1-based record number, with the\noriginal parse error (if any) as its `cause` — unless `invalidRecords: 'skip'` says to drop it.",
|
|
116
|
-
"since": "
|
|
116
|
+
"since": "3.1.3",
|
|
117
117
|
"signatures": [
|
|
118
118
|
{
|
|
119
119
|
"signature": "parseSequence<T = unknown>(text: string, options: ParseSequenceOptions): T[]",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"name": "parseStrict",
|
|
169
169
|
"kind": "function",
|
|
170
170
|
"description": "Parses strict JSON (RFC 8259) — exactly what `JSON.parse` accepts, nothing more.\n\n**Accepts:** standard JSON only — double-quoted strings and keys, finite decimal numbers,\n`true`/`false`/`null`, objects and arrays, surrounding whitespace.\n\n**Rejects:** comments, trailing commas, single quotes, unquoted keys, hexadecimal numbers,\n`NaN`/`Infinity`, a leading byte order mark (U+FEFF), and anything else that isn't strict JSON.\n\n**On invalid input:** throws the native `SyntaxError` from `JSON.parse`.\n\nUse it to validate input that must be strict JSON, e.g. an API payload. To also read config\nfiles with comments or JSON5, use parse. To never throw, use safeParseStrict.",
|
|
171
|
-
"since": "
|
|
171
|
+
"since": "3.1.3",
|
|
172
172
|
"signatures": [
|
|
173
173
|
{
|
|
174
174
|
"signature": "parseStrict<T = unknown>(text: string): T",
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
"name": "safeParse",
|
|
211
211
|
"kind": "function",
|
|
212
212
|
"description": "Parses JSON permissively like parse — strict JSON, JSONC (HuJSON, JWCC) and JSON5 —\nbut returns `null` (or `fallback`) instead of throwing on invalid input.\n\n**Accepts / rejects:** exactly what parse does — see there for the full list.\n\n**On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\napart from an omitted argument — and `null` otherwise. Never throws.",
|
|
213
|
-
"since": "
|
|
213
|
+
"since": "3.1.3",
|
|
214
214
|
"signatures": [
|
|
215
215
|
{
|
|
216
216
|
"signature": "safeParse<T = unknown>(text: string): T | null",
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
"name": "safeParseLines",
|
|
283
283
|
"kind": "function",
|
|
284
284
|
"description": "Parses newline-delimited JSON (NDJSON, JSON Lines) like parseLines, but returns `null`\n(or `fallback`) instead of throwing on invalid input.\n\n**Accepts / rejects:** exactly what parseLines does, with the same\nParseLinesOptions.\n\n**On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\napart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\na fallback, pass `null` as the fallback.",
|
|
285
|
-
"since": "
|
|
285
|
+
"since": "3.1.3",
|
|
286
286
|
"signatures": [
|
|
287
287
|
{
|
|
288
288
|
"signature": "safeParseLines<T = unknown>(text: string): T[] | null",
|
|
@@ -367,7 +367,7 @@
|
|
|
367
367
|
"name": "safeParseSequence",
|
|
368
368
|
"kind": "function",
|
|
369
369
|
"description": "Parses a JSON text sequence (RFC 7464) like parseSequence, but returns `null` (or\n`fallback`) instead of throwing on invalid input.\n\n**Accepts / rejects:** exactly what parseSequence does, with the same\nParseSequenceOptions.\n\n**On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\napart from an omitted argument — and `null` otherwise. Never throws. To pass `options` without\na fallback, pass `null` as the fallback.",
|
|
370
|
-
"since": "
|
|
370
|
+
"since": "3.1.3",
|
|
371
371
|
"signatures": [
|
|
372
372
|
{
|
|
373
373
|
"signature": "safeParseSequence<T = unknown>(text: string): T[] | null",
|
|
@@ -452,7 +452,7 @@
|
|
|
452
452
|
"name": "safeParseStrict",
|
|
453
453
|
"kind": "function",
|
|
454
454
|
"description": "Parses strict JSON like parseStrict, but returns `null` (or `fallback`) instead of\nthrowing on invalid input.\n\n**Accepts / rejects:** exactly what parseStrict does — standard JSON only, no comments,\nno trailing commas, no JSON5 syntax, no leading byte order mark.\n\n**On invalid input:** returns `fallback` when one is given — even `undefined`, which is told\napart from an omitted argument — and `null` otherwise. Never throws.",
|
|
455
|
-
"since": "
|
|
455
|
+
"since": "3.1.3",
|
|
456
456
|
"signatures": [
|
|
457
457
|
{
|
|
458
458
|
"signature": "safeParseStrict<T = unknown>(text: string): T | null",
|
|
@@ -524,7 +524,7 @@
|
|
|
524
524
|
"name": "stringify",
|
|
525
525
|
"kind": "function",
|
|
526
526
|
"description": "Serializes a value to JSON text — pretty-printed with 2 spaces by default, or canonical.\n\n**Formatting:**\n- default — indented with 2 spaces, like a hand-written config file\n- `{ indent: n }` — indented with `n` spaces (an integer from 0 to 10); `{ indent: 0 }` gives a\n compact single line, the same as `JSON.stringify(value)`\n- `'canonical'` — canonical JSON (RFC 8785, JSON Canonicalization Scheme): object keys sorted\n by UTF-16 code units, no whitespace at all, numbers in their shortest ECMAScript form. Two\n equal values always give the same bytes, so the output can be hashed, signed or compared.\n Canonical output can't be indented — the RFC fixes every byte.\n\n**Same as `JSON.stringify`:** `toJSON()` is called (a `Date` becomes its ISO string),\n`undefined`, functions and symbols are dropped from objects and become `null` in arrays, and\n`Number`/`String`/`Boolean` objects are unwrapped. Outside `'canonical'`, `NaN` and `±Infinity`\nsilently become `null`, as there.\n\n**Throws** instead of returning `undefined` or dropping data silently:\n- a `TypeError` when `value` itself is `undefined`, a function or a symbol\n- a `TypeError` on a circular structure or a `BigInt` (like `JSON.stringify`)\n- with `'canonical'`, a `RangeError` on `NaN`, `±Infinity` or a string with a lone surrogate,\n which canonical JSON can't hold\n- a `RangeError` when `indent` isn't an integer from 0 to 10\n\nThe output is strict JSON, so it is also valid JSONC and JSON5.",
|
|
527
|
-
"since": "
|
|
527
|
+
"since": "3.1.3",
|
|
528
528
|
"signatures": [
|
|
529
529
|
{
|
|
530
530
|
"signature": "stringify(value: unknown, formatting: StringifyFormatting): string",
|
|
@@ -578,7 +578,7 @@
|
|
|
578
578
|
"name": "stringifyLines",
|
|
579
579
|
"kind": "function",
|
|
580
580
|
"description": "Serializes values as newline-delimited JSON — one compact JSON value per line, each followed\nby `\\n`. The output is both NDJSON and JSON Lines (`.jsonl`), which are the same format.\n\n**Formatting:**\n- default — each value compact, like `JSON.stringify(value)`\n- `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes, for\n hashing or diffing logs line by line\n\nIndentation isn't available: a line break inside a value would split it across lines. String\nvalues can't break a line either — `JSON.stringify` escapes `\\n` and `\\r` inside them.\n\n**Output:** every value is followed by `\\n`, including the last one (NDJSON requires it, and\nJSON Lines recommends it, so files can be concatenated). An empty array gives `''`.\n\n**Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\nrepresentation (`undefined`, a function, a symbol, a `BigInt`, a circular structure) — rather\nthan writing a line that would read back as something else. With `'canonical'`, also a\n`RangeError` on `NaN`, `±Infinity` or a lone surrogate (see stringify).",
|
|
581
|
-
"since": "
|
|
581
|
+
"since": "3.1.3",
|
|
582
582
|
"signatures": [
|
|
583
583
|
{
|
|
584
584
|
"signature": "stringifyLines(values: readonly unknown[], formatting?: \"canonical\"): string",
|
|
@@ -620,7 +620,7 @@
|
|
|
620
620
|
"name": "stringifySequence",
|
|
621
621
|
"kind": "function",
|
|
622
622
|
"description": "Serializes values as a JSON text sequence (RFC 7464, `application/json-seq`): each value is\nwritten as the ASCII record separator (RS, U+001E), the compact JSON text, then `\\n` — the\nexact framing the RFC requires of encoders, as `jq --seq` writes it.\n\n**Formatting:**\n- default — each value compact, like `JSON.stringify(value)`\n- `'canonical'` — each value as canonical JSON (RFC 8785): sorted keys, reproducible bytes\n\nIndentation isn't offered, for symmetry with stringifyLines: the trailing `\\n` is what\nlets a reader detect a truncated top-level number, `true`, `false` or `null` (RFC 7464 §2.4).\n\n**Output:** an empty array gives `''`.\n\n**Throws** a `TypeError` when `values` isn't an array, or when one of them has no JSON\nrepresentation (`undefined`, a function, a symbol, a `BigInt`, a circular structure). With\n`'canonical'`, also a `RangeError` on `NaN`, `±Infinity` or a lone surrogate (see\nstringify).",
|
|
623
|
-
"since": "
|
|
623
|
+
"since": "3.1.3",
|
|
624
624
|
"signatures": [
|
|
625
625
|
{
|
|
626
626
|
"signature": "stringifySequence(values: readonly unknown[], formatting?: \"canonical\"): string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helpers4/json",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "A set of helpers in TS/JS, compatible with tree-shaking, for json.",
|
|
5
5
|
"author": "baxyz <craft@baxyz.dev>",
|
|
6
6
|
"license": "LGPL-3.0",
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=26.0.0"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|