@helpers4/json 3.1.4 → 3.1.6
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/README.md +7 -0
- package/lib/index.d.ts +69 -11
- package/lib/index.js +41 -1
- package/lib/index.js.map +1 -1
- package/llms.txt +58 -9
- package/meta/api.json +49 -13
- package/meta/examples.json +15 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ A set of helpers for working with URLs.
|
|
|
21
21
|
- safeParseSequence
|
|
22
22
|
- safeParseStrict
|
|
23
23
|
- stringify
|
|
24
|
+
- stringifyForHtml
|
|
24
25
|
- stringifyLines
|
|
25
26
|
- stringifySequence
|
|
26
27
|
<!-- /AUTOMATIC-METHODS -->
|
|
@@ -28,12 +29,15 @@ A set of helpers for working with URLs.
|
|
|
28
29
|
## See
|
|
29
30
|
|
|
30
31
|
<!-- AUTOMATIC-SIBLINGS -->
|
|
32
|
+
- [animation](../animation)
|
|
31
33
|
- [array](../array)
|
|
34
|
+
- [browser](../browser)
|
|
32
35
|
- [ci](../ci)
|
|
33
36
|
- [color](../color)
|
|
34
37
|
- [commit](../commit)
|
|
35
38
|
- [date](../date)
|
|
36
39
|
- [function](../function)
|
|
40
|
+
- [geometry](../geometry)
|
|
37
41
|
- [guard](../guard)
|
|
38
42
|
- [id](../id)
|
|
39
43
|
- [license](../license)
|
|
@@ -57,12 +61,15 @@ A set of helpers for working with URLs.
|
|
|
57
61
|
<!-- AUTOMATIC-CATEGORIES-TABLE -->
|
|
58
62
|
| Name | Package | Source Code | Description |
|
|
59
63
|
|------|---------|-------------|-------------|
|
|
64
|
+
| animation | [@helpers4/animation](https://www.npmjs.com/package/@helpers4/animation) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/animation) | Timing and interpolation for animations |
|
|
60
65
|
| array | [@helpers4/array](https://www.npmjs.com/package/@helpers4/array) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/array) | Array manipulation utilities |
|
|
66
|
+
| browser | [@helpers4/browser](https://www.npmjs.com/package/@helpers4/browser) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/browser) | Browser-specific utilities |
|
|
61
67
|
| ci | [@helpers4/ci](https://www.npmjs.com/package/@helpers4/ci) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/ci) | CI/CD workflow status utilities |
|
|
62
68
|
| color | [@helpers4/color](https://www.npmjs.com/package/@helpers4/color) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/color) | Color conversion and validation utilities |
|
|
63
69
|
| commit | [@helpers4/commit](https://www.npmjs.com/package/@helpers4/commit) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/commit) | Conventional Commits parsing and analysis |
|
|
64
70
|
| date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | Date and time utility functions |
|
|
65
71
|
| function | [@helpers4/function](https://www.npmjs.com/package/@helpers4/function) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/function) | Function utilities and type guards |
|
|
72
|
+
| geometry | [@helpers4/geometry](https://www.npmjs.com/package/@helpers4/geometry) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/geometry) | 2D points, rectangles and affine matrices |
|
|
66
73
|
| guard | [@helpers4/guard](https://www.npmjs.com/package/@helpers4/guard) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/guard) | Runtime type guard utilities |
|
|
67
74
|
| id | [@helpers4/id](https://www.npmjs.com/package/@helpers4/id) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/id) | Unique identifier generation utilities |
|
|
68
75
|
| json | [@helpers4/json](https://www.npmjs.com/package/@helpers4/json) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/json) | JSON parsing and serialization, with its common variants |
|
package/lib/index.d.ts
CHANGED
|
@@ -215,8 +215,7 @@ declare function parseStrict<T = unknown>(text: string): T;
|
|
|
215
215
|
* apart from an omitted argument — and `null` otherwise. Never throws.
|
|
216
216
|
*
|
|
217
217
|
* @param text - The JSON, JSONC or JSON5 text to parse
|
|
218
|
-
* @
|
|
219
|
-
* @returns The parsed value typed as `T`, or `fallback` on invalid input
|
|
218
|
+
* @returns The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
220
219
|
* @see {@link parse} — same parsing, throws a `SyntaxError` instead
|
|
221
220
|
* @see {@link safeParseStrict} — strict JSON only
|
|
222
221
|
* @see {@link safeParseLines} — one value per line (NDJSON, JSON Lines)
|
|
@@ -228,6 +227,14 @@ declare function parseStrict<T = unknown>(text: string): T;
|
|
|
228
227
|
* @since 3.1.3
|
|
229
228
|
*/
|
|
230
229
|
declare function safeParse<T = unknown>(text: string): T | null;
|
|
230
|
+
/**
|
|
231
|
+
* Overload taking a `fallback`: returns it instead of `null` on invalid input.
|
|
232
|
+
*
|
|
233
|
+
* @param text - The JSON, JSONC or JSON5 text to parse
|
|
234
|
+
* @param fallback - Value returned on invalid input
|
|
235
|
+
* @returns The parsed value typed as `T`, or `fallback` on invalid input
|
|
236
|
+
* @since 3.1.3
|
|
237
|
+
*/
|
|
231
238
|
declare function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F;
|
|
232
239
|
|
|
233
240
|
/**
|
|
@@ -248,9 +255,7 @@ declare function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F
|
|
|
248
255
|
* a fallback, pass `null` as the fallback.
|
|
249
256
|
*
|
|
250
257
|
* @param text - The newline-delimited JSON text
|
|
251
|
-
* @
|
|
252
|
-
* @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}
|
|
253
|
-
* @returns The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
258
|
+
* @returns The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
254
259
|
* @see {@link parseLines} — same parsing, throws a `SyntaxError` instead
|
|
255
260
|
* @see {@link safeParseSequence} — JSON text sequences (RFC 7464)
|
|
256
261
|
* @example
|
|
@@ -260,6 +265,15 @@ declare function safeParse<T = unknown, F = T>(text: string, fallback: F): T | F
|
|
|
260
265
|
* @since 3.1.3
|
|
261
266
|
*/
|
|
262
267
|
declare function safeParseLines<T = unknown>(text: string): T[] | null;
|
|
268
|
+
/**
|
|
269
|
+
* Overload taking a `fallback`: returns it instead of `null` on invalid input.
|
|
270
|
+
*
|
|
271
|
+
* @param text - The newline-delimited JSON text
|
|
272
|
+
* @param fallback - Value returned on invalid input
|
|
273
|
+
* @param options - How to handle blank and invalid lines — see {@link ParseLinesOptions}
|
|
274
|
+
* @returns The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
275
|
+
* @since 3.1.3
|
|
276
|
+
*/
|
|
263
277
|
declare function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseLinesOptions): T[] | F;
|
|
264
278
|
|
|
265
279
|
/**
|
|
@@ -280,9 +294,7 @@ declare function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F,
|
|
|
280
294
|
* a fallback, pass `null` as the fallback.
|
|
281
295
|
*
|
|
282
296
|
* @param text - The JSON text sequence
|
|
283
|
-
* @
|
|
284
|
-
* @param options - How to handle invalid records — see {@link ParseSequenceOptions}
|
|
285
|
-
* @returns The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
297
|
+
* @returns The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
286
298
|
* @see {@link parseSequence} — same parsing, throws a `SyntaxError` instead
|
|
287
299
|
* @see {@link safeParseLines} — newline-delimited JSON (NDJSON, JSON Lines)
|
|
288
300
|
* @example
|
|
@@ -292,6 +304,15 @@ declare function safeParseLines<T = unknown, F = T[]>(text: string, fallback: F,
|
|
|
292
304
|
* @since 3.1.3
|
|
293
305
|
*/
|
|
294
306
|
declare function safeParseSequence<T = unknown>(text: string): T[] | null;
|
|
307
|
+
/**
|
|
308
|
+
* Overload taking a `fallback`: returns it instead of `null` on invalid input.
|
|
309
|
+
*
|
|
310
|
+
* @param text - The JSON text sequence
|
|
311
|
+
* @param fallback - Value returned on invalid input
|
|
312
|
+
* @param options - How to handle invalid records — see {@link ParseSequenceOptions}
|
|
313
|
+
* @returns The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
314
|
+
* @since 3.1.3
|
|
315
|
+
*/
|
|
295
316
|
declare function safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseSequenceOptions): T[] | F;
|
|
296
317
|
|
|
297
318
|
/**
|
|
@@ -310,8 +331,7 @@ declare function safeParseSequence<T = unknown, F = T[]>(text: string, fallback:
|
|
|
310
331
|
* apart from an omitted argument — and `null` otherwise. Never throws.
|
|
311
332
|
*
|
|
312
333
|
* @param text - The JSON text to parse
|
|
313
|
-
* @
|
|
314
|
-
* @returns The parsed value typed as `T`, or `fallback` on invalid input
|
|
334
|
+
* @returns The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
315
335
|
* @see {@link parseStrict} — same parsing, throws a `SyntaxError` instead
|
|
316
336
|
* @see {@link safeParse} — also accepts JSONC and JSON5
|
|
317
337
|
* @example
|
|
@@ -321,6 +341,14 @@ declare function safeParseSequence<T = unknown, F = T[]>(text: string, fallback:
|
|
|
321
341
|
* @since 3.1.3
|
|
322
342
|
*/
|
|
323
343
|
declare function safeParseStrict<T = unknown>(text: string): T | null;
|
|
344
|
+
/**
|
|
345
|
+
* Overload taking a `fallback`: returns it instead of `null` on invalid input.
|
|
346
|
+
*
|
|
347
|
+
* @param text - The JSON text to parse
|
|
348
|
+
* @param fallback - Value returned on invalid input
|
|
349
|
+
* @returns The parsed value typed as `T`, or `fallback` on invalid input
|
|
350
|
+
* @since 3.1.3
|
|
351
|
+
*/
|
|
324
352
|
declare function safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F;
|
|
325
353
|
|
|
326
354
|
/**
|
|
@@ -381,6 +409,36 @@ type StringifyFormatting = 'canonical' | {
|
|
|
381
409
|
*/
|
|
382
410
|
declare function stringify(value: unknown, formatting?: StringifyFormatting): string;
|
|
383
411
|
|
|
412
|
+
/**
|
|
413
|
+
* This file is part of helpers4.
|
|
414
|
+
* Copyright (C) 2025 baxyz
|
|
415
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
416
|
+
*/
|
|
417
|
+
/**
|
|
418
|
+
* Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a
|
|
419
|
+
* `<script type="application/json">` block or a script assignment.
|
|
420
|
+
*
|
|
421
|
+
* `<`, `>` and `&` are written as `\u003c`, `\u003e` and `\u0026`, so the text can never close
|
|
422
|
+
* the script element (`</script>`), open a comment (`<!--`) or be read as an entity. U+2028 and
|
|
423
|
+
* U+2029, valid in JSON but line terminators in some script contexts, are escaped too. These
|
|
424
|
+
* characters can only appear inside JSON strings, so the escaped text parses back to exactly the
|
|
425
|
+
* same value with `JSON.parse`.
|
|
426
|
+
*
|
|
427
|
+
* It throws like {@link stringify} does (a `TypeError` for `undefined`, a function, a symbol, a
|
|
428
|
+
* `BigInt` or a circular structure).
|
|
429
|
+
*
|
|
430
|
+
* @param value - The value to serialize
|
|
431
|
+
* @returns Compact JSON text with no raw `<`, `>`, `&`, U+2028 or U+2029
|
|
432
|
+
* @throws {TypeError} When `value` can't be represented as JSON
|
|
433
|
+
* @example
|
|
434
|
+
* stringifyForHtml({ html: '</script><b>' })
|
|
435
|
+
* // => '{"html":"\\u003c/script\\u003e\\u003cb\\u003e"}'
|
|
436
|
+
* @example
|
|
437
|
+
* `<script type="application/json" id="data">${stringifyForHtml(payload)}</script>`
|
|
438
|
+
* @since 3.1.5
|
|
439
|
+
*/
|
|
440
|
+
declare function stringifyForHtml(value: unknown): string;
|
|
441
|
+
|
|
384
442
|
/**
|
|
385
443
|
* This file is part of helpers4.
|
|
386
444
|
* Copyright (C) 2025 baxyz
|
|
@@ -459,5 +517,5 @@ declare function stringifyLines(values: readonly unknown[], formatting?: 'canoni
|
|
|
459
517
|
*/
|
|
460
518
|
declare function stringifySequence(values: readonly unknown[], formatting?: 'canonical'): string;
|
|
461
519
|
|
|
462
|
-
export { parse, parseLines, parseSequence, parseStrict, safeParse, safeParseLines, safeParseSequence, safeParseStrict, stringify, stringifyLines, stringifySequence };
|
|
520
|
+
export { parse, parseLines, parseSequence, parseStrict, safeParse, safeParseLines, safeParseSequence, safeParseStrict, stringify, stringifyForHtml, stringifyLines, stringifySequence };
|
|
463
521
|
export type { ParseLinesOptions, ParseSequenceOptions, StringifyFormatting };
|
package/lib/index.js
CHANGED
|
@@ -815,6 +815,46 @@ function stringify(value, formatting = {}) {
|
|
|
815
815
|
return text;
|
|
816
816
|
}
|
|
817
817
|
//#endregion
|
|
818
|
+
//#region helpers/json/stringifyForHtml.ts
|
|
819
|
+
/**
|
|
820
|
+
* This file is part of helpers4.
|
|
821
|
+
* Copyright (C) 2025 baxyz
|
|
822
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
823
|
+
*/
|
|
824
|
+
var ESCAPES = {
|
|
825
|
+
"<": "\\u003c",
|
|
826
|
+
">": "\\u003e",
|
|
827
|
+
"&": "\\u0026",
|
|
828
|
+
"\u2028": "\\u2028",
|
|
829
|
+
"\u2029": "\\u2029"
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a
|
|
833
|
+
* `<script type="application/json">` block or a script assignment.
|
|
834
|
+
*
|
|
835
|
+
* `<`, `>` and `&` are written as `\u003c`, `\u003e` and `\u0026`, so the text can never close
|
|
836
|
+
* the script element (`<\/script>`), open a comment (`<!--`) or be read as an entity. U+2028 and
|
|
837
|
+
* U+2029, valid in JSON but line terminators in some script contexts, are escaped too. These
|
|
838
|
+
* characters can only appear inside JSON strings, so the escaped text parses back to exactly the
|
|
839
|
+
* same value with `JSON.parse`.
|
|
840
|
+
*
|
|
841
|
+
* It throws like {@link stringify} does (a `TypeError` for `undefined`, a function, a symbol, a
|
|
842
|
+
* `BigInt` or a circular structure).
|
|
843
|
+
*
|
|
844
|
+
* @param value - The value to serialize
|
|
845
|
+
* @returns Compact JSON text with no raw `<`, `>`, `&`, U+2028 or U+2029
|
|
846
|
+
* @throws {TypeError} When `value` can't be represented as JSON
|
|
847
|
+
* @example
|
|
848
|
+
* stringifyForHtml({ html: '<\/script><b>' })
|
|
849
|
+
* // => '{"html":"\\u003c/script\\u003e\\u003cb\\u003e"}'
|
|
850
|
+
* @example
|
|
851
|
+
* `<script type="application/json" id="data">${stringifyForHtml(payload)}<\/script>`
|
|
852
|
+
* @since 3.1.5
|
|
853
|
+
*/
|
|
854
|
+
function stringifyForHtml(value) {
|
|
855
|
+
return stringify(value, { indent: 0 }).replace(/[<>&\u2028\u2029]/g, (char) => ESCAPES[char]);
|
|
856
|
+
}
|
|
857
|
+
//#endregion
|
|
818
858
|
//#region helpers/json/_serializeRecords.ts
|
|
819
859
|
/**
|
|
820
860
|
* This file is part of helpers4.
|
|
@@ -923,6 +963,6 @@ function stringifySequence(values, formatting) {
|
|
|
923
963
|
return serializeRecords("stringifySequence", values, formatting).map((text) => `\u001E${text}\n`).join("");
|
|
924
964
|
}
|
|
925
965
|
//#endregion
|
|
926
|
-
export { parse, parseLines, parseSequence, parseStrict, safeParse, safeParseLines, safeParseSequence, safeParseStrict, stringify, stringifyLines, stringifySequence };
|
|
966
|
+
export { parse, parseLines, parseSequence, parseStrict, safeParse, safeParseLines, safeParseSequence, safeParseStrict, stringify, stringifyForHtml, stringifyLines, stringifySequence };
|
|
927
967
|
|
|
928
968
|
//# sourceMappingURL=index.js.map
|
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 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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"}
|
|
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/stringifyForHtml.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 * @returns The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)\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;\n/**\n * Overload taking a `fallback`: returns it instead of `null` on invalid input.\n *\n * @param text - The JSON, JSONC or JSON5 text to parse\n * @param fallback - Value returned on invalid input\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @since 3.1.3\n */\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 * @returns The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)\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;\n/**\n * Overload taking a `fallback`: returns it instead of `null` on invalid input.\n *\n * @param text - The newline-delimited JSON text\n * @param fallback - Value returned on invalid input\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 * @since 3.1.3\n */\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 * @returns The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)\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;\n/**\n * Overload taking a `fallback`: returns it instead of `null` on invalid input.\n *\n * @param text - The JSON text sequence\n * @param fallback - Value returned on invalid input\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 * @since 3.1.3\n */\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 * @returns The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)\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;\n/**\n * Overload taking a `fallback`: returns it instead of `null` on invalid input.\n *\n * @param text - The JSON text to parse\n * @param fallback - Value returned on invalid input\n * @returns The parsed value typed as `T`, or `fallback` on invalid input\n * @since 3.1.3\n */\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\nimport { stringify } from './stringify';\n\nconst ESCAPES: Record<string, string> = {\n '<': '\\\\u003c',\n '>': '\\\\u003e',\n '&': '\\\\u0026',\n '\\u2028': '\\\\u2028',\n '\\u2029': '\\\\u2029',\n};\n\n/**\n * Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a\n * `<script type=\"application/json\">` block or a script assignment.\n *\n * `<`, `>` and `&` are written as `\\u003c`, `\\u003e` and `\\u0026`, so the text can never close\n * the script element (`</script>`), open a comment (`<!--`) or be read as an entity. U+2028 and\n * U+2029, valid in JSON but line terminators in some script contexts, are escaped too. These\n * characters can only appear inside JSON strings, so the escaped text parses back to exactly the\n * same value with `JSON.parse`.\n *\n * It throws like {@link stringify} does (a `TypeError` for `undefined`, a function, a symbol, a\n * `BigInt` or a circular structure).\n *\n * @param value - The value to serialize\n * @returns Compact JSON text with no raw `<`, `>`, `&`, U+2028 or U+2029\n * @throws {TypeError} When `value` can't be represented as JSON\n * @example\n * stringifyForHtml({ html: '</script><b>' })\n * // => '{\"html\":\"\\\\u003c/script\\\\u003e\\\\u003cb\\\\u003e\"}'\n * @example\n * `<script type=\"application/json\" id=\"data\">${stringifyForHtml(payload)}</script>`\n * @since 3.1.5\n */\nexport function stringifyForHtml(value: unknown): string {\n return stringify(value, { indent: 0 }).replace(/[<>&\\u2028\\u2029]/g, (char) => ESCAPES[char] as string);\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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @helpers4/json
|
|
2
2
|
|
|
3
3
|
> Tree-shakable TypeScript utility functions for the `json` domain.
|
|
4
|
-
> Package: `@helpers4/json` — Version: 3.1.
|
|
4
|
+
> Package: `@helpers4/json` — Version: 3.1.6
|
|
5
5
|
> License: LGPL-3.0-or-later
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
@@ -31,6 +31,7 @@ import { parse, parseLines, parseSequence, ... } from '@helpers4/json';
|
|
|
31
31
|
| `safeParseSequence` | Parses a JSON text sequence (RFC 7464) like parseSequence, but returns `null` (or `fallback`) instea |
|
|
32
32
|
| `safeParseStrict` | Parses strict JSON like parseStrict, but returns `null` (or `fallback`) instead of throwing on inval |
|
|
33
33
|
| `stringify` | Serializes a value to JSON text — pretty-printed with 2 spaces by default, or canonical. **Formatti |
|
|
34
|
+
| `stringifyForHtml` | Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a `<script t |
|
|
34
35
|
| `stringifyLines` | Serializes values as newline-delimited JSON — one compact JSON value per line, each followed by `\n` |
|
|
35
36
|
| `stringifySequence` | Serializes values as a JSON text sequence (RFC 7464, `application/json-seq`): each value is written |
|
|
36
37
|
|
|
@@ -301,7 +302,7 @@ safeParse<T = unknown>(text: string): T | null
|
|
|
301
302
|
|
|
302
303
|
- `text: string` — The JSON, JSONC or JSON5 text to parse
|
|
303
304
|
|
|
304
|
-
**Returns:** `T | null` — The parsed value typed as `T`, or `
|
|
305
|
+
**Returns:** `T | null` — The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
305
306
|
|
|
306
307
|
```typescript
|
|
307
308
|
import { safeParse } from '@helpers4/json';
|
|
@@ -312,7 +313,7 @@ safeParse<T = unknown, F = T>(text: string, fallback: F): T | F
|
|
|
312
313
|
**Parameters:**
|
|
313
314
|
|
|
314
315
|
- `text: string` — The JSON, JSONC or JSON5 text to parse
|
|
315
|
-
- `fallback: F` — Value returned on invalid input
|
|
316
|
+
- `fallback: F` — Value returned on invalid input
|
|
316
317
|
|
|
317
318
|
**Returns:** `T | F` — The parsed value typed as `T`, or `fallback` on invalid input
|
|
318
319
|
|
|
@@ -360,7 +361,7 @@ safeParseLines<T = unknown>(text: string): T[] | null
|
|
|
360
361
|
|
|
361
362
|
- `text: string` — The newline-delimited JSON text
|
|
362
363
|
|
|
363
|
-
**Returns:** `T[] | null` — The parsed values typed as `T[]`, or `
|
|
364
|
+
**Returns:** `T[] | null` — The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
364
365
|
|
|
365
366
|
```typescript
|
|
366
367
|
import { safeParseLines } from '@helpers4/json';
|
|
@@ -371,7 +372,7 @@ safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseL
|
|
|
371
372
|
**Parameters:**
|
|
372
373
|
|
|
373
374
|
- `text: string` — The newline-delimited JSON text
|
|
374
|
-
- `fallback: F` — Value returned on invalid input
|
|
375
|
+
- `fallback: F` — Value returned on invalid input
|
|
375
376
|
- `options?: ParseLinesOptions` — How to handle blank and invalid lines — see ParseLinesOptions
|
|
376
377
|
|
|
377
378
|
**Returns:** `F | T[]` — The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
@@ -420,7 +421,7 @@ safeParseSequence<T = unknown>(text: string): T[] | null
|
|
|
420
421
|
|
|
421
422
|
- `text: string` — The JSON text sequence
|
|
422
423
|
|
|
423
|
-
**Returns:** `T[] | null` — The parsed values typed as `T[]`, or `
|
|
424
|
+
**Returns:** `T[] | null` — The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
424
425
|
|
|
425
426
|
```typescript
|
|
426
427
|
import { safeParseSequence } from '@helpers4/json';
|
|
@@ -431,7 +432,7 @@ safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: Par
|
|
|
431
432
|
**Parameters:**
|
|
432
433
|
|
|
433
434
|
- `text: string` — The JSON text sequence
|
|
434
|
-
- `fallback: F` — Value returned on invalid input
|
|
435
|
+
- `fallback: F` — Value returned on invalid input
|
|
435
436
|
- `options?: ParseSequenceOptions` — How to handle invalid records — see ParseSequenceOptions
|
|
436
437
|
|
|
437
438
|
**Returns:** `F | T[]` — The parsed values typed as `T[]`, or `fallback` on invalid input
|
|
@@ -479,7 +480,7 @@ safeParseStrict<T = unknown>(text: string): T | null
|
|
|
479
480
|
|
|
480
481
|
- `text: string` — The JSON text to parse
|
|
481
482
|
|
|
482
|
-
**Returns:** `T | null` — The parsed value typed as `T`, or `
|
|
483
|
+
**Returns:** `T | null` — The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)
|
|
483
484
|
|
|
484
485
|
```typescript
|
|
485
486
|
import { safeParseStrict } from '@helpers4/json';
|
|
@@ -490,7 +491,7 @@ safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F
|
|
|
490
491
|
**Parameters:**
|
|
491
492
|
|
|
492
493
|
- `text: string` — The JSON text to parse
|
|
493
|
-
- `fallback: F` — Value returned on invalid input
|
|
494
|
+
- `fallback: F` — Value returned on invalid input
|
|
494
495
|
|
|
495
496
|
**Returns:** `T | F` — The parsed value typed as `T`, or `fallback` on invalid input
|
|
496
497
|
|
|
@@ -587,6 +588,54 @@ stringify({ b: 1, a: 2 }, 'canonical')
|
|
|
587
588
|
|
|
588
589
|
---
|
|
589
590
|
|
|
591
|
+
### `stringifyForHtml`
|
|
592
|
+
|
|
593
|
+
Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a
|
|
594
|
+
`<script type="application/json">` block or a script assignment.
|
|
595
|
+
|
|
596
|
+
`<`, `>` and `&` are written as `\u003c`, `\u003e` and `\u0026`, so the text can never close
|
|
597
|
+
the script element (`</script>`), open a comment (`<!--`) or be read as an entity. U+2028 and
|
|
598
|
+
U+2029, valid in JSON but line terminators in some script contexts, are escaped too. These
|
|
599
|
+
characters can only appear inside JSON strings, so the escaped text parses back to exactly the
|
|
600
|
+
same value with `JSON.parse`.
|
|
601
|
+
|
|
602
|
+
It throws like stringify does (a `TypeError` for `undefined`, a function, a symbol, a
|
|
603
|
+
`BigInt` or a circular structure).
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
import { stringifyForHtml } from '@helpers4/json';
|
|
607
|
+
|
|
608
|
+
stringifyForHtml(value: unknown): string
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**Parameters:**
|
|
612
|
+
|
|
613
|
+
- `value: unknown` — The value to serialize
|
|
614
|
+
|
|
615
|
+
**Returns:** `string` — Compact JSON text with no raw `<`, `>`, `&`, U+2028 or U+2029
|
|
616
|
+
|
|
617
|
+
**Examples:**
|
|
618
|
+
|
|
619
|
+
*Inline data in a script block*
|
|
620
|
+
|
|
621
|
+
A value containing </script> can no longer close the element it is embedded in.
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
stringifyForHtml({ note: '</script><b>' })
|
|
625
|
+
// => '{"note":"\\u003c/script\\u003e\\u003cb\\u003e"}'
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
*Same value after parsing*
|
|
629
|
+
|
|
630
|
+
The escapes are plain JSON escapes: JSON.parse gives back the original value.
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
JSON.parse(stringifyForHtml({ a: '<&>' })).a
|
|
634
|
+
// => '<&>'
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
590
639
|
### `stringifyLines`
|
|
591
640
|
|
|
592
641
|
Serializes values as newline-delimited JSON — one compact JSON value per line, each followed
|
package/meta/api.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"category": "json",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.6",
|
|
4
4
|
"functions": [
|
|
5
5
|
{
|
|
6
6
|
"name": "parse",
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
],
|
|
225
225
|
"returns": {
|
|
226
226
|
"type": "T | null",
|
|
227
|
-
"description": "The parsed value typed as `T`, or `
|
|
227
|
+
"description": "The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)"
|
|
228
228
|
},
|
|
229
229
|
"typeParameters": [
|
|
230
230
|
{
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
237
|
"signature": "safeParse<T = unknown, F = T>(text: string, fallback: F): T | F",
|
|
238
|
-
"description": "
|
|
238
|
+
"description": "Overload taking a `fallback`: returns it instead of `null` on invalid input.",
|
|
239
239
|
"params": [
|
|
240
240
|
{
|
|
241
241
|
"name": "text",
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
{
|
|
246
246
|
"name": "fallback",
|
|
247
247
|
"type": "F",
|
|
248
|
-
"description": "Value returned on invalid input
|
|
248
|
+
"description": "Value returned on invalid input"
|
|
249
249
|
}
|
|
250
250
|
],
|
|
251
251
|
"returns": {
|
|
@@ -296,7 +296,7 @@
|
|
|
296
296
|
],
|
|
297
297
|
"returns": {
|
|
298
298
|
"type": "T[] | null",
|
|
299
|
-
"description": "The parsed values typed as `T[]`, or `
|
|
299
|
+
"description": "The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)"
|
|
300
300
|
},
|
|
301
301
|
"typeParameters": [
|
|
302
302
|
{
|
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
},
|
|
308
308
|
{
|
|
309
309
|
"signature": "safeParseLines<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseLinesOptions): F | T[]",
|
|
310
|
-
"description": "
|
|
310
|
+
"description": "Overload taking a `fallback`: returns it instead of `null` on invalid input.",
|
|
311
311
|
"params": [
|
|
312
312
|
{
|
|
313
313
|
"name": "text",
|
|
@@ -317,7 +317,7 @@
|
|
|
317
317
|
{
|
|
318
318
|
"name": "fallback",
|
|
319
319
|
"type": "F",
|
|
320
|
-
"description": "Value returned on invalid input
|
|
320
|
+
"description": "Value returned on invalid input"
|
|
321
321
|
},
|
|
322
322
|
{
|
|
323
323
|
"name": "options",
|
|
@@ -381,7 +381,7 @@
|
|
|
381
381
|
],
|
|
382
382
|
"returns": {
|
|
383
383
|
"type": "T[] | null",
|
|
384
|
-
"description": "The parsed values typed as `T[]`, or `
|
|
384
|
+
"description": "The parsed values typed as `T[]`, or `null` on invalid input (pass a `fallback` to get it instead)"
|
|
385
385
|
},
|
|
386
386
|
"typeParameters": [
|
|
387
387
|
{
|
|
@@ -392,7 +392,7 @@
|
|
|
392
392
|
},
|
|
393
393
|
{
|
|
394
394
|
"signature": "safeParseSequence<T = unknown, F = T[]>(text: string, fallback: F, options?: ParseSequenceOptions): F | T[]",
|
|
395
|
-
"description": "
|
|
395
|
+
"description": "Overload taking a `fallback`: returns it instead of `null` on invalid input.",
|
|
396
396
|
"params": [
|
|
397
397
|
{
|
|
398
398
|
"name": "text",
|
|
@@ -402,7 +402,7 @@
|
|
|
402
402
|
{
|
|
403
403
|
"name": "fallback",
|
|
404
404
|
"type": "F",
|
|
405
|
-
"description": "Value returned on invalid input
|
|
405
|
+
"description": "Value returned on invalid input"
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
"name": "options",
|
|
@@ -466,7 +466,7 @@
|
|
|
466
466
|
],
|
|
467
467
|
"returns": {
|
|
468
468
|
"type": "T | null",
|
|
469
|
-
"description": "The parsed value typed as `T`, or `
|
|
469
|
+
"description": "The parsed value typed as `T`, or `null` on invalid input (pass a `fallback` to get it instead)"
|
|
470
470
|
},
|
|
471
471
|
"typeParameters": [
|
|
472
472
|
{
|
|
@@ -477,7 +477,7 @@
|
|
|
477
477
|
},
|
|
478
478
|
{
|
|
479
479
|
"signature": "safeParseStrict<T = unknown, F = T>(text: string, fallback: F): T | F",
|
|
480
|
-
"description": "
|
|
480
|
+
"description": "Overload taking a `fallback`: returns it instead of `null` on invalid input.",
|
|
481
481
|
"params": [
|
|
482
482
|
{
|
|
483
483
|
"name": "text",
|
|
@@ -487,7 +487,7 @@
|
|
|
487
487
|
{
|
|
488
488
|
"name": "fallback",
|
|
489
489
|
"type": "F",
|
|
490
|
-
"description": "Value returned on invalid input
|
|
490
|
+
"description": "Value returned on invalid input"
|
|
491
491
|
}
|
|
492
492
|
],
|
|
493
493
|
"returns": {
|
|
@@ -574,6 +574,42 @@
|
|
|
574
574
|
}
|
|
575
575
|
]
|
|
576
576
|
},
|
|
577
|
+
{
|
|
578
|
+
"name": "stringifyForHtml",
|
|
579
|
+
"kind": "function",
|
|
580
|
+
"description": "Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a\n`<script type=\"application/json\">` block or a script assignment.\n\n`<`, `>` and `&` are written as `\\u003c`, `\\u003e` and `\\u0026`, so the text can never close\nthe script element (`</script>`), open a comment (`<!--`) or be read as an entity. U+2028 and\nU+2029, valid in JSON but line terminators in some script contexts, are escaped too. These\ncharacters can only appear inside JSON strings, so the escaped text parses back to exactly the\nsame value with `JSON.parse`.\n\nIt throws like stringify does (a `TypeError` for `undefined`, a function, a symbol, a\n`BigInt` or a circular structure).",
|
|
581
|
+
"since": "3.1.5",
|
|
582
|
+
"signatures": [
|
|
583
|
+
{
|
|
584
|
+
"signature": "stringifyForHtml(value: unknown): string",
|
|
585
|
+
"description": "Serializes a value to compact JSON that is safe to inline in an HTML page, typically in a\n`<script type=\"application/json\">` block or a script assignment.\n\n`<`, `>` and `&` are written as `\\u003c`, `\\u003e` and `\\u0026`, so the text can never close\nthe script element (`</script>`), open a comment (`<!--`) or be read as an entity. U+2028 and\nU+2029, valid in JSON but line terminators in some script contexts, are escaped too. These\ncharacters can only appear inside JSON strings, so the escaped text parses back to exactly the\nsame value with `JSON.parse`.\n\nIt throws like stringify does (a `TypeError` for `undefined`, a function, a symbol, a\n`BigInt` or a circular structure).",
|
|
586
|
+
"params": [
|
|
587
|
+
{
|
|
588
|
+
"name": "value",
|
|
589
|
+
"type": "unknown",
|
|
590
|
+
"description": "The value to serialize"
|
|
591
|
+
}
|
|
592
|
+
],
|
|
593
|
+
"returns": {
|
|
594
|
+
"type": "string",
|
|
595
|
+
"description": "Compact JSON text with no raw `<`, `>`, `&`, U+2028 or U+2029"
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
],
|
|
599
|
+
"examples": [
|
|
600
|
+
{
|
|
601
|
+
"title": "Inline data in a script block",
|
|
602
|
+
"description": "A value containing </script> can no longer close the element it is embedded in.",
|
|
603
|
+
"code": "stringifyForHtml({ note: '</script><b>' })\n// => '{\"note\":\"\\\\u003c/script\\\\u003e\\\\u003cb\\\\u003e\"}'"
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
"title": "Same value after parsing",
|
|
607
|
+
"description": "The escapes are plain JSON escapes: JSON.parse gives back the original value.",
|
|
608
|
+
"code": "JSON.parse(stringifyForHtml({ a: '<&>' })).a\n// => '<&>'"
|
|
609
|
+
}
|
|
610
|
+
],
|
|
611
|
+
"sourceFile": "stringifyForHtml.ts"
|
|
612
|
+
},
|
|
577
613
|
{
|
|
578
614
|
"name": "stringifyLines",
|
|
579
615
|
"kind": "function",
|
package/meta/examples.json
CHANGED
|
@@ -151,6 +151,21 @@
|
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
},
|
|
154
|
+
{
|
|
155
|
+
"name": "stringifyForHtml",
|
|
156
|
+
"examples": [
|
|
157
|
+
{
|
|
158
|
+
"title": "Inline data in a script block",
|
|
159
|
+
"description": "A value containing </script> can no longer close the element it is embedded in.",
|
|
160
|
+
"code": "stringifyForHtml({ note: '</script><b>' })\n// => '{\"note\":\"\\\\u003c/script\\\\u003e\\\\u003cb\\\\u003e\"}'"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"title": "Same value after parsing",
|
|
164
|
+
"description": "The escapes are plain JSON escapes: JSON.parse gives back the original value.",
|
|
165
|
+
"code": "JSON.parse(stringifyForHtml({ a: '<&>' })).a\n// => '<&>'"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
},
|
|
154
169
|
{
|
|
155
170
|
"name": "stringifyLines",
|
|
156
171
|
"examples": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helpers4/json",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.6",
|
|
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",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"safeParseSequence",
|
|
37
37
|
"safeParseStrict",
|
|
38
38
|
"stringify",
|
|
39
|
+
"stringifyForHtml",
|
|
39
40
|
"stringifyLines",
|
|
40
41
|
"stringifySequence"
|
|
41
42
|
],
|