@cbortech/cbor 0.27.0 → 0.27.1
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.ja.md +73 -0
- package/README.md +75 -0
- package/dist/ast/CborAppSeqResult.d.ts +37 -4
- package/dist/ast/CborArray.d.ts +2 -2
- package/dist/ast/CborByteString.d.ts +2 -2
- package/dist/ast/CborEmbeddedCBOR.d.ts +1 -1
- package/dist/ast/CborFloat.d.ts +1 -1
- package/dist/ast/CborIndefiniteByteString.d.ts +1 -1
- package/dist/ast/CborIndefiniteTextString.d.ts +1 -1
- package/dist/ast/CborItem.d.ts +297 -7
- package/dist/ast/CborMap.d.ts +2 -2
- package/dist/ast/CborNint.d.ts +1 -1
- package/dist/ast/CborTag.d.ts +4 -4
- package/dist/ast/CborTextString.d.ts +2 -2
- package/dist/ast/CborUint.d.ts +1 -1
- package/dist/ast/index.cjs +1 -1
- package/dist/ast/index.js +1 -1
- package/dist/cddl/index.cjs +1 -1
- package/dist/cddl/index.js +1 -1
- package/dist/cdn/index.cjs +1 -1
- package/dist/cdn/index.js +1 -1
- package/dist/cdn/serialize-utils.d.ts +30 -2
- package/dist/extensions/cri.d.ts +2 -2
- package/dist/extensions/dt.d.ts +4 -4
- package/dist/extensions/ip.d.ts +3 -3
- package/dist/extensions/types.d.ts +40 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/{mapEntries-CvLdiN0h.js → mapEntries-CCLaJSaJ.js} +1114 -933
- package/dist/mapEntries-CCLaJSaJ.js.map +1 -0
- package/dist/mapEntries-CZZJScaj.cjs +13 -0
- package/dist/mapEntries-CZZJScaj.cjs.map +1 -0
- package/dist/{schema-CNfrVRYp.js → schema-DN9inJny.js} +3 -3
- package/dist/{schema-CNfrVRYp.js.map → schema-DN9inJny.js.map} +1 -1
- package/dist/{schema-iXpYtKQl.cjs → schema-zsg5yCPK.cjs} +2 -2
- package/dist/{schema-iXpYtKQl.cjs.map → schema-zsg5yCPK.cjs.map} +1 -1
- package/dist/{serialize-utils-CjTqQivB.cjs → serialize-utils-DhlW61ZX.cjs} +6 -6
- package/dist/serialize-utils-DhlW61ZX.cjs.map +1 -0
- package/dist/{serialize-utils-BuIZPaUc.js → serialize-utils-h-CVB9rg.js} +57 -47
- package/dist/{serialize-utils-BuIZPaUc.js.map → serialize-utils-h-CVB9rg.js.map} +1 -1
- package/dist/types.d.ts +273 -0
- package/dist/utils/hexfloat.d.ts +10 -2
- package/package.json +7 -8
- package/dist/mapEntries-C1f7G0AM.cjs +0 -13
- package/dist/mapEntries-C1f7G0AM.cjs.map +0 -1
- package/dist/mapEntries-CvLdiN0h.js.map +0 -1
- package/dist/serialize-utils-CjTqQivB.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize-utils-BuIZPaUc.js","names":[],"sources":["../src/cdn/errors.ts","../src/utils/hex.ts","../src/utils/base64.ts","../src/cdn/tokenizer.ts","../src/cdn/serialize-utils.ts"],"sourcesContent":["/**\n * Structured syntax error thrown by the CDN tokenizer and parser.\n *\n * Carries the source position of the failure so tooling (editors, linters,\n * playgrounds) can point at the offending range without parsing the message.\n * Position fields are present whenever the failure site knows them.\n */\nexport class CdnSyntaxError extends SyntaxError {\n /** Character offset of the start of the offending range in the source input. */\n readonly offset?: number;\n /** 1-based line number of the offending range. */\n readonly line?: number;\n /** 1-based column number of the offending range. */\n readonly column?: number;\n /** Character offset just past the end of the offending range. */\n readonly endOffset?: number;\n\n constructor(\n message: string,\n position?: {\n offset?: number;\n line?: number;\n column?: number;\n endOffset?: number;\n }\n ) {\n const loc =\n position?.line !== undefined\n ? ` at line ${position.line}, column ${position.column}`\n : '';\n super(`EDN parse error${loc}: ${message}`);\n this.name = 'CdnSyntaxError';\n this.offset = position?.offset;\n this.line = position?.line;\n this.column = position?.column;\n this.endOffset = position?.endOffset;\n }\n}\n","/**\n * Hex codec helpers shared by the CDN serializer, parser, and extensions.\n *\n * Native `Uint8Array.prototype.toHex` is the fastest option at every size, so\n * it is used whenever available. Native `Uint8Array.fromHex` carries a fixed\n * ~300–400 ns argument-validation overhead per call (measured on Node 25/26),\n * which makes a lookup-table loop 5–6× faster for small payloads such as\n * UUIDs; native only wins from ~128 bytes up. `hexToBytes` therefore switches\n * implementations on input length.\n */\n\nconst HEX_DIGITS = Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n// Maps hex char codes (both cases) to their value; -1 marks invalid chars so\n// the decode loop can detect them with a single sign check per byte.\nconst HEX_VALUES = new Int8Array(128).fill(-1);\nfor (let i = 0; i < 16; i++) {\n HEX_VALUES['0123456789abcdef'.charCodeAt(i)] = i;\n HEX_VALUES['0123456789ABCDEF'.charCodeAt(i)] = i;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeToHex =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (Uint8Array.prototype as any).toHex === 'function';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeFromHex =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (Uint8Array as any).fromHex === 'function';\n\n// Below this many hex digits the LUT loop beats native fromHex.\nconst NATIVE_FROM_HEX_MIN_DIGITS = 256;\n\n/** Encode bytes as lowercase hex. */\nexport function bytesToHex(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToHex) return (bytes as any).toHex();\n let out = '';\n for (let i = 0; i < bytes.length; i++) out += HEX_DIGITS[bytes[i]!];\n return out;\n}\n\n// Uppercase table for the annotated hex-dump format (RFC 8949 §3 style).\nconst HEX_DIGITS_UPPER = Array.from({ length: 256 }, (_, i) =>\n i.toString(16).toUpperCase().padStart(2, '0')\n);\n\n/** Encode one byte as two uppercase hex digits (e.g. 10 → \"0A\"). */\nexport function byteToHexUpper(b: number): string {\n return HEX_DIGITS_UPPER[b]!;\n}\n\n/** Encode bytes as space-separated uppercase hex (e.g. \"0A FF\"), the\n * per-line format used by `toHexDump()`. */\nexport function bytesToSpacedHexUpper(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n if (i > 0) out += ' ';\n out += HEX_DIGITS_UPPER[bytes[i]!];\n }\n return out;\n}\n\n/**\n * Decode a hex string to bytes.\n *\n * Throws SyntaxError on odd-length input or non-hex characters (the native\n * fromHex path throws its own SyntaxError with a different message).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0)\n throw new SyntaxError(`hex string has odd length: ${hex.length}`);\n if (_hasNativeFromHex && hex.length >= NATIVE_FROM_HEX_MIN_DIGITS)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (Uint8Array as any).fromHex(hex) as Uint8Array;\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0, j = 0; i < hex.length; i += 2, j++) {\n const c1 = hex.charCodeAt(i);\n const c2 = hex.charCodeAt(i + 1);\n const hi = c1 < 128 ? HEX_VALUES[c1]! : -1;\n const lo = c2 < 128 ? HEX_VALUES[c2]! : -1;\n if ((hi | lo) < 0) {\n const bad = hi < 0 ? hex[i]! : hex[i + 1]!;\n throw new SyntaxError(\n `invalid character ${JSON.stringify(bad)} in hex string`\n );\n }\n out[j] = (hi << 4) | lo;\n }\n return out;\n}\n","/**\n * Decode base64 text (classic or URL-safe alphabet, padding optional) into\n * bytes, with strict RFC 4648 validation.\n *\n * Used by the CDN parser (b64'…' literals, §6.2.2) and the CDDL tokenizer\n * (b64'…' byte strings, RFC 8610 §3.1).\n *\n * Recoverable deviations (padding-count mismatches, non-zero trailing bits)\n * are reported through `onRecoverableError` when provided; otherwise they\n * throw a plain SyntaxError, which callers wrap with position information.\n */\nexport function base64ToBytes(\n b64: string,\n onRecoverableError?: (msg: string) => void\n): Uint8Array {\n // Separate data characters from trailing '=' padding.\n const eqIdx = b64.indexOf('=');\n const data = eqIdx >= 0 ? b64.slice(0, eqIdx) : b64;\n const pad = eqIdx >= 0 ? b64.slice(eqIdx) : '';\n\n // draft-27 b64dig = ALPHA / DIGIT / \"-\" / \"_\" / \"+\" / \"/\"\n // Classic (+/) and URL-safe (-_) position-62/63 chars are both valid in the\n // same literal. Reject anything outside this set as a hard error.\n if (/[^A-Za-z0-9+/\\-_]/.test(data)) {\n const bad = [...data].find((c) => !/[A-Za-z0-9+/\\-_]/.test(c)) ?? '';\n throw new SyntaxError(\n `invalid character ${JSON.stringify(bad)} in base64 data`\n );\n }\n if (pad && !/^=+$/.test(pad))\n throw new SyntaxError(`invalid character after base64 '=' padding`);\n\n const rem = data.length % 4;\n\n // rem === 1 cannot arise from any valid byte sequence (always invalid).\n if (rem === 1)\n throw new SyntaxError(\n `invalid base64 length: ${data.length} data characters (length mod 4 = 1 is never valid)`\n );\n\n // Expected number of '=' characters for this data length.\n const expectedPad = rem === 0 ? 0 : 4 - rem;\n\n if (pad.length > expectedPad) {\n const msg = `base64 has ${pad.length} '=' character${pad.length > 1 ? 's' : ''} but the data length (${data.length}) requires at most ${expectedPad}`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n\n // Partial padding: some '=' present but fewer than the full required amount.\n // draft-27 accommodates NO padding; any '=' present must be the full set.\n if (pad.length > 0 && pad.length < expectedPad) {\n const msg = `base64 has ${pad.length} '=' character${pad.length > 1 ? 's' : ''} but needs exactly ${expectedPad} — use full padding or no padding at all`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n // Zero '=': draft-27 allows omitting padding entirely — always accepted.\n\n // Non-zero trailing bits in the last data character (RFC 4648 §3.5).\n // Normalize URL-safe chars first so the lookup is against the classic table.\n // rem=2 (1-byte quantum): bottom 4 bits of the final char must be zero.\n // rem=3 (2-byte quantum): bottom 2 bits of the final char must be zero.\n if (rem !== 0 && data.length > 0) {\n const ALPHA =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n const lastChar = data[data.length - 1]!.replace('-', '+').replace('_', '/');\n const lastVal = ALPHA.indexOf(lastChar);\n if (lastVal >= 0) {\n const mask = rem === 2 ? 0x0f : 0x03;\n if ((lastVal & mask) !== 0) {\n const msg = `base64 has non-zero trailing bits in the final quantum (RFC 4648 §3.5)`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n }\n }\n\n // Normalize URL-safe chars to classic and add any missing padding so the\n // underlying decoder accepts the input regardless of what was originally used.\n const normalized =\n data.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(expectedPad);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (Uint8Array as any).fromBase64 === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (Uint8Array as any).fromBase64(normalized, {\n alphabet: 'base64',\n lastChunkHandling: 'loose',\n });\n }\n const binary = atob(normalized);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n","/**\n * CDN lexer (internal).\n *\n * Used by parser.ts for parsing and by CborTextString serialization to collect\n * source offsets after parseCDN() has already validated embedded CDN.\n */\n\nimport { CdnSyntaxError } from './errors';\nimport { bytesToHex } from '../utils/hex';\n\nexport type TokenType =\n | 'INTEGER'\n | 'FLOAT'\n | 'TSTR'\n | 'SQSTR'\n | 'RAWSTRING'\n | 'BYTES_HEX'\n | 'BYTES_HEX_ELIDED'\n | 'BYTES_B64'\n | 'APP_STRING'\n | 'APP_SEQUENCE'\n | 'EMPTY_INDEF_BYTES'\n | 'EMPTY_INDEF_TEXT'\n | 'TRUE'\n | 'FALSE'\n | 'NULL'\n | 'UNDEFINED'\n | 'SIMPLE'\n | 'LBRACKET'\n | 'RBRACKET'\n | 'LBRACE'\n | 'RBRACE'\n | 'LPAREN'\n | 'RPAREN'\n | 'COLON'\n | 'COMMA'\n | 'PLUS'\n | 'UNDERSCORE'\n | 'ENCODING_INDICATOR'\n | 'LT_LT'\n | 'GT_GT'\n | 'ELLIPSIS'\n | 'EOF'\n /** Synthetic token emitted by tokenizeLenient() for the unscannable tail. */\n | 'ERROR';\n\nexport interface Token {\n type: TokenType;\n /** Processed value: decoded string content, raw number text, raw byte content, etc. */\n value: string;\n /** Original source text for this token. */\n raw: string;\n line: number;\n col: number;\n /** Character offset of the first character of this token in the source input. */\n offset: number;\n /** Character offset just past the last character of this token in the source input. */\n endOffset: number;\n /** Only set when type === 'APP_STRING': the extension prefix (e.g. 'dt', 'DT'). */\n appPrefix?: string;\n}\n\n/**\n * @internal\n * SQSTR tokens carry the UTF-8 payload the tokenizer already encoded, so the\n * parser does not decode the hex `value` back into the same bytes. The\n * property is non-enumerable and deliberately absent from the public `Token`\n * type: the tokenize() API shape (keys, JSON.stringify, spread) is unchanged.\n */\nexport interface SqstrToken extends Token {\n readonly _sqstrBytes?: Uint8Array;\n}\n\nexport interface TokenizerOptions {\n /** Character offset at which tokenization starts. */\n offset?: number;\n /** When true, RS (U+001E, RFC 7464 record separator) is treated as whitespace. */\n skipRS?: boolean;\n}\n\nexport interface EdnComment {\n kind: 'line' | 'block';\n marker: '#' | '//' | '/*' | '/';\n text: string;\n start: number;\n end: number;\n line: number;\n col: number;\n}\n\n/** Inverse of positionAt; only used on the cold error path. */\nfunction offsetAt(input: string, line: number, col: number): number {\n let l = 1;\n let c = 1;\n for (let i = 0; i < input.length; i++) {\n if (l === line && c === col) return i;\n if (input[i] === '\\n') {\n l++;\n c = 1;\n } else {\n c++;\n }\n }\n return input.length;\n}\n\nfunction positionAt(\n input: string,\n offset: number\n): { line: number; col: number } {\n let line = 1;\n let col = 1;\n for (let i = 0; i < offset; i++) {\n if (input[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n return { line, col };\n}\n\n// ─── Scanning helpers (hot path) ─────────────────────────────────────────────\n//\n// Token content is consumed in bulk runs: a charCodeAt loop locates the next\n// character that needs individual handling, and everything before it is\n// appended with a single slice instead of per-character concatenation.\n\nfunction isHexDigitCode(c: number): boolean {\n return (\n (c >= 0x30 && c <= 0x39) || // 0-9\n (c >= 0x61 && c <= 0x66) || // a-f\n (c >= 0x41 && c <= 0x46) // A-F\n );\n}\n\n/** Shared encoder — constructing TextEncoder per token is needlessly slow. */\nconst textEncoder = new TextEncoder();\n\nexport class Tokenizer {\n private pos: number;\n private line: number;\n private col: number;\n private _peeked: Token | null = null;\n private _lastConsumedEndOffset: number;\n private readonly skipRS: boolean;\n /** Comments encountered while scanning, appended in source order. */\n readonly comments: EdnComment[] = [];\n /**\n * When set, non-standard-but-JS-valid escape sequences are accepted instead\n * of throwing. The callback receives a message and the position of the `\\`\n * (offset, line, column) plus the offset just past the escape sequence, so\n * the parser can forward it as a range-carrying ParseWarning.\n */\n onEscapeWarning?: (\n msg: string,\n offset: number,\n line: number,\n col: number,\n endOffset: number\n ) => void;\n constructor(\n private readonly input: string,\n options?: TokenizerOptions\n ) {\n const offset = options?.offset ?? 0;\n this.skipRS = options?.skipRS ?? false;\n if (!Number.isInteger(offset) || offset < 0 || offset > input.length)\n throw new RangeError(\n `EDN parse offset must be an integer between 0 and ${input.length}`\n );\n const position = positionAt(input, offset);\n this.pos = offset;\n this.line = position.line;\n this.col = position.col;\n this._lastConsumedEndOffset = offset;\n }\n\n peek(): Token {\n if (this._peeked === null) this._peeked = this._readNext();\n return this._peeked;\n }\n\n consume(): Token {\n const tok = this._peeked !== null ? this._peeked : this._readNext();\n this._peeked = null;\n this._lastConsumedEndOffset = tok.endOffset;\n return tok;\n }\n\n /** Character offset just past the last character of the most recently consumed token. */\n get lastEndOffset(): number {\n return this._lastConsumedEndOffset;\n }\n\n /** The full source text supplied to this tokenizer. */\n get source(): string {\n return this.input;\n }\n\n // ── Internal helpers ─────────────────────────────────────────────────────\n\n private _ch(): string {\n return this.input[this.pos] ?? '';\n }\n private _eof(): boolean {\n return this.pos >= this.input.length;\n }\n\n private _advance(): string {\n const c = this.input[this.pos++] ?? '';\n if (c === '\\n') {\n this.line++;\n this.col = 1;\n } else {\n this.col++;\n }\n return c;\n }\n\n private _fail(msg: string, line = this.line, col = this.col): never {\n const offset =\n line === this.line && col === this.col\n ? this.pos\n : offsetAt(this.input, line, col);\n // The scan position sits at the end of the offending construct when the\n // failure was reported against an earlier start position; cover at least\n // one character so tooling can underline a range (zero-width only at EOF).\n const endOffset = Math.min(\n Math.max(this.pos, offset + 1),\n this.input.length\n );\n throw new CdnSyntaxError(msg, { offset, line, column: col, endOffset });\n }\n\n private _skipWS(): void {\n for (;;) {\n // Skip whitespace characters. Common ASCII whitespace is matched with\n // direct comparisons; printable ASCII can never match /\\s/, so the\n // regex only runs for the rare remaining characters (e.g. \\f, NBSP).\n for (;;) {\n const ws = this.input[this.pos];\n if (ws === undefined) return;\n if (\n ws === ' ' ||\n ws === '\\n' ||\n ws === '\\t' ||\n ws === '\\r' ||\n (this.skipRS && ws === '\\x1e')\n ) {\n this._advance();\n continue;\n }\n if (ws > ' ' && ws <= '~') break; // printable ASCII — not whitespace\n if (/\\s/.test(ws)) {\n this._advance();\n continue;\n }\n break;\n }\n\n const c = this._ch();\n\n // CDN line comment: # to end of line\n if (c === '#') {\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n while (!this._eof() && this._ch() !== '\\n') this._advance();\n this.comments.push({\n kind: 'line',\n marker: '#',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n\n // Comments starting with /\n if (c === '/') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === '/') {\n // EDN end-of-line comment: // to end of line (§2.1)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() !== '\\n') this._advance();\n this.comments.push({\n kind: 'line',\n marker: '//',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n if (next === '*') {\n // EDN block comment: /* ... */ (§2.1)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance();\n this._advance();\n this._skipBlockCommentStar();\n this.comments.push({\n kind: 'block',\n marker: '/*',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n // EDN slash-delimited comment: / ... / (§2.1, first char must not be * or /)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance(); // consume opening /\n this._skipBlockCommentSlash();\n this.comments.push({\n kind: 'block',\n marker: '/',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n\n return;\n }\n }\n\n /**\n * Skip a comment in a quoted byte string literal (h'', b64'').\n * Returns true if a comment was consumed, false if the current char is not a\n * comment start. `quote` is the closing delimiter character.\n *\n * Supports / ... /, /* *\\/, //, and # comment forms (§2.1).\n */\n private _skipByteStringComment(quote: string): boolean {\n const ch = this._ch();\n if (ch === '/') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === '/') {\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof() && this._ch() !== '\\n') this._advance();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n return true;\n }\n if (next === '*') {\n this._advance();\n this._advance();\n this._skipBlockCommentStar();\n return true;\n }\n this._advance();\n this._skipBlockCommentSlash();\n return true;\n }\n if (ch === '#') {\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance(); // consume '\\'\n if (this._eof() || this._ch() === '\\n') continue;\n const escaped = this._advance();\n if (escaped === 'u') this._validateHexCommentUnicodeEscape();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n return true;\n }\n return false;\n }\n\n /**\n * Validate a `\\uXXXX` or `\\u{N}` escape inside a hex-string comment.\n *\n * Called immediately after the `u` character has been consumed. Rejects\n * lone surrogates and invalid surrogate pairs; tolerates truncated/\n * non-hex sequences (comments are informational, but surrogates are\n * always illegal).\n */\n private _validateHexCommentUnicodeEscape(): void {\n const line = this.line,\n col = this.col;\n\n // Extended form \\u{XXXXXX}\n if (!this._eof() && this._ch() === '{') {\n this._advance(); // {\n let hex = '';\n while (!this._eof() && this._ch() !== '}' && this._ch() !== '\\n')\n hex += this._advance();\n if (!this._eof() && this._ch() === '}') this._advance(); // }\n const cp = parseInt(hex || '0', 16);\n if (cp >= 0xd800 && cp <= 0xdfff)\n this._fail(\n `\\\\u{${hex}} is a surrogate code point, not allowed in hex string comments`,\n line,\n col\n );\n return;\n }\n\n // Standard \\uXXXX — read up to 4 hex digits\n let hex = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof() || this._ch() === '\\n') break;\n if (!/[0-9a-fA-F]/.test(this._ch())) break;\n hex += this._advance();\n }\n if (hex.length < 4) return; // truncated / non-hex — not our problem\n\n const cp = parseInt(hex, 16);\n\n // High surrogate: must be followed immediately by a low-surrogate escape\n if (cp >= 0xd800 && cp <= 0xdbff) {\n if (this._ch() !== '\\\\' || (this.input[this.pos + 1] ?? '') !== 'u')\n this._fail(\n `lone high surrogate \\\\u${hex} in hex string comment`,\n line,\n col\n );\n this._advance(); // \\\n this._advance(); // u\n let hex2 = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof() || this._ch() === '\\n') break;\n if (!/[0-9a-fA-F]/.test(this._ch())) break;\n hex2 += this._advance();\n }\n const cp2 = parseInt(hex2 || '0', 16);\n if (cp2 < 0xdc00 || cp2 > 0xdfff)\n this._fail(\n `\\\\u${hex} (high surrogate) not followed by valid low surrogate in hex string comment`,\n line,\n col\n );\n return;\n }\n\n if (cp >= 0xdc00 && cp <= 0xdfff)\n this._fail(\n `lone low surrogate \\\\u${hex} in hex string comment`,\n line,\n col\n );\n }\n\n /**\n * Skip a comment in a raw byte string (h``, b64``).\n * Called with `i` pointing at the comment-start character.\n * Returns the index after the comment, or -1 if no comment was found.\n *\n * Supports / ... /, /* *\\/, //, and # comment forms (§2.1).\n * `context` is used in unterminated-comment error messages.\n */\n private _skipRawComment(\n raw: string,\n i: number,\n context: string,\n tokenLine: number,\n tokenCol: number\n ): number {\n const ch = raw[i];\n if (ch === '/') {\n i++;\n if (raw[i] === '/') {\n i++;\n while (i < raw.length && raw[i] !== '\\n') i++;\n return i;\n }\n if (raw[i] === '*') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '*' && raw[i + 1] === '/') return i + 2;\n i++;\n }\n return i; // EOF inside comment — fall through; caller will report\n }\n // / … / comment\n while (i < raw.length && raw[i] !== '/') i++;\n if (i >= raw.length)\n this._fail(\n `unterminated block comment in ${context}`,\n tokenLine,\n tokenCol\n );\n return i + 1; // consume closing /\n }\n if (ch === '#') {\n while (i < raw.length && raw[i] !== '\\n') i++;\n return i;\n }\n return -1; // not a comment\n }\n\n /** Skip content until a closing `/` (CDN block comment). */\n private _skipBlockCommentSlash(): void {\n const line = this.line,\n col = this.col;\n while (!this._eof()) {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof()) this._advance();\n continue;\n }\n if (this._ch() === '/') break;\n this._advance();\n }\n if (this._eof()) this._fail('unterminated block comment', line, col);\n this._advance(); // consume closing /\n }\n\n /** Skip content until a closing `*\\/` (JSONC block comment). */\n private _skipBlockCommentStar(): void {\n const line = this.line,\n col = this.col;\n while (!this._eof()) {\n if (this._ch() === '*' && (this.input[this.pos + 1] ?? '') === '/') {\n this._advance();\n this._advance();\n return;\n }\n this._advance();\n }\n this._fail('unterminated block comment', line, col);\n }\n\n /**\n * Read content between `quote` delimiters, processing escape sequences.\n *\n * Strict spec compliance:\n * - Literal LF (U+000A) is allowed; all other C0 controls and U+007F are rejected.\n * - Literal CR (U+000D) is silently stripped (source-level CRLF normalisation).\n * - Only spec-defined escape sequences are accepted; `\\q` etc. throw SyntaxError.\n * - `\\/` is valid only in double-quoted strings (not in escapable-s, §6.1).\n * - `\\\\` (backslash) is valid in both single- and double-quoted strings.\n * - `\\uXXXX` for a high surrogate must be immediately followed by `\\uXXXX` for\n * the corresponding low surrogate; lone surrogates are rejected.\n * - `\\u{N}` … `\\u{10FFFF}` extended syntax is supported; surrogates are rejected.\n * - In single-quoted strings, `\\u` escapes to printable ASCII (U+0020–U+007E)\n * are forbidden (hexchar-s restriction, draft-ietf-cbor-edn-literals-27 §6.1).\n */\n private _readStringContent(quote: string): string {\n this._advance(); // opening quote\n const quoteCode = quote.charCodeAt(0);\n const inputLen = this.input.length;\n let out = '';\n while (!this._eof() && this._ch() !== quote) {\n // Fast path: bulk-consume a run of ordinary characters up to the next\n // delimiter, backslash, CR, or control character. LF is ordinary\n // content; it is counted here so line/col stay correct.\n let p = this.pos;\n let newlines = 0;\n let lastNewline = -1;\n while (p < inputLen) {\n const cc = this.input.charCodeAt(p);\n if (cc === quoteCode || cc === 0x5c /* \\ */ || cc === 0x7f /* DEL */)\n break;\n if (cc < 0x20) {\n if (cc !== 0x0a) break; // CR / other C0 controls → slow path\n newlines++;\n lastNewline = p;\n }\n p++;\n }\n if (p > this.pos) {\n out += this.input.slice(this.pos, p);\n if (newlines > 0) {\n this.line += newlines;\n this.col = p - lastNewline;\n } else {\n this.col += p - this.pos;\n }\n this.pos = p;\n continue;\n }\n\n const ch = this._ch();\n\n // Strip literal CR (cross-platform source normalisation — spec §1.3.5)\n if (ch === '\\r') {\n this._advance();\n continue;\n }\n\n // Reject unescaped C0 control characters (except LF) and DEL — spec §6.1 unescaped\n const cp = ch.codePointAt(0)!;\n if ((cp < 0x20 && cp !== 0x0a) || cp === 0x7f)\n this._fail(\n `unescaped control character U+${cp.toString(16).padStart(4, '0')} is not allowed in string literals`\n );\n\n if (ch === '\\\\') {\n // Capture position of the backslash itself before consuming it.\n const eOffset = this.pos,\n eLine = this.line,\n eCol = this.col;\n this._advance();\n const e = this._advance();\n switch (e) {\n case 'n':\n out += '\\n';\n break;\n case 'r':\n out += '\\r';\n break;\n case 't':\n out += '\\t';\n break;\n case 'b':\n out += '\\b';\n break;\n case 'f':\n out += '\\f';\n break;\n case '\\\\':\n out += '\\\\';\n break;\n case 'u':\n out += this._readUnicodeEscape(quote, eOffset, eLine, eCol);\n break;\n default:\n // Escaped delimiter char (e.g. \\' inside '...' or \\\" inside \"...\")\n if (e === quote) {\n out += e;\n break;\n }\n if (e === '/') {\n if (quote === \"'\")\n this._fail(\n `\\\\/ is not a valid escape in single-quoted byte strings (§6.1)`,\n eLine,\n eCol\n );\n out += '/';\n break;\n }\n // Non-standard JS escape sequences — accepted when onEscapeWarning is set.\n if (this.onEscapeWarning) {\n if (e === '0') {\n this.onEscapeWarning(\n '\\\\0 is a non-standard escape sequence; use \\\\u0000 instead',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += '\\0';\n break;\n }\n if (e === 'v') {\n this.onEscapeWarning(\n '\\\\v is a non-standard escape sequence; use \\\\u000b instead',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += '\\v';\n break;\n }\n if (e === 'x') {\n // \\xHH — two hex digits\n const h1 = this._ch();\n const h2 = this.input[this.pos + 1] ?? '';\n if (!/[0-9a-fA-F]/.test(h1) || !/[0-9a-fA-F]/.test(h2)) {\n this._fail(\n '\\\\x escape requires exactly two hex digits',\n eLine,\n eCol\n );\n }\n this._advance();\n this._advance();\n const codePoint = parseInt(h1 + h2, 16);\n this.onEscapeWarning(\n `\\\\x${h1}${h2} is a non-standard escape sequence; use \\\\u00${h1}${h2} instead`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += String.fromCharCode(codePoint);\n break;\n }\n // Cross-quote delimiter (e.g. \\\" inside '...' or \\' inside \"...\")\n if (e === '\"' || e === \"'\") {\n this.onEscapeWarning(\n `\\\\${e} inside ${quote === '\"' ? 'double' : 'single'}-quoted string is non-standard`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += e;\n break;\n }\n // JS line continuation: \\ + LF / CR / CRLF → nothing added\n if (e === '\\n' || e === '\\r') {\n if (e === '\\r' && this._ch() === '\\n') this._advance(); // consume CRLF\n this.onEscapeWarning(\n 'line continuation (\\\\<newline>) is non-standard; the newline is ignored',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n break;\n }\n // Identity escape: \\X → X (JS accepts any \\X as just X)\n this.onEscapeWarning(\n `\\\\${e} is an unknown escape sequence; interpreted as '${e}'`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += e;\n break;\n }\n this._fail(\n `invalid escape sequence \\\\${e} in ${quote === '\"' ? 'double' : 'single'}-quoted string`,\n eLine,\n eCol\n );\n }\n } else {\n out += this._advance();\n }\n }\n if (this._eof()) this._fail('unterminated string literal');\n this._advance(); // closing quote\n return out;\n }\n\n /**\n * Parse a Unicode escape immediately after `\\u` has been consumed.\n *\n * @param quote - The enclosing string delimiter (`\"` or `'`).\n *\n * Handles two forms:\n * - `\\u{N}` … `\\u{10FFFF}`: direct Unicode scalar value (surrogates rejected)\n * - `\\uXXXX`: exactly four hex digits; a high surrogate must be followed by\n * `\\uXXXX` for the matching low surrogate to form a valid surrogate pair,\n * which is then decoded into the corresponding non-BMP code point.\n *\n * In single-quoted strings (`quote === \"'\"`), `\\u` escapes that resolve to\n * printable ASCII (U+0020–U+007E) are rejected per draft-ietf-cbor-edn-literals-27\n * §6.1 hexchar-s.\n * Use `\\\\` for backslash (U+005C) and `\\'` for the single-quote delimiter.\n */\n private _readUnicodeEscape(\n quote: string,\n bsOffset?: number,\n bsLine?: number,\n bsCol?: number\n ): string {\n const line = this.line,\n col = this.col;\n\n /** Warn or throw when this is a single-quoted string and the code point is printable ASCII. */\n const checkSingleQuotedPrintable = (cp: number): void => {\n // Per draft-ietf-cbor-edn-literals-27 §6.1 hexchar-s, \\u escapes for printable ASCII (U+0020–U+007E)\n // are not valid in single-quoted strings. Use \\\\ for backslash and \\' for\n // the single-quote delimiter. In lenient mode (onEscapeWarning set) we emit\n // a warning and accept the value rather than hard-failing.\n if (quote === \"'\" && cp >= 0x20 && cp <= 0x7e) {\n const msg = `\\\\u escape for printable ASCII U+${cp.toString(16).padStart(4, '0').toUpperCase()} is not allowed in single-quoted strings (§6.1 hexchar-s)`;\n if (this.onEscapeWarning) {\n this.onEscapeWarning(\n msg,\n bsOffset ?? this.pos,\n bsLine ?? line,\n bsCol ?? col,\n this.pos\n );\n return;\n }\n this._fail(msg, line, col);\n }\n };\n\n // Extended form \\u{NNN}\n if (!this._eof() && this._ch() === '{') {\n this._advance(); // {\n let hex = '';\n while (!this._eof() && this._ch() !== '}') {\n const c = this._ch();\n if (!/[0-9a-fA-F]/.test(c))\n this._fail(\n `invalid character in \\\\u{} escape: ${JSON.stringify(c)}`,\n line,\n col\n );\n hex += this._advance();\n }\n if (this._eof()) this._fail('unterminated \\\\u{} escape', line, col);\n this._advance(); // }\n if (hex.length === 0) this._fail('empty \\\\u{} escape', line, col);\n const cp = parseInt(hex, 16);\n if (cp > 0x10_ffff)\n this._fail(\n `\\\\u{${hex}} exceeds maximum Unicode code point U+10FFFF`,\n line,\n col\n );\n if (cp >= 0xd800 && cp <= 0xdfff)\n this._fail(\n `\\\\u{${hex}} is a surrogate code point, which is not a valid Unicode scalar value`,\n line,\n col\n );\n checkSingleQuotedPrintable(cp);\n return String.fromCodePoint(cp);\n }\n\n // Standard form \\uXXXX\n let hex = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof()) this._fail('truncated \\\\uXXXX escape', line, col);\n const c = this._ch();\n if (!/[0-9a-fA-F]/.test(c))\n this._fail(\n `invalid hex digit in \\\\uXXXX escape: ${JSON.stringify(c)}`,\n line,\n col\n );\n hex += this._advance();\n }\n const cp = parseInt(hex, 16);\n\n // High surrogate: must be immediately followed by a low-surrogate escape\n if (cp >= 0xd800 && cp <= 0xdbff) {\n if (this._ch() !== '\\\\' || (this.input[this.pos + 1] ?? '') !== 'u')\n this._fail(\n `lone high surrogate \\\\u${hex} must be followed by \\\\uDC00–\\\\uDFFF`,\n line,\n col\n );\n this._advance(); // \\\n this._advance(); // u\n const line2 = this.line,\n col2 = this.col;\n let hex2 = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof())\n this._fail('truncated low-surrogate escape', line2, col2);\n hex2 += this._advance();\n }\n const cp2 = parseInt(hex2, 16);\n if (cp2 < 0xdc00 || cp2 > 0xdfff)\n this._fail(\n `\\\\u${hex} (high surrogate) not followed by a valid low surrogate (got \\\\u${hex2})`,\n line,\n col\n );\n // Surrogate pairs always resolve to non-BMP (> U+FFFF), never printable ASCII\n return String.fromCodePoint(\n 0x10000 + (cp - 0xd800) * 0x400 + (cp2 - 0xdc00)\n );\n }\n\n // Low surrogate without a preceding high surrogate is invalid\n if (cp >= 0xdc00 && cp <= 0xdfff)\n this._fail(`lone low surrogate \\\\u${hex} is not valid`, line, col);\n\n checkSingleQuotedPrintable(cp);\n return String.fromCharCode(cp);\n }\n\n /**\n * Read raw text-string content between N-backtick delimiters\n * (§2.3.3 of draft-ietf-cbor-edn-literals-27).\n *\n * - The opening delimiter is the maximal run of consecutive backticks (N ≥ 1).\n * - No escape sequences are processed — content is taken verbatim.\n * - Literal CR is stripped for source-level CRLF normalisation (§1.3.5).\n * - The closing delimiter is a run of exactly N backticks (alikerawdelim);\n * shorter runs are content, longer runs are an error.\n * - A single leading newline (LF or CRLF) is stripped; if that rule did not\n * apply and the inner string both starts and ends with a space, exactly\n * one leading and one trailing space are stripped.\n */\n private _readRawStringContent(): string {\n const openLine = this.line,\n openCol = this.col;\n\n // Count opening backticks (greedy)\n let n = 0;\n while (!this._eof() && this._ch() === '`') {\n this._advance();\n n++;\n }\n\n // Strip a single leading CRLF or LF (§2.3.3, first trimming rule)\n let newlineStripped = false;\n if (!this._eof() && this._ch() === '\\r') this._advance(); // CR\n if (!this._eof() && this._ch() === '\\n') {\n this._advance(); // LF\n newlineStripped = true;\n }\n\n const inputLen = this.input.length;\n let out = '';\n while (!this._eof()) {\n // Fast path: bulk-consume a run of ordinary characters up to the next\n // backtick, CR, or control character. LF is ordinary content; it is\n // counted here so line/col stay correct.\n let p = this.pos;\n let newlines = 0;\n let lastNewline = -1;\n while (p < inputLen) {\n const cc = this.input.charCodeAt(p);\n if (cc === 0x60 /* ` */ || cc === 0x7f /* DEL */) break;\n if (cc < 0x20) {\n if (cc !== 0x0a) break; // CR / other C0 controls → slow path\n newlines++;\n lastNewline = p;\n }\n p++;\n }\n if (p > this.pos) {\n out += this.input.slice(this.pos, p);\n if (newlines > 0) {\n this.line += newlines;\n this.col = p - lastNewline;\n } else {\n this.col += p - this.pos;\n }\n this.pos = p;\n continue;\n }\n\n const ch = this._ch();\n\n // Source-level CRLF normalisation: strip bare CR\n if (ch === '\\r') {\n this._advance();\n continue;\n }\n\n if (ch === '`') {\n // Count this backtick run\n let m = 0;\n const runLine = this.line,\n runCol = this.col;\n while (!this._eof() && this._ch() === '`') {\n this._advance();\n m++;\n }\n if (m === n) {\n // Closing delimiter found (alikerawdelim: exactly N backticks).\n // Second trimming rule (§2.3.3): if no leading newline was\n // stripped and the inner string starts AND ends with a space,\n // strip exactly one of each.\n if (\n !newlineStripped &&\n out.length >= 2 &&\n out.startsWith(' ') &&\n out.endsWith(' ')\n )\n out = out.slice(1, -1);\n if (out === '')\n this._fail(\n 'raw string must not be empty (§2.3.3)',\n openLine,\n openCol\n );\n return out;\n }\n if (m > n) {\n // Longer runs can neither be content (shortrawdelim) nor close the\n // string (alikerawdelim) — §2.3.3 / §6.1.\n this._fail(\n `raw string contains a run of ${m} backquotes, longer than the ${n}-backquote delimiter; use longer delimiters`,\n runLine,\n runCol\n );\n }\n // Shorter run — all backticks become content\n out += '`'.repeat(m);\n } else {\n const cp = ch.codePointAt(0)!;\n // rawchars = 1*(%x0a/%x0d / %x20-5f / %x61-7e / NONASCII) — HT and other C0 controls forbidden\n if (cp < 0x20 && cp !== 0x0a && cp !== 0x0d) {\n this._fail(\n `raw string content must not contain control character U+${cp.toString(16).toUpperCase().padStart(4, '0')} (§2.3.3)`,\n this.line,\n this.col\n );\n }\n if (cp === 0x7f) {\n this._fail(\n 'raw string content must not contain DEL (U+007F) (§2.3.3)',\n this.line,\n this.col\n );\n }\n out += this._advance();\n }\n }\n\n this._fail('unterminated raw string literal', openLine, openCol);\n }\n\n /**\n * Post-process raw hex content from a `h``…``\\` raw string (§6.3.3).\n *\n * Skips:\n * - lblank whitespace (LF, SP; also CR for source-level normalisation)\n * - `/ … /` block comments\n * - `# …` line comments (up to but not including LF)\n * Detects `...` ellipsis sequences.\n *\n * A trailing `# comment` immediately before the closing delimiter is allowed\n * per §6.3.3 `r-app-string-h`.\n *\n * Returns { value: hex-string-with-ellipsis-markers, elided: boolean }\n */\n private _processRawHexContent(\n raw: string,\n tokenLine: number,\n tokenCol: number\n ): { value: string; elided: boolean } {\n let hex = '';\n let elided = false;\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n // lblank / CR — skip\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n i++;\n continue;\n }\n // HT is still forbidden (rawchars excludes %x09)\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside h`` raw byte string literals (§6.3.3)',\n tokenLine,\n tokenCol\n );\n }\n // Comments (§2.1)\n const afterComment = this._skipRawComment(\n raw,\n i,\n 'h`` raw byte string',\n tokenLine,\n tokenCol\n );\n if (afterComment !== -1) {\n i = afterComment;\n continue;\n }\n // Ellipsis: ... (three or more dots)\n if (ch === '.' && raw[i + 1] === '.' && raw[i + 2] === '.') {\n i += 3;\n while (i < raw.length && raw[i] === '.') i++;\n hex += '...';\n elided = true;\n continue;\n }\n // Hex digits — consume the whole run at once\n if (isHexDigitCode(raw.charCodeAt(i))) {\n const runStart = i;\n while (i < raw.length && isHexDigitCode(raw.charCodeAt(i))) i++;\n hex += raw.slice(runStart, i);\n continue;\n }\n this._fail(\n `unexpected character ${JSON.stringify(ch)} in h\\`\\` raw byte string`,\n tokenLine,\n tokenCol\n );\n }\n return { value: hex, elided };\n }\n\n /**\n * Post-process raw base64 content from a `b64``…``\\` raw string (§6.3.4).\n *\n * Skips:\n * - lblank whitespace (LF, SP; also CR for source-level normalisation)\n * - `# …` line comments (up to but not including LF)\n *\n * Returns the stripped base64 string.\n */\n private _processRawB64Content(\n raw: string,\n tokenLine: number,\n tokenCol: number\n ): string {\n let out = '';\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n // lblank / CR — skip\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n i++;\n continue;\n }\n // HT forbidden\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside b64`` raw byte string literals (§6.3.4)',\n tokenLine,\n tokenCol\n );\n }\n // Line comment: # … (to end of line)\n // Note: // is NOT treated as a comment because / is a valid B64DIGIT\n // (e.g. 0xFF 0xFF encodes to //8= in standard base64).\n if (ch === '#') {\n while (i < raw.length && raw[i] !== '\\n') i++;\n continue;\n }\n // Run of data characters — consume in bulk up to the next terminator\n const runStart = i;\n while (i < raw.length) {\n const d = raw[i];\n if (d === '\\n' || d === ' ' || d === '\\r' || d === '\\t' || d === '#')\n break;\n i++;\n }\n out += raw.slice(runStart, i);\n }\n return out;\n }\n\n /**\n * Read raw byte-string content between `quote` chars (b64 / b64url).\n *\n * Strips whitespace and skips `# ...` line comments per §6.2.2.\n * `/` is NOT treated as a comment delimiter because it is a valid base64 character.\n */\n private _readByteContent(quote: string): string {\n this._advance(); // opening quote\n let raw = '';\n while (!this._eof() && this._ch() !== quote) {\n const ch = this._ch();\n // lblank = %x0A / %x20 — only LF and SP are whitespace (§6.2.2 Fig 4); HT is forbidden\n if (ch === '\\n' || ch === ' ') {\n this._advance();\n continue;\n }\n if (ch === '\\r') {\n // CR is not lblank; skip silently as source-level normalization only\n this._advance();\n continue;\n }\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside byte string literals (§6.2.2)',\n this.line,\n this.col\n );\n }\n // # line comment — stop at newline or the closing quote (whichever comes first)\n // Note: // is NOT treated as a comment here because / is a valid B64DIGIT;\n // treating // as a comment would corrupt base64 data that naturally contains\n // consecutive slashes (e.g. 0xFF 0xFF encodes to //8= in standard base64).\n if (ch === '#') {\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof() && this._ch() !== '\\n') this._advance();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n continue;\n }\n // Run of data characters — consume in bulk up to the next terminator.\n // Newlines terminate the run, so a plain column update is safe.\n const runStart = this.pos;\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const d = this.input[p];\n if (\n d === quote ||\n d === '\\n' ||\n d === ' ' ||\n d === '\\r' ||\n d === '\\t' ||\n d === '#'\n )\n break;\n p++;\n }\n this.col += p - runStart;\n this.pos = p;\n raw += this.input.slice(runStart, p);\n }\n if (this._eof()) this._fail('unterminated byte string literal');\n this._advance(); // closing quote\n return raw;\n }\n\n /**\n * Read hex byte-string content, recognising `...` ellipsis sequences (§5.2).\n *\n * Returns the raw hex string (with `...` markers embedded) and a flag\n * indicating whether any ellipsis was found.\n */\n private _readHexByteContentElisionAware(quote: string): {\n value: string;\n elided: boolean;\n } {\n this._advance(); // opening quote\n let hex = '';\n let elided = false;\n // Tracks whether `hex` currently ends with an ellipsis, without asking\n // `hex` itself: `hex` is built by repeated `+=` and can end up as an\n // unflattened V8 rope string, where `.endsWith()` forces a flatten —\n // negligible once, but this runs per `...` occurrence in the literal,\n // making a many-ellipsis literal (e.g. thousands of `...` markers)\n // quadratic instead of linear.\n let hexEndsWithEllipsis = false;\n while (!this._eof() && this._ch() !== quote) {\n const ch = this._ch();\n // lblank = %x0A / %x20 only; HT is forbidden per §6.2.1 Figure 3\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n this._advance();\n continue;\n }\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside hex byte string literals (§6.2.1)',\n this.line,\n this.col\n );\n }\n if (this._skipByteStringComment(quote)) continue;\n // Detect '...' ellipsis inside hex literal\n if (\n ch === '.' &&\n (this.input[this.pos + 1] ?? '') === '.' &&\n (this.input[this.pos + 2] ?? '') === '.'\n ) {\n this._advance();\n this._advance();\n this._advance();\n // consume any additional dots (spec says \"three or more\")\n while (!this._eof() && this._ch() === '.') this._advance();\n // adjacent ... separated only by whitespace collapse into a single ellipsis\n if (!hexEndsWithEllipsis) hex += '...';\n elided = true;\n hexEndsWithEllipsis = true;\n continue;\n }\n if (isHexDigitCode(ch.charCodeAt(0))) {\n // Run of hex digits — consume in bulk (digits contain no newlines)\n const runStart = this.pos;\n let p = this.pos;\n const n = this.input.length;\n while (p < n && isHexDigitCode(this.input.charCodeAt(p))) p++;\n this.col += p - runStart;\n this.pos = p;\n hex += this.input.slice(runStart, p);\n hexEndsWithEllipsis = false;\n continue;\n }\n this._fail(\n `unexpected character ${JSON.stringify(ch)} in hex byte string`\n );\n }\n if (this._eof()) this._fail('unterminated hex byte string literal');\n this._advance(); // closing quote\n return { value: hex, elided };\n }\n\n // ── Token reader ─────────────────────────────────────────────────────────\n\n /** Start offset of the token currently being read (set by _readNext). */\n private _tokStart = 0;\n\n private _readNext(): Token {\n this._skipWS();\n this._tokStart = this.pos;\n return this._readNextCore();\n }\n\n /**\n * Build a complete Token for the source range [_tokStart, pos).\n * Every token is constructed exactly once here — the previous two-step\n * \"partial object, then spread in raw/offsets\" cost an extra object and a\n * property-copy pass per token on the parse hot path.\n *\n * `appPrefix` is added only for app-string/app-sequence tokens so that\n * ordinary tokens keep `'appPrefix' in tok === false`, matching the public\n * tokenize() API shape documented on the Token interface.\n *\n * `raw` stays an eagerly-sliced own data property: Token is public API, and\n * a getter would vanish under the consumer's own `{ ...token }` spread or\n * JSON.stringify. The slice cost is minor next to the removed extra object.\n */\n private _tok(\n type: TokenType,\n value: string,\n line: number,\n col: number,\n appPrefix?: string\n ): Token {\n const offset = this._tokStart;\n const tok: Token = {\n type,\n value,\n raw: this.input.slice(offset, this.pos),\n line,\n col,\n offset,\n endOffset: this.pos,\n };\n if (appPrefix !== undefined) tok.appPrefix = appPrefix;\n return tok;\n }\n\n /**\n * {@link _tok} variant for tokens whose processed `value` IS the raw source\n * text — punctuation, keywords, and numbers without a leading `+`. Reuses\n * `value` as `raw`, skipping a per-token slice on the densest token kinds.\n * Callers must guarantee `value === input.slice(_tokStart, pos)`.\n */\n private _tokV(\n type: TokenType,\n value: string,\n line: number,\n col: number\n ): Token {\n return {\n type,\n value,\n raw: value,\n line,\n col,\n offset: this._tokStart,\n endOffset: this.pos,\n };\n }\n\n private _readNextCore(): Token {\n const line = this.line,\n col = this.col;\n if (this._eof()) return this._tokV('EOF', '', line, col);\n\n const c = this._ch();\n\n switch (c) {\n case '[':\n this._advance();\n return this._tokV('LBRACKET', '[', line, col);\n case ']':\n this._advance();\n return this._tokV('RBRACKET', ']', line, col);\n case '{':\n this._advance();\n return this._tokV('LBRACE', '{', line, col);\n case '}':\n this._advance();\n return this._tokV('RBRACE', '}', line, col);\n case '(':\n this._advance();\n return this._tokV('LPAREN', '(', line, col);\n case ')':\n this._advance();\n return this._tokV('RPAREN', ')', line, col);\n case ':':\n this._advance();\n return this._tokV('COLON', ':', line, col);\n case ',':\n this._advance();\n return this._tokV('COMMA', ',', line, col);\n case '<':\n if ((this.input[this.pos + 1] ?? '') === '<') {\n this._advance();\n this._advance();\n return this._tokV('LT_LT', '<<', line, col);\n }\n this._fail(`unexpected character '<'`, line, col);\n case '>':\n if ((this.input[this.pos + 1] ?? '') === '>') {\n this._advance();\n this._advance();\n return this._tokV('GT_GT', '>>', line, col);\n }\n this._fail(`unexpected character '>'`, line, col);\n case '+': {\n // +Infinity[_N]\n const posInf = this._readSignedInfinity('+', line, col);\n if (posInf !== null) return posInf;\n // Numeric literal with explicit positive sign\n const afterPlus = this.input[this.pos + 1] ?? '';\n if ((afterPlus >= '0' && afterPlus <= '9') || afterPlus === '.') {\n this._advance(); // consume '+'\n return this._readNumber(line, col);\n }\n // String concatenation operator\n this._advance();\n return this._tokV('PLUS', '+', line, col);\n }\n case '`':\n return this._tok('RAWSTRING', this._readRawStringContent(), line, col);\n case '\"': {\n const strVal = this._readStringContent('\"');\n if (\n strVal === '' &&\n this._ch() === '_' &&\n !/[0-7i]/.test(this.input[this.pos + 1] ?? '')\n ) {\n this._advance(); // _\n return this._tok('EMPTY_INDEF_TEXT', '', line, col);\n }\n return this._tok('TSTR', strVal, line, col);\n }\n case \"'\": {\n // ''_ → empty indefinite byte string (but ''_N is sqstr + encoding indicator)\n if (\n (this.input[this.pos + 1] ?? '') === \"'\" &&\n (this.input[this.pos + 2] ?? '') === '_' &&\n !/[0-7i]/.test(this.input[this.pos + 3] ?? '')\n ) {\n this._advance(); // first '\n this._advance(); // second '\n this._advance(); // _\n return this._tok('EMPTY_INDEF_BYTES', '', line, col);\n }\n // 'text' → UTF-8 encoded byte string (major type 2)\n const strVal = this._readStringContent(\"'\");\n const utf8 = textEncoder.encode(strVal);\n const tok = this._tok('SQSTR', bytesToHex(utf8), line, col);\n // Attach the payload for the parser (see SqstrToken). defineProperty\n // keeps it out of keys/JSON/spread; SQSTR is rare enough that the\n // defineProperty cost does not matter.\n Object.defineProperty(tok, '_sqstrBytes', { value: utf8 });\n return tok;\n }\n }\n\n // -Infinity (check before generic '-' handling)\n if (c === '-') {\n const negInf = this._readSignedInfinity('-', line, col);\n if (negInf !== null) return negInf;\n return this._readNumber(line, col);\n }\n\n if (c >= '0' && c <= '9') return this._readNumber(line, col);\n // Leading-dot float: .5, .1e2, etc. (same as +.5 / -.5)\n if (c === '.' && /[0-9]/.test(this.input[this.pos + 1] ?? ''))\n return this._readNumber(line, col);\n if (/[a-zA-Z_]/.test(c)) return this._readIdent(line, col);\n\n // Three or more dots → ellipsis notation (§5.2)\n if (c === '.') {\n if (\n (this.input[this.pos + 1] ?? '') === '.' &&\n (this.input[this.pos + 2] ?? '') === '.'\n ) {\n this._advance();\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() === '.') this._advance();\n return this._tok('ELLIPSIS', '...', line, col);\n }\n this._fail(`unexpected character '.'`, line, col);\n }\n\n this._fail(`unexpected character ${JSON.stringify(c)}`, line, col);\n }\n\n /**\n * Try to read `Infinity[_N]` immediately after a `+`/`-` sign at this.pos.\n *\n * Returns null when the input is not an Infinity literal (e.g. an identifier\n * like `Infinityx` that merely starts with \"Infinity\"); the caller then\n * falls back to its sign handling.\n *\n * All encoding-indicator suffixes _0–_7/_i are tokenized here; the parser\n * validates them and rejects/warns on the invalid ones (_0, _4–_7, _i).\n *\n * Uses startsWith with a position argument instead of slicing the remainder\n * of the input, which would allocate a substring for every sign token.\n */\n private _readSignedInfinity(\n sign: '+' | '-',\n line: number,\n col: number\n ): Token | null {\n if (!this.input.startsWith('Infinity', this.pos + 1)) return null;\n const after = this.input[this.pos + 9] ?? '';\n const hasSuffix =\n after === '_' &&\n /[0-7i]/.test(this.input[this.pos + 10] ?? '') &&\n !/[a-zA-Z0-9_]/.test(this.input[this.pos + 11] ?? '');\n if (/[a-zA-Z0-9_]/.test(after) && !hasSuffix) return null;\n this._advance(); // sign\n for (let i = 0; i < 8; i++) this._advance(); // Infinity\n let value = sign === '-' ? '-Infinity' : 'Infinity';\n if (hasSuffix) value += this._advance() + this._advance(); // _N\n return this._tok('FLOAT', value, line, col);\n }\n\n /** Advance past a run of hex digits. Digits contain no newlines, so a\n * plain column update is safe. */\n private _skipHexDigits(): void {\n let p = this.pos;\n const n = this.input.length;\n while (p < n && isHexDigitCode(this.input.charCodeAt(p))) p++;\n this.col += p - this.pos;\n this.pos = p;\n }\n\n /** Advance past a run of decimal digits (same newline-free guarantee). */\n private _skipDecimalDigits(): void {\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const c = this.input.charCodeAt(p);\n if (c < 0x30 || c > 0x39) break;\n p++;\n }\n this.col += p - this.pos;\n this.pos = p;\n }\n\n /**\n * Consume a trailing _0–_7/_i encoding-indicator suffix when present and\n * not followed by another identifier character.\n */\n private _tryConsumeEncodingSuffix(): void {\n if (this._ch() !== '_') return;\n const d = this.input[this.pos + 1] ?? '';\n const after = this.input[this.pos + 2] ?? '';\n if (((d >= '0' && d <= '7') || d === 'i') && !/[0-9a-zA-Z_]/.test(after)) {\n this._advance();\n this._advance();\n }\n }\n\n private _readNumber(line: number, col: number): Token {\n // The token value is the raw consumed text; it is collected with a single\n // slice at the end instead of per-character string concatenation.\n const start = this.pos;\n const consumed = () => this.input.slice(start, this.pos);\n // consumed() is the exact source range unless a leading '+' was eaten\n // by the caller before _readNumber; only then does raw need its own slice.\n const numTok = (type: TokenType): Token =>\n start === this._tokStart\n ? this._tokV(type, consumed(), line, col)\n : this._tok(type, consumed(), line, col);\n if (this._ch() === '-') this._advance();\n\n // Alternative bases: 0x 0o 0b\n if (this._ch() === '0') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === 'x' || next === 'X') {\n this._advance();\n this._advance(); // '0x'\n const intStart = this.pos;\n this._skipHexDigits();\n const hasIntDigits = this.pos > intStart;\n // Hex float: optional '.[hex]' fractional part followed by 'p'/'P' exponent\n let isHexFloat = false;\n let hasFracDigits = false;\n if (!this._eof() && this._ch() === '.') {\n isHexFloat = true;\n this._advance();\n const fracStart = this.pos;\n this._skipHexDigits();\n hasFracDigits = this.pos > fracStart;\n }\n if (!this._eof() && (this._ch() === 'p' || this._ch() === 'P')) {\n isHexFloat = true;\n // Validate mantissa: need at least one hex digit before or after dot\n if (!hasIntDigits && !hasFracDigits)\n this._fail(\n `hex float has no mantissa digits: ${consumed()}`,\n line,\n col\n );\n this._advance();\n if (!this._eof() && (this._ch() === '+' || this._ch() === '-'))\n this._advance();\n const expStart = this.pos;\n this._skipDecimalDigits();\n // Validate exponent: at least one decimal digit required\n if (this.pos === expStart)\n this._fail(\n `hex float missing exponent digits: ${consumed()}`,\n line,\n col\n );\n } else if (isHexFloat) {\n // Had a dot but no 'p' — missing exponent\n this._fail(\n `hex float missing 'p' exponent: ${consumed()}`,\n line,\n col\n );\n }\n if (isHexFloat) {\n // Encoding-indicator suffix _0/_1/_2/_3/_4/_5/_6/_7/_i for hex floats\n this._tryConsumeEncodingSuffix();\n return numTok('FLOAT');\n }\n return numTok('INTEGER');\n }\n if (next === 'o' || next === 'O') {\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() >= '0' && this._ch() <= '7')\n this._advance();\n return numTok('INTEGER');\n }\n if (next === 'b' || next === 'B') {\n this._advance();\n this._advance();\n while (!this._eof() && (this._ch() === '0' || this._ch() === '1'))\n this._advance();\n return numTok('INTEGER');\n }\n }\n\n // Decimal digits\n this._skipDecimalDigits();\n\n let isFloat = false;\n if (!this._eof() && this._ch() === '.') {\n isFloat = true;\n this._advance();\n this._skipDecimalDigits();\n }\n if (!this._eof() && (this._ch() === 'e' || this._ch() === 'E')) {\n isFloat = true;\n this._advance();\n if (!this._eof() && (this._ch() === '+' || this._ch() === '-'))\n this._advance();\n const expStart = this.pos;\n this._skipDecimalDigits();\n if (this.pos === expStart)\n this._fail(\n `float exponent has no digits: ${JSON.stringify(consumed())}`,\n line,\n col\n );\n }\n\n // Encoding-indicator suffix _0–_7 / _i (no whitespace, not followed by\n // more ident chars). The suffix is included in the token value.\n // isFloat is NOT set here — a float is only a float when it contains\n // '.' or 'e'/'E'. The parser extracts encoding width from the suffix.\n this._tryConsumeEncodingSuffix();\n\n return numTok(isFloat ? 'FLOAT' : 'INTEGER');\n }\n\n private _readIdent(line: number, col: number): Token {\n // Idents contain no newlines, so a plain column update is safe.\n const identStart = this.pos;\n {\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const cc = this.input.charCodeAt(p);\n const isIdentChar =\n (cc >= 0x61 && cc <= 0x7a) || // a-z\n (cc >= 0x41 && cc <= 0x5a) || // A-Z\n (cc >= 0x30 && cc <= 0x39) || // 0-9\n cc === 0x5f; // _\n if (!isIdentChar) break;\n p++;\n }\n this.col += p - this.pos;\n this.pos = p;\n }\n let ident = this.input.slice(identStart, this.pos);\n\n // Known keywords — checked first so they are never shadowed by app-strings.\n switch (ident) {\n case 'true':\n return this._tokV('TRUE', ident, line, col);\n case 'false':\n return this._tokV('FALSE', ident, line, col);\n case 'null':\n return this._tokV('NULL', ident, line, col);\n case 'undefined':\n return this._tokV('UNDEFINED', ident, line, col);\n case 'NaN':\n case 'NaN_0':\n case 'NaN_1':\n case 'NaN_2':\n case 'NaN_3':\n case 'NaN_4':\n case 'NaN_5':\n case 'NaN_6':\n case 'NaN_7':\n case 'NaN_i':\n case 'Infinity':\n case 'Infinity_0':\n case 'Infinity_1':\n case 'Infinity_2':\n case 'Infinity_3':\n case 'Infinity_4':\n case 'Infinity_5':\n case 'Infinity_6':\n case 'Infinity_7':\n case 'Infinity_i':\n return this._tokV('FLOAT', ident, line, col);\n case 'simple':\n return this._tokV('SIMPLE', ident, line, col);\n case '_':\n return this._tokV('UNDERSCORE', '_', line, col);\n // Encoding indicators used in array/map/string/bytes contexts\n case '_0':\n return this._tok('ENCODING_INDICATOR', '0', line, col);\n case '_1':\n return this._tok('ENCODING_INDICATOR', '1', line, col);\n case '_2':\n return this._tok('ENCODING_INDICATOR', '2', line, col);\n case '_3':\n return this._tok('ENCODING_INDICATOR', '3', line, col);\n case '_4':\n return this._tok('ENCODING_INDICATOR', '4', line, col);\n case '_5':\n return this._tok('ENCODING_INDICATOR', '5', line, col);\n case '_6':\n return this._tok('ENCODING_INDICATOR', '6', line, col);\n case '_7':\n // _7 = AI 31 = indefinite-length; kept as ENCODING_INDICATOR so that\n // bare `_` (UNDERSCORE) and explicit `_7` stay distinguishable.\n return this._tok('ENCODING_INDICATOR', '7', line, col);\n case '_i':\n return this._tok('ENCODING_INDICATOR', 'i', line, col);\n }\n\n // Byte-string prefixes or app-string extensions.\n // App-prefix grammar (§6.1 of draft-ietf-cbor-edn-literals-27):\n // app-prefix = lcalpha *lcldh / ucalpha *ucldh\n // lcldh = lcalpha / DIGIT / \"-\"\n // ucldh = ucalpha / DIGIT / \"-\"\n // Mixed-case or underscore-containing idents are not valid app-prefixes.\n const firstChar = ident[0] ?? '';\n const isLower = firstChar >= 'a' && firstChar <= 'z';\n const isUpper = firstChar >= 'A' && firstChar <= 'Z';\n\n if (isLower || isUpper) {\n // Validate chars already consumed by the main loop (no underscore, correct case).\n const restAlreadyRead = ident.slice(1);\n const restValid = isLower\n ? /^[a-z0-9]*$/.test(restAlreadyRead)\n : /^[A-Z0-9]*$/.test(restAlreadyRead);\n\n if (restValid) {\n // Extend the prefix with any remaining lcldh / ucldh chars.\n // The main loop stops at '-', so we need to consume hyphen-segments here.\n const extStart = this.pos;\n while (!this._eof()) {\n const ch = this._ch();\n const validCh = isLower\n ? (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch === '-'\n : (ch >= 'A' && ch <= 'Z') ||\n (ch >= '0' && ch <= '9') ||\n ch === '-';\n if (!validCh) break;\n this.pos++;\n }\n if (this.pos > extStart) {\n this.col += this.pos - extStart;\n ident += this.input.slice(extStart, this.pos);\n }\n\n const q = this._ch();\n // Double quotes are not valid for app-string / byte-string prefixes.\n // app-string = app-prefix sqstr (sqstr uses single quotes only)\n if (q === '\"')\n this._fail(\n `\"${ident}\" prefix requires single quotes or backticks, not double quotes`,\n line,\n col\n );\n if (q === \"'\") {\n switch (ident) {\n case 'h': {\n const { value: hexVal, elided } =\n this._readHexByteContentElisionAware(q);\n return this._tok(\n elided ? 'BYTES_HEX_ELIDED' : 'BYTES_HEX',\n hexVal,\n line,\n col\n );\n }\n case 'b64':\n return this._tok(\n 'BYTES_B64',\n this._readByteContent(q),\n line,\n col\n );\n default:\n return this._tok(\n 'APP_STRING',\n this._readStringContent(q),\n line,\n col,\n ident\n );\n }\n }\n\n // app-rstring: prefix followed by backtick raw string (§2.3.3 / app-rstring)\n if (q === '`') {\n const raw = this._readRawStringContent();\n switch (ident) {\n case 'h': {\n // §6.3.3: lblank + / / block comments + # line comments + ellipsis\n const { value: hexVal, elided } = this._processRawHexContent(\n raw,\n line,\n col\n );\n return this._tok(\n elided ? 'BYTES_HEX_ELIDED' : 'BYTES_HEX',\n hexVal,\n line,\n col\n );\n }\n case 'b64':\n // §6.3.4: lblank + # line comments\n return this._tok(\n 'BYTES_B64',\n this._processRawB64Content(raw, line, col),\n line,\n col\n );\n default:\n return this._tok('APP_STRING', raw, line, col, ident);\n }\n }\n\n // App-sequence extension: prefix<<items...>>\n // The tokenizer consumes only prefix + \"<<\"; the parser reads items until \">>\".\n if (q === '<' && (this.input[this.pos + 1] ?? '') === '<') {\n this._advance();\n this._advance(); // <<\n return this._tok('APP_SEQUENCE', '', line, col, ident);\n }\n }\n }\n\n this._fail(`unknown identifier ${JSON.stringify(ident)}`, line, col);\n }\n}\n","/**\n * Pure utility functions for EDN serialization.\n * No AST imports — safe to import from any AST class.\n */\n\nimport type { CborComment, CborComments, ToCDNOptions } from '../types';\nimport type { EncodingWidth } from '../cbor/encode';\nimport type { AppSeqEncodingEdit, AppSeqSourceFeatures } from '../ast/CborItem';\nimport { bytesToHex as toHex, hexToBytes } from '../utils/hex';\nimport { base64ToBytes } from '../utils/base64';\nimport { Tokenizer, type Token, type SqstrToken } from './tokenizer';\n\n/**\n * Append every element of `source` onto `target` in place.\n *\n * Not `target.push(...source)`: spreading a large array as call arguments\n * can exceed the engine's argument-count limit (observed with hex-dump\n * lines for a deeply nested large array/map, and with CDN reflow\n * breakpoints for a large embedded array — RangeError: Maximum call stack\n * size exceeded).\n */\nexport function pushAll<T>(target: T[], source: readonly T[]): void {\n for (const item of source) target.push(item);\n}\n\n// ─── Indent helpers ───────────────────────────────────────────────────────────\n\n/** Resolve indent option to a string, or null for single-line output. */\nexport function resolveIndent(\n options: ToCDNOptions | undefined\n): string | null {\n const indent = options?.indent;\n if (indent === undefined) return null;\n const indentStr = typeof indent === 'number' ? ' '.repeat(indent) : indent;\n // `0` / `''` disable pretty-printing entirely (like `JSON.stringify`).\n return indentStr === '' ? null : indentStr;\n}\n\n/** Build the indent prefix for a given depth. */\nexport function indentOf(indentStr: string, depth: number): string {\n return indentStr.repeat(depth);\n}\n\n/**\n * Join pre-serialized string-concatenation part literals with `+`.\n *\n * Single-line (` + `) when indent is disabled; otherwise each continuation\n * part starts on its own line, indented one level deeper than the owner.\n *\n * `midComments`, when given, holds already-converted comment lines for each\n * gap between two consecutive parts (`midComments[i]` sits between\n * `literals[i]` and `literals[i + 1]`) — e.g. a comment between two\n * `+`-joined byte-string literals, which has nowhere else to attach since\n * there is no per-part AST node. Ignored in single-line mode, matching every\n * other comment kind.\n */\nexport function joinConcatParts(\n literals: readonly string[],\n indentStr: string | null,\n depth: number,\n midComments?: readonly (readonly string[])[]\n): string {\n if (indentStr === null) return literals.join(' + ');\n const indent = indentOf(indentStr, depth + 1);\n let out = literals[0]!;\n for (let i = 1; i < literals.length; i++) {\n out += ' +\\n';\n for (const comment of midComments?.[i - 1] ?? []) {\n out += `${indent}${comment}\\n`;\n }\n out += indent + literals[i];\n }\n return out;\n}\n\n/**\n * Serialize string parts as a `t1<<...>>` / `b1<<...>>` app-sequence\n * (draft-ietf-cbor-edn-literals-27 §3.5) — the `modernConcat` replacement\n * for `joinConcatParts`'s `+`-joining. Unlike a `+` chain, this\n * notation has its own closing delimiter, so (matching how `<<...>>`/\n * `CborEmbeddedCBOR` places its own encoding-width indicator, and unlike\n * `emitParts`, which has nowhere else to put it) `suffix` is appended after\n * `>>` rather than onto the last literal — it describes the one merged value\n * `t1<<...>>` denotes as a whole, not any individual argument.\n *\n * Always single-line (an app-sequence is loose/collapsible, like\n * every other `<<...>>` form), except when there's a mid-chain comment to\n * preserve — nothing else forces it multi-line, since (unlike a real `+`\n * chain) there's no risk of an unbounded single line growing unreadable that\n * this format was ever meant to solve; a comment is the one thing a single\n * line genuinely cannot hold, mirroring `joinConcatParts`'s own reason for\n * going multi-line.\n */\nexport function joinAppSeqParts(\n prefix: 't1' | 'b1',\n literals: readonly string[],\n suffix: string,\n indentStr: string | null,\n depth: number,\n midComments?: readonly (readonly string[])[]\n): string {\n const hasMidComments = midComments?.some((c) => c.length > 0) ?? false;\n if (indentStr === null || !hasMidComments) {\n return `${prefix}<<${literals.join(', ')}>>${suffix}`;\n }\n const indent = indentOf(indentStr, depth + 1);\n const closeIndent = indentOf(indentStr, depth);\n const lines: string[] = [];\n for (let i = 0; i < literals.length; i++) {\n const sep = i < literals.length - 1 ? ',' : '';\n lines.push(`${indent}${literals[i]}${sep}`);\n for (const comment of midComments?.[i] ?? []) {\n lines.push(`${indent}${comment}`);\n }\n }\n return `${prefix}<<\\n${lines.join('\\n')}\\n${closeIndent}>>${suffix}`;\n}\n\n// ─── Comment helpers ─────────────────────────────────────────────────────────\n\nexport interface Commented {\n comments?: CborComments;\n blankLineBefore?: boolean;\n}\n\nexport function hasPreservedComments(item: Commented): boolean {\n return Boolean(\n item.comments?.leading?.length ||\n item.comments?.trailing?.length ||\n item.comments?.dangling?.length\n );\n}\n\nexport function hasContainerLayoutComments(item: Commented): boolean {\n // Only dangling comments force the container itself onto multiple lines —\n // they live inside the brackets on their own line. A trailing comment on\n // the container is appended after the closing bracket by the caller (root\n // `toCDN()` or the parent's `entryTrailing`), so it never needs the body\n // to break, and single/flat rendering stays available.\n return Boolean(item.comments?.dangling?.length);\n}\n\n/**\n * Subset of `ToCDNOptions` needed to resolve comment on/off + style —\n * accepted structurally so callers with a narrower/wider options type (or a\n * plain `FromCDNOptions`, which shares both fields) don't need a cast.\n */\ninterface CommentOptions {\n preserveComments?: boolean | 'c-style' | 'cdn-style';\n comments?: 'strip' | 'c-style' | 'cdn-style';\n}\n\n/**\n * Whether comments should be emitted for freshly-regenerated output (as\n * opposed to a preserved app-sequence/raw-tag source — see\n * `decideTaggedAppSeqRendering`'s own comment handling for that case, which\n * has a different \"nothing set\" default).\n *\n * `preserveComments: true` always emits (verbatim); otherwise, comments are\n * emitted only when `comments` requests a real style (not `'strip'`,\n * the default when unset) — matching the deprecated `preserveComments:\n * 'c-style'/'cdn-style'` shorthand, which behaves the same as `comments`\n * set to that value.\n */\nexport function shouldEmitComments(\n options: CommentOptions | undefined\n): boolean {\n if (options?.preserveComments === true) return true;\n if (typeof options?.preserveComments === 'string') return true;\n return options?.comments !== undefined && options.comments !== 'strip';\n}\n\n/**\n * The marker style to normalize emitted comments to, or `undefined` for\n * verbatim (original markers kept as-is). Only meaningful when\n * `shouldEmitComments` is `true`; see its doc for the on/off precedence.\n */\nexport function resolveCommentStyle(\n options: CommentOptions | undefined\n): 'c-style' | 'cdn-style' | undefined {\n if (options?.preserveComments === true) return undefined;\n if (typeof options?.preserveComments === 'string')\n return options.preserveComments;\n const style = options?.comments;\n return style === 'strip' ? undefined : style;\n}\n\n/**\n * Convert a single comment's text to the requested marker style.\n *\n * Conversion table:\n * c-style : `#` → `//`, `/ … /` → `/* … *\\/`\n * cdn-style: `//` → `#`, `/* … *\\/` → `/ … /`\n *\n * Special case for cdn-style: when the inner content of `/* … *\\/` starts\n * with `*` or `/` the result would look like `/*…` or `//…` — a different\n * comment form. A single space is inserted after the opening `/` to prevent\n * this (e.g. `/**…*\\/` → `/ *…/`).\n */\nexport function convertCommentText(\n comment: CborComment,\n style: 'c-style' | 'cdn-style' | undefined\n): string {\n if (!style) return comment.text;\n const { marker, text } = comment;\n\n if (style === 'c-style') {\n if (marker === '#') return '//' + text.slice(1);\n if (marker === '/') return '/*' + text.slice(1, -1) + '*/';\n return text; // already // or /*...*/\n }\n\n // cdn-style\n if (marker === '//') return '#' + text.slice(2);\n if (marker === '/*') {\n const inner = text.slice(2, -2);\n // / … / comments have no escape mechanism for '/', so if the content\n // contains one we must keep the /* … */ form to avoid corrupting output.\n if (inner.includes('/')) return text;\n const safeInner =\n inner.startsWith('*') || inner.startsWith('/') ? ' ' + inner : inner;\n return '/' + safeInner + '/';\n }\n return text; // already # or /.../\n}\n\n/**\n * Bucket a flat, source-ordered list of comments (typically a node's own\n * `comments.dangling`) by which gap between two consecutive `parts` each\n * one's offset falls into — `result[i]` sits between `parts[i]` and\n * `parts[i + 1]`, already converted to the requested marker style.\n *\n * Used for a comment that sits between two `+`-joined fragments merged into\n * a single value with no per-fragment AST node of its own to attach to (a\n * concatenated `CborByteString`'s own `ednParts`, or — inside a bytes\n * elision — a `CborEllipsis` item's `ednParts`): `attachComments` can only\n * land such a comment on the merged node as a whole, as `dangling`, so this\n * re-derives which specific gap it belongs in from each part's own\n * `start`/`end` span. A comment is dropped (as it already was before this\n * function existed) when either neighbouring part lacks a known span — a\n * part merged from a single elided literal's own internal segments, which\n * cannot have a comment between them anyway (see `_elidedHexAtoms`).\n *\n * Returns `undefined` (rather than an all-empty array) when nothing landed\n * in any gap, so callers can cheaply skip the mid-comment rendering path\n * entirely in the common case.\n */\nexport function danglingCommentsByGap(\n dangling: readonly CborComment[] | undefined,\n parts: readonly { start?: number; end?: number }[] | undefined,\n style: 'c-style' | 'cdn-style' | undefined\n): string[][] | undefined {\n if (!dangling || dangling.length === 0 || !parts || parts.length < 2)\n return undefined;\n const gaps: string[][] = parts.slice(1).map(() => []);\n let anyFound = false;\n for (const comment of dangling) {\n for (let i = 0; i < parts.length - 1; i++) {\n const prevEnd = parts[i]!.end;\n const nextStart = parts[i + 1]!.start;\n if (\n prevEnd !== undefined &&\n nextStart !== undefined &&\n comment.start >= prevEnd &&\n comment.end <= nextStart\n ) {\n gaps[i]!.push(convertCommentText(comment, style));\n anyFound = true;\n break;\n }\n }\n }\n return anyFound ? gaps : undefined;\n}\n\n/**\n * Split an item's leading comments into ones that get their own line above\n * it, and a trailing run of comments the parser found on the same source\n * line as the item itself (`CborComment.sameLine`) — e.g.\n * `/ protected / << ... >>,` in an RFC 9052-style annotated array. Since\n * comments and the item they lead up to appear in strictly increasing\n * source order, `sameLine` comments always form a contiguous run at the end\n * of the list (nothing can sit between a same-line comment and the item\n * without itself being on that same line).\n *\n * `ownLines` renders like `formatLeadingComments` used to; `inlinePrefix` is\n * meant to be prepended directly to the item's own rendered line (already\n * includes a trailing space per comment, or `''` when there is none).\n */\nexport function splitLeadingComments(\n item: Commented,\n indent: string,\n style?: 'c-style' | 'cdn-style' | undefined\n): { ownLines: string[]; inlinePrefix: string } {\n const leading = item.comments?.leading ?? [];\n let splitAt = leading.length;\n while (splitAt > 0 && leading[splitAt - 1]!.sameLine) splitAt--;\n return {\n ownLines: leading\n .slice(0, splitAt)\n .map((comment) => indent + convertCommentText(comment, style)),\n inlinePrefix: leading\n .slice(splitAt)\n .map((comment) => convertCommentText(comment, style) + ' ')\n .join(''),\n };\n}\n\nexport function formatTrailingComments(\n item: Commented,\n style?: 'c-style' | 'cdn-style' | undefined\n): string {\n const comments = item.comments?.trailing ?? [];\n if (comments.length === 0) return '';\n return (\n ' ' +\n comments.map((comment) => convertCommentText(comment, style)).join(' ')\n );\n}\n\nexport function formatDanglingComments(\n item: Commented,\n indent: string,\n style?: 'c-style' | 'cdn-style' | undefined\n): string[] {\n return (item.comments?.dangling ?? []).map(\n (comment) => indent + convertCommentText(comment, style)\n );\n}\n\n// ─── Comma / separator helpers ────────────────────────────────────────────────\n\n/**\n * Resolve separator options into concrete strings.\n *\n * @param compact - When `true` (no `indent` option), omit spaces around\n * separators to produce compact single-line output (like `JSON.stringify`).\n *\n * @returns\n * - `inlineSep` – between items on a single line\n * - `multilineSep` – appended after each non-last line in multi-line mode\n * - `trailSep` – appended after the last item (empty string or `,`)\n * - `colSep` – between map key and value (`': '` or `':'`)\n */\nexport function resolveSeparators(\n options: ToCDNOptions | undefined,\n compact = false\n): {\n inlineSep: string;\n multilineSep: string;\n trailSep: string;\n colSep: string;\n} {\n const commas = options?.commas ?? 'comma';\n const useCommas = commas !== 'none';\n const trailing = commas === 'trailing';\n return {\n inlineSep: useCommas ? (compact ? ',' : ', ') : ' ',\n multilineSep: useCommas ? ',' : '',\n trailSep: trailing ? ',' : '',\n colSep: compact ? ':' : ': ',\n };\n}\n\n// ─── Container serialization ─────────────────────────────────────────────────\n\n/**\n * Shared CDN serialization for bracketed containers (CborArray / CborMap /\n * indefinite-length string chunks `(_ ...)`):\n * encoding-indicator / `_` prefix resolution, single-line vs multi-line\n * selection, separators, and per-entry leading/trailing plus container\n * dangling comments. Single-line output (no `indent`) always strips\n * comments — line comments can only be terminated by a newline.\n *\n * Entries are accessed through per-index callbacks (not materialised entry\n * objects) so the common no-comments/no-blank-line path allocates nothing\n * per entry. `hasEntryComments` and `entryTrailing` are consulted only when\n * `preserveComments` is set; `entryLeadingNode` is also consulted when\n * `preserveBlankLines` is set, independently of `preserveComments`, to read\n * its `blankLineBefore` flag. `renderEntry` receives the resolved `colSep`\n * (': ' or ':' depending on compact mode) for rendering map pairs.\n */\nexport function serializeContainer(p: {\n node: Commented;\n options: ToCDNOptions | undefined;\n depth: number;\n openChar: string;\n closeChar: string;\n count: number;\n indefiniteLength: boolean;\n /**\n * Whether an indefinite-length container shows the `_` marker\n * (`(_ \"a\", \"b\")`) before its content. Defaults to `true`; set `false` for\n * a container that denotes an indefinite-length value through some other\n * notation entirely (e.g. `ilts<<\"a\", \"b\">>`) rather than through the\n * `_`-marked legacy streamstring form — the value is still genuinely\n * indefinite-length (so `indefiniteLength: true` still correctly\n * suppresses any encoding-width suffix, which has no meaning for it), but\n * that other notation has no `_` marker of its own to show.\n */\n indefiniteMarker?: boolean;\n encodingWidth: EncodingWidth | undefined;\n /**\n * Where the resolved encoding-indicator suffix is placed.\n * - `'open'` (default): right after `openChar`, before the content\n * (`[_2 1,2,3]`) — the head this indicator describes encodes entry count.\n * - `'close'`: right after `closeChar`, with no separating space\n * (`<<1,2>>_1`) — for `CborEmbeddedCBOR`, whose byte-string head encodes\n * content byte length, not entry count.\n */\n eiPosition?: 'open' | 'close';\n /**\n * Basis for canonical-encoding-width detection (`encodingIndicators:\n * 'auto'`/`'always'` with no explicit `encodingWidth`). Defaults to\n * `count`, matching the CBOR array/map head. `CborEmbeddedCBOR` overrides\n * this to its encoded content's byte length instead.\n */\n canonicalCount?: () => bigint;\n hasEntryComments: () => boolean;\n /** Render entry `i` at child depth (`item` or `key: value`). */\n renderEntry: (i: number, colSep: string) => string;\n /**\n * Whether entry `i` contains no nested array/map, so it may stay on the\n * container's line under `inlineLeafContainers` (or always, when\n * `alwaysInlineLeaf` is set). Omitted = always a leaf (used by\n * `CborEmbeddedCBOR`, where an entry that is itself a container still\n * inlines as long as its own rendering fits on one line).\n */\n entryIsLeaf?: (i: number) => boolean;\n /**\n * Whether entry `i` is, or wraps, a text string or byte string with two or\n * more words (`isMultiWordText` / `isMultiWordByteString`). When true,\n * disqualifies the container from staying on one line under\n * `inlineLeafContainers` (or `alwaysInlineLeaf`) even though the entry has\n * no nested array/map — a multi-word string reads better with a line of\n * its own. This does *not* also cover a prefixed literal like `h'...'`\n * (which has no word count to check at all, but still disqualifies under\n * the strict rule) — that's covered separately, generically, by\n * `isPrefixedLiteralText` (checked against the rendered entry `s` below)\n * or, for a `CborTag`, `isMultiWordRenderedLiteral`. Omitted = never\n * disqualifies.\n */\n entryIsMultiWordText?: (i: number) => boolean;\n /**\n * Always run the one-line collapse probe, regardless of\n * `options.inlineLeafContainers`. Set only by `CborEmbeddedCBOR`\n * (`<<...>>`): unlike `CborArray`/`CborMap`, where spreading entries one\n * per line is a deliberate structural default that `inlineLeafContainers`\n * opts out of, a flat sequence of encoded items has no such structure to\n * display — there's nothing gained by always breaking it, so it\n * collapses onto one line whenever it fits independent of the option.\n * Indefinite-length string groups (`(_ \"a\", \"b\")`) do *not* get this\n * treatment — they follow CborArray/CborMap's option-gated default\n * instead, providing `entryIsLeaf` the same way (see `strict` below),\n * despite also being a \"loose rule\" container in the\n * `_containsCdnContainer`/`entryHasContainer` sense (a chunk can never\n * actually be an array/map, so that distinction is moot for them in\n * practice). This flag and the loose/strict distinction are genuinely\n * independent concerns, not the same thing.\n */\n alwaysInlineLeaf?: boolean;\n /** Node whose leading comments are emitted above entry `i` (item / map key). */\n entryLeadingNode: (i: number) => Commented;\n /** Pre-formatted trailing comment text for entry `i` (starts with ' ', or ''). */\n entryTrailing: (\n i: number,\n style: 'c-style' | 'cdn-style' | undefined\n ) => string;\n}): string {\n const { options, depth, openChar, closeChar, count } = p;\n const indentStr = resolveIndent(options);\n const preserveComments = shouldEmitComments(options);\n const commentStyle = resolveCommentStyle(options);\n const hasComments =\n indentStr !== null &&\n preserveComments &&\n (hasContainerLayoutComments(p.node) || p.hasEntryComments());\n const preserveBlankLines =\n indentStr !== null && !!options?.preserveBlankLines;\n let hasBlankLines = false;\n if (preserveBlankLines) {\n for (let i = 0; i < count; i++) {\n if (p.entryLeadingNode(i).blankLineBefore) {\n hasBlankLines = true;\n break;\n }\n }\n }\n const { inlineSep, multilineSep, trailSep, colSep } = resolveSeparators(\n options,\n indentStr === null\n );\n const eiPosition = p.eiPosition ?? 'open';\n const eiRaw = p.indefiniteLength\n ? ''\n : resolveEiSuffix(options, p.encodingWidth, () =>\n canonicalEncodingWidth(\n p.canonicalCount ? p.canonicalCount() : BigInt(count)\n )\n );\n const eiSuffix = eiPosition === 'open' && eiRaw ? eiRaw + ' ' : '';\n const closeSuffix = eiPosition === 'close' ? eiRaw : '';\n const showIndef =\n p.indefiniteLength &&\n (p.indefiniteMarker ?? true) &&\n (options?.encodingIndicators ?? 'auto') !== 'never';\n\n const singleLine = (inner: string): string => {\n if (p.indefiniteLength) {\n return showIndef\n ? count === 0\n ? `${openChar}_ ${closeChar}`\n : `${openChar}_ ${inner}${closeChar}`\n : `${openChar}${inner}${closeChar}`;\n }\n return `${openChar}${eiSuffix}${inner}${closeChar}${closeSuffix}`;\n };\n\n if (indentStr === null || (count === 0 && !hasComments)) {\n // single-line\n let inner = '';\n for (let i = 0; i < count; i++) {\n if (i > 0) inner += inlineSep;\n inner += p.renderEntry(i, colSep);\n }\n return singleLine(inner);\n }\n\n // inlineLeafContainers: keep the container on one line when no entry holds\n // a nested array/map, no entry is a multi-word string, and every entry\n // renders without a line break. `alwaysInlineLeaf` runs the same probe\n // unconditionally (see its doc) — the container-specific option value\n // doesn't otherwise change what the probe checks.\n // Entries rendered here via `renderEntry` are reused below if the probe\n // fails, so *this* function never calls `renderEntry` more than once per\n // entry per parent render. This doesn't extend to what `entryIsLeaf`/\n // `entryIsMultiWordText` do internally, though: `CborTag`'s\n // `_isMultiWordText` deliberately renders `this.content` once here (via\n // its prefixed-literal fallback) and `renderEntry` renders it again for\n // real — an accepted double-render, not an oversight (see CborTag.ts for\n // why an instance-level cache to avoid it turned out to be unsafe).\n let probed: string[] | null = null;\n if (\n (options?.inlineLeafContainers || p.alwaysInlineLeaf) &&\n count > 0 &&\n !hasComments &&\n !hasBlankLines\n ) {\n // `entryIsLeaf`'s presence doubles as the strict/loose signal here:\n // CborArray/CborMap and the indefinite-length string groups (the\n // strict rule) all provide it — only CborEmbeddedCBOR (the one\n // container whose collapse isn't gated behind `inlineLeafContainers`\n // at all) omits it. Reused below to gate `isPrefixedLiteralText`\n // (and, for a `CborTag`, `isMultiWordRenderedLiteral`'s equivalent\n // gating): a prefixed literal like `h'...'` disqualifies under the\n // strict rule but is an ordinary leaf under the loose one — e.g.\n // `<<h'00'>>` stays inline, but `(_ h'00')`/`[h'00']` still disqualify.\n const strict = !!p.entryIsLeaf;\n const rendered: string[] = [];\n let flat = true;\n for (let i = 0; i < count; i++) {\n if (p.entryIsLeaf && !p.entryIsLeaf(i)) {\n flat = false;\n break;\n }\n if (p.entryIsMultiWordText?.(i)) {\n flat = false;\n break;\n }\n const s = p.renderEntry(i, colSep);\n rendered.push(s);\n if (s.includes('\\n')) {\n flat = false;\n break;\n }\n if (strict && isPrefixedLiteralText(s)) {\n flat = false;\n break;\n }\n }\n if (flat) return singleLine(rendered.join(inlineSep));\n probed = rendered;\n }\n\n // multi-line\n const childIndent = indentOf(indentStr, depth + 1);\n const closeIndent = indentOf(indentStr, depth);\n const open = p.indefiniteLength\n ? showIndef\n ? `${openChar}_ `\n : openChar\n : `${openChar}${eiSuffix}`;\n const lines: string[] = [];\n for (let i = 0; i < count; i++) {\n if (preserveBlankLines && p.entryLeadingNode(i).blankLineBefore) {\n lines.push('');\n }\n let inlinePrefix = '';\n if (preserveComments) {\n const { ownLines, inlinePrefix: prefix } = splitLeadingComments(\n p.entryLeadingNode(i),\n childIndent,\n commentStyle\n );\n pushAll(lines, ownLines);\n inlinePrefix = prefix;\n }\n const sep = i < count - 1 ? multilineSep : trailSep;\n const entry = probed?.[i] ?? p.renderEntry(i, colSep);\n lines.push(\n `${childIndent}${inlinePrefix}${entry}${sep}${preserveComments ? p.entryTrailing(i, commentStyle) : ''}`\n );\n }\n if (preserveComments)\n pushAll(lines, formatDanglingComments(p.node, childIndent, commentStyle));\n const body = lines.join('\\n');\n return `${open}\\n${body}\\n${closeIndent}${closeChar}${closeSuffix}`;\n}\n\n/**\n * Single-child counterpart to `serializeContainer`, for a wrapper that\n * holds exactly one child inside `openChar`/`closeChar` (currently just\n * `CborTag`'s `(content)`) rather than a comma-separated list of entries.\n *\n * Emits the child's own leading/trailing comments, and the wrapper node's\n * `dangling` comments (a comment positioned after the child but still\n * inside the brackets, with nothing following it to attach to as leading —\n * mirroring how `serializeContainer` handles a container's own dangling\n * comments). Falls back to the plain single-line `(content)` form — the\n * common, zero-allocation-beyond-string-concat path — when comments aren't\n * requested/applicable (no indent, no `preserveComments`, or neither the\n * child nor the wrapper has any).\n *\n * `renderChild` is called with the child's depth exactly once, resolved\n * *before* calling it: `depth + 1` when comments force multi-line\n * rendering, `depth` otherwise (matching a plain value's existing\n * \"transparent\" nesting — `tag(content)` doesn't indent `content` an extra\n * level when there's nothing to justify going multi-line for).\n */\nexport function renderSingleChildWithComments(\n child: Commented,\n wrapper: Commented,\n options: ToCDNOptions | undefined,\n depth: number,\n renderChild: (childDepth: number) => string,\n openChar: '(',\n closeChar: ')'\n): string {\n const indentStr = resolveIndent(options);\n const hasComments =\n indentStr !== null &&\n shouldEmitComments(options) &&\n (hasPreservedComments(child) || hasContainerLayoutComments(wrapper));\n if (!hasComments) return `${openChar}${renderChild(depth)}${closeChar}`;\n const commentStyle = resolveCommentStyle(options);\n const childIndent = indentOf(indentStr!, depth + 1);\n const closeIndent = indentOf(indentStr!, depth);\n const { ownLines, inlinePrefix } = splitLeadingComments(\n child,\n childIndent,\n commentStyle\n );\n const lines = [\n ...ownLines,\n `${childIndent}${inlinePrefix}${renderChild(depth + 1)}${formatTrailingComments(child, commentStyle)}`,\n ...formatDanglingComments(wrapper, childIndent, commentStyle),\n ];\n return `${openChar}\\n${lines.join('\\n')}\\n${closeIndent}${closeChar}`;\n}\n\n// ─── Byte string encoding ─────────────────────────────────────────────────────\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeToBase64 =\n typeof (new Uint8Array(0) as any).toBase64 === 'function';\n\nfunction toBase64(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToBase64) return (bytes as any).toBase64({ omitPadding: true });\n let binary = '';\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/=/g, '');\n}\n\nfunction toBase64Url(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToBase64)\n return (bytes as any).toBase64({\n alphabet: 'base64url',\n omitPadding: true,\n });\n let binary = '';\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nconst B32_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';\nconst H32_ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUV';\n\nfunction base32Encode(bytes: Uint8Array, alpha: string): string {\n let result = '';\n let buf = 0,\n bufBits = 0;\n for (const b of bytes) {\n buf = (buf << 8) | b;\n bufBits += 8;\n while (bufBits >= 5) {\n bufBits -= 5;\n result += alpha[(buf >> bufBits) & 0x1f];\n }\n }\n if (bufBits > 0) result += alpha[(buf << (5 - bufBits)) & 0x1f];\n return result;\n}\n\n/**\n * Returns true if the string contains any C0 control character (U+0000–U+001F)\n * or DEL (U+007F).\n */\nfunction _hasNonPrintable(s: string): boolean {\n for (const char of s) {\n const cp = char.codePointAt(0)!;\n if (cp < 0x20 || cp === 0x7f) return true;\n }\n return false;\n}\n\n/**\n * The decoded text `bytes` would render as under a bare sqstr literal\n * (`'...'`) for the given `sqstr` option, or `null` when it would instead\n * render as a prefixed literal (`h'...'`, `b64'...'`, ...). Shared by\n * `serializeBytes` (the actual rendering decision) and `isMultiWordByteString`\n * (which needs to know the same thing without rendering).\n */\nfunction _sqstrTextOrNull(\n bytes: Uint8Array,\n sqstr?: 'printable-string' | 'string' | 'none'\n): string | null {\n if (sqstr === 'string') {\n const s = _tryDecodeUtf8(bytes);\n if (s != null) return s;\n }\n if (sqstr === 'printable-string' || sqstr === undefined) {\n const s = _tryDecodeUtf8(bytes);\n if (s != null && !_hasNonPrintable(s)) return s;\n }\n return null;\n}\n\nexport function serializeBytes(\n bytes: Uint8Array,\n encoding?: 'hex' | 'base64' | 'base64url' | 'base32' | 'base32hex',\n sqstr?: 'printable-string' | 'string' | 'none'\n): string {\n const sqstrText = _sqstrTextOrNull(bytes, sqstr);\n if (sqstrText !== null) return _escapeSingleQuoted(sqstrText);\n switch (encoding) {\n case 'base64':\n return `b64'${toBase64(bytes)}'`;\n case 'base64url':\n return `b64'${toBase64Url(bytes)}'`;\n case 'base32':\n return `b32'${base32Encode(bytes, B32_ALPHA)}'`;\n case 'base32hex':\n return `h32'${base32Encode(bytes, H32_ALPHA)}'`;\n case 'hex':\n default:\n return `h'${toHex(bytes)}'`;\n }\n}\n\n/**\n * True when `bytes` would render as a bare sqstr literal (`'...'`) under\n * `sqstr` *and* its decoded text has two or more words — same rule as a\n * plain text string's own word count. Otherwise (it would render as a\n * prefixed literal like `h'...'`/`b64'...'`, or as something else entirely\n * via a subclass overriding `_toCDN()`) this returns `false`: a prefixed\n * literal has no natural word boundary to predict from raw bytes alone,\n * and — unlike this function, which never renders anything — the actual\n * \"does the real output look like a disqualifying prefixed literal, tag\n * wrapping, or app-sequence spelling\" question is answered generically\n * from the *rendered* text instead, by `isPrefixedLiteralText` (for a bare\n * entry) or `isMultiWordRenderedLiteral` (for a `CborTag`, which needs to\n * see through its own digits/parens onto whatever they wrap).\n */\nexport function isMultiWordByteString(\n bytes: Uint8Array,\n sqstr?: 'printable-string' | 'string' | 'none'\n): boolean {\n const text = _sqstrTextOrNull(bytes, sqstr);\n return text !== null && isMultiWordText(text);\n}\n\n/** An identifier immediately followed by `'` or a backtick — see `isPrefixedLiteralText`. */\nconst PREFIXED_LITERAL_RE = /^[A-Za-z][A-Za-z0-9-]*['`]/;\n\n/**\n * True when `rendered` — a single entry's own CDN rendering — is shaped\n * like a prefixed literal: an identifier immediately followed by `'` or a\n * backtick (`h'...'`, `b64'...'`, `ip'...'`, `dt'...'`, or any other\n * app-string extension's own spelling, built-in or user-defined). These\n * have no natural word boundary to check, so — like a byte string's own\n * prefixed-literal case in `isMultiWordByteString` — the strict\n * `inlineLeafContainers` rule (`CborArray`/`CborMap`, and the\n * indefinite-length string groups) always disqualifies a container from\n * collapsing onto one line when an entry looks like this; the loose rule\n * (only `CborEmbeddedCBOR`/`<<...>>`) treats it as an ordinary leaf\n * instead.\n *\n * This is a generic, rendering-based catch-all — unlike `isMultiWordByteString`,\n * it doesn't need per-extension-class support, so it also covers any\n * app-string extension (registered under `CborExtension.appStringPrefixes`)\n * without that extension's own `CborItem` subclass needing to know about\n * `inlineLeafContainers` at all. It only sees a *bare* prefixed literal\n * (nothing else in `rendered`); `CborTag` uses `isMultiWordRenderedLiteral`\n * instead to see through its own tag digits/parens onto whatever they wrap.\n */\nexport function isPrefixedLiteralText(rendered: string): boolean {\n return PREFIXED_LITERAL_RE.test(rendered);\n}\n\nconst textDecoderForRenderedLiteral = new TextDecoder();\n\n/**\n * True when `rendered` — a leaf entry's own, already-rendered CDN text —\n * counts as multi-word for `inlineLeafContainers`'s purposes, determined by\n * tokenizing `rendered` itself rather than predicting from whichever\n * `CborItem` subclass produced it. This makes it exact regardless of *how*\n * the text came to look the way it does — a `CborTag` subclass\n * (`CborTaggedIpExt`) overriding `_toCDN()` to render `IP<<'...'>>` instead\n * of generic `52(...)` tag notation, a preserved `preserveByteString`\n * spelling, `encodingIndicators: 'always'` adding an explicit `_N`/`_i`\n * suffix everywhere, or anything else — since it never assumes a rendering\n * path, only reads the result.\n *\n * Recognizes these shapes. Any of them may be followed by one trailing\n * `ENCODING_INDICATOR` token (`_0`.._3`/`_i`) — stripped *before* any shape\n * is recognized (not just for a bare literal), since it can trail a tag or\n * an app-sequence wrapper too and never changes a value's own shape or\n * word count:\n * - A bare quoted literal (`\"...\"`, `` `...` ``, or a bare `'...'` sqstr):\n * always counts if its *decoded* content has two or more words,\n * regardless of `strict` — matching a text string's own word count.\n * - A prefixed literal (`h'...'`, `b64'...'`, `ip'...'`, `dt'...'`, ...):\n * has no natural word boundary to check, so it counts only when `strict`.\n * - A generic tag wrapper (`tagNum[_EI](...)`) spanning the *entire* input:\n * peels off just that one layer and recurses on what's inside (handling\n * nested tags one layer at a time) — this is what lets a plain `CborTag`\n * whose content is one of the shapes above still count, e.g.\n * `100(dt'...')`, `100(\"two words\")`, or (with `encodingIndicators:\n * 'always'`) `100_0(\"two words\"_i)`.\n * - An app-sequence wrapper (`prefix<<item item ...>>`, tokenized as one\n * `APP_SEQUENCE` opener and a plain `GT_GT` closer) spanning the *entire*\n * input: unlike a tag, its own `<<...>>` is never peeled away — reading\n * fine inline is the whole point of that notation, not a transparent\n * single-value rewrap — but each top-level item inside (items may be\n * separated by a comma, by whitespace alone, or both, per CDN's own\n * grammar — `consumeOneItem` finds each one's extent structurally rather\n * than only splitting at commas) is checked under the *loose* rule\n * (`strict: false`, matching `<<...>>` itself) regardless of the\n * `strict` this function was called with, so a multi-word text item\n * (`ilts<<\"two words\">>`, or `ilts<<\"two words\" \"x\">>` with no comma at\n * all) still always counts, while a prefixed-literal item\n * (`ilbs<<h'00'>>`) — unlike the same literal bare or tag-wrapped —\n * does not.\n * - Anything else (a number, `true`/`false`, multiple top-level tokens that\n * aren't one of the wrappers above, ...) never counts.\n *\n * Tokenizing can throw on malformed input; since `rendered` is always this\n * library's own output, that should never happen, but a failure is treated\n * as \"not multi-word\" rather than propagating.\n */\nexport function isMultiWordRenderedLiteral(\n rendered: string,\n strict: boolean\n): boolean {\n let tokens: Token[];\n try {\n tokens = tokenizeAll(rendered);\n } catch {\n return false;\n }\n return isMultiWordTokenRange(tokens, 0, tokens.length, strict);\n}\n\nfunction tokenizeAll(source: string): Token[] {\n const tokenizer = new Tokenizer(source);\n const tokens: Token[] = [];\n for (;;) {\n const token = tokenizer.consume();\n if (token.type === 'EOF') return tokens;\n tokens.push(token);\n }\n}\n\n// Token types that open/close a bracket-like span. A single, type-agnostic\n// depth counter is safe for matching (no need to verify e.g. RPAREN closes\n// specifically an LPAREN) because `rendered` is always this library's own,\n// already-well-formed output — bracket families never interleave in valid\n// CDN, so a generic opener/closer never has to disambiguate which family\n// it belongs to.\nconst BRACKET_OPENERS = new Set([\n 'LPAREN',\n 'LBRACKET',\n 'LBRACE',\n 'LT_LT',\n 'APP_SEQUENCE',\n]);\nconst BRACKET_CLOSERS = new Set(['RPAREN', 'RBRACKET', 'RBRACE', 'GT_GT']);\n\n// Token types that can appear as any part — the chain's own first value,\n// or any later one joined by `+` — of a `+`-concatenation chain: a\n// text-string/byte-string literal (draft-25 §5.1), or `ELLIPSIS` (`...`), CDN's\n// elision-chain notation (src/cdn/parser.ts's own `+`-chain grammar\n// accepts it both as the chain's *own* first value — `... + \"b\"`, an\n// unknown prefix concatenated with a known suffix — and as any later\n// continuation — `\"a\" + ...` — building a tag-888-wrapped value instead of\n// a plain joined string) for a part deliberately omitted. Never numbers,\n// tags, containers, or app-strings.\nconst CHAIN_ATOM_TYPES = new Set([\n 'TSTR',\n 'RAWSTRING',\n 'SQSTR',\n 'BYTES_HEX',\n 'BYTES_HEX_ELIDED',\n 'BYTES_B64',\n 'ELLIPSIS',\n]);\n\n/**\n * Index of the token that closes the bracket opened at `openIdx`, scanning\n * up to (excluding) `end`. Returns `null` if unmatched in range.\n */\nfunction findMatchingClose(\n tokens: Token[],\n openIdx: number,\n end: number\n): number | null {\n let depth = 1;\n for (let j = openIdx + 1; j < end; j++) {\n const t = tokens[j].type;\n if (BRACKET_OPENERS.has(t)) depth++;\n else if (BRACKET_CLOSERS.has(t)) {\n depth--;\n if (depth === 0) return j;\n }\n }\n return null;\n}\n\n/**\n * Index one past the end of the single CDN value starting at `start`\n * (scanning up to, exclusive, `end`), or `null` if `start` isn't the start\n * of a recognizable value at all (`end <= start`). This mirrors CDN's\n * value grammar shape closely enough to find an item's own extent without\n * knowing its specific semantic type — needed because app-sequence (and\n * array/map) items may be separated by a comma *or* by nothing but\n * whitespace (which leaves no token of its own), so finding the next\n * item's start means first walking to the end of the current one:\n * - `INTEGER [ENCODING_INDICATOR] LPAREN ... RPAREN` (a tag) — consumes\n * the whole bracketed span.\n * - Any other bracket opener (`(`, `[`, `{`, `<<`, an app-sequence) —\n * consumes its whole matching span, then one trailing\n * `ENCODING_INDICATOR` if present (e.g. `[1, 2]_1`, `<<1, 2>>_1`).\n * - Anything else — a single atom token (`TSTR`, `BYTES_HEX`, `SIMPLE`,\n * `FLOAT`, ...), then one trailing `ENCODING_INDICATOR` if present. If\n * that atom is a `CHAIN_ATOM_TYPES` member (a string/byte-string literal,\n * or an elision-chain `ELLIPSIS`) and is followed by `PLUS`, the whole\n * `+`-concatenation chain (`\"a\" + \"b\" + h'63'`, `\"a\" + ...`, `... + \"b\"`,\n * ...) is consumed as this one item — a chain never continues past any\n * other atom. **Except**: when the chain's own first atom is `ELLIPSIS`,\n * `src/cdn/parser.ts`'s grammar reads each `+`-joined continuation via\n * its *general* value parser (`parseValue()`), not the restricted\n * string/byte-literal-only rule that governs every other chain — so\n * `... + (_ \"a\")`, `... + [1, 2]`, `... + 100(2)`, even `... + ...`, are\n * all valid, and each continuation's extent is found by recursing into\n * this same function instead of checking `CHAIN_ATOM_TYPES` membership.\n */\nfunction consumeOneItem(\n tokens: Token[],\n start: number,\n end: number\n): number | null {\n if (start >= end) return null;\n if (tokens[start].type === 'INTEGER') {\n let p = start + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n if (p < end && tokens[p].type === 'LPAREN') {\n const close = findMatchingClose(tokens, p, end);\n return close !== null ? close + 1 : null;\n }\n return p;\n }\n if (BRACKET_OPENERS.has(tokens[start].type)) {\n const close = findMatchingClose(tokens, start, end);\n if (close === null) return null;\n let p = close + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n return p;\n }\n let p = start + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n\n if (tokens[start].type === 'ELLIPSIS') {\n // An elision-chain start: each continuation after a `+` may be *any*\n // value shape (a tag, container, indefinite-length string group,\n // app-sequence, a nested ellipsis chain, ...), not just a string/byte\n // literal — so find its extent generically by recursing, rather than\n // checking `CHAIN_ATOM_TYPES` membership the way every other chain\n // shape does below.\n while (p < end && tokens[p].type === 'PLUS') {\n const nextEnd = consumeOneItem(tokens, p + 1, end);\n if (nextEnd === null) return null;\n p = nextEnd;\n }\n return p;\n }\n\n const isChainable = CHAIN_ATOM_TYPES.has(tokens[start].type);\n while (isChainable && p < end && tokens[p].type === 'PLUS') {\n const nextStart = p + 1;\n if (nextStart >= end || !CHAIN_ATOM_TYPES.has(tokens[nextStart].type)) {\n return null; // trailing `+` with nothing after, or a malformed chain\n }\n p = nextStart + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n }\n return p;\n}\n\n/**\n * Splits `tokens[start:end)` into top-level item ranges — items may be\n * separated by a comma, by whitespace alone (no token at all), or both\n * (a comma with incidental whitespace around it, which the tokenizer\n * already discards) — per CDN's own array/app-sequence grammar. Returns\n * `[]` if any item's own extent can't be determined (`consumeOneItem`\n * failed to find a bracket's matching close within range), rather than\n * guess at wrong boundaries.\n */\nfunction splitTopLevelItems(\n tokens: Token[],\n start: number,\n end: number\n): [number, number][] {\n const items: [number, number][] = [];\n let p = start;\n while (p < end) {\n const itemEnd = consumeOneItem(tokens, p, end);\n if (itemEnd === null) return [];\n items.push([p, itemEnd]);\n p = itemEnd;\n if (p < end && tokens[p].type === 'COMMA') p++;\n }\n return items;\n}\n\nfunction isMultiWordTokenRange(\n tokens: Token[],\n start: number,\n end: number,\n strict: boolean\n): boolean {\n if (end <= start) return false;\n\n // Strip a trailing encoding indicator up front, before checking for any\n // wrapper shape below — it can trail a bare literal, a tag wrapper\n // (`100(2)_1`, hypothetically), or an app-sequence wrapper\n // (`same<<\"two words\">>_i` is valid CDN: `same` resolves to a plain\n // TSTR, so its own EI can trail the `>>`) — and never changes any of\n // their shape or word count either way.\n let contentEnd = end;\n if (tokens[contentEnd - 1].type === 'ENCODING_INDICATOR') contentEnd--;\n\n // Tag wrapper: INTEGER [ENCODING_INDICATOR] LPAREN ... RPAREN spanning\n // the whole range — peel it and recurse on what's inside.\n if (tokens[start].type === 'INTEGER') {\n let i = start + 1;\n if (i < contentEnd && tokens[i].type === 'ENCODING_INDICATOR') i++;\n if (i < contentEnd && tokens[i].type === 'LPAREN') {\n const close = findMatchingClose(tokens, i, contentEnd);\n if (close !== null && close + 1 === contentEnd) {\n return isMultiWordTokenRange(tokens, i + 1, close, strict);\n }\n }\n }\n\n // App-sequence wrapper: prefix<< item item ... >> spanning the whole\n // range. Its own <<...>> is never peeled away (see doc above), but each\n // top-level item inside — separated by a comma, whitespace, or both — is\n // checked under the loose rule, matching how `<<...>>` itself always\n // treats its entries.\n if (tokens[start].type === 'APP_SEQUENCE') {\n const close = findMatchingClose(tokens, start, contentEnd);\n if (close !== null && close + 1 === contentEnd) {\n for (const [itemStart, itemEnd] of splitTopLevelItems(\n tokens,\n start + 1,\n close\n )) {\n if (isMultiWordTokenRange(tokens, itemStart, itemEnd, false)) {\n return true;\n }\n }\n return false;\n }\n }\n\n // `+`-concatenation chain spanning the whole range (`\"a\" + \"b\"`,\n // `h'00' + \"x\"`, `... + \"b\"`, ...) — CDN concatenation preserves each\n // part's own spelling rather than merging into one literal, so it's\n // never caught by the single-literal check below; it has to be\n // recognized as its own shape. A chain's *element type* is fixed by its\n // first part (draft-25 §5.1): a text-leading chain (`TSTR`/`RAWSTRING`/bare\n // `SQSTR` first — the same three types the single-literal switch below\n // checks by decoded word count rather than always-strict) decodes and\n // merges every part — including any prefixed byte-string-shaped parts,\n // which get UTF-8-decoded in per the same rule that lets `\"a\" + h'62'`\n // denote text `\"ab\"` — into one string, then checks *that* for word\n // count, matching what a single merged text literal would report. An\n // elision chain (`ELLIPSIS` first — `... + \"b\"`, an unknown prefix\n // concatenated with a known suffix) is handled the *same* way: the\n // merge-and-decode attempt fails immediately (an `ELLIPSIS` part always\n // decodes to `null`), so the combined word count always comes back\n // \"unknown\" — correctly indeterminate regardless of what visible parts\n // follow it, matching how a *continuation* `ELLIPSIS` already makes the\n // whole chain indeterminate (round 8). A byte-leading chain (first part\n // a prefixed `h'...'`/`b64'...'`) denotes a byte string; concatenation\n // never re-spells it as one bare `sqstr`, so rather than guess at the\n // combined bytes' printability it's treated like any other prefixed byte\n // literal — disqualifying only under the strict rule, same as a lone\n // `h'...'`/`b64'...'`.\n if (contentEnd - start > 1 && isPlusChainRange(tokens, start, contentEnd)) {\n if (\n tokens[start].type === 'TSTR' ||\n tokens[start].type === 'RAWSTRING' ||\n tokens[start].type === 'SQSTR' ||\n tokens[start].type === 'ELLIPSIS'\n ) {\n const merged = decodePlusChainText(tokens, start, contentEnd);\n return merged !== null && isMultiWordText(merged);\n }\n return strict;\n }\n\n // A single literal token (the encoding indicator, if any, was already\n // stripped above).\n if (contentEnd - start !== 1) return false;\n const token = tokens[start];\n switch (token.type) {\n case 'TSTR':\n case 'RAWSTRING':\n return isMultiWordText(token.value);\n case 'SQSTR': {\n const bytes = (token as SqstrToken)._sqstrBytes;\n return bytes !== undefined\n ? isMultiWordText(textDecoderForRenderedLiteral.decode(bytes))\n : false;\n }\n case 'BYTES_HEX':\n case 'BYTES_HEX_ELIDED':\n case 'BYTES_B64':\n case 'APP_STRING':\n return strict;\n default:\n return false;\n }\n}\n\n/**\n * Whether `tokens[start:end)` is exactly one `+`-concatenation chain (or a\n * single stringish literal) with nothing left over — reuses\n * `consumeOneItem`'s own chain-walking so the shape recognized here can\n * never drift from the shape it actually consumes as one item elsewhere.\n */\nfunction isPlusChainRange(\n tokens: Token[],\n start: number,\n end: number\n): boolean {\n return (\n CHAIN_ATOM_TYPES.has(tokens[start].type) &&\n consumeOneItem(tokens, start, end) === end\n );\n}\n\n/**\n * Decodes and concatenates every part of a `+`-concatenation chain spanning\n * `tokens[start:end)` into the single string it denotes, or `null` if any\n * part can't be decoded — `ELLIPSIS` (an elision-chain link with no content\n * of its own) and `BYTES_HEX_ELIDED` (missing data by construction) always\n * make the combined result unknowable; a malformed hex/base64 part\n * shouldn't happen in this library's own output but isn't assumed either.\n */\nfunction decodePlusChainText(\n tokens: Token[],\n start: number,\n end: number\n): string | null {\n let result = '';\n let i = start;\n for (;;) {\n const part = decodeStringishTokenText(tokens[i]);\n if (part === null) return null;\n result += part;\n i++;\n if (i < end && tokens[i].type === 'ENCODING_INDICATOR') i++;\n if (i < end && tokens[i].type === 'PLUS') {\n i++;\n continue;\n }\n break;\n }\n return i === end ? result : null;\n}\n\n/** Decodes a single stringish token to the text it denotes, or `null`. */\nfunction decodeStringishTokenText(token: Token): string | null {\n switch (token.type) {\n case 'TSTR':\n case 'RAWSTRING':\n return token.value;\n case 'SQSTR': {\n const bytes = (token as SqstrToken)._sqstrBytes;\n return bytes !== undefined\n ? textDecoderForRenderedLiteral.decode(bytes)\n : null;\n }\n case 'BYTES_HEX':\n try {\n return textDecoderForRenderedLiteral.decode(hexToBytes(token.value));\n } catch {\n return null;\n }\n case 'BYTES_B64':\n try {\n return textDecoderForRenderedLiteral.decode(base64ToBytes(token.value));\n } catch {\n return null;\n }\n case 'BYTES_HEX_ELIDED':\n // Ellipsis-elided hex is missing data by construction — the full\n // byte content (and thus decoded text) can't be recovered.\n return null;\n case 'ELLIPSIS':\n // An elision-chain link (`\"a\" + ...`) stands for a deliberately\n // omitted part — there's no content to decode at all, so the whole\n // chain's combined word count is unknowable, not just this part's.\n return null;\n default:\n return null;\n }\n}\n\n/**\n * Which comment syntax a byte-string literal's raw source recognizes —\n * `undefined` when it has none at all (its content is data, not a comment\n * host). Set once, at parse time, by whoever actually knows the literal's\n * real origin (the tokenizer for `h'...'`/`b64'...'`/bare sqstr, or the\n * parser comparing the resolved extension against the specific built-in\n * `b32`/`h32` objects by reference — never guessed later from the prefix\n * string, since a user extension can register under any prefix, including\n * one a built-in also uses; see `CborByteString.ednCommentSyntax`).\n * - `'full'`: `#`, `//`, `/* *\\/`, and `/ /` (§6.2.1/§6.3.3) — `h'...'`\n * and its backtick form, and the built-in `b32'...'`/`h32'...'`\n * extensions, which share hex's comment syntax (`utils/strip-comments.ts`).\n * - `'hash-only'`: only `#` line comments — standard base64 (`b64'...'`),\n * where `/` is valid data (e.g. `//8=` decodes to 0xFFFF), never a\n * comment marker (see Tokenizer._readByteContent, §6.2.2).\n */\nexport type ByteCommentSyntax = 'full' | 'hash-only';\n\n/**\n * Strip comments from inside a preserved byte-string literal's raw source,\n * keeping everything else — case, whitespace, `...` — untouched. Used when\n * `preserveByteString` is set but `preserveComments` is not: the preserved\n * spelling should still drop comments, the same as an unpreserved literal\n * re-derived from its decoded value would. `syntax` selects the comment\n * rules to apply (see `ByteCommentSyntax`); the caller is responsible for\n * knowing which one is correct — this function does not guess from `raw`.\n *\n * Only scans the quote-delimited content (not the prefix or a trailing\n * encoding-indicator suffix), and mirrors the tokenizer's own\n * comment-recognition closely enough for realistic input; a comment\n * containing a literal copy of the delimiter quote character is not\n * specially handled (the input is already known-valid, so at worst this\n * shifts where the content/comment boundary is drawn, never produces\n * unparseable output).\n */\nexport function stripByteLiteralComments(\n raw: string,\n syntax: ByteCommentSyntax\n): string {\n let open = 0;\n while (open < raw.length && raw[open] !== \"'\" && raw[open] !== '`') open++;\n if (open >= raw.length) return raw;\n const quote = raw[open];\n const close = raw.lastIndexOf(quote);\n if (close <= open) return raw;\n const content = raw.slice(open + 1, close);\n const stripped =\n syntax === 'hash-only'\n ? _stripHashOnlyComments(content)\n : _stripFullByteCommentSyntax(content);\n return raw.slice(0, open + 1) + stripped + raw.slice(close);\n}\n\n/** `#` line comments only — used by standard base64 (`b64'...'`). */\nfunction _stripHashOnlyComments(content: string): string {\n let out = '';\n let i = 0;\n while (i < content.length) {\n if (content[i] === '#') {\n while (i < content.length && content[i] !== '\\n') {\n i += content[i] === '\\\\' && i + 1 < content.length ? 2 : 1;\n }\n continue;\n }\n out += content[i];\n i++;\n }\n return out;\n}\n\n/**\n * `#`, `//`, `/* *\\/`, and `/ /` comments — used by `h'...'`/backtick raw hex\n * and extension-defined byte literals sharing that syntax (b32, h32, ...).\n */\nfunction _stripFullByteCommentSyntax(content: string): string {\n let out = '';\n let i = 0;\n while (i < content.length) {\n const ch = content[i];\n const next = content[i + 1];\n if (ch === '#' || (ch === '/' && next === '/')) {\n i += ch === '#' ? 1 : 2;\n while (i < content.length && content[i] !== '\\n') {\n i += content[i] === '\\\\' && i + 1 < content.length ? 2 : 1;\n }\n continue;\n }\n if (ch === '/' && next === '*') {\n const end = content.indexOf('*/', i + 2);\n i = end === -1 ? content.length : end + 2;\n continue;\n }\n if (ch === '/') {\n let j = i + 1;\n while (j < content.length && content[j] !== '/') {\n j += content[j] === '\\\\' && j + 1 < content.length ? 2 : 1;\n }\n i = j < content.length ? j + 1 : content.length;\n continue;\n }\n out += ch;\n i++;\n }\n return out;\n}\n\nconst _utf8Strict = new TextDecoder('utf-8', { fatal: true });\n\n/** Decode bytes as UTF-8; returns null if the bytes are not valid UTF-8. */\nfunction _tryDecodeUtf8(bytes: Uint8Array): string | null {\n try {\n return _utf8Strict.decode(bytes);\n } catch {\n return null;\n }\n}\n\n// ─── Text string escaping ─────────────────────────────────────────────────────\n\n/**\n * Core EDN string escaper.\n *\n * Produces a quoted literal delimited by `quote` (`\"` or `'`).\n * Iterates by Unicode code point so characters above U+FFFF are emitted as a\n * single character rather than two surrogate `\\uXXXX` escapes.\n *\n * Always escapes:\n * - the delimiter character itself\n * - `\\` (backslash)\n * - `\\n`, `\\r`, `\\t`\n * - U+0000–U+001F (C0 controls), U+007F (DEL)\n * - U+2028 / U+2029 (JS line terminators)\n * - U+200B–U+200D (zero-width characters), U+FEFF (BOM)\n */\n/**\n * Returns true if `s` contains any character that {@link _escapeQuoted}\n * would escape: the quote, backslash, C0 controls, DEL, U+2028/U+2029,\n * U+200B–U+200D, or U+FEFF. charCodeAt is safe here — every escaped\n * character is a single UTF-16 unit, and surrogate halves never match.\n */\nfunction _needsEscape(s: string, quoteCode: number): boolean {\n for (let i = 0; i < s.length; i++) {\n const cc = s.charCodeAt(i);\n if (cc === quoteCode || cc === 0x5c || cc < 0x20 || cc === 0x7f)\n return true;\n if (cc >= 0x2000) {\n if (\n cc === 0x2028 ||\n cc === 0x2029 ||\n (cc >= 0x200b && cc <= 0x200d) ||\n cc === 0xfeff\n )\n return true;\n }\n }\n return false;\n}\n\nfunction _escapeQuoted(s: string, quote: string): string {\n const quoteCP = quote.codePointAt(0)!;\n // Fast path: nothing to escape (the common case) — a single concatenation.\n if (!_needsEscape(s, quoteCP)) return quote + s + quote;\n let result = quote;\n for (const char of s) {\n const cp = char.codePointAt(0)!;\n switch (cp) {\n case quoteCP:\n result += `\\\\${quote}`;\n break;\n case 0x5c: // \\\n result += '\\\\\\\\';\n break;\n case 0x0a: // \\n\n result += '\\\\n';\n break;\n case 0x0d: // \\r\n result += '\\\\r';\n break;\n case 0x09: // \\t\n result += '\\\\t';\n break;\n default:\n if (\n cp < 0x20 ||\n cp === 0x7f ||\n cp === 0x2028 ||\n cp === 0x2029 ||\n cp === 0x200b ||\n cp === 0x200c ||\n cp === 0x200d ||\n cp === 0xfeff\n )\n result += `\\\\u${cp.toString(16).padStart(4, '0')}`;\n else result += char;\n }\n }\n return result + quote;\n}\n\n/** Produce a single-quoted EDN byte string literal `'...'` from a string value. */\nfunction _escapeSingleQuoted(s: string): string {\n return _escapeQuoted(s, \"'\");\n}\n\n/**\n * Produce a single-quoted EDN app-string content `'...'` from a string value.\n * Exported for use by app-extension `_toCDN` implementations.\n */\nexport function escapeAppString(s: string): string {\n return _escapeQuoted(s, \"'\");\n}\n\n/**\n * Produce an EDN double-quoted string literal `\"...\"` from a string value.\n */\nexport function escapeString(s: string): string {\n return _escapeQuoted(s, '\"');\n}\n\n// Locale pinned (rather than left to the host's default) so output is\n// deterministic across environments regardless of system locale — the word\n// dictionary for script-based languages (Japanese, Chinese, Thai, ...) is\n// selected by the text's own script either way, not by this locale tag.\nconst wordSegmenter = new Intl.Segmenter('en', { granularity: 'word' });\n\n/**\n * True when `value` contains two or more \"words\" per `Intl.Segmenter`'s\n * word-boundary rules (UAX #29): e.g. `\"Hello, World!\"` is two words (a\n * comma breaks them), `\"3.14\"` is one (a decimal point between digits\n * doesn't), and space-less scripts like Japanese/Chinese still split on\n * their own dictionary-based word boundaries. Used by `inlineLeafContainers`\n * to keep a multi-word string entry off the container's shared line even\n * when it would otherwise qualify as a leaf.\n */\nexport function isMultiWordText(value: string): boolean {\n let count = 0;\n for (const { isWordLike } of wordSegmenter.segment(value)) {\n if (!isWordLike) continue;\n count++;\n if (count >= 2) return true;\n }\n return false;\n}\n\n// ─── Float formatting ─────────────────────────────────────────────────────────\n\n/** Produce the numeric string for a float value (with decimal point if needed). */\nexport function floatValueToString(value: number): string {\n if (isNaN(value)) return 'NaN';\n if (!isFinite(value)) return value > 0 ? 'Infinity' : '-Infinity';\n if (Object.is(value, -0)) return '-0.0';\n const s = value.toString();\n // Ensure a decimal point is present to distinguish from CBOR integer types\n return s.includes('.') || s.includes('e') ? s : s + '.0';\n}\n\n/**\n * EDN encoding-indicator suffix for a float precision.\n * Returns '' when the auto-selected precision matches (no suffix needed) in auto mode.\n */\nexport function floatSuffix(\n _value: number,\n precision: 'half' | 'single' | 'double' | undefined,\n autoSelected: 'half' | 'single' | 'double',\n mode?: 'always' | 'auto' | 'never'\n): string {\n if (mode === 'never') return '';\n const actual = precision ?? autoSelected;\n if (mode === 'always')\n return actual === 'half' ? '_1' : actual === 'single' ? '_2' : '_3';\n // 'auto' (default)\n if (precision === undefined || precision === autoSelected) return '';\n return precision === 'half' ? '_1' : precision === 'single' ? '_2' : '_3';\n}\n\n/** Compute the canonical (minimum) CBOR encoding width for a non-negative integer argument. */\nexport function canonicalEncodingWidth(n: bigint): EncodingWidth {\n if (n <= 23n) return 'i';\n if (n <= 0xffn) return 0;\n if (n <= 0xffffn) return 1;\n if (n <= 0xffff_ffffn) return 2;\n return 3;\n}\n\n/**\n * Resolve the encoding-indicator suffix string (`''` or `'_N'`) based on\n * `options.encodingIndicators` and the item's recorded encoding width.\n *\n * @param options - toCDN options (may be undefined)\n * @param encodingWidth - width stored on the item (undefined = canonical)\n * @param getCanonical - lazily compute the canonical width (only called in 'always' mode)\n */\nexport function resolveEiSuffix(\n options: ToCDNOptions | undefined,\n encodingWidth: EncodingWidth | undefined,\n getCanonical: () => EncodingWidth\n): string {\n const mode = options?.encodingIndicators ?? 'auto';\n if (mode === 'never') return '';\n if (mode === 'always') return `_${encodingWidth ?? getCanonical()}`;\n return encodingWidth !== undefined ? `_${encodingWidth}` : '';\n}\n\n// ─── Comment handling for a preserved app-sequence/raw-tag source ────────────\n//\n// Different default than `shouldEmitComments`/`resolveCommentStyle` above:\n// leaving both `preserveComments` and `comments` unset here means \"don't\n// touch this spelling's comments at all\" (they stay exactly as originally\n// written, as part of the preserved text), not \"strip them\" — an *explicit*\n// request is required to edit them one way or the other.\n\n/** Whether the caller said anything at all about comments (either field set). */\nfunction hasExplicitCommentRequest(\n options: CommentOptions | undefined\n): boolean {\n return (\n options?.preserveComments !== undefined || options?.comments !== undefined\n );\n}\n\n/**\n * Whether an explicit request asks to strip comments from a preserved\n * source: not verbatim (`preserveComments !== true`, which always wins —\n * same precedence as `shouldEmitComments`/`resolveCommentStyle` above) and\n * no real style was requested via `comments`/the deprecated string\n * shorthand either. Safe to call unconditionally — returns `false` (leave\n * as-is) when nothing was requested at all, same as when `preserveComments`\n * is `true`.\n */\nfunction wantsCommentsStripped(options: CommentOptions | undefined): boolean {\n if (!hasExplicitCommentRequest(options)) return false;\n if (options?.preserveComments === true) return false;\n return requestedCommentStyle(options) === undefined;\n}\n\n/**\n * The normalization style an explicit request asks for, or `undefined` for\n * verbatim (`preserveComments === true`, which always wins) / strip / no\n * explicit style (including when nothing was requested at all).\n */\nfunction requestedCommentStyle(\n options: CommentOptions | undefined\n): 'c-style' | 'cdn-style' | undefined {\n if (options?.preserveComments === true) return undefined;\n if (typeof options?.preserveComments === 'string')\n return options.preserveComments;\n const style = options?.comments;\n return style === 'strip' ? undefined : style;\n}\n\n/** How a node should render under `preserveAppPrefix`. */\nexport type AppSeqRenderDecision =\n 'verbatim' | 'adjusted' | 'source' | 'structural' | 'normal';\n\n/**\n * Decide how an extension result node — from a `prefix'...'` /\n * `` prefix`...` `` / `prefix<<...>>` source, or (for a tag-wrapper node\n * that also has a generic `CborTag` fallback to delegate to) a raw tag\n * literal `N(...)` — should render under `ToCDNOptions.preserveAppPrefix`.\n *\n * A raw-tag source is recognised by `ednSource !== undefined`: the parser\n * only ever sets a tag-wrapper's `ednSource` (the tag *number's* digit\n * spelling) when it was reached via `N(...)`, never via one of the\n * app-string/-sequence forms. Leaf (non-tag-wrapper) nodes have no raw-tag\n * form at all — always pass `undefined` for `ednSource` there.\n *\n * Returns:\n * - `'verbatim'`: re-emit `appSeqSource` as-is. Only reachable for a\n * raw-tag source: its encoding-indicator suffixes are nested at two\n * independent positions (tag number and inner content), so this is only\n * safe in `'auto'` mode with no relevant sibling option overridden.\n * - `'source'`: keep a raw-tag source structurally verbatim, applying\n * comment and encoding-indicator changes by their captured source spans.\n * This avoids changing unrelated literal spelling or layout.\n * - `'adjusted'`: for an app-string/-sequence source, strip whatever\n * *outer* indicator suffix is already at the end of `appSeqSource` (or,\n * under `'never'`, also an *inner* one immediately before `<<...>>`'s\n * closing `>>` — the app-sequence's sole item's own indicator) and let\n * the caller append one recomputed via `resolveEiSuffix`/`floatSuffix`\n * for the current mode via `adjustAppSeqIndicator` — correct in every\n * mode, without losing the source's notation family. (An inner indicator\n * can only be *stripped*, not *recomputed*: the item's own encoding\n * width isn't tracked once resolved to a plain date/address string, so\n * `'always'` cannot add a missing one — it is left absent.)\n * - `'structural'`: keep the raw-tag notation *family* (as opposed to\n * upgrading to `prefix'...'`) but re-derive it structurally — via the\n * node's own `CborTag` rendering — instead of using `appSeqSource`\n * verbatim. Needed whenever verbatim text would ignore a sibling option\n * that must apply per nested node: an explicit `preserveNumberFormat` /\n * `preserveByteString` / `preserveTextString` / `preserveRawString` /\n * `preserveConcatenation` override.\n * Verbatim raw-tag text inherently contains the nested literal spelling.\n * - `'normal'`: fall through to the class's own notation regeneration\n * (`prefix'...'`), unaffected by `preserveAppPrefix`. For `<<...>>`,\n * this is also used when replaying its sole inner item would defeat an\n * explicitly disabled, relevant literal-preservation option.\n *\n * `editsComplete` (from `CborItem.appSeqEncodingEditsComplete`, raw-tag\n * sources only) is `false` when the tag's content contains a node type\n * `collectContentEncodingEdits` doesn't cover (e.g. a `CborMap` nested in an\n * `ip` array's raw-tag content). `'source'` relies on those edits to apply\n * `encodingIndicators: 'always'`/`'never'`, so incomplete coverage would\n * silently leave the uncovered node's own indicator unchanged; `'structural'`\n * is used instead, since it re-derives every nested indicator recursively.\n */\nexport function decideTaggedAppSeqRendering(\n options: ToCDNOptions | undefined,\n appSeqSource: string | undefined,\n ednSource: string | undefined,\n sourceFeatures?: AppSeqSourceFeatures,\n editsComplete?: boolean\n): AppSeqRenderDecision {\n if (!options?.preserveAppPrefix || appSeqSource === undefined)\n return 'normal';\n if (resolveIndent(options) === null && /[\\r\\n]/.test(appSeqSource))\n return 'normal';\n const isRawTagSource = ednSource !== undefined;\n // App-string/-sequence sources carry relative comment spans, so their\n // spelling can stay intact while adjustAppSeqIndicator converts or removes\n // comments. Raw tags instead have a structural CborTag fallback that\n // applies comment formatting together with all other nested-node options.\n if (!isRawTagSource) {\n const innerSourceOverridden =\n (sourceFeatures?.byteString && options?.preserveByteString === false) ||\n (sourceFeatures?.textString && options?.preserveTextString === false) ||\n (sourceFeatures?.rawString && options?.preserveRawString === false) ||\n (sourceFeatures?.concatenation &&\n options?.preserveConcatenation === false);\n return innerSourceOverridden ? 'normal' : 'adjusted';\n }\n const commentsNeedEditing =\n wantsCommentsStripped(options) ||\n requestedCommentStyle(options) !== undefined ||\n (options?.preserveComments === true && resolveIndent(options) === null);\n const mode = options?.encodingIndicators ?? 'auto';\n const siblingOverridden =\n options?.preserveNumberFormat === false ||\n (sourceFeatures?.byteString && options?.preserveByteString === false) ||\n (sourceFeatures?.textString && options?.preserveTextString === false) ||\n (sourceFeatures?.rawString && options?.preserveRawString === false) ||\n (sourceFeatures?.concatenation && options?.preserveConcatenation === false);\n if (siblingOverridden) return 'structural';\n if (mode !== 'auto' && editsComplete === false) return 'structural';\n return mode !== 'auto' || commentsNeedEditing ? 'source' : 'verbatim';\n}\n\n/**\n * Replacement text for a comment being stripped entirely (not converted):\n * empty, unless removing it would fuse two otherwise-separate tokens\n * together — e.g. \"24/x/h'...'\" would become \"24h'...'\", which the parser\n * rejects as two array items with no separator between them. A single\n * space keeps the tokens apart in that case, the same concern\n * `sourceSuffixEdit`'s own separator handles for an inserted indicator.\n *\n * The two neighbouring characters are checked generically (any non-space,\n * non-comma character needs a separator), not just \"word\" characters —\n * `24/x/'abc'` needs the same space as `24/x/h'...'` even though `'` isn't\n * itself part of a token that could lexically fuse with `24`: the parser's\n * \"array items must be separated\" check is purely positional (are the two\n * tokens flush against each other), not about what those tokens are. A\n * comma on either side never needs a separator of its own, since it's\n * already a valid separator by itself.\n *\n * `text`/`start`/`end` share one coordinate space (the source being edited\n * and the comment's offsets within it).\n */\nfunction stripCommentReplacement(\n text: string,\n start: number,\n end: number\n): string {\n const before = start > 0 ? text[start - 1]! : '';\n const after = end < text.length ? text[end]! : '';\n const needsSeparator = (ch: string) => ch !== '' && !/[\\s,]/.test(ch);\n return needsSeparator(before) && needsSeparator(after) ? ' ' : '';\n}\n\nfunction rewriteAppSeqComments(\n appSeqSource: string,\n options: ToCDNOptions | undefined,\n comments: readonly CborComment[] | undefined,\n removedAt?: number\n): string {\n if (!hasExplicitCommentRequest(options) || !comments?.length)\n return appSeqSource;\n const stripComments =\n wantsCommentsStripped(options) || resolveIndent(options) === null;\n const style = requestedCommentStyle(options);\n let text = appSeqSource;\n // Apply replacements from right to left so an earlier comment's offsets\n // are unaffected by a later replacement. Account for characters already\n // removed before a following comment.\n const ordered = [...comments].sort((a, b) => b.start - a.start);\n for (const comment of ordered) {\n const shift =\n removedAt !== undefined && comment.start >= removedAt ? -2 : 0;\n const start = comment.start + shift;\n const end = comment.end + shift;\n const replacement = stripComments\n ? stripCommentReplacement(text, start, end)\n : convertCommentText(comment, style);\n text = text.slice(0, start) + replacement + text.slice(end);\n }\n return text;\n}\n\n/** Apply comment/EI options directly to a preserved raw-tag source. */\nexport function adjustRawAppSeqSource(\n appSeqSource: string,\n options: ToCDNOptions | undefined,\n comments: readonly CborComment[] | undefined,\n encodingEdits: readonly AppSeqEncodingEdit[] | undefined\n): string {\n const replacements: {\n start: number;\n end: number;\n replacement: string;\n }[] = [];\n if (hasExplicitCommentRequest(options) && comments?.length) {\n const stripComments =\n wantsCommentsStripped(options) || resolveIndent(options) === null;\n const style = requestedCommentStyle(options);\n for (const comment of comments)\n replacements.push({\n start: comment.start,\n end: comment.end,\n replacement: stripComments\n ? stripCommentReplacement(appSeqSource, comment.start, comment.end)\n : convertCommentText(comment, style),\n });\n }\n const mode = options?.encodingIndicators ?? 'auto';\n if (mode !== 'auto' && encodingEdits)\n for (const edit of encodingEdits)\n replacements.push({\n start: edit.start,\n end: edit.end,\n replacement: mode === 'always' ? edit.always : edit.never,\n });\n\n // Right-to-left edits keep every stored source offset valid. At the same\n // offset, replace a non-empty span before performing a zero-width insert.\n replacements.sort((a, b) => b.start - a.start || b.end - a.end);\n let text = appSeqSource;\n for (const edit of replacements)\n text = text.slice(0, edit.start) + edit.replacement + text.slice(edit.end);\n return text;\n}\n\n/**\n * Adjust an `'adjusted'` app-string/-sequence source: apply requested comment\n * conversion/removal by captured source span, strip the existing\n * encoding-indicator suffix(es), then append `newSuffix` (the outer/wrapper\n * indicator recomputed for the current mode) — see\n * `decideTaggedAppSeqRendering`.\n *\n * Under `encodingIndicators: 'never'`, an inner (item-level) indicator is\n * also stripped, using\n * `innerItemEnd` (see `CborItem.appSeqInnerEnd`) to find it by its actual\n * parsed position rather than by pattern-matching text near the closing\n * `>>` — whitespace, a trailing comma, and/or a comment can all separate\n * the two, in any combination, so a position-based cut is the only fully\n * reliable way to locate it.\n */\nexport function adjustAppSeqIndicator(\n appSeqSource: string,\n newSuffix: string,\n options: ToCDNOptions | undefined,\n innerItemEnd: number | undefined,\n comments: readonly CborComment[] | undefined\n): string {\n let text = appSeqSource;\n let removedInnerAt: number | undefined;\n if (\n (options?.encodingIndicators ?? 'auto') === 'never' &&\n innerItemEnd !== undefined\n ) {\n const beforeInner = text.slice(0, innerItemEnd);\n if (/_[0-3i]$/.test(beforeInner)) {\n removedInnerAt = innerItemEnd - 2;\n text = beforeInner.slice(0, -2) + text.slice(innerItemEnd);\n }\n }\n\n text = rewriteAppSeqComments(text, options, comments, removedInnerAt);\n return text.replace(/_[0-3i]$/, '') + newSuffix;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"serialize-utils-h-CVB9rg.js","names":[],"sources":["../src/cdn/errors.ts","../src/utils/hex.ts","../src/utils/base64.ts","../src/cdn/tokenizer.ts","../src/cdn/serialize-utils.ts"],"sourcesContent":["/**\n * Structured syntax error thrown by the CDN tokenizer and parser.\n *\n * Carries the source position of the failure so tooling (editors, linters,\n * playgrounds) can point at the offending range without parsing the message.\n * Position fields are present whenever the failure site knows them.\n */\nexport class CdnSyntaxError extends SyntaxError {\n /** Character offset of the start of the offending range in the source input. */\n readonly offset?: number;\n /** 1-based line number of the offending range. */\n readonly line?: number;\n /** 1-based column number of the offending range. */\n readonly column?: number;\n /** Character offset just past the end of the offending range. */\n readonly endOffset?: number;\n\n constructor(\n message: string,\n position?: {\n offset?: number;\n line?: number;\n column?: number;\n endOffset?: number;\n }\n ) {\n const loc =\n position?.line !== undefined\n ? ` at line ${position.line}, column ${position.column}`\n : '';\n super(`EDN parse error${loc}: ${message}`);\n this.name = 'CdnSyntaxError';\n this.offset = position?.offset;\n this.line = position?.line;\n this.column = position?.column;\n this.endOffset = position?.endOffset;\n }\n}\n","/**\n * Hex codec helpers shared by the CDN serializer, parser, and extensions.\n *\n * Native `Uint8Array.prototype.toHex` is the fastest option at every size, so\n * it is used whenever available. Native `Uint8Array.fromHex` carries a fixed\n * ~300–400 ns argument-validation overhead per call (measured on Node 25/26),\n * which makes a lookup-table loop 5–6× faster for small payloads such as\n * UUIDs; native only wins from ~128 bytes up. `hexToBytes` therefore switches\n * implementations on input length.\n */\n\nconst HEX_DIGITS = Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n// Maps hex char codes (both cases) to their value; -1 marks invalid chars so\n// the decode loop can detect them with a single sign check per byte.\nconst HEX_VALUES = new Int8Array(128).fill(-1);\nfor (let i = 0; i < 16; i++) {\n HEX_VALUES['0123456789abcdef'.charCodeAt(i)] = i;\n HEX_VALUES['0123456789ABCDEF'.charCodeAt(i)] = i;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeToHex =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (Uint8Array.prototype as any).toHex === 'function';\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeFromHex =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (Uint8Array as any).fromHex === 'function';\n\n// Below this many hex digits the LUT loop beats native fromHex.\nconst NATIVE_FROM_HEX_MIN_DIGITS = 256;\n\n/** Encode bytes as lowercase hex. */\nexport function bytesToHex(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToHex) return (bytes as any).toHex();\n let out = '';\n for (let i = 0; i < bytes.length; i++) out += HEX_DIGITS[bytes[i]!];\n return out;\n}\n\n// Uppercase table for the annotated hex-dump format (RFC 8949 §3 style).\nconst HEX_DIGITS_UPPER = Array.from({ length: 256 }, (_, i) =>\n i.toString(16).toUpperCase().padStart(2, '0')\n);\n\n/** Encode one byte as two uppercase hex digits (e.g. 10 → \"0A\"). */\nexport function byteToHexUpper(b: number): string {\n return HEX_DIGITS_UPPER[b]!;\n}\n\n/** Encode bytes as space-separated uppercase hex (e.g. \"0A FF\"), the\n * per-line format used by `toHexDump()`. */\nexport function bytesToSpacedHexUpper(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n if (i > 0) out += ' ';\n out += HEX_DIGITS_UPPER[bytes[i]!];\n }\n return out;\n}\n\n/**\n * Decode a hex string to bytes.\n *\n * Throws SyntaxError on odd-length input or non-hex characters (the native\n * fromHex path throws its own SyntaxError with a different message).\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0)\n throw new SyntaxError(`hex string has odd length: ${hex.length}`);\n if (_hasNativeFromHex && hex.length >= NATIVE_FROM_HEX_MIN_DIGITS)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (Uint8Array as any).fromHex(hex) as Uint8Array;\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0, j = 0; i < hex.length; i += 2, j++) {\n const c1 = hex.charCodeAt(i);\n const c2 = hex.charCodeAt(i + 1);\n const hi = c1 < 128 ? HEX_VALUES[c1]! : -1;\n const lo = c2 < 128 ? HEX_VALUES[c2]! : -1;\n if ((hi | lo) < 0) {\n const bad = hi < 0 ? hex[i]! : hex[i + 1]!;\n throw new SyntaxError(\n `invalid character ${JSON.stringify(bad)} in hex string`\n );\n }\n out[j] = (hi << 4) | lo;\n }\n return out;\n}\n","/**\n * Decode base64 text (classic or URL-safe alphabet, padding optional) into\n * bytes, with strict RFC 4648 validation.\n *\n * Used by the CDN parser (b64'…' literals, §6.2.2) and the CDDL tokenizer\n * (b64'…' byte strings, RFC 8610 §3.1).\n *\n * Recoverable deviations (padding-count mismatches, non-zero trailing bits)\n * are reported through `onRecoverableError` when provided; otherwise they\n * throw a plain SyntaxError, which callers wrap with position information.\n */\nexport function base64ToBytes(\n b64: string,\n onRecoverableError?: (msg: string) => void\n): Uint8Array {\n // Separate data characters from trailing '=' padding.\n const eqIdx = b64.indexOf('=');\n const data = eqIdx >= 0 ? b64.slice(0, eqIdx) : b64;\n const pad = eqIdx >= 0 ? b64.slice(eqIdx) : '';\n\n // draft-27 b64dig = ALPHA / DIGIT / \"-\" / \"_\" / \"+\" / \"/\"\n // Classic (+/) and URL-safe (-_) position-62/63 chars are both valid in the\n // same literal. Reject anything outside this set as a hard error.\n if (/[^A-Za-z0-9+/\\-_]/.test(data)) {\n const bad = [...data].find((c) => !/[A-Za-z0-9+/\\-_]/.test(c)) ?? '';\n throw new SyntaxError(\n `invalid character ${JSON.stringify(bad)} in base64 data`\n );\n }\n if (pad && !/^=+$/.test(pad))\n throw new SyntaxError(`invalid character after base64 '=' padding`);\n\n const rem = data.length % 4;\n\n // rem === 1 cannot arise from any valid byte sequence (always invalid).\n if (rem === 1)\n throw new SyntaxError(\n `invalid base64 length: ${data.length} data characters (length mod 4 = 1 is never valid)`\n );\n\n // Expected number of '=' characters for this data length.\n const expectedPad = rem === 0 ? 0 : 4 - rem;\n\n if (pad.length > expectedPad) {\n const msg = `base64 has ${pad.length} '=' character${pad.length > 1 ? 's' : ''} but the data length (${data.length}) requires at most ${expectedPad}`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n\n // Partial padding: some '=' present but fewer than the full required amount.\n // draft-27 accommodates NO padding; any '=' present must be the full set.\n if (pad.length > 0 && pad.length < expectedPad) {\n const msg = `base64 has ${pad.length} '=' character${pad.length > 1 ? 's' : ''} but needs exactly ${expectedPad} — use full padding or no padding at all`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n // Zero '=': draft-27 allows omitting padding entirely — always accepted.\n\n // Non-zero trailing bits in the last data character (RFC 4648 §3.5).\n // Normalize URL-safe chars first so the lookup is against the classic table.\n // rem=2 (1-byte quantum): bottom 4 bits of the final char must be zero.\n // rem=3 (2-byte quantum): bottom 2 bits of the final char must be zero.\n if (rem !== 0 && data.length > 0) {\n const ALPHA =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n const lastChar = data[data.length - 1]!.replace('-', '+').replace('_', '/');\n const lastVal = ALPHA.indexOf(lastChar);\n if (lastVal >= 0) {\n const mask = rem === 2 ? 0x0f : 0x03;\n if ((lastVal & mask) !== 0) {\n const msg = `base64 has non-zero trailing bits in the final quantum (RFC 4648 §3.5)`;\n if (onRecoverableError) onRecoverableError(msg);\n else throw new SyntaxError(msg);\n }\n }\n }\n\n // Normalize URL-safe chars to classic and add any missing padding so the\n // underlying decoder accepts the input regardless of what was originally used.\n const normalized =\n data.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(expectedPad);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (Uint8Array as any).fromBase64 === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (Uint8Array as any).fromBase64(normalized, {\n alphabet: 'base64',\n lastChunkHandling: 'loose',\n });\n }\n const binary = atob(normalized);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n","/**\n * CDN lexer (internal).\n *\n * Used by parser.ts for parsing and by CborTextString serialization to collect\n * source offsets after parseCDN() has already validated embedded CDN.\n */\n\nimport { CdnSyntaxError } from './errors';\nimport { bytesToHex } from '../utils/hex';\n\nexport type TokenType =\n | 'INTEGER'\n | 'FLOAT'\n | 'TSTR'\n | 'SQSTR'\n | 'RAWSTRING'\n | 'BYTES_HEX'\n | 'BYTES_HEX_ELIDED'\n | 'BYTES_B64'\n | 'APP_STRING'\n | 'APP_SEQUENCE'\n | 'EMPTY_INDEF_BYTES'\n | 'EMPTY_INDEF_TEXT'\n | 'TRUE'\n | 'FALSE'\n | 'NULL'\n | 'UNDEFINED'\n | 'SIMPLE'\n | 'LBRACKET'\n | 'RBRACKET'\n | 'LBRACE'\n | 'RBRACE'\n | 'LPAREN'\n | 'RPAREN'\n | 'COLON'\n | 'COMMA'\n | 'PLUS'\n | 'UNDERSCORE'\n | 'ENCODING_INDICATOR'\n | 'LT_LT'\n | 'GT_GT'\n | 'ELLIPSIS'\n | 'EOF'\n /** Synthetic token emitted by tokenizeLenient() for the unscannable tail. */\n | 'ERROR';\n\nexport interface Token {\n type: TokenType;\n /** Processed value: decoded string content, raw number text, raw byte content, etc. */\n value: string;\n /** Original source text for this token. */\n raw: string;\n line: number;\n col: number;\n /** Character offset of the first character of this token in the source input. */\n offset: number;\n /** Character offset just past the last character of this token in the source input. */\n endOffset: number;\n /** Only set when type === 'APP_STRING': the extension prefix (e.g. 'dt', 'DT'). */\n appPrefix?: string;\n}\n\n/**\n * @internal\n * SQSTR tokens carry the UTF-8 payload the tokenizer already encoded, so the\n * parser does not decode the hex `value` back into the same bytes. The\n * property is non-enumerable and deliberately absent from the public `Token`\n * type: the tokenize() API shape (keys, JSON.stringify, spread) is unchanged.\n */\nexport interface SqstrToken extends Token {\n readonly _sqstrBytes?: Uint8Array;\n}\n\nexport interface TokenizerOptions {\n /** Character offset at which tokenization starts. */\n offset?: number;\n /** When true, RS (U+001E, RFC 7464 record separator) is treated as whitespace. */\n skipRS?: boolean;\n}\n\nexport interface EdnComment {\n kind: 'line' | 'block';\n marker: '#' | '//' | '/*' | '/';\n text: string;\n start: number;\n end: number;\n line: number;\n col: number;\n}\n\n/** Inverse of positionAt; only used on the cold error path. */\nfunction offsetAt(input: string, line: number, col: number): number {\n let l = 1;\n let c = 1;\n for (let i = 0; i < input.length; i++) {\n if (l === line && c === col) return i;\n if (input[i] === '\\n') {\n l++;\n c = 1;\n } else {\n c++;\n }\n }\n return input.length;\n}\n\nfunction positionAt(\n input: string,\n offset: number\n): { line: number; col: number } {\n let line = 1;\n let col = 1;\n for (let i = 0; i < offset; i++) {\n if (input[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n return { line, col };\n}\n\n// ─── Scanning helpers (hot path) ─────────────────────────────────────────────\n//\n// Token content is consumed in bulk runs: a charCodeAt loop locates the next\n// character that needs individual handling, and everything before it is\n// appended with a single slice instead of per-character concatenation.\n\nfunction isHexDigitCode(c: number): boolean {\n return (\n (c >= 0x30 && c <= 0x39) || // 0-9\n (c >= 0x61 && c <= 0x66) || // a-f\n (c >= 0x41 && c <= 0x46) // A-F\n );\n}\n\n/** Shared encoder — constructing TextEncoder per token is needlessly slow. */\nconst textEncoder = new TextEncoder();\n\nexport class Tokenizer {\n private pos: number;\n private line: number;\n private col: number;\n private _peeked: Token | null = null;\n private _lastConsumedEndOffset: number;\n private readonly skipRS: boolean;\n /** Comments encountered while scanning, appended in source order. */\n readonly comments: EdnComment[] = [];\n /**\n * When set, non-standard-but-JS-valid escape sequences are accepted instead\n * of throwing. The callback receives a message and the position of the `\\`\n * (offset, line, column) plus the offset just past the escape sequence, so\n * the parser can forward it as a range-carrying ParseWarning.\n */\n onEscapeWarning?: (\n msg: string,\n offset: number,\n line: number,\n col: number,\n endOffset: number\n ) => void;\n constructor(\n private readonly input: string,\n options?: TokenizerOptions\n ) {\n const offset = options?.offset ?? 0;\n this.skipRS = options?.skipRS ?? false;\n if (!Number.isInteger(offset) || offset < 0 || offset > input.length)\n throw new RangeError(\n `EDN parse offset must be an integer between 0 and ${input.length}`\n );\n const position = positionAt(input, offset);\n this.pos = offset;\n this.line = position.line;\n this.col = position.col;\n this._lastConsumedEndOffset = offset;\n }\n\n peek(): Token {\n if (this._peeked === null) this._peeked = this._readNext();\n return this._peeked;\n }\n\n consume(): Token {\n const tok = this._peeked !== null ? this._peeked : this._readNext();\n this._peeked = null;\n this._lastConsumedEndOffset = tok.endOffset;\n return tok;\n }\n\n /** Character offset just past the last character of the most recently consumed token. */\n get lastEndOffset(): number {\n return this._lastConsumedEndOffset;\n }\n\n /** The full source text supplied to this tokenizer. */\n get source(): string {\n return this.input;\n }\n\n // ── Internal helpers ─────────────────────────────────────────────────────\n\n private _ch(): string {\n return this.input[this.pos] ?? '';\n }\n private _eof(): boolean {\n return this.pos >= this.input.length;\n }\n\n private _advance(): string {\n const c = this.input[this.pos++] ?? '';\n if (c === '\\n') {\n this.line++;\n this.col = 1;\n } else {\n this.col++;\n }\n return c;\n }\n\n private _fail(msg: string, line = this.line, col = this.col): never {\n const offset =\n line === this.line && col === this.col\n ? this.pos\n : offsetAt(this.input, line, col);\n // The scan position sits at the end of the offending construct when the\n // failure was reported against an earlier start position; cover at least\n // one character so tooling can underline a range (zero-width only at EOF).\n const endOffset = Math.min(\n Math.max(this.pos, offset + 1),\n this.input.length\n );\n throw new CdnSyntaxError(msg, { offset, line, column: col, endOffset });\n }\n\n private _skipWS(): void {\n for (;;) {\n // Skip whitespace characters. Common ASCII whitespace is matched with\n // direct comparisons; printable ASCII can never match /\\s/, so the\n // regex only runs for the rare remaining characters (e.g. \\f, NBSP).\n for (;;) {\n const ws = this.input[this.pos];\n if (ws === undefined) return;\n if (\n ws === ' ' ||\n ws === '\\n' ||\n ws === '\\t' ||\n ws === '\\r' ||\n (this.skipRS && ws === '\\x1e')\n ) {\n this._advance();\n continue;\n }\n if (ws > ' ' && ws <= '~') break; // printable ASCII — not whitespace\n if (/\\s/.test(ws)) {\n this._advance();\n continue;\n }\n break;\n }\n\n const c = this._ch();\n\n // CDN line comment: # to end of line\n if (c === '#') {\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n while (!this._eof() && this._ch() !== '\\n') this._advance();\n this.comments.push({\n kind: 'line',\n marker: '#',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n\n // Comments starting with /\n if (c === '/') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === '/') {\n // EDN end-of-line comment: // to end of line (§2.1)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() !== '\\n') this._advance();\n this.comments.push({\n kind: 'line',\n marker: '//',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n if (next === '*') {\n // EDN block comment: /* ... */ (§2.1)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance();\n this._advance();\n this._skipBlockCommentStar();\n this.comments.push({\n kind: 'block',\n marker: '/*',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n // EDN slash-delimited comment: / ... / (§2.1, first char must not be * or /)\n const start = this.pos;\n const line = this.line;\n const col = this.col;\n this._advance(); // consume opening /\n this._skipBlockCommentSlash();\n this.comments.push({\n kind: 'block',\n marker: '/',\n text: this.input.slice(start, this.pos),\n start,\n end: this.pos,\n line,\n col,\n });\n continue;\n }\n\n return;\n }\n }\n\n /**\n * Skip a comment in a quoted byte string literal (h'', b64'').\n * Returns true if a comment was consumed, false if the current char is not a\n * comment start. `quote` is the closing delimiter character.\n *\n * Supports / ... /, /* *\\/, //, and # comment forms (§2.1).\n */\n private _skipByteStringComment(quote: string): boolean {\n const ch = this._ch();\n if (ch === '/') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === '/') {\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof() && this._ch() !== '\\n') this._advance();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n return true;\n }\n if (next === '*') {\n this._advance();\n this._advance();\n this._skipBlockCommentStar();\n return true;\n }\n this._advance();\n this._skipBlockCommentSlash();\n return true;\n }\n if (ch === '#') {\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance(); // consume '\\'\n if (this._eof() || this._ch() === '\\n') continue;\n const escaped = this._advance();\n if (escaped === 'u') this._validateHexCommentUnicodeEscape();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n return true;\n }\n return false;\n }\n\n /**\n * Validate a `\\uXXXX` or `\\u{N}` escape inside a hex-string comment.\n *\n * Called immediately after the `u` character has been consumed. Rejects\n * lone surrogates and invalid surrogate pairs; tolerates truncated/\n * non-hex sequences (comments are informational, but surrogates are\n * always illegal).\n */\n private _validateHexCommentUnicodeEscape(): void {\n const line = this.line,\n col = this.col;\n\n // Extended form \\u{XXXXXX}\n if (!this._eof() && this._ch() === '{') {\n this._advance(); // {\n let hex = '';\n while (!this._eof() && this._ch() !== '}' && this._ch() !== '\\n')\n hex += this._advance();\n if (!this._eof() && this._ch() === '}') this._advance(); // }\n const cp = parseInt(hex || '0', 16);\n if (cp >= 0xd800 && cp <= 0xdfff)\n this._fail(\n `\\\\u{${hex}} is a surrogate code point, not allowed in hex string comments`,\n line,\n col\n );\n return;\n }\n\n // Standard \\uXXXX — read up to 4 hex digits\n let hex = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof() || this._ch() === '\\n') break;\n if (!/[0-9a-fA-F]/.test(this._ch())) break;\n hex += this._advance();\n }\n if (hex.length < 4) return; // truncated / non-hex — not our problem\n\n const cp = parseInt(hex, 16);\n\n // High surrogate: must be followed immediately by a low-surrogate escape\n if (cp >= 0xd800 && cp <= 0xdbff) {\n if (this._ch() !== '\\\\' || (this.input[this.pos + 1] ?? '') !== 'u')\n this._fail(\n `lone high surrogate \\\\u${hex} in hex string comment`,\n line,\n col\n );\n this._advance(); // \\\n this._advance(); // u\n let hex2 = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof() || this._ch() === '\\n') break;\n if (!/[0-9a-fA-F]/.test(this._ch())) break;\n hex2 += this._advance();\n }\n const cp2 = parseInt(hex2 || '0', 16);\n if (cp2 < 0xdc00 || cp2 > 0xdfff)\n this._fail(\n `\\\\u${hex} (high surrogate) not followed by valid low surrogate in hex string comment`,\n line,\n col\n );\n return;\n }\n\n if (cp >= 0xdc00 && cp <= 0xdfff)\n this._fail(\n `lone low surrogate \\\\u${hex} in hex string comment`,\n line,\n col\n );\n }\n\n /**\n * Skip a comment in a raw byte string (h``, b64``).\n * Called with `i` pointing at the comment-start character.\n * Returns the index after the comment, or -1 if no comment was found.\n *\n * Supports / ... /, /* *\\/, //, and # comment forms (§2.1).\n * `context` is used in unterminated-comment error messages.\n */\n private _skipRawComment(\n raw: string,\n i: number,\n context: string,\n tokenLine: number,\n tokenCol: number\n ): number {\n const ch = raw[i];\n if (ch === '/') {\n i++;\n if (raw[i] === '/') {\n i++;\n while (i < raw.length && raw[i] !== '\\n') i++;\n return i;\n }\n if (raw[i] === '*') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '*' && raw[i + 1] === '/') return i + 2;\n i++;\n }\n return i; // EOF inside comment — fall through; caller will report\n }\n // / … / comment\n while (i < raw.length && raw[i] !== '/') i++;\n if (i >= raw.length)\n this._fail(\n `unterminated block comment in ${context}`,\n tokenLine,\n tokenCol\n );\n return i + 1; // consume closing /\n }\n if (ch === '#') {\n while (i < raw.length && raw[i] !== '\\n') i++;\n return i;\n }\n return -1; // not a comment\n }\n\n /** Skip content until a closing `/` (CDN block comment). */\n private _skipBlockCommentSlash(): void {\n const line = this.line,\n col = this.col;\n while (!this._eof()) {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof()) this._advance();\n continue;\n }\n if (this._ch() === '/') break;\n this._advance();\n }\n if (this._eof()) this._fail('unterminated block comment', line, col);\n this._advance(); // consume closing /\n }\n\n /** Skip content until a closing `*\\/` (JSONC block comment). */\n private _skipBlockCommentStar(): void {\n const line = this.line,\n col = this.col;\n while (!this._eof()) {\n if (this._ch() === '*' && (this.input[this.pos + 1] ?? '') === '/') {\n this._advance();\n this._advance();\n return;\n }\n this._advance();\n }\n this._fail('unterminated block comment', line, col);\n }\n\n /**\n * Read content between `quote` delimiters, processing escape sequences.\n *\n * Strict spec compliance:\n * - Literal LF (U+000A) is allowed; all other C0 controls and U+007F are rejected.\n * - Literal CR (U+000D) is silently stripped (source-level CRLF normalisation).\n * - Only spec-defined escape sequences are accepted; `\\q` etc. throw SyntaxError.\n * - `\\/` is valid only in double-quoted strings (not in escapable-s, §6.1).\n * - `\\\\` (backslash) is valid in both single- and double-quoted strings.\n * - `\\uXXXX` for a high surrogate must be immediately followed by `\\uXXXX` for\n * the corresponding low surrogate; lone surrogates are rejected.\n * - `\\u{N}` … `\\u{10FFFF}` extended syntax is supported; surrogates are rejected.\n * - In single-quoted strings, `\\u` escapes to printable ASCII (U+0020–U+007E)\n * are forbidden (hexchar-s restriction, draft-ietf-cbor-edn-literals-27 §6.1).\n */\n private _readStringContent(quote: string): string {\n this._advance(); // opening quote\n const quoteCode = quote.charCodeAt(0);\n const inputLen = this.input.length;\n let out = '';\n while (!this._eof() && this._ch() !== quote) {\n // Fast path: bulk-consume a run of ordinary characters up to the next\n // delimiter, backslash, CR, or control character. LF is ordinary\n // content; it is counted here so line/col stay correct.\n let p = this.pos;\n let newlines = 0;\n let lastNewline = -1;\n while (p < inputLen) {\n const cc = this.input.charCodeAt(p);\n if (cc === quoteCode || cc === 0x5c /* \\ */ || cc === 0x7f /* DEL */)\n break;\n if (cc < 0x20) {\n if (cc !== 0x0a) break; // CR / other C0 controls → slow path\n newlines++;\n lastNewline = p;\n }\n p++;\n }\n if (p > this.pos) {\n out += this.input.slice(this.pos, p);\n if (newlines > 0) {\n this.line += newlines;\n this.col = p - lastNewline;\n } else {\n this.col += p - this.pos;\n }\n this.pos = p;\n continue;\n }\n\n const ch = this._ch();\n\n // Strip literal CR (cross-platform source normalisation — spec §1.3.5)\n if (ch === '\\r') {\n this._advance();\n continue;\n }\n\n // Reject unescaped C0 control characters (except LF) and DEL — spec §6.1 unescaped\n const cp = ch.codePointAt(0)!;\n if ((cp < 0x20 && cp !== 0x0a) || cp === 0x7f)\n this._fail(\n `unescaped control character U+${cp.toString(16).padStart(4, '0')} is not allowed in string literals`\n );\n\n if (ch === '\\\\') {\n // Capture position of the backslash itself before consuming it.\n const eOffset = this.pos,\n eLine = this.line,\n eCol = this.col;\n this._advance();\n const e = this._advance();\n switch (e) {\n case 'n':\n out += '\\n';\n break;\n case 'r':\n out += '\\r';\n break;\n case 't':\n out += '\\t';\n break;\n case 'b':\n out += '\\b';\n break;\n case 'f':\n out += '\\f';\n break;\n case '\\\\':\n out += '\\\\';\n break;\n case 'u':\n out += this._readUnicodeEscape(quote, eOffset, eLine, eCol);\n break;\n default:\n // Escaped delimiter char (e.g. \\' inside '...' or \\\" inside \"...\")\n if (e === quote) {\n out += e;\n break;\n }\n if (e === '/') {\n if (quote === \"'\")\n this._fail(\n `\\\\/ is not a valid escape in single-quoted byte strings (§6.1)`,\n eLine,\n eCol\n );\n out += '/';\n break;\n }\n // Non-standard JS escape sequences — accepted when onEscapeWarning is set.\n if (this.onEscapeWarning) {\n if (e === '0') {\n this.onEscapeWarning(\n '\\\\0 is a non-standard escape sequence; use \\\\u0000 instead',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += '\\0';\n break;\n }\n if (e === 'v') {\n this.onEscapeWarning(\n '\\\\v is a non-standard escape sequence; use \\\\u000b instead',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += '\\v';\n break;\n }\n if (e === 'x') {\n // \\xHH — two hex digits\n const h1 = this._ch();\n const h2 = this.input[this.pos + 1] ?? '';\n if (!/[0-9a-fA-F]/.test(h1) || !/[0-9a-fA-F]/.test(h2)) {\n this._fail(\n '\\\\x escape requires exactly two hex digits',\n eLine,\n eCol\n );\n }\n this._advance();\n this._advance();\n const codePoint = parseInt(h1 + h2, 16);\n this.onEscapeWarning(\n `\\\\x${h1}${h2} is a non-standard escape sequence; use \\\\u00${h1}${h2} instead`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += String.fromCharCode(codePoint);\n break;\n }\n // Cross-quote delimiter (e.g. \\\" inside '...' or \\' inside \"...\")\n if (e === '\"' || e === \"'\") {\n this.onEscapeWarning(\n `\\\\${e} inside ${quote === '\"' ? 'double' : 'single'}-quoted string is non-standard`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += e;\n break;\n }\n // JS line continuation: \\ + LF / CR / CRLF → nothing added\n if (e === '\\n' || e === '\\r') {\n if (e === '\\r' && this._ch() === '\\n') this._advance(); // consume CRLF\n this.onEscapeWarning(\n 'line continuation (\\\\<newline>) is non-standard; the newline is ignored',\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n break;\n }\n // Identity escape: \\X → X (JS accepts any \\X as just X)\n this.onEscapeWarning(\n `\\\\${e} is an unknown escape sequence; interpreted as '${e}'`,\n eOffset,\n eLine,\n eCol,\n this.pos\n );\n out += e;\n break;\n }\n this._fail(\n `invalid escape sequence \\\\${e} in ${quote === '\"' ? 'double' : 'single'}-quoted string`,\n eLine,\n eCol\n );\n }\n } else {\n out += this._advance();\n }\n }\n if (this._eof()) this._fail('unterminated string literal');\n this._advance(); // closing quote\n return out;\n }\n\n /**\n * Parse a Unicode escape immediately after `\\u` has been consumed.\n *\n * @param quote - The enclosing string delimiter (`\"` or `'`).\n *\n * Handles two forms:\n * - `\\u{N}` … `\\u{10FFFF}`: direct Unicode scalar value (surrogates rejected)\n * - `\\uXXXX`: exactly four hex digits; a high surrogate must be followed by\n * `\\uXXXX` for the matching low surrogate to form a valid surrogate pair,\n * which is then decoded into the corresponding non-BMP code point.\n *\n * In single-quoted strings (`quote === \"'\"`), `\\u` escapes that resolve to\n * printable ASCII (U+0020–U+007E) are rejected per draft-ietf-cbor-edn-literals-27\n * §6.1 hexchar-s.\n * Use `\\\\` for backslash (U+005C) and `\\'` for the single-quote delimiter.\n */\n private _readUnicodeEscape(\n quote: string,\n bsOffset?: number,\n bsLine?: number,\n bsCol?: number\n ): string {\n const line = this.line,\n col = this.col;\n\n /** Warn or throw when this is a single-quoted string and the code point is printable ASCII. */\n const checkSingleQuotedPrintable = (cp: number): void => {\n // Per draft-ietf-cbor-edn-literals-27 §6.1 hexchar-s, \\u escapes for printable ASCII (U+0020–U+007E)\n // are not valid in single-quoted strings. Use \\\\ for backslash and \\' for\n // the single-quote delimiter. In lenient mode (onEscapeWarning set) we emit\n // a warning and accept the value rather than hard-failing.\n if (quote === \"'\" && cp >= 0x20 && cp <= 0x7e) {\n const msg = `\\\\u escape for printable ASCII U+${cp.toString(16).padStart(4, '0').toUpperCase()} is not allowed in single-quoted strings (§6.1 hexchar-s)`;\n if (this.onEscapeWarning) {\n this.onEscapeWarning(\n msg,\n bsOffset ?? this.pos,\n bsLine ?? line,\n bsCol ?? col,\n this.pos\n );\n return;\n }\n this._fail(msg, line, col);\n }\n };\n\n // Extended form \\u{NNN}\n if (!this._eof() && this._ch() === '{') {\n this._advance(); // {\n let hex = '';\n while (!this._eof() && this._ch() !== '}') {\n const c = this._ch();\n if (!/[0-9a-fA-F]/.test(c))\n this._fail(\n `invalid character in \\\\u{} escape: ${JSON.stringify(c)}`,\n line,\n col\n );\n hex += this._advance();\n }\n if (this._eof()) this._fail('unterminated \\\\u{} escape', line, col);\n this._advance(); // }\n if (hex.length === 0) this._fail('empty \\\\u{} escape', line, col);\n const cp = parseInt(hex, 16);\n if (cp > 0x10_ffff)\n this._fail(\n `\\\\u{${hex}} exceeds maximum Unicode code point U+10FFFF`,\n line,\n col\n );\n if (cp >= 0xd800 && cp <= 0xdfff)\n this._fail(\n `\\\\u{${hex}} is a surrogate code point, which is not a valid Unicode scalar value`,\n line,\n col\n );\n checkSingleQuotedPrintable(cp);\n return String.fromCodePoint(cp);\n }\n\n // Standard form \\uXXXX\n let hex = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof()) this._fail('truncated \\\\uXXXX escape', line, col);\n const c = this._ch();\n if (!/[0-9a-fA-F]/.test(c))\n this._fail(\n `invalid hex digit in \\\\uXXXX escape: ${JSON.stringify(c)}`,\n line,\n col\n );\n hex += this._advance();\n }\n const cp = parseInt(hex, 16);\n\n // High surrogate: must be immediately followed by a low-surrogate escape\n if (cp >= 0xd800 && cp <= 0xdbff) {\n if (this._ch() !== '\\\\' || (this.input[this.pos + 1] ?? '') !== 'u')\n this._fail(\n `lone high surrogate \\\\u${hex} must be followed by \\\\uDC00–\\\\uDFFF`,\n line,\n col\n );\n this._advance(); // \\\n this._advance(); // u\n const line2 = this.line,\n col2 = this.col;\n let hex2 = '';\n for (let i = 0; i < 4; i++) {\n if (this._eof())\n this._fail('truncated low-surrogate escape', line2, col2);\n hex2 += this._advance();\n }\n const cp2 = parseInt(hex2, 16);\n if (cp2 < 0xdc00 || cp2 > 0xdfff)\n this._fail(\n `\\\\u${hex} (high surrogate) not followed by a valid low surrogate (got \\\\u${hex2})`,\n line,\n col\n );\n // Surrogate pairs always resolve to non-BMP (> U+FFFF), never printable ASCII\n return String.fromCodePoint(\n 0x10000 + (cp - 0xd800) * 0x400 + (cp2 - 0xdc00)\n );\n }\n\n // Low surrogate without a preceding high surrogate is invalid\n if (cp >= 0xdc00 && cp <= 0xdfff)\n this._fail(`lone low surrogate \\\\u${hex} is not valid`, line, col);\n\n checkSingleQuotedPrintable(cp);\n return String.fromCharCode(cp);\n }\n\n /**\n * Read raw text-string content between N-backtick delimiters\n * (§2.3.3 of draft-ietf-cbor-edn-literals-27).\n *\n * - The opening delimiter is the maximal run of consecutive backticks (N ≥ 1).\n * - No escape sequences are processed — content is taken verbatim.\n * - Literal CR is stripped for source-level CRLF normalisation (§1.3.5).\n * - The closing delimiter is a run of exactly N backticks (alikerawdelim);\n * shorter runs are content, longer runs are an error.\n * - A single leading newline (LF or CRLF) is stripped; if that rule did not\n * apply and the inner string both starts and ends with a space, exactly\n * one leading and one trailing space are stripped.\n */\n private _readRawStringContent(): string {\n const openLine = this.line,\n openCol = this.col;\n\n // Count opening backticks (greedy)\n let n = 0;\n while (!this._eof() && this._ch() === '`') {\n this._advance();\n n++;\n }\n\n // Strip a single leading CRLF or LF (§2.3.3, first trimming rule)\n let newlineStripped = false;\n if (!this._eof() && this._ch() === '\\r') this._advance(); // CR\n if (!this._eof() && this._ch() === '\\n') {\n this._advance(); // LF\n newlineStripped = true;\n }\n\n const inputLen = this.input.length;\n let out = '';\n while (!this._eof()) {\n // Fast path: bulk-consume a run of ordinary characters up to the next\n // backtick, CR, or control character. LF is ordinary content; it is\n // counted here so line/col stay correct.\n let p = this.pos;\n let newlines = 0;\n let lastNewline = -1;\n while (p < inputLen) {\n const cc = this.input.charCodeAt(p);\n if (cc === 0x60 /* ` */ || cc === 0x7f /* DEL */) break;\n if (cc < 0x20) {\n if (cc !== 0x0a) break; // CR / other C0 controls → slow path\n newlines++;\n lastNewline = p;\n }\n p++;\n }\n if (p > this.pos) {\n out += this.input.slice(this.pos, p);\n if (newlines > 0) {\n this.line += newlines;\n this.col = p - lastNewline;\n } else {\n this.col += p - this.pos;\n }\n this.pos = p;\n continue;\n }\n\n const ch = this._ch();\n\n // Source-level CRLF normalisation: strip bare CR\n if (ch === '\\r') {\n this._advance();\n continue;\n }\n\n if (ch === '`') {\n // Count this backtick run\n let m = 0;\n const runLine = this.line,\n runCol = this.col;\n while (!this._eof() && this._ch() === '`') {\n this._advance();\n m++;\n }\n if (m === n) {\n // Closing delimiter found (alikerawdelim: exactly N backticks).\n // Second trimming rule (§2.3.3): if no leading newline was\n // stripped and the inner string starts AND ends with a space,\n // strip exactly one of each.\n if (\n !newlineStripped &&\n out.length >= 2 &&\n out.startsWith(' ') &&\n out.endsWith(' ')\n )\n out = out.slice(1, -1);\n if (out === '')\n this._fail(\n 'raw string must not be empty (§2.3.3)',\n openLine,\n openCol\n );\n return out;\n }\n if (m > n) {\n // Longer runs can neither be content (shortrawdelim) nor close the\n // string (alikerawdelim) — §2.3.3 / §6.1.\n this._fail(\n `raw string contains a run of ${m} backquotes, longer than the ${n}-backquote delimiter; use longer delimiters`,\n runLine,\n runCol\n );\n }\n // Shorter run — all backticks become content\n out += '`'.repeat(m);\n } else {\n const cp = ch.codePointAt(0)!;\n // rawchars = 1*(%x0a/%x0d / %x20-5f / %x61-7e / NONASCII) — HT and other C0 controls forbidden\n if (cp < 0x20 && cp !== 0x0a && cp !== 0x0d) {\n this._fail(\n `raw string content must not contain control character U+${cp.toString(16).toUpperCase().padStart(4, '0')} (§2.3.3)`,\n this.line,\n this.col\n );\n }\n if (cp === 0x7f) {\n this._fail(\n 'raw string content must not contain DEL (U+007F) (§2.3.3)',\n this.line,\n this.col\n );\n }\n out += this._advance();\n }\n }\n\n this._fail('unterminated raw string literal', openLine, openCol);\n }\n\n /**\n * Post-process raw hex content from a `h``…``\\` raw string (§6.3.3).\n *\n * Skips:\n * - lblank whitespace (LF, SP; also CR for source-level normalisation)\n * - `/ … /` block comments\n * - `# …` line comments (up to but not including LF)\n * Detects `...` ellipsis sequences.\n *\n * A trailing `# comment` immediately before the closing delimiter is allowed\n * per §6.3.3 `r-app-string-h`.\n *\n * Returns { value: hex-string-with-ellipsis-markers, elided: boolean }\n */\n private _processRawHexContent(\n raw: string,\n tokenLine: number,\n tokenCol: number\n ): { value: string; elided: boolean } {\n let hex = '';\n let elided = false;\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n // lblank / CR — skip\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n i++;\n continue;\n }\n // HT is still forbidden (rawchars excludes %x09)\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside h`` raw byte string literals (§6.3.3)',\n tokenLine,\n tokenCol\n );\n }\n // Comments (§2.1)\n const afterComment = this._skipRawComment(\n raw,\n i,\n 'h`` raw byte string',\n tokenLine,\n tokenCol\n );\n if (afterComment !== -1) {\n i = afterComment;\n continue;\n }\n // Ellipsis: ... (three or more dots)\n if (ch === '.' && raw[i + 1] === '.' && raw[i + 2] === '.') {\n i += 3;\n while (i < raw.length && raw[i] === '.') i++;\n hex += '...';\n elided = true;\n continue;\n }\n // Hex digits — consume the whole run at once\n if (isHexDigitCode(raw.charCodeAt(i))) {\n const runStart = i;\n while (i < raw.length && isHexDigitCode(raw.charCodeAt(i))) i++;\n hex += raw.slice(runStart, i);\n continue;\n }\n this._fail(\n `unexpected character ${JSON.stringify(ch)} in h\\`\\` raw byte string`,\n tokenLine,\n tokenCol\n );\n }\n return { value: hex, elided };\n }\n\n /**\n * Post-process raw base64 content from a `b64``…``\\` raw string (§6.3.4).\n *\n * Skips:\n * - lblank whitespace (LF, SP; also CR for source-level normalisation)\n * - `# …` line comments (up to but not including LF)\n *\n * Returns the stripped base64 string.\n */\n private _processRawB64Content(\n raw: string,\n tokenLine: number,\n tokenCol: number\n ): string {\n let out = '';\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n // lblank / CR — skip\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n i++;\n continue;\n }\n // HT forbidden\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside b64`` raw byte string literals (§6.3.4)',\n tokenLine,\n tokenCol\n );\n }\n // Line comment: # … (to end of line)\n // Note: // is NOT treated as a comment because / is a valid B64DIGIT\n // (e.g. 0xFF 0xFF encodes to //8= in standard base64).\n if (ch === '#') {\n while (i < raw.length && raw[i] !== '\\n') i++;\n continue;\n }\n // Run of data characters — consume in bulk up to the next terminator\n const runStart = i;\n while (i < raw.length) {\n const d = raw[i];\n if (d === '\\n' || d === ' ' || d === '\\r' || d === '\\t' || d === '#')\n break;\n i++;\n }\n out += raw.slice(runStart, i);\n }\n return out;\n }\n\n /**\n * Read raw byte-string content between `quote` chars (b64 / b64url).\n *\n * Strips whitespace and skips `# ...` line comments per §6.2.2.\n * `/` is NOT treated as a comment delimiter because it is a valid base64 character.\n */\n private _readByteContent(quote: string): string {\n this._advance(); // opening quote\n let raw = '';\n while (!this._eof() && this._ch() !== quote) {\n const ch = this._ch();\n // lblank = %x0A / %x20 — only LF and SP are whitespace (§6.2.2 Fig 4); HT is forbidden\n if (ch === '\\n' || ch === ' ') {\n this._advance();\n continue;\n }\n if (ch === '\\r') {\n // CR is not lblank; skip silently as source-level normalization only\n this._advance();\n continue;\n }\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside byte string literals (§6.2.2)',\n this.line,\n this.col\n );\n }\n // # line comment — stop at newline or the closing quote (whichever comes first)\n // Note: // is NOT treated as a comment here because / is a valid B64DIGIT;\n // treating // as a comment would corrupt base64 data that naturally contains\n // consecutive slashes (e.g. 0xFF 0xFF encodes to //8= in standard base64).\n if (ch === '#') {\n while (!this._eof() && this._ch() !== '\\n') {\n if (this._ch() === '\\\\') {\n this._advance();\n if (!this._eof() && this._ch() !== '\\n') this._advance();\n continue;\n }\n if (this._ch() === quote) break;\n this._advance();\n }\n continue;\n }\n // Run of data characters — consume in bulk up to the next terminator.\n // Newlines terminate the run, so a plain column update is safe.\n const runStart = this.pos;\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const d = this.input[p];\n if (\n d === quote ||\n d === '\\n' ||\n d === ' ' ||\n d === '\\r' ||\n d === '\\t' ||\n d === '#'\n )\n break;\n p++;\n }\n this.col += p - runStart;\n this.pos = p;\n raw += this.input.slice(runStart, p);\n }\n if (this._eof()) this._fail('unterminated byte string literal');\n this._advance(); // closing quote\n return raw;\n }\n\n /**\n * Read hex byte-string content, recognising `...` ellipsis sequences (§5.2).\n *\n * Returns the raw hex string (with `...` markers embedded) and a flag\n * indicating whether any ellipsis was found.\n */\n private _readHexByteContentElisionAware(quote: string): {\n value: string;\n elided: boolean;\n } {\n this._advance(); // opening quote\n let hex = '';\n let elided = false;\n // Tracks whether `hex` currently ends with an ellipsis, without asking\n // `hex` itself: `hex` is built by repeated `+=` and can end up as an\n // unflattened V8 rope string, where `.endsWith()` forces a flatten —\n // negligible once, but this runs per `...` occurrence in the literal,\n // making a many-ellipsis literal (e.g. thousands of `...` markers)\n // quadratic instead of linear.\n let hexEndsWithEllipsis = false;\n while (!this._eof() && this._ch() !== quote) {\n const ch = this._ch();\n // lblank = %x0A / %x20 only; HT is forbidden per §6.2.1 Figure 3\n if (ch === '\\n' || ch === ' ' || ch === '\\r') {\n this._advance();\n continue;\n }\n if (ch === '\\t') {\n this._fail(\n 'horizontal tab (HT) is not allowed inside hex byte string literals (§6.2.1)',\n this.line,\n this.col\n );\n }\n if (this._skipByteStringComment(quote)) continue;\n // Detect '...' ellipsis inside hex literal\n if (\n ch === '.' &&\n (this.input[this.pos + 1] ?? '') === '.' &&\n (this.input[this.pos + 2] ?? '') === '.'\n ) {\n this._advance();\n this._advance();\n this._advance();\n // consume any additional dots (spec says \"three or more\")\n while (!this._eof() && this._ch() === '.') this._advance();\n // adjacent ... separated only by whitespace collapse into a single ellipsis\n if (!hexEndsWithEllipsis) hex += '...';\n elided = true;\n hexEndsWithEllipsis = true;\n continue;\n }\n if (isHexDigitCode(ch.charCodeAt(0))) {\n // Run of hex digits — consume in bulk (digits contain no newlines)\n const runStart = this.pos;\n let p = this.pos;\n const n = this.input.length;\n while (p < n && isHexDigitCode(this.input.charCodeAt(p))) p++;\n this.col += p - runStart;\n this.pos = p;\n hex += this.input.slice(runStart, p);\n hexEndsWithEllipsis = false;\n continue;\n }\n this._fail(\n `unexpected character ${JSON.stringify(ch)} in hex byte string`\n );\n }\n if (this._eof()) this._fail('unterminated hex byte string literal');\n this._advance(); // closing quote\n return { value: hex, elided };\n }\n\n // ── Token reader ─────────────────────────────────────────────────────────\n\n /** Start offset of the token currently being read (set by _readNext). */\n private _tokStart = 0;\n\n private _readNext(): Token {\n this._skipWS();\n this._tokStart = this.pos;\n return this._readNextCore();\n }\n\n /**\n * Build a complete Token for the source range [_tokStart, pos).\n * Every token is constructed exactly once here — the previous two-step\n * \"partial object, then spread in raw/offsets\" cost an extra object and a\n * property-copy pass per token on the parse hot path.\n *\n * `appPrefix` is added only for app-string/app-sequence tokens so that\n * ordinary tokens keep `'appPrefix' in tok === false`, matching the public\n * tokenize() API shape documented on the Token interface.\n *\n * `raw` stays an eagerly-sliced own data property: Token is public API, and\n * a getter would vanish under the consumer's own `{ ...token }` spread or\n * JSON.stringify. The slice cost is minor next to the removed extra object.\n */\n private _tok(\n type: TokenType,\n value: string,\n line: number,\n col: number,\n appPrefix?: string\n ): Token {\n const offset = this._tokStart;\n const tok: Token = {\n type,\n value,\n raw: this.input.slice(offset, this.pos),\n line,\n col,\n offset,\n endOffset: this.pos,\n };\n if (appPrefix !== undefined) tok.appPrefix = appPrefix;\n return tok;\n }\n\n /**\n * {@link _tok} variant for tokens whose processed `value` IS the raw source\n * text — punctuation, keywords, and numbers without a leading `+`. Reuses\n * `value` as `raw`, skipping a per-token slice on the densest token kinds.\n * Callers must guarantee `value === input.slice(_tokStart, pos)`.\n */\n private _tokV(\n type: TokenType,\n value: string,\n line: number,\n col: number\n ): Token {\n return {\n type,\n value,\n raw: value,\n line,\n col,\n offset: this._tokStart,\n endOffset: this.pos,\n };\n }\n\n private _readNextCore(): Token {\n const line = this.line,\n col = this.col;\n if (this._eof()) return this._tokV('EOF', '', line, col);\n\n const c = this._ch();\n\n switch (c) {\n case '[':\n this._advance();\n return this._tokV('LBRACKET', '[', line, col);\n case ']':\n this._advance();\n return this._tokV('RBRACKET', ']', line, col);\n case '{':\n this._advance();\n return this._tokV('LBRACE', '{', line, col);\n case '}':\n this._advance();\n return this._tokV('RBRACE', '}', line, col);\n case '(':\n this._advance();\n return this._tokV('LPAREN', '(', line, col);\n case ')':\n this._advance();\n return this._tokV('RPAREN', ')', line, col);\n case ':':\n this._advance();\n return this._tokV('COLON', ':', line, col);\n case ',':\n this._advance();\n return this._tokV('COMMA', ',', line, col);\n case '<':\n if ((this.input[this.pos + 1] ?? '') === '<') {\n this._advance();\n this._advance();\n return this._tokV('LT_LT', '<<', line, col);\n }\n this._fail(`unexpected character '<'`, line, col);\n case '>':\n if ((this.input[this.pos + 1] ?? '') === '>') {\n this._advance();\n this._advance();\n return this._tokV('GT_GT', '>>', line, col);\n }\n this._fail(`unexpected character '>'`, line, col);\n case '+': {\n // +Infinity[_N]\n const posInf = this._readSignedInfinity('+', line, col);\n if (posInf !== null) return posInf;\n // Numeric literal with explicit positive sign\n const afterPlus = this.input[this.pos + 1] ?? '';\n if ((afterPlus >= '0' && afterPlus <= '9') || afterPlus === '.') {\n this._advance(); // consume '+'\n return this._readNumber(line, col);\n }\n // String concatenation operator\n this._advance();\n return this._tokV('PLUS', '+', line, col);\n }\n case '`':\n return this._tok('RAWSTRING', this._readRawStringContent(), line, col);\n case '\"': {\n const strVal = this._readStringContent('\"');\n if (\n strVal === '' &&\n this._ch() === '_' &&\n !/[0-7i]/.test(this.input[this.pos + 1] ?? '')\n ) {\n this._advance(); // _\n return this._tok('EMPTY_INDEF_TEXT', '', line, col);\n }\n return this._tok('TSTR', strVal, line, col);\n }\n case \"'\": {\n // ''_ → empty indefinite byte string (but ''_N is sqstr + encoding indicator)\n if (\n (this.input[this.pos + 1] ?? '') === \"'\" &&\n (this.input[this.pos + 2] ?? '') === '_' &&\n !/[0-7i]/.test(this.input[this.pos + 3] ?? '')\n ) {\n this._advance(); // first '\n this._advance(); // second '\n this._advance(); // _\n return this._tok('EMPTY_INDEF_BYTES', '', line, col);\n }\n // 'text' → UTF-8 encoded byte string (major type 2)\n const strVal = this._readStringContent(\"'\");\n const utf8 = textEncoder.encode(strVal);\n const tok = this._tok('SQSTR', bytesToHex(utf8), line, col);\n // Attach the payload for the parser (see SqstrToken). defineProperty\n // keeps it out of keys/JSON/spread; SQSTR is rare enough that the\n // defineProperty cost does not matter.\n Object.defineProperty(tok, '_sqstrBytes', { value: utf8 });\n return tok;\n }\n }\n\n // -Infinity (check before generic '-' handling)\n if (c === '-') {\n const negInf = this._readSignedInfinity('-', line, col);\n if (negInf !== null) return negInf;\n return this._readNumber(line, col);\n }\n\n if (c >= '0' && c <= '9') return this._readNumber(line, col);\n // Leading-dot float: .5, .1e2, etc. (same as +.5 / -.5)\n if (c === '.' && /[0-9]/.test(this.input[this.pos + 1] ?? ''))\n return this._readNumber(line, col);\n if (/[a-zA-Z_]/.test(c)) return this._readIdent(line, col);\n\n // Three or more dots → ellipsis notation (§5.2)\n if (c === '.') {\n if (\n (this.input[this.pos + 1] ?? '') === '.' &&\n (this.input[this.pos + 2] ?? '') === '.'\n ) {\n this._advance();\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() === '.') this._advance();\n return this._tok('ELLIPSIS', '...', line, col);\n }\n this._fail(`unexpected character '.'`, line, col);\n }\n\n this._fail(`unexpected character ${JSON.stringify(c)}`, line, col);\n }\n\n /**\n * Try to read `Infinity[_N]` immediately after a `+`/`-` sign at this.pos.\n *\n * Returns null when the input is not an Infinity literal (e.g. an identifier\n * like `Infinityx` that merely starts with \"Infinity\"); the caller then\n * falls back to its sign handling.\n *\n * All encoding-indicator suffixes _0–_7/_i are tokenized here; the parser\n * validates them and rejects/warns on the invalid ones (_0, _4–_7, _i).\n *\n * Uses startsWith with a position argument instead of slicing the remainder\n * of the input, which would allocate a substring for every sign token.\n */\n private _readSignedInfinity(\n sign: '+' | '-',\n line: number,\n col: number\n ): Token | null {\n if (!this.input.startsWith('Infinity', this.pos + 1)) return null;\n const after = this.input[this.pos + 9] ?? '';\n const hasSuffix =\n after === '_' &&\n /[0-7i]/.test(this.input[this.pos + 10] ?? '') &&\n !/[a-zA-Z0-9_]/.test(this.input[this.pos + 11] ?? '');\n if (/[a-zA-Z0-9_]/.test(after) && !hasSuffix) return null;\n this._advance(); // sign\n for (let i = 0; i < 8; i++) this._advance(); // Infinity\n let value = sign === '-' ? '-Infinity' : 'Infinity';\n if (hasSuffix) value += this._advance() + this._advance(); // _N\n return this._tok('FLOAT', value, line, col);\n }\n\n /** Advance past a run of hex digits. Digits contain no newlines, so a\n * plain column update is safe. */\n private _skipHexDigits(): void {\n let p = this.pos;\n const n = this.input.length;\n while (p < n && isHexDigitCode(this.input.charCodeAt(p))) p++;\n this.col += p - this.pos;\n this.pos = p;\n }\n\n /** Advance past a run of decimal digits (same newline-free guarantee). */\n private _skipDecimalDigits(): void {\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const c = this.input.charCodeAt(p);\n if (c < 0x30 || c > 0x39) break;\n p++;\n }\n this.col += p - this.pos;\n this.pos = p;\n }\n\n /**\n * Consume a trailing _0–_7/_i encoding-indicator suffix when present and\n * not followed by another identifier character.\n */\n private _tryConsumeEncodingSuffix(): void {\n if (this._ch() !== '_') return;\n const d = this.input[this.pos + 1] ?? '';\n const after = this.input[this.pos + 2] ?? '';\n if (((d >= '0' && d <= '7') || d === 'i') && !/[0-9a-zA-Z_]/.test(after)) {\n this._advance();\n this._advance();\n }\n }\n\n private _readNumber(line: number, col: number): Token {\n // The token value is the raw consumed text; it is collected with a single\n // slice at the end instead of per-character string concatenation.\n const start = this.pos;\n const consumed = () => this.input.slice(start, this.pos);\n // consumed() is the exact source range unless a leading '+' was eaten\n // by the caller before _readNumber; only then does raw need its own slice.\n const numTok = (type: TokenType): Token =>\n start === this._tokStart\n ? this._tokV(type, consumed(), line, col)\n : this._tok(type, consumed(), line, col);\n if (this._ch() === '-') this._advance();\n\n // Alternative bases: 0x 0o 0b\n if (this._ch() === '0') {\n const next = this.input[this.pos + 1] ?? '';\n if (next === 'x' || next === 'X') {\n this._advance();\n this._advance(); // '0x'\n const intStart = this.pos;\n this._skipHexDigits();\n const hasIntDigits = this.pos > intStart;\n // Hex float: optional '.[hex]' fractional part followed by 'p'/'P' exponent\n let isHexFloat = false;\n let hasFracDigits = false;\n if (!this._eof() && this._ch() === '.') {\n isHexFloat = true;\n this._advance();\n const fracStart = this.pos;\n this._skipHexDigits();\n hasFracDigits = this.pos > fracStart;\n }\n if (!this._eof() && (this._ch() === 'p' || this._ch() === 'P')) {\n isHexFloat = true;\n // Validate mantissa: need at least one hex digit before or after dot\n if (!hasIntDigits && !hasFracDigits)\n this._fail(\n `hex float has no mantissa digits: ${consumed()}`,\n line,\n col\n );\n this._advance();\n if (!this._eof() && (this._ch() === '+' || this._ch() === '-'))\n this._advance();\n const expStart = this.pos;\n this._skipDecimalDigits();\n // Validate exponent: at least one decimal digit required\n if (this.pos === expStart)\n this._fail(\n `hex float missing exponent digits: ${consumed()}`,\n line,\n col\n );\n } else if (isHexFloat) {\n // Had a dot but no 'p' — missing exponent\n this._fail(\n `hex float missing 'p' exponent: ${consumed()}`,\n line,\n col\n );\n }\n if (isHexFloat) {\n // Encoding-indicator suffix _0/_1/_2/_3/_4/_5/_6/_7/_i for hex floats\n this._tryConsumeEncodingSuffix();\n return numTok('FLOAT');\n }\n return numTok('INTEGER');\n }\n if (next === 'o' || next === 'O') {\n this._advance();\n this._advance();\n while (!this._eof() && this._ch() >= '0' && this._ch() <= '7')\n this._advance();\n return numTok('INTEGER');\n }\n if (next === 'b' || next === 'B') {\n this._advance();\n this._advance();\n while (!this._eof() && (this._ch() === '0' || this._ch() === '1'))\n this._advance();\n return numTok('INTEGER');\n }\n }\n\n // Decimal digits\n this._skipDecimalDigits();\n\n let isFloat = false;\n if (!this._eof() && this._ch() === '.') {\n isFloat = true;\n this._advance();\n this._skipDecimalDigits();\n }\n if (!this._eof() && (this._ch() === 'e' || this._ch() === 'E')) {\n isFloat = true;\n this._advance();\n if (!this._eof() && (this._ch() === '+' || this._ch() === '-'))\n this._advance();\n const expStart = this.pos;\n this._skipDecimalDigits();\n if (this.pos === expStart)\n this._fail(\n `float exponent has no digits: ${JSON.stringify(consumed())}`,\n line,\n col\n );\n }\n\n // Encoding-indicator suffix _0–_7 / _i (no whitespace, not followed by\n // more ident chars). The suffix is included in the token value.\n // isFloat is NOT set here — a float is only a float when it contains\n // '.' or 'e'/'E'. The parser extracts encoding width from the suffix.\n this._tryConsumeEncodingSuffix();\n\n return numTok(isFloat ? 'FLOAT' : 'INTEGER');\n }\n\n private _readIdent(line: number, col: number): Token {\n // Idents contain no newlines, so a plain column update is safe.\n const identStart = this.pos;\n {\n let p = this.pos;\n const n = this.input.length;\n while (p < n) {\n const cc = this.input.charCodeAt(p);\n const isIdentChar =\n (cc >= 0x61 && cc <= 0x7a) || // a-z\n (cc >= 0x41 && cc <= 0x5a) || // A-Z\n (cc >= 0x30 && cc <= 0x39) || // 0-9\n cc === 0x5f; // _\n if (!isIdentChar) break;\n p++;\n }\n this.col += p - this.pos;\n this.pos = p;\n }\n let ident = this.input.slice(identStart, this.pos);\n\n // Known keywords — checked first so they are never shadowed by app-strings.\n switch (ident) {\n case 'true':\n return this._tokV('TRUE', ident, line, col);\n case 'false':\n return this._tokV('FALSE', ident, line, col);\n case 'null':\n return this._tokV('NULL', ident, line, col);\n case 'undefined':\n return this._tokV('UNDEFINED', ident, line, col);\n case 'NaN':\n case 'NaN_0':\n case 'NaN_1':\n case 'NaN_2':\n case 'NaN_3':\n case 'NaN_4':\n case 'NaN_5':\n case 'NaN_6':\n case 'NaN_7':\n case 'NaN_i':\n case 'Infinity':\n case 'Infinity_0':\n case 'Infinity_1':\n case 'Infinity_2':\n case 'Infinity_3':\n case 'Infinity_4':\n case 'Infinity_5':\n case 'Infinity_6':\n case 'Infinity_7':\n case 'Infinity_i':\n return this._tokV('FLOAT', ident, line, col);\n case 'simple':\n return this._tokV('SIMPLE', ident, line, col);\n case '_':\n return this._tokV('UNDERSCORE', '_', line, col);\n // Encoding indicators used in array/map/string/bytes contexts\n case '_0':\n return this._tok('ENCODING_INDICATOR', '0', line, col);\n case '_1':\n return this._tok('ENCODING_INDICATOR', '1', line, col);\n case '_2':\n return this._tok('ENCODING_INDICATOR', '2', line, col);\n case '_3':\n return this._tok('ENCODING_INDICATOR', '3', line, col);\n case '_4':\n return this._tok('ENCODING_INDICATOR', '4', line, col);\n case '_5':\n return this._tok('ENCODING_INDICATOR', '5', line, col);\n case '_6':\n return this._tok('ENCODING_INDICATOR', '6', line, col);\n case '_7':\n // _7 = AI 31 = indefinite-length; kept as ENCODING_INDICATOR so that\n // bare `_` (UNDERSCORE) and explicit `_7` stay distinguishable.\n return this._tok('ENCODING_INDICATOR', '7', line, col);\n case '_i':\n return this._tok('ENCODING_INDICATOR', 'i', line, col);\n }\n\n // Byte-string prefixes or app-string extensions.\n // App-prefix grammar (§6.1 of draft-ietf-cbor-edn-literals-27):\n // app-prefix = lcalpha *lcldh / ucalpha *ucldh\n // lcldh = lcalpha / DIGIT / \"-\"\n // ucldh = ucalpha / DIGIT / \"-\"\n // Mixed-case or underscore-containing idents are not valid app-prefixes.\n const firstChar = ident[0] ?? '';\n const isLower = firstChar >= 'a' && firstChar <= 'z';\n const isUpper = firstChar >= 'A' && firstChar <= 'Z';\n\n if (isLower || isUpper) {\n // Validate chars already consumed by the main loop (no underscore, correct case).\n const restAlreadyRead = ident.slice(1);\n const restValid = isLower\n ? /^[a-z0-9]*$/.test(restAlreadyRead)\n : /^[A-Z0-9]*$/.test(restAlreadyRead);\n\n if (restValid) {\n // Extend the prefix with any remaining lcldh / ucldh chars.\n // The main loop stops at '-', so we need to consume hyphen-segments here.\n const extStart = this.pos;\n while (!this._eof()) {\n const ch = this._ch();\n const validCh = isLower\n ? (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch === '-'\n : (ch >= 'A' && ch <= 'Z') ||\n (ch >= '0' && ch <= '9') ||\n ch === '-';\n if (!validCh) break;\n this.pos++;\n }\n if (this.pos > extStart) {\n this.col += this.pos - extStart;\n ident += this.input.slice(extStart, this.pos);\n }\n\n const q = this._ch();\n // Double quotes are not valid for app-string / byte-string prefixes.\n // app-string = app-prefix sqstr (sqstr uses single quotes only)\n if (q === '\"')\n this._fail(\n `\"${ident}\" prefix requires single quotes or backticks, not double quotes`,\n line,\n col\n );\n if (q === \"'\") {\n switch (ident) {\n case 'h': {\n const { value: hexVal, elided } =\n this._readHexByteContentElisionAware(q);\n return this._tok(\n elided ? 'BYTES_HEX_ELIDED' : 'BYTES_HEX',\n hexVal,\n line,\n col\n );\n }\n case 'b64':\n return this._tok(\n 'BYTES_B64',\n this._readByteContent(q),\n line,\n col\n );\n default:\n return this._tok(\n 'APP_STRING',\n this._readStringContent(q),\n line,\n col,\n ident\n );\n }\n }\n\n // app-rstring: prefix followed by backtick raw string (§2.3.3 / app-rstring)\n if (q === '`') {\n const raw = this._readRawStringContent();\n switch (ident) {\n case 'h': {\n // §6.3.3: lblank + / / block comments + # line comments + ellipsis\n const { value: hexVal, elided } = this._processRawHexContent(\n raw,\n line,\n col\n );\n return this._tok(\n elided ? 'BYTES_HEX_ELIDED' : 'BYTES_HEX',\n hexVal,\n line,\n col\n );\n }\n case 'b64':\n // §6.3.4: lblank + # line comments\n return this._tok(\n 'BYTES_B64',\n this._processRawB64Content(raw, line, col),\n line,\n col\n );\n default:\n return this._tok('APP_STRING', raw, line, col, ident);\n }\n }\n\n // App-sequence extension: prefix<<items...>>\n // The tokenizer consumes only prefix + \"<<\"; the parser reads items until \">>\".\n if (q === '<' && (this.input[this.pos + 1] ?? '') === '<') {\n this._advance();\n this._advance(); // <<\n return this._tok('APP_SEQUENCE', '', line, col, ident);\n }\n }\n }\n\n this._fail(`unknown identifier ${JSON.stringify(ident)}`, line, col);\n }\n}\n","/**\n * Pure utility functions for EDN serialization.\n * No AST imports — safe to import from any AST class.\n */\n\nimport type { CborComment, CborComments, ToCDNOptions } from '../types';\nimport type { EncodingWidth } from '../cbor/encode';\nimport type { AppSeqEncodingEdit, AppSeqSourceFeatures } from '../ast/CborItem';\nimport { bytesToHex as toHex, hexToBytes } from '../utils/hex';\nimport { base64ToBytes } from '../utils/base64';\nimport { Tokenizer, type Token, type SqstrToken } from './tokenizer';\n\n/**\n * Append every element of `source` onto `target` in place.\n *\n * Not `target.push(...source)`: spreading a large array as call arguments\n * can exceed the engine's argument-count limit (observed with hex-dump\n * lines for a deeply nested large array/map, and with CDN reflow\n * breakpoints for a large embedded array — RangeError: Maximum call stack\n * size exceeded).\n */\nexport function pushAll<T>(target: T[], source: readonly T[]): void {\n for (const item of source) target.push(item);\n}\n\n// ─── Indent helpers ───────────────────────────────────────────────────────────\n\n/** Resolve indent option to a string, or null for single-line output. */\nexport function resolveIndent(\n options: ToCDNOptions | undefined\n): string | null {\n const indent = options?.indent;\n if (indent === undefined) return null;\n const indentStr = typeof indent === 'number' ? ' '.repeat(indent) : indent;\n // `0` / `''` disable pretty-printing entirely (like `JSON.stringify`).\n return indentStr === '' ? null : indentStr;\n}\n\n/** Build the indent prefix for a given depth. */\nexport function indentOf(indentStr: string, depth: number): string {\n return indentStr.repeat(depth);\n}\n\n/**\n * Join pre-serialized string-concatenation part literals with `+`.\n *\n * Single-line (` + `) when indent is disabled; otherwise each continuation\n * part starts on its own line, indented one level deeper than the owner.\n *\n * `midComments`, when given, holds already-converted comment lines for each\n * gap between two consecutive parts (`midComments[i]` sits between\n * `literals[i]` and `literals[i + 1]`) — e.g. a comment between two\n * `+`-joined byte-string literals, which has nowhere else to attach since\n * there is no per-part AST node. Ignored in single-line mode, matching every\n * other comment kind.\n */\nexport function joinConcatParts(\n literals: readonly string[],\n indentStr: string | null,\n depth: number,\n midComments?: readonly (readonly string[])[]\n): string {\n if (indentStr === null) return literals.join(' + ');\n const indent = indentOf(indentStr, depth + 1);\n let out = literals[0]!;\n for (let i = 1; i < literals.length; i++) {\n out += ' +\\n';\n for (const comment of midComments?.[i - 1] ?? []) {\n out += `${indent}${comment}\\n`;\n }\n out += indent + literals[i];\n }\n return out;\n}\n\n/**\n * Serialize string parts as a `t1<<...>>` / `b1<<...>>` app-sequence\n * (draft-ietf-cbor-edn-literals-27 §3.5) — the `modernConcat` replacement\n * for `joinConcatParts`'s `+`-joining. Unlike a `+` chain, this\n * notation has its own closing delimiter, so (matching how `<<...>>`/\n * `CborEmbeddedCBOR` places its own encoding-width indicator, and unlike\n * `emitParts`, which has nowhere else to put it) `suffix` is appended after\n * `>>` rather than onto the last literal — it describes the one merged value\n * `t1<<...>>` denotes as a whole, not any individual argument.\n *\n * Always single-line (an app-sequence is loose/collapsible, like\n * every other `<<...>>` form), except when there's a mid-chain comment to\n * preserve — nothing else forces it multi-line, since (unlike a real `+`\n * chain) there's no risk of an unbounded single line growing unreadable that\n * this format was ever meant to solve; a comment is the one thing a single\n * line genuinely cannot hold, mirroring `joinConcatParts`'s own reason for\n * going multi-line.\n */\nexport function joinAppSeqParts(\n prefix: 't1' | 'b1',\n literals: readonly string[],\n suffix: string,\n indentStr: string | null,\n depth: number,\n midComments?: readonly (readonly string[])[]\n): string {\n const hasMidComments = midComments?.some((c) => c.length > 0) ?? false;\n if (indentStr === null || !hasMidComments) {\n return `${prefix}<<${literals.join(', ')}>>${suffix}`;\n }\n const indent = indentOf(indentStr, depth + 1);\n const closeIndent = indentOf(indentStr, depth);\n const lines: string[] = [];\n for (let i = 0; i < literals.length; i++) {\n const sep = i < literals.length - 1 ? ',' : '';\n lines.push(`${indent}${literals[i]}${sep}`);\n for (const comment of midComments?.[i] ?? []) {\n lines.push(`${indent}${comment}`);\n }\n }\n return `${prefix}<<\\n${lines.join('\\n')}\\n${closeIndent}>>${suffix}`;\n}\n\n// ─── Comment helpers ─────────────────────────────────────────────────────────\n\nexport interface Commented {\n comments?: CborComments;\n blankLineBefore?: boolean;\n}\n\nexport function hasPreservedComments(item: Commented): boolean {\n return Boolean(\n item.comments?.leading?.length ||\n item.comments?.trailing?.length ||\n item.comments?.dangling?.length\n );\n}\n\nexport function hasContainerLayoutComments(item: Commented): boolean {\n // Only dangling comments force the container itself onto multiple lines —\n // they live inside the brackets on their own line. A trailing comment on\n // the container is appended after the closing bracket by the caller (root\n // `toCDN()` or the parent's `entryTrailing`), so it never needs the body\n // to break, and single/flat rendering stays available.\n return Boolean(item.comments?.dangling?.length);\n}\n\n/**\n * Subset of `ToCDNOptions` needed to resolve comment on/off + style —\n * accepted structurally so callers with a narrower/wider options type (or a\n * plain `FromCDNOptions`, which shares both fields) don't need a cast.\n */\ninterface CommentOptions {\n preserveComments?: boolean | 'c-style' | 'cdn-style';\n comments?: 'strip' | 'c-style' | 'cdn-style';\n}\n\n/**\n * Whether comments should be emitted for freshly-regenerated output (as\n * opposed to a preserved app-sequence/raw-tag source — see\n * `decideTaggedAppSeqRendering`'s own comment handling for that case, which\n * has a different \"nothing set\" default).\n *\n * `preserveComments: true` always emits (verbatim); otherwise, comments are\n * emitted only when `comments` requests a real style (not `'strip'`,\n * the default when unset) — matching the deprecated `preserveComments:\n * 'c-style'/'cdn-style'` shorthand, which behaves the same as `comments`\n * set to that value.\n */\nexport function shouldEmitComments(\n options: CommentOptions | undefined\n): boolean {\n if (options?.preserveComments === true) return true;\n if (typeof options?.preserveComments === 'string') return true;\n return options?.comments !== undefined && options.comments !== 'strip';\n}\n\n/**\n * The marker style to normalize emitted comments to, or `undefined` for\n * verbatim (original markers kept as-is). Only meaningful when\n * `shouldEmitComments` is `true`; see its doc for the on/off precedence.\n */\nexport function resolveCommentStyle(\n options: CommentOptions | undefined\n): 'c-style' | 'cdn-style' | undefined {\n if (options?.preserveComments === true) return undefined;\n if (typeof options?.preserveComments === 'string')\n return options.preserveComments;\n const style = options?.comments;\n return style === 'strip' ? undefined : style;\n}\n\n/**\n * Convert a single comment's text to the requested marker style.\n *\n * Conversion table:\n * c-style : `#` → `//`, `/ … /` → `/* … *\\/`\n * cdn-style: `//` → `#`, `/* … *\\/` → `/ … /`\n *\n * Special case for cdn-style: when the inner content of `/* … *\\/` starts\n * with `*` or `/` the result would look like `/*…` or `//…` — a different\n * comment form. A single space is inserted after the opening `/` to prevent\n * this (e.g. `/**…*\\/` → `/ *…/`).\n */\nexport function convertCommentText(\n comment: CborComment,\n style: 'c-style' | 'cdn-style' | undefined\n): string {\n if (!style) return comment.text;\n const { marker, text } = comment;\n\n if (style === 'c-style') {\n if (marker === '#') return '//' + text.slice(1);\n if (marker === '/') return '/*' + text.slice(1, -1) + '*/';\n return text; // already // or /*...*/\n }\n\n // cdn-style\n if (marker === '//') return '#' + text.slice(2);\n if (marker === '/*') {\n const inner = text.slice(2, -2);\n // / … / comments have no escape mechanism for '/', so if the content\n // contains one we must keep the /* … */ form to avoid corrupting output.\n if (inner.includes('/')) return text;\n const safeInner =\n inner.startsWith('*') || inner.startsWith('/') ? ' ' + inner : inner;\n return '/' + safeInner + '/';\n }\n return text; // already # or /.../\n}\n\n/**\n * Bucket a flat, source-ordered list of comments (typically a node's own\n * `comments.dangling`) by which gap between two consecutive `parts` each\n * one's offset falls into — `result[i]` sits between `parts[i]` and\n * `parts[i + 1]`, already converted to the requested marker style.\n *\n * Used for a comment that sits between two `+`-joined fragments merged into\n * a single value with no per-fragment AST node of its own to attach to (a\n * concatenated `CborByteString`'s own `ednParts`, or — inside a bytes\n * elision — a `CborEllipsis` item's `ednParts`): `attachComments` can only\n * land such a comment on the merged node as a whole, as `dangling`, so this\n * re-derives which specific gap it belongs in from each part's own\n * `start`/`end` span. A comment is dropped (as it already was before this\n * function existed) when either neighbouring part lacks a known span — a\n * part merged from a single elided literal's own internal segments, which\n * cannot have a comment between them anyway (see `_elidedHexAtoms`).\n *\n * Returns `undefined` (rather than an all-empty array) when nothing landed\n * in any gap, so callers can cheaply skip the mid-comment rendering path\n * entirely in the common case.\n */\nexport function danglingCommentsByGap(\n dangling: readonly CborComment[] | undefined,\n parts: readonly { start?: number; end?: number }[] | undefined,\n style: 'c-style' | 'cdn-style' | undefined\n): string[][] | undefined {\n if (!dangling || dangling.length === 0 || !parts || parts.length < 2)\n return undefined;\n const gaps: string[][] = parts.slice(1).map(() => []);\n let anyFound = false;\n for (const comment of dangling) {\n for (let i = 0; i < parts.length - 1; i++) {\n const prevEnd = parts[i]!.end;\n const nextStart = parts[i + 1]!.start;\n if (\n prevEnd !== undefined &&\n nextStart !== undefined &&\n comment.start >= prevEnd &&\n comment.end <= nextStart\n ) {\n gaps[i]!.push(convertCommentText(comment, style));\n anyFound = true;\n break;\n }\n }\n }\n return anyFound ? gaps : undefined;\n}\n\n/**\n * Split an item's leading comments into ones that get their own line above\n * it, and a trailing run of comments the parser found on the same source\n * line as the item itself (`CborComment.sameLine`) — e.g.\n * `/ protected / << ... >>,` in an RFC 9052-style annotated array. Since\n * comments and the item they lead up to appear in strictly increasing\n * source order, `sameLine` comments always form a contiguous run at the end\n * of the list (nothing can sit between a same-line comment and the item\n * without itself being on that same line).\n *\n * `ownLines` renders like `formatLeadingComments` used to; `inlinePrefix` is\n * meant to be prepended directly to the item's own rendered line (already\n * includes a trailing space per comment, or `''` when there is none).\n */\nexport function splitLeadingComments(\n item: Commented,\n indent: string,\n style?: 'c-style' | 'cdn-style' | undefined\n): { ownLines: string[]; inlinePrefix: string } {\n const leading = item.comments?.leading ?? [];\n let splitAt = leading.length;\n while (splitAt > 0 && leading[splitAt - 1]!.sameLine) splitAt--;\n return {\n ownLines: leading\n .slice(0, splitAt)\n .map((comment) => indent + convertCommentText(comment, style)),\n inlinePrefix: leading\n .slice(splitAt)\n .map((comment) => convertCommentText(comment, style) + ' ')\n .join(''),\n };\n}\n\nexport function formatTrailingComments(\n item: Commented,\n style?: 'c-style' | 'cdn-style' | undefined\n): string {\n const comments = item.comments?.trailing ?? [];\n if (comments.length === 0) return '';\n return (\n ' ' +\n comments.map((comment) => convertCommentText(comment, style)).join(' ')\n );\n}\n\nexport function formatDanglingComments(\n item: Commented,\n indent: string,\n style?: 'c-style' | 'cdn-style' | undefined\n): string[] {\n return (item.comments?.dangling ?? []).map(\n (comment) => indent + convertCommentText(comment, style)\n );\n}\n\n// ─── Comma / separator helpers ────────────────────────────────────────────────\n\n/**\n * Resolve separator options into concrete strings.\n *\n * @param compact - When `true` (no `indent` option), omit spaces around\n * separators to produce compact single-line output (like `JSON.stringify`).\n *\n * @returns\n * - `inlineSep` – between items on a single line\n * - `multilineSep` – appended after each non-last line in multi-line mode\n * - `trailSep` – appended after the last item (empty string or `,`)\n * - `colSep` – between map key and value (`': '` or `':'`)\n */\nexport function resolveSeparators(\n options: ToCDNOptions | undefined,\n compact = false\n): {\n inlineSep: string;\n multilineSep: string;\n trailSep: string;\n colSep: string;\n} {\n const commas = options?.commas ?? 'comma';\n const useCommas = commas !== 'none';\n const trailing = commas === 'trailing';\n return {\n inlineSep: useCommas ? (compact ? ',' : ', ') : ' ',\n multilineSep: useCommas ? ',' : '',\n trailSep: trailing ? ',' : '',\n colSep: compact ? ':' : ': ',\n };\n}\n\n// ─── Container serialization ─────────────────────────────────────────────────\n\n/**\n * Shared CDN serialization for bracketed containers (CborArray / CborMap /\n * indefinite-length string chunks `(_ ...)`):\n * encoding-indicator / `_` prefix resolution, single-line vs multi-line\n * selection, separators, and per-entry leading/trailing plus container\n * dangling comments. Single-line output (no `indent`) always strips\n * comments — line comments can only be terminated by a newline.\n *\n * Entries are accessed through per-index callbacks (not materialised entry\n * objects) so the common no-comments/no-blank-line path allocates nothing\n * per entry. `hasEntryComments` and `entryTrailing` are consulted only when\n * `preserveComments` is set; `entryLeadingNode` is also consulted when\n * `preserveBlankLines` is set, independently of `preserveComments`, to read\n * its `blankLineBefore` flag. `renderEntry` receives the resolved `colSep`\n * (': ' or ':' depending on compact mode) for rendering map pairs.\n */\nexport function serializeContainer(p: {\n node: Commented;\n options: ToCDNOptions | undefined;\n depth: number;\n openChar: string;\n closeChar: string;\n count: number;\n indefiniteLength: boolean;\n /**\n * Whether an indefinite-length container shows the `_` marker\n * (`(_ \"a\", \"b\")`) before its content. Defaults to `true`; set `false` for\n * a container that denotes an indefinite-length value through some other\n * notation entirely (e.g. `ilts<<\"a\", \"b\">>`) rather than through the\n * `_`-marked legacy streamstring form — the value is still genuinely\n * indefinite-length (so `indefiniteLength: true` still correctly\n * suppresses any encoding-width suffix, which has no meaning for it), but\n * that other notation has no `_` marker of its own to show.\n */\n indefiniteMarker?: boolean;\n encodingWidth: EncodingWidth | undefined;\n /**\n * Where the resolved encoding-indicator suffix is placed.\n * - `'open'` (default): right after `openChar`, before the content\n * (`[_2 1,2,3]`) — the head this indicator describes encodes entry count.\n * - `'close'`: right after `closeChar`, with no separating space\n * (`<<1,2>>_1`) — for `CborEmbeddedCBOR`, whose byte-string head encodes\n * content byte length, not entry count.\n */\n eiPosition?: 'open' | 'close';\n /**\n * Basis for canonical-encoding-width detection (`encodingIndicators:\n * 'auto'`/`'always'` with no explicit `encodingWidth`). Defaults to\n * `count`, matching the CBOR array/map head. `CborEmbeddedCBOR` overrides\n * this to its encoded content's byte length instead.\n */\n canonicalCount?: () => bigint;\n /**\n * Whether entry `i` structurally has any captured comments (parse-time\n * presence only — not whether they'll actually be shown; see `hasComments`\n * in the implementation, which additionally consults `entryOptions(i)` so\n * an entry whose own override hides its comments doesn't force multi-line\n * layout, and an entry whose own override *shows* comments the container's\n * own `preserveComments` would otherwise hide still gets the chance to).\n */\n hasEntryComments: (i: number) => boolean;\n /** Render entry `i` at child depth (`item` or `key: value`). */\n renderEntry: (i: number, colSep: string) => string;\n /**\n * Whether entry `i` contains no nested array/map, so it may stay on the\n * container's line under `inlineLeafContainers` (or always, when\n * `alwaysInlineLeaf` is set). Omitted = always a leaf (used by\n * `CborEmbeddedCBOR`, where an entry that is itself a container still\n * inlines as long as its own rendering fits on one line).\n */\n entryIsLeaf?: (i: number) => boolean;\n /**\n * Whether entry `i` is, or wraps, a text string or byte string with two or\n * more words (`isMultiWordText` / `isMultiWordByteString`). When true,\n * disqualifies the container from staying on one line under\n * `inlineLeafContainers` (or `alwaysInlineLeaf`) even though the entry has\n * no nested array/map — a multi-word string reads better with a line of\n * its own. This does *not* also cover a prefixed literal like `h'...'`\n * (which has no word count to check at all, but still disqualifies under\n * the strict rule) — that's covered separately, generically, by\n * `isPrefixedLiteralText` (checked against the rendered entry `s` below)\n * or, for a `CborTag`, `isMultiWordRenderedLiteral`. Omitted = never\n * disqualifies.\n */\n entryIsMultiWordText?: (i: number) => boolean;\n /**\n * Always run the one-line collapse probe, regardless of\n * `options.inlineLeafContainers`. Set only by `CborEmbeddedCBOR`\n * (`<<...>>`): unlike `CborArray`/`CborMap`, where spreading entries one\n * per line is a deliberate structural default that `inlineLeafContainers`\n * opts out of, a flat sequence of encoded items has no such structure to\n * display — there's nothing gained by always breaking it, so it\n * collapses onto one line whenever it fits independent of the option.\n * Indefinite-length string groups (`(_ \"a\", \"b\")`) do *not* get this\n * treatment — they follow CborArray/CborMap's option-gated default\n * instead, providing `entryIsLeaf` the same way (see `strict` below),\n * despite also being a \"loose rule\" container in the\n * `_containsCdnContainer`/`entryHasContainer` sense (a chunk can never\n * actually be an array/map, so that distinction is moot for them in\n * practice). This flag and the loose/strict distinction are genuinely\n * independent concerns, not the same thing.\n */\n alwaysInlineLeaf?: boolean;\n /** Node whose leading comments are emitted above entry `i` (item / map key). */\n entryLeadingNode: (i: number) => Commented;\n /** Pre-formatted trailing comment text for entry `i` (starts with ' ', or ''). */\n entryTrailing: (\n i: number,\n style: 'c-style' | 'cdn-style' | undefined\n ) => string;\n /**\n * Per-entry options for entry `i`'s own comment handling (whether to\n * emit its comments at all, and in which style) — distinct from\n * `options` above, which still governs the container-wide layout\n * decisions (single-line vs multi-line, `hasComments`'s own gate, the\n * container's own dangling comments). Omitted when the caller never\n * resolves per-entry options at all (`toCDN()`'s `itemOptions` isn't in\n * play), in which case every entry falls back to `options` — identical\n * to this parameter not existing.\n */\n entryOptions?: (i: number) => ToCDNOptions | undefined;\n}): string {\n const { options, depth, openChar, closeChar, count } = p;\n const indentStr = resolveIndent(options);\n const preserveComments = shouldEmitComments(options);\n const commentStyle = resolveCommentStyle(options);\n // Whether *any* comment will actually end up visible — not merely\n // captured — decides whether to go multi-line at all. The container's own\n // layout comments (its dangling comments) follow the container-wide\n // `options`, same as their own emission below; each entry's own captured\n // comments are only counted when that entry's own resolved options (see\n // `entryOptions`) would actually show them, so an override hiding the one\n // entry that has comments doesn't force an otherwise-pointless multi-line\n // layout, and an override showing comments for one entry still triggers\n // multi-line layout even when the container-wide `preserveComments` alone\n // would not have.\n let anyEntryHasVisibleComments = false;\n if (indentStr !== null) {\n for (let i = 0; i < count; i++) {\n if (\n p.hasEntryComments(i) &&\n shouldEmitComments(p.entryOptions ? p.entryOptions(i) : options)\n ) {\n anyEntryHasVisibleComments = true;\n break;\n }\n }\n }\n const hasComments =\n indentStr !== null &&\n ((preserveComments && hasContainerLayoutComments(p.node)) ||\n anyEntryHasVisibleComments);\n const preserveBlankLines =\n indentStr !== null && !!options?.preserveBlankLines;\n let hasBlankLines = false;\n if (preserveBlankLines) {\n for (let i = 0; i < count; i++) {\n if (p.entryLeadingNode(i).blankLineBefore) {\n hasBlankLines = true;\n break;\n }\n }\n }\n const { inlineSep, multilineSep, trailSep, colSep } = resolveSeparators(\n options,\n indentStr === null\n );\n const eiPosition = p.eiPosition ?? 'open';\n const eiRaw = p.indefiniteLength\n ? ''\n : resolveEiSuffix(options, p.encodingWidth, () =>\n canonicalEncodingWidth(\n p.canonicalCount ? p.canonicalCount() : BigInt(count)\n )\n );\n const eiSuffix = eiPosition === 'open' && eiRaw ? eiRaw + ' ' : '';\n const closeSuffix = eiPosition === 'close' ? eiRaw : '';\n const showIndef =\n p.indefiniteLength &&\n (p.indefiniteMarker ?? true) &&\n (options?.encodingIndicators ?? 'auto') !== 'never';\n\n const singleLine = (inner: string): string => {\n if (p.indefiniteLength) {\n return showIndef\n ? count === 0\n ? `${openChar}_ ${closeChar}`\n : `${openChar}_ ${inner}${closeChar}`\n : `${openChar}${inner}${closeChar}`;\n }\n return `${openChar}${eiSuffix}${inner}${closeChar}${closeSuffix}`;\n };\n\n if (indentStr === null || (count === 0 && !hasComments)) {\n // single-line\n let inner = '';\n for (let i = 0; i < count; i++) {\n if (i > 0) inner += inlineSep;\n inner += p.renderEntry(i, colSep);\n }\n return singleLine(inner);\n }\n\n // inlineLeafContainers: keep the container on one line when no entry holds\n // a nested array/map, no entry is a multi-word string, and every entry\n // renders without a line break. `alwaysInlineLeaf` runs the same probe\n // unconditionally (see its doc) — the container-specific option value\n // doesn't otherwise change what the probe checks.\n // Entries rendered here via `renderEntry` are reused below if the probe\n // fails, so *this* function never calls `renderEntry` more than once per\n // entry per parent render. This doesn't extend to what `entryIsLeaf`/\n // `entryIsMultiWordText` do internally, though: `CborTag`'s\n // `_isMultiWordText` deliberately renders `this.content` once here (via\n // its prefixed-literal fallback) and `renderEntry` renders it again for\n // real — an accepted double-render, not an oversight (see CborTag.ts for\n // why an instance-level cache to avoid it turned out to be unsafe).\n let probed: string[] | null = null;\n if (\n (options?.inlineLeafContainers || p.alwaysInlineLeaf) &&\n count > 0 &&\n !hasComments &&\n !hasBlankLines\n ) {\n // `entryIsLeaf`'s presence doubles as the strict/loose signal here:\n // CborArray/CborMap and the indefinite-length string groups (the\n // strict rule) all provide it — only CborEmbeddedCBOR (the one\n // container whose collapse isn't gated behind `inlineLeafContainers`\n // at all) omits it. Reused below to gate `isPrefixedLiteralText`\n // (and, for a `CborTag`, `isMultiWordRenderedLiteral`'s equivalent\n // gating): a prefixed literal like `h'...'` disqualifies under the\n // strict rule but is an ordinary leaf under the loose one — e.g.\n // `<<h'00'>>` stays inline, but `(_ h'00')`/`[h'00']` still disqualify.\n const strict = !!p.entryIsLeaf;\n const rendered: string[] = [];\n let flat = true;\n for (let i = 0; i < count; i++) {\n if (p.entryIsLeaf && !p.entryIsLeaf(i)) {\n flat = false;\n break;\n }\n if (p.entryIsMultiWordText?.(i)) {\n flat = false;\n break;\n }\n const s = p.renderEntry(i, colSep);\n rendered.push(s);\n if (s.includes('\\n')) {\n flat = false;\n break;\n }\n if (strict && isPrefixedLiteralText(s)) {\n flat = false;\n break;\n }\n }\n if (flat) return singleLine(rendered.join(inlineSep));\n probed = rendered;\n }\n\n // multi-line\n const childIndent = indentOf(indentStr, depth + 1);\n const closeIndent = indentOf(indentStr, depth);\n const open = p.indefiniteLength\n ? showIndef\n ? `${openChar}_ `\n : openChar\n : `${openChar}${eiSuffix}`;\n const lines: string[] = [];\n for (let i = 0; i < count; i++) {\n if (preserveBlankLines && p.entryLeadingNode(i).blankLineBefore) {\n lines.push('');\n }\n // Entry `i`'s own comment handling — whether to emit at all, and in\n // which style — comes from *its own* resolved options (see\n // `entryOptions`), not the container-wide `preserveComments`/\n // `commentStyle` above, so an `itemOptions` override on this one entry\n // (e.g. `{ preserveComments: false, comments: 'strip' }`) takes effect\n // for it specifically.\n const ePreserveComments = shouldEmitComments(\n p.entryOptions ? p.entryOptions(i) : options\n );\n const eCommentStyle = resolveCommentStyle(\n p.entryOptions ? p.entryOptions(i) : options\n );\n let inlinePrefix = '';\n if (ePreserveComments) {\n const { ownLines, inlinePrefix: prefix } = splitLeadingComments(\n p.entryLeadingNode(i),\n childIndent,\n eCommentStyle\n );\n pushAll(lines, ownLines);\n inlinePrefix = prefix;\n }\n const sep = i < count - 1 ? multilineSep : trailSep;\n const entry = probed?.[i] ?? p.renderEntry(i, colSep);\n lines.push(\n `${childIndent}${inlinePrefix}${entry}${sep}${ePreserveComments ? p.entryTrailing(i, eCommentStyle) : ''}`\n );\n }\n if (preserveComments)\n pushAll(lines, formatDanglingComments(p.node, childIndent, commentStyle));\n const body = lines.join('\\n');\n return `${open}\\n${body}\\n${closeIndent}${closeChar}${closeSuffix}`;\n}\n\n/**\n * Single-child counterpart to `serializeContainer`, for a wrapper that\n * holds exactly one child inside `openChar`/`closeChar` (currently just\n * `CborTag`'s `(content)`) rather than a comma-separated list of entries.\n *\n * Emits the child's own leading/trailing comments, and the wrapper node's\n * `dangling` comments (a comment positioned after the child but still\n * inside the brackets, with nothing following it to attach to as leading —\n * mirroring how `serializeContainer` handles a container's own dangling\n * comments). Falls back to the plain single-line `(content)` form — the\n * common, zero-allocation-beyond-string-concat path — when comments aren't\n * requested/applicable (no indent, no `preserveComments`, or neither the\n * child nor the wrapper has any).\n *\n * `renderChild` is called with the child's depth exactly once, resolved\n * *before* calling it: `depth + 1` when comments force multi-line\n * rendering, `depth` otherwise (matching a plain value's existing\n * \"transparent\" nesting — `tag(content)` doesn't indent `content` an extra\n * level when there's nothing to justify going multi-line for).\n *\n * `childOptions` — the child's own resolved options, distinct from\n * `options` (the wrapper's) when `toCDN()`'s `itemOptions` has overridden\n * something for the child specifically (see `CborTag._toCDN`) — governs\n * only the child's *own* leading/trailing comments (whether to show them\n * at all, and in which style); `options` still governs whether to go\n * multi-line at all and the wrapper's own dangling comments, the same way\n * `serializeContainer`'s container-wide `options` does for its own\n * dangling comments even when its `entryOptions` resolves per-entry ones.\n */\nexport function renderSingleChildWithComments(\n child: Commented,\n wrapper: Commented,\n options: ToCDNOptions | undefined,\n childOptions: ToCDNOptions | undefined,\n depth: number,\n renderChild: (childDepth: number) => string,\n openChar: '(',\n closeChar: ')'\n): string {\n const indentStr = resolveIndent(options);\n const preserveComments = shouldEmitComments(options);\n const childShowsComments = shouldEmitComments(childOptions);\n // Same \"actually visible, not merely captured\" gate as\n // `serializeContainer`'s own `hasComments` — the wrapper's own (dangling)\n // comments follow the wrapper-level `options`, while the child's own\n // leading/trailing comments follow the child's own resolved `childOptions`\n // (see `CborTag._toCDN`), so an override hiding the child's comments while\n // the wrapper has none of its own collapses back to the single-line form,\n // and one showing the child's comments still goes multi-line even when\n // the wrapper-level `options` alone would not have.\n const hasComments =\n indentStr !== null &&\n ((childShowsComments && hasPreservedComments(child)) ||\n (preserveComments && hasContainerLayoutComments(wrapper)));\n if (!hasComments) return `${openChar}${renderChild(depth)}${closeChar}`;\n const commentStyle = resolveCommentStyle(options);\n const childCommentStyle = resolveCommentStyle(childOptions);\n const childIndent = indentOf(indentStr!, depth + 1);\n const closeIndent = indentOf(indentStr!, depth);\n const { ownLines, inlinePrefix } = childShowsComments\n ? splitLeadingComments(child, childIndent, childCommentStyle)\n : { ownLines: [] as string[], inlinePrefix: '' };\n const lines = [\n ...ownLines,\n `${childIndent}${inlinePrefix}${renderChild(depth + 1)}${childShowsComments ? formatTrailingComments(child, childCommentStyle) : ''}`,\n ...(preserveComments\n ? formatDanglingComments(wrapper, childIndent, commentStyle)\n : []),\n ];\n return `${openChar}\\n${lines.join('\\n')}\\n${closeIndent}${closeChar}`;\n}\n\n// ─── Byte string encoding ─────────────────────────────────────────────────────\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _hasNativeToBase64 =\n typeof (new Uint8Array(0) as any).toBase64 === 'function';\n\nfunction toBase64(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToBase64) return (bytes as any).toBase64({ omitPadding: true });\n let binary = '';\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/=/g, '');\n}\n\nfunction toBase64Url(bytes: Uint8Array): string {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (_hasNativeToBase64)\n return (bytes as any).toBase64({\n alphabet: 'base64url',\n omitPadding: true,\n });\n let binary = '';\n for (const b of bytes) binary += String.fromCharCode(b);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nconst B32_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';\nconst H32_ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUV';\n\nfunction base32Encode(bytes: Uint8Array, alpha: string): string {\n let result = '';\n let buf = 0,\n bufBits = 0;\n for (const b of bytes) {\n buf = (buf << 8) | b;\n bufBits += 8;\n while (bufBits >= 5) {\n bufBits -= 5;\n result += alpha[(buf >> bufBits) & 0x1f];\n }\n }\n if (bufBits > 0) result += alpha[(buf << (5 - bufBits)) & 0x1f];\n return result;\n}\n\n/**\n * Returns true if the string contains any C0 control character (U+0000–U+001F)\n * or DEL (U+007F).\n */\nfunction _hasNonPrintable(s: string): boolean {\n for (const char of s) {\n const cp = char.codePointAt(0)!;\n if (cp < 0x20 || cp === 0x7f) return true;\n }\n return false;\n}\n\n/**\n * The decoded text `bytes` would render as under a bare sqstr literal\n * (`'...'`) for the given `sqstr` option, or `null` when it would instead\n * render as a prefixed literal (`h'...'`, `b64'...'`, ...). Shared by\n * `serializeBytes` (the actual rendering decision) and `isMultiWordByteString`\n * (which needs to know the same thing without rendering).\n */\nfunction _sqstrTextOrNull(\n bytes: Uint8Array,\n sqstr?: 'printable-string' | 'string' | 'none'\n): string | null {\n if (sqstr === 'string') {\n const s = _tryDecodeUtf8(bytes);\n if (s != null) return s;\n }\n if (sqstr === 'printable-string' || sqstr === undefined) {\n const s = _tryDecodeUtf8(bytes);\n if (s != null && !_hasNonPrintable(s)) return s;\n }\n return null;\n}\n\nexport function serializeBytes(\n bytes: Uint8Array,\n encoding?: 'hex' | 'base64' | 'base64url' | 'base32' | 'base32hex',\n sqstr?: 'printable-string' | 'string' | 'none'\n): string {\n const sqstrText = _sqstrTextOrNull(bytes, sqstr);\n if (sqstrText !== null) return _escapeSingleQuoted(sqstrText);\n switch (encoding) {\n case 'base64':\n return `b64'${toBase64(bytes)}'`;\n case 'base64url':\n return `b64'${toBase64Url(bytes)}'`;\n case 'base32':\n return `b32'${base32Encode(bytes, B32_ALPHA)}'`;\n case 'base32hex':\n return `h32'${base32Encode(bytes, H32_ALPHA)}'`;\n case 'hex':\n default:\n return `h'${toHex(bytes)}'`;\n }\n}\n\n/**\n * True when `bytes` would render as a bare sqstr literal (`'...'`) under\n * `sqstr` *and* its decoded text has two or more words — same rule as a\n * plain text string's own word count. Otherwise (it would render as a\n * prefixed literal like `h'...'`/`b64'...'`, or as something else entirely\n * via a subclass overriding `_toCDN()`) this returns `false`: a prefixed\n * literal has no natural word boundary to predict from raw bytes alone,\n * and — unlike this function, which never renders anything — the actual\n * \"does the real output look like a disqualifying prefixed literal, tag\n * wrapping, or app-sequence spelling\" question is answered generically\n * from the *rendered* text instead, by `isPrefixedLiteralText` (for a bare\n * entry) or `isMultiWordRenderedLiteral` (for a `CborTag`, which needs to\n * see through its own digits/parens onto whatever they wrap).\n */\nexport function isMultiWordByteString(\n bytes: Uint8Array,\n sqstr?: 'printable-string' | 'string' | 'none'\n): boolean {\n const text = _sqstrTextOrNull(bytes, sqstr);\n return text !== null && isMultiWordText(text);\n}\n\n/** An identifier immediately followed by `'` or a backtick — see `isPrefixedLiteralText`. */\nconst PREFIXED_LITERAL_RE = /^[A-Za-z][A-Za-z0-9-]*['`]/;\n\n/**\n * True when `rendered` — a single entry's own CDN rendering — is shaped\n * like a prefixed literal: an identifier immediately followed by `'` or a\n * backtick (`h'...'`, `b64'...'`, `ip'...'`, `dt'...'`, or any other\n * app-string extension's own spelling, built-in or user-defined). These\n * have no natural word boundary to check, so — like a byte string's own\n * prefixed-literal case in `isMultiWordByteString` — the strict\n * `inlineLeafContainers` rule (`CborArray`/`CborMap`, and the\n * indefinite-length string groups) always disqualifies a container from\n * collapsing onto one line when an entry looks like this; the loose rule\n * (only `CborEmbeddedCBOR`/`<<...>>`) treats it as an ordinary leaf\n * instead.\n *\n * This is a generic, rendering-based catch-all — unlike `isMultiWordByteString`,\n * it doesn't need per-extension-class support, so it also covers any\n * app-string extension (registered under `CborExtension.appStringPrefixes`)\n * without that extension's own `CborItem` subclass needing to know about\n * `inlineLeafContainers` at all. It only sees a *bare* prefixed literal\n * (nothing else in `rendered`); `CborTag` uses `isMultiWordRenderedLiteral`\n * instead to see through its own tag digits/parens onto whatever they wrap.\n */\nexport function isPrefixedLiteralText(rendered: string): boolean {\n return PREFIXED_LITERAL_RE.test(rendered);\n}\n\nconst textDecoderForRenderedLiteral = new TextDecoder();\n\n/**\n * True when `rendered` — a leaf entry's own, already-rendered CDN text —\n * counts as multi-word for `inlineLeafContainers`'s purposes, determined by\n * tokenizing `rendered` itself rather than predicting from whichever\n * `CborItem` subclass produced it. This makes it exact regardless of *how*\n * the text came to look the way it does — a `CborTag` subclass\n * (`CborTaggedIpExt`) overriding `_toCDN()` to render `IP<<'...'>>` instead\n * of generic `52(...)` tag notation, a preserved `preserveByteString`\n * spelling, `encodingIndicators: 'always'` adding an explicit `_N`/`_i`\n * suffix everywhere, or anything else — since it never assumes a rendering\n * path, only reads the result.\n *\n * Recognizes these shapes. Any of them may be followed by one trailing\n * `ENCODING_INDICATOR` token (`_0`.._3`/`_i`) — stripped *before* any shape\n * is recognized (not just for a bare literal), since it can trail a tag or\n * an app-sequence wrapper too and never changes a value's own shape or\n * word count:\n * - A bare quoted literal (`\"...\"`, `` `...` ``, or a bare `'...'` sqstr):\n * always counts if its *decoded* content has two or more words,\n * regardless of `strict` — matching a text string's own word count.\n * - A prefixed literal (`h'...'`, `b64'...'`, `ip'...'`, `dt'...'`, ...):\n * has no natural word boundary to check, so it counts only when `strict`.\n * - A generic tag wrapper (`tagNum[_EI](...)`) spanning the *entire* input:\n * peels off just that one layer and recurses on what's inside (handling\n * nested tags one layer at a time) — this is what lets a plain `CborTag`\n * whose content is one of the shapes above still count, e.g.\n * `100(dt'...')`, `100(\"two words\")`, or (with `encodingIndicators:\n * 'always'`) `100_0(\"two words\"_i)`.\n * - An app-sequence wrapper (`prefix<<item item ...>>`, tokenized as one\n * `APP_SEQUENCE` opener and a plain `GT_GT` closer) spanning the *entire*\n * input: unlike a tag, its own `<<...>>` is never peeled away — reading\n * fine inline is the whole point of that notation, not a transparent\n * single-value rewrap — but each top-level item inside (items may be\n * separated by a comma, by whitespace alone, or both, per CDN's own\n * grammar — `consumeOneItem` finds each one's extent structurally rather\n * than only splitting at commas) is checked under the *loose* rule\n * (`strict: false`, matching `<<...>>` itself) regardless of the\n * `strict` this function was called with, so a multi-word text item\n * (`ilts<<\"two words\">>`, or `ilts<<\"two words\" \"x\">>` with no comma at\n * all) still always counts, while a prefixed-literal item\n * (`ilbs<<h'00'>>`) — unlike the same literal bare or tag-wrapped —\n * does not.\n * - Anything else (a number, `true`/`false`, multiple top-level tokens that\n * aren't one of the wrappers above, ...) never counts.\n *\n * Tokenizing can throw on malformed input; since `rendered` is always this\n * library's own output, that should never happen, but a failure is treated\n * as \"not multi-word\" rather than propagating.\n */\nexport function isMultiWordRenderedLiteral(\n rendered: string,\n strict: boolean\n): boolean {\n let tokens: Token[];\n try {\n tokens = tokenizeAll(rendered);\n } catch {\n return false;\n }\n return isMultiWordTokenRange(tokens, 0, tokens.length, strict);\n}\n\nfunction tokenizeAll(source: string): Token[] {\n const tokenizer = new Tokenizer(source);\n const tokens: Token[] = [];\n for (;;) {\n const token = tokenizer.consume();\n if (token.type === 'EOF') return tokens;\n tokens.push(token);\n }\n}\n\n// Token types that open/close a bracket-like span. A single, type-agnostic\n// depth counter is safe for matching (no need to verify e.g. RPAREN closes\n// specifically an LPAREN) because `rendered` is always this library's own,\n// already-well-formed output — bracket families never interleave in valid\n// CDN, so a generic opener/closer never has to disambiguate which family\n// it belongs to.\nconst BRACKET_OPENERS = new Set([\n 'LPAREN',\n 'LBRACKET',\n 'LBRACE',\n 'LT_LT',\n 'APP_SEQUENCE',\n]);\nconst BRACKET_CLOSERS = new Set(['RPAREN', 'RBRACKET', 'RBRACE', 'GT_GT']);\n\n// Token types that can appear as any part — the chain's own first value,\n// or any later one joined by `+` — of a `+`-concatenation chain: a\n// text-string/byte-string literal (draft-25 §5.1), or `ELLIPSIS` (`...`), CDN's\n// elision-chain notation (src/cdn/parser.ts's own `+`-chain grammar\n// accepts it both as the chain's *own* first value — `... + \"b\"`, an\n// unknown prefix concatenated with a known suffix — and as any later\n// continuation — `\"a\" + ...` — building a tag-888-wrapped value instead of\n// a plain joined string) for a part deliberately omitted. Never numbers,\n// tags, containers, or app-strings.\nconst CHAIN_ATOM_TYPES = new Set([\n 'TSTR',\n 'RAWSTRING',\n 'SQSTR',\n 'BYTES_HEX',\n 'BYTES_HEX_ELIDED',\n 'BYTES_B64',\n 'ELLIPSIS',\n]);\n\n/**\n * Index of the token that closes the bracket opened at `openIdx`, scanning\n * up to (excluding) `end`. Returns `null` if unmatched in range.\n */\nfunction findMatchingClose(\n tokens: Token[],\n openIdx: number,\n end: number\n): number | null {\n let depth = 1;\n for (let j = openIdx + 1; j < end; j++) {\n const t = tokens[j].type;\n if (BRACKET_OPENERS.has(t)) depth++;\n else if (BRACKET_CLOSERS.has(t)) {\n depth--;\n if (depth === 0) return j;\n }\n }\n return null;\n}\n\n/**\n * Index one past the end of the single CDN value starting at `start`\n * (scanning up to, exclusive, `end`), or `null` if `start` isn't the start\n * of a recognizable value at all (`end <= start`). This mirrors CDN's\n * value grammar shape closely enough to find an item's own extent without\n * knowing its specific semantic type — needed because app-sequence (and\n * array/map) items may be separated by a comma *or* by nothing but\n * whitespace (which leaves no token of its own), so finding the next\n * item's start means first walking to the end of the current one:\n * - `INTEGER [ENCODING_INDICATOR] LPAREN ... RPAREN` (a tag) — consumes\n * the whole bracketed span.\n * - Any other bracket opener (`(`, `[`, `{`, `<<`, an app-sequence) —\n * consumes its whole matching span, then one trailing\n * `ENCODING_INDICATOR` if present (e.g. `[1, 2]_1`, `<<1, 2>>_1`).\n * - Anything else — a single atom token (`TSTR`, `BYTES_HEX`, `SIMPLE`,\n * `FLOAT`, ...), then one trailing `ENCODING_INDICATOR` if present. If\n * that atom is a `CHAIN_ATOM_TYPES` member (a string/byte-string literal,\n * or an elision-chain `ELLIPSIS`) and is followed by `PLUS`, the whole\n * `+`-concatenation chain (`\"a\" + \"b\" + h'63'`, `\"a\" + ...`, `... + \"b\"`,\n * ...) is consumed as this one item — a chain never continues past any\n * other atom. **Except**: when the chain's own first atom is `ELLIPSIS`,\n * `src/cdn/parser.ts`'s grammar reads each `+`-joined continuation via\n * its *general* value parser (`parseValue()`), not the restricted\n * string/byte-literal-only rule that governs every other chain — so\n * `... + (_ \"a\")`, `... + [1, 2]`, `... + 100(2)`, even `... + ...`, are\n * all valid, and each continuation's extent is found by recursing into\n * this same function instead of checking `CHAIN_ATOM_TYPES` membership.\n */\nfunction consumeOneItem(\n tokens: Token[],\n start: number,\n end: number\n): number | null {\n if (start >= end) return null;\n if (tokens[start].type === 'INTEGER') {\n let p = start + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n if (p < end && tokens[p].type === 'LPAREN') {\n const close = findMatchingClose(tokens, p, end);\n return close !== null ? close + 1 : null;\n }\n return p;\n }\n if (BRACKET_OPENERS.has(tokens[start].type)) {\n const close = findMatchingClose(tokens, start, end);\n if (close === null) return null;\n let p = close + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n return p;\n }\n let p = start + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n\n if (tokens[start].type === 'ELLIPSIS') {\n // An elision-chain start: each continuation after a `+` may be *any*\n // value shape (a tag, container, indefinite-length string group,\n // app-sequence, a nested ellipsis chain, ...), not just a string/byte\n // literal — so find its extent generically by recursing, rather than\n // checking `CHAIN_ATOM_TYPES` membership the way every other chain\n // shape does below.\n while (p < end && tokens[p].type === 'PLUS') {\n const nextEnd = consumeOneItem(tokens, p + 1, end);\n if (nextEnd === null) return null;\n p = nextEnd;\n }\n return p;\n }\n\n const isChainable = CHAIN_ATOM_TYPES.has(tokens[start].type);\n while (isChainable && p < end && tokens[p].type === 'PLUS') {\n const nextStart = p + 1;\n if (nextStart >= end || !CHAIN_ATOM_TYPES.has(tokens[nextStart].type)) {\n return null; // trailing `+` with nothing after, or a malformed chain\n }\n p = nextStart + 1;\n if (p < end && tokens[p].type === 'ENCODING_INDICATOR') p++;\n }\n return p;\n}\n\n/**\n * Splits `tokens[start:end)` into top-level item ranges — items may be\n * separated by a comma, by whitespace alone (no token at all), or both\n * (a comma with incidental whitespace around it, which the tokenizer\n * already discards) — per CDN's own array/app-sequence grammar. Returns\n * `[]` if any item's own extent can't be determined (`consumeOneItem`\n * failed to find a bracket's matching close within range), rather than\n * guess at wrong boundaries.\n */\nfunction splitTopLevelItems(\n tokens: Token[],\n start: number,\n end: number\n): [number, number][] {\n const items: [number, number][] = [];\n let p = start;\n while (p < end) {\n const itemEnd = consumeOneItem(tokens, p, end);\n if (itemEnd === null) return [];\n items.push([p, itemEnd]);\n p = itemEnd;\n if (p < end && tokens[p].type === 'COMMA') p++;\n }\n return items;\n}\n\nfunction isMultiWordTokenRange(\n tokens: Token[],\n start: number,\n end: number,\n strict: boolean\n): boolean {\n if (end <= start) return false;\n\n // Strip a trailing encoding indicator up front, before checking for any\n // wrapper shape below — it can trail a bare literal, a tag wrapper\n // (`100(2)_1`, hypothetically), or an app-sequence wrapper\n // (`same<<\"two words\">>_i` is valid CDN: `same` resolves to a plain\n // TSTR, so its own EI can trail the `>>`) — and never changes any of\n // their shape or word count either way.\n let contentEnd = end;\n if (tokens[contentEnd - 1].type === 'ENCODING_INDICATOR') contentEnd--;\n\n // Tag wrapper: INTEGER [ENCODING_INDICATOR] LPAREN ... RPAREN spanning\n // the whole range — peel it and recurse on what's inside.\n if (tokens[start].type === 'INTEGER') {\n let i = start + 1;\n if (i < contentEnd && tokens[i].type === 'ENCODING_INDICATOR') i++;\n if (i < contentEnd && tokens[i].type === 'LPAREN') {\n const close = findMatchingClose(tokens, i, contentEnd);\n if (close !== null && close + 1 === contentEnd) {\n return isMultiWordTokenRange(tokens, i + 1, close, strict);\n }\n }\n }\n\n // App-sequence wrapper: prefix<< item item ... >> spanning the whole\n // range. Its own <<...>> is never peeled away (see doc above), but each\n // top-level item inside — separated by a comma, whitespace, or both — is\n // checked under the loose rule, matching how `<<...>>` itself always\n // treats its entries.\n if (tokens[start].type === 'APP_SEQUENCE') {\n const close = findMatchingClose(tokens, start, contentEnd);\n if (close !== null && close + 1 === contentEnd) {\n for (const [itemStart, itemEnd] of splitTopLevelItems(\n tokens,\n start + 1,\n close\n )) {\n if (isMultiWordTokenRange(tokens, itemStart, itemEnd, false)) {\n return true;\n }\n }\n return false;\n }\n }\n\n // `+`-concatenation chain spanning the whole range (`\"a\" + \"b\"`,\n // `h'00' + \"x\"`, `... + \"b\"`, ...) — CDN concatenation preserves each\n // part's own spelling rather than merging into one literal, so it's\n // never caught by the single-literal check below; it has to be\n // recognized as its own shape. A chain's *element type* is fixed by its\n // first part (draft-25 §5.1): a text-leading chain (`TSTR`/`RAWSTRING`/bare\n // `SQSTR` first — the same three types the single-literal switch below\n // checks by decoded word count rather than always-strict) decodes and\n // merges every part — including any prefixed byte-string-shaped parts,\n // which get UTF-8-decoded in per the same rule that lets `\"a\" + h'62'`\n // denote text `\"ab\"` — into one string, then checks *that* for word\n // count, matching what a single merged text literal would report. An\n // elision chain (`ELLIPSIS` first — `... + \"b\"`, an unknown prefix\n // concatenated with a known suffix) is handled the *same* way: the\n // merge-and-decode attempt fails immediately (an `ELLIPSIS` part always\n // decodes to `null`), so the combined word count always comes back\n // \"unknown\" — correctly indeterminate regardless of what visible parts\n // follow it, matching how a *continuation* `ELLIPSIS` already makes the\n // whole chain indeterminate (round 8). A byte-leading chain (first part\n // a prefixed `h'...'`/`b64'...'`) denotes a byte string; concatenation\n // never re-spells it as one bare `sqstr`, so rather than guess at the\n // combined bytes' printability it's treated like any other prefixed byte\n // literal — disqualifying only under the strict rule, same as a lone\n // `h'...'`/`b64'...'`.\n if (contentEnd - start > 1 && isPlusChainRange(tokens, start, contentEnd)) {\n if (\n tokens[start].type === 'TSTR' ||\n tokens[start].type === 'RAWSTRING' ||\n tokens[start].type === 'SQSTR' ||\n tokens[start].type === 'ELLIPSIS'\n ) {\n const merged = decodePlusChainText(tokens, start, contentEnd);\n return merged !== null && isMultiWordText(merged);\n }\n return strict;\n }\n\n // A single literal token (the encoding indicator, if any, was already\n // stripped above).\n if (contentEnd - start !== 1) return false;\n const token = tokens[start];\n switch (token.type) {\n case 'TSTR':\n case 'RAWSTRING':\n return isMultiWordText(token.value);\n case 'SQSTR': {\n const bytes = (token as SqstrToken)._sqstrBytes;\n return bytes !== undefined\n ? isMultiWordText(textDecoderForRenderedLiteral.decode(bytes))\n : false;\n }\n case 'BYTES_HEX':\n case 'BYTES_HEX_ELIDED':\n case 'BYTES_B64':\n case 'APP_STRING':\n return strict;\n default:\n return false;\n }\n}\n\n/**\n * Whether `tokens[start:end)` is exactly one `+`-concatenation chain (or a\n * single stringish literal) with nothing left over — reuses\n * `consumeOneItem`'s own chain-walking so the shape recognized here can\n * never drift from the shape it actually consumes as one item elsewhere.\n */\nfunction isPlusChainRange(\n tokens: Token[],\n start: number,\n end: number\n): boolean {\n return (\n CHAIN_ATOM_TYPES.has(tokens[start].type) &&\n consumeOneItem(tokens, start, end) === end\n );\n}\n\n/**\n * Decodes and concatenates every part of a `+`-concatenation chain spanning\n * `tokens[start:end)` into the single string it denotes, or `null` if any\n * part can't be decoded — `ELLIPSIS` (an elision-chain link with no content\n * of its own) and `BYTES_HEX_ELIDED` (missing data by construction) always\n * make the combined result unknowable; a malformed hex/base64 part\n * shouldn't happen in this library's own output but isn't assumed either.\n */\nfunction decodePlusChainText(\n tokens: Token[],\n start: number,\n end: number\n): string | null {\n let result = '';\n let i = start;\n for (;;) {\n const part = decodeStringishTokenText(tokens[i]);\n if (part === null) return null;\n result += part;\n i++;\n if (i < end && tokens[i].type === 'ENCODING_INDICATOR') i++;\n if (i < end && tokens[i].type === 'PLUS') {\n i++;\n continue;\n }\n break;\n }\n return i === end ? result : null;\n}\n\n/** Decodes a single stringish token to the text it denotes, or `null`. */\nfunction decodeStringishTokenText(token: Token): string | null {\n switch (token.type) {\n case 'TSTR':\n case 'RAWSTRING':\n return token.value;\n case 'SQSTR': {\n const bytes = (token as SqstrToken)._sqstrBytes;\n return bytes !== undefined\n ? textDecoderForRenderedLiteral.decode(bytes)\n : null;\n }\n case 'BYTES_HEX':\n try {\n return textDecoderForRenderedLiteral.decode(hexToBytes(token.value));\n } catch {\n return null;\n }\n case 'BYTES_B64':\n try {\n return textDecoderForRenderedLiteral.decode(base64ToBytes(token.value));\n } catch {\n return null;\n }\n case 'BYTES_HEX_ELIDED':\n // Ellipsis-elided hex is missing data by construction — the full\n // byte content (and thus decoded text) can't be recovered.\n return null;\n case 'ELLIPSIS':\n // An elision-chain link (`\"a\" + ...`) stands for a deliberately\n // omitted part — there's no content to decode at all, so the whole\n // chain's combined word count is unknowable, not just this part's.\n return null;\n default:\n return null;\n }\n}\n\n/**\n * Which comment syntax a byte-string literal's raw source recognizes —\n * `undefined` when it has none at all (its content is data, not a comment\n * host). Set once, at parse time, by whoever actually knows the literal's\n * real origin (the tokenizer for `h'...'`/`b64'...'`/bare sqstr, or the\n * parser comparing the resolved extension against the specific built-in\n * `b32`/`h32` objects by reference — never guessed later from the prefix\n * string, since a user extension can register under any prefix, including\n * one a built-in also uses; see `CborByteString.ednCommentSyntax`).\n * - `'full'`: `#`, `//`, `/* *\\/`, and `/ /` (§6.2.1/§6.3.3) — `h'...'`\n * and its backtick form, and the built-in `b32'...'`/`h32'...'`\n * extensions, which share hex's comment syntax (`utils/strip-comments.ts`).\n * - `'hash-only'`: only `#` line comments — standard base64 (`b64'...'`),\n * where `/` is valid data (e.g. `//8=` decodes to 0xFFFF), never a\n * comment marker (see Tokenizer._readByteContent, §6.2.2).\n */\nexport type ByteCommentSyntax = 'full' | 'hash-only';\n\n/**\n * Strip comments from inside a preserved byte-string literal's raw source,\n * keeping everything else — case, whitespace, `...` — untouched. Used when\n * `preserveByteString` is set but `preserveComments` is not: the preserved\n * spelling should still drop comments, the same as an unpreserved literal\n * re-derived from its decoded value would. `syntax` selects the comment\n * rules to apply (see `ByteCommentSyntax`); the caller is responsible for\n * knowing which one is correct — this function does not guess from `raw`.\n *\n * Only scans the quote-delimited content (not the prefix or a trailing\n * encoding-indicator suffix), and mirrors the tokenizer's own\n * comment-recognition closely enough for realistic input; a comment\n * containing a literal copy of the delimiter quote character is not\n * specially handled (the input is already known-valid, so at worst this\n * shifts where the content/comment boundary is drawn, never produces\n * unparseable output).\n */\nexport function stripByteLiteralComments(\n raw: string,\n syntax: ByteCommentSyntax\n): string {\n let open = 0;\n while (open < raw.length && raw[open] !== \"'\" && raw[open] !== '`') open++;\n if (open >= raw.length) return raw;\n const quote = raw[open];\n const close = raw.lastIndexOf(quote);\n if (close <= open) return raw;\n const content = raw.slice(open + 1, close);\n const stripped =\n syntax === 'hash-only'\n ? _stripHashOnlyComments(content)\n : _stripFullByteCommentSyntax(content);\n return raw.slice(0, open + 1) + stripped + raw.slice(close);\n}\n\n/** `#` line comments only — used by standard base64 (`b64'...'`). */\nfunction _stripHashOnlyComments(content: string): string {\n let out = '';\n let i = 0;\n while (i < content.length) {\n if (content[i] === '#') {\n while (i < content.length && content[i] !== '\\n') {\n i += content[i] === '\\\\' && i + 1 < content.length ? 2 : 1;\n }\n continue;\n }\n out += content[i];\n i++;\n }\n return out;\n}\n\n/**\n * `#`, `//`, `/* *\\/`, and `/ /` comments — used by `h'...'`/backtick raw hex\n * and extension-defined byte literals sharing that syntax (b32, h32, ...).\n */\nfunction _stripFullByteCommentSyntax(content: string): string {\n let out = '';\n let i = 0;\n while (i < content.length) {\n const ch = content[i];\n const next = content[i + 1];\n if (ch === '#' || (ch === '/' && next === '/')) {\n i += ch === '#' ? 1 : 2;\n while (i < content.length && content[i] !== '\\n') {\n i += content[i] === '\\\\' && i + 1 < content.length ? 2 : 1;\n }\n continue;\n }\n if (ch === '/' && next === '*') {\n const end = content.indexOf('*/', i + 2);\n i = end === -1 ? content.length : end + 2;\n continue;\n }\n if (ch === '/') {\n let j = i + 1;\n while (j < content.length && content[j] !== '/') {\n j += content[j] === '\\\\' && j + 1 < content.length ? 2 : 1;\n }\n i = j < content.length ? j + 1 : content.length;\n continue;\n }\n out += ch;\n i++;\n }\n return out;\n}\n\nconst _utf8Strict = new TextDecoder('utf-8', { fatal: true });\n\n/** Decode bytes as UTF-8; returns null if the bytes are not valid UTF-8. */\nfunction _tryDecodeUtf8(bytes: Uint8Array): string | null {\n try {\n return _utf8Strict.decode(bytes);\n } catch {\n return null;\n }\n}\n\n// ─── Text string escaping ─────────────────────────────────────────────────────\n\n/**\n * Core EDN string escaper.\n *\n * Produces a quoted literal delimited by `quote` (`\"` or `'`).\n * Iterates by Unicode code point so characters above U+FFFF are emitted as a\n * single character rather than two surrogate `\\uXXXX` escapes.\n *\n * Always escapes:\n * - the delimiter character itself\n * - `\\` (backslash)\n * - `\\n`, `\\r`, `\\t`\n * - U+0000–U+001F (C0 controls), U+007F (DEL)\n * - U+2028 / U+2029 (JS line terminators)\n * - U+200B–U+200D (zero-width characters), U+FEFF (BOM)\n */\n/**\n * Returns true if `s` contains any character that {@link _escapeQuoted}\n * would escape: the quote, backslash, C0 controls, DEL, U+2028/U+2029,\n * U+200B–U+200D, or U+FEFF. charCodeAt is safe here — every escaped\n * character is a single UTF-16 unit, and surrogate halves never match.\n */\nfunction _needsEscape(s: string, quoteCode: number): boolean {\n for (let i = 0; i < s.length; i++) {\n const cc = s.charCodeAt(i);\n if (cc === quoteCode || cc === 0x5c || cc < 0x20 || cc === 0x7f)\n return true;\n if (cc >= 0x2000) {\n if (\n cc === 0x2028 ||\n cc === 0x2029 ||\n (cc >= 0x200b && cc <= 0x200d) ||\n cc === 0xfeff\n )\n return true;\n }\n }\n return false;\n}\n\nfunction _escapeQuoted(s: string, quote: string): string {\n const quoteCP = quote.codePointAt(0)!;\n // Fast path: nothing to escape (the common case) — a single concatenation.\n if (!_needsEscape(s, quoteCP)) return quote + s + quote;\n let result = quote;\n for (const char of s) {\n const cp = char.codePointAt(0)!;\n switch (cp) {\n case quoteCP:\n result += `\\\\${quote}`;\n break;\n case 0x5c: // \\\n result += '\\\\\\\\';\n break;\n case 0x0a: // \\n\n result += '\\\\n';\n break;\n case 0x0d: // \\r\n result += '\\\\r';\n break;\n case 0x09: // \\t\n result += '\\\\t';\n break;\n default:\n if (\n cp < 0x20 ||\n cp === 0x7f ||\n cp === 0x2028 ||\n cp === 0x2029 ||\n cp === 0x200b ||\n cp === 0x200c ||\n cp === 0x200d ||\n cp === 0xfeff\n )\n result += `\\\\u${cp.toString(16).padStart(4, '0')}`;\n else result += char;\n }\n }\n return result + quote;\n}\n\n/** Produce a single-quoted EDN byte string literal `'...'` from a string value. */\nfunction _escapeSingleQuoted(s: string): string {\n return _escapeQuoted(s, \"'\");\n}\n\n/**\n * Produce a single-quoted EDN app-string content `'...'` from a string value.\n * Exported for use by app-extension `_toCDN` implementations.\n */\nexport function escapeAppString(s: string): string {\n return _escapeQuoted(s, \"'\");\n}\n\n/**\n * Produce an EDN double-quoted string literal `\"...\"` from a string value.\n */\nexport function escapeString(s: string): string {\n return _escapeQuoted(s, '\"');\n}\n\n// Locale pinned (rather than left to the host's default) so output is\n// deterministic across environments regardless of system locale — the word\n// dictionary for script-based languages (Japanese, Chinese, Thai, ...) is\n// selected by the text's own script either way, not by this locale tag.\nconst wordSegmenter = new Intl.Segmenter('en', { granularity: 'word' });\n\n/**\n * True when `value` contains two or more \"words\" per `Intl.Segmenter`'s\n * word-boundary rules (UAX #29): e.g. `\"Hello, World!\"` is two words (a\n * comma breaks them), `\"3.14\"` is one (a decimal point between digits\n * doesn't), and space-less scripts like Japanese/Chinese still split on\n * their own dictionary-based word boundaries. Used by `inlineLeafContainers`\n * to keep a multi-word string entry off the container's shared line even\n * when it would otherwise qualify as a leaf.\n */\nexport function isMultiWordText(value: string): boolean {\n let count = 0;\n for (const { isWordLike } of wordSegmenter.segment(value)) {\n if (!isWordLike) continue;\n count++;\n if (count >= 2) return true;\n }\n return false;\n}\n\n// ─── Float formatting ─────────────────────────────────────────────────────────\n\n/** Produce the numeric string for a float value (with decimal point if needed). */\nexport function floatValueToString(value: number): string {\n if (isNaN(value)) return 'NaN';\n if (!isFinite(value)) return value > 0 ? 'Infinity' : '-Infinity';\n if (Object.is(value, -0)) return '-0.0';\n const s = value.toString();\n // Ensure a decimal point is present to distinguish from CBOR integer types\n return s.includes('.') || s.includes('e') ? s : s + '.0';\n}\n\n/**\n * EDN encoding-indicator suffix for a float precision.\n * Returns '' when the auto-selected precision matches (no suffix needed) in auto mode.\n */\nexport function floatSuffix(\n _value: number,\n precision: 'half' | 'single' | 'double' | undefined,\n autoSelected: 'half' | 'single' | 'double',\n mode?: 'always' | 'auto' | 'never'\n): string {\n if (mode === 'never') return '';\n const actual = precision ?? autoSelected;\n if (mode === 'always')\n return actual === 'half' ? '_1' : actual === 'single' ? '_2' : '_3';\n // 'auto' (default)\n if (precision === undefined || precision === autoSelected) return '';\n return precision === 'half' ? '_1' : precision === 'single' ? '_2' : '_3';\n}\n\n/** Compute the canonical (minimum) CBOR encoding width for a non-negative integer argument. */\nexport function canonicalEncodingWidth(n: bigint): EncodingWidth {\n if (n <= 23n) return 'i';\n if (n <= 0xffn) return 0;\n if (n <= 0xffffn) return 1;\n if (n <= 0xffff_ffffn) return 2;\n return 3;\n}\n\n/**\n * Resolve the encoding-indicator suffix string (`''` or `'_N'`) based on\n * `options.encodingIndicators` and the item's recorded encoding width.\n *\n * @param options - toCDN options (may be undefined)\n * @param encodingWidth - width stored on the item (undefined = canonical)\n * @param getCanonical - lazily compute the canonical width (only called in 'always' mode)\n */\nexport function resolveEiSuffix(\n options: ToCDNOptions | undefined,\n encodingWidth: EncodingWidth | undefined,\n getCanonical: () => EncodingWidth\n): string {\n const mode = options?.encodingIndicators ?? 'auto';\n if (mode === 'never') return '';\n if (mode === 'always') return `_${encodingWidth ?? getCanonical()}`;\n return encodingWidth !== undefined ? `_${encodingWidth}` : '';\n}\n\n// ─── Comment handling for a preserved app-sequence/raw-tag source ────────────\n//\n// Different default than `shouldEmitComments`/`resolveCommentStyle` above:\n// leaving both `preserveComments` and `comments` unset here means \"don't\n// touch this spelling's comments at all\" (they stay exactly as originally\n// written, as part of the preserved text), not \"strip them\" — an *explicit*\n// request is required to edit them one way or the other.\n\n/** Whether the caller said anything at all about comments (either field set). */\nfunction hasExplicitCommentRequest(\n options: CommentOptions | undefined\n): boolean {\n return (\n options?.preserveComments !== undefined || options?.comments !== undefined\n );\n}\n\n/**\n * Whether an explicit request asks to strip comments from a preserved\n * source: not verbatim (`preserveComments !== true`, which always wins —\n * same precedence as `shouldEmitComments`/`resolveCommentStyle` above) and\n * no real style was requested via `comments`/the deprecated string\n * shorthand either. Safe to call unconditionally — returns `false` (leave\n * as-is) when nothing was requested at all, same as when `preserveComments`\n * is `true`.\n */\nfunction wantsCommentsStripped(options: CommentOptions | undefined): boolean {\n if (!hasExplicitCommentRequest(options)) return false;\n if (options?.preserveComments === true) return false;\n return requestedCommentStyle(options) === undefined;\n}\n\n/**\n * The normalization style an explicit request asks for, or `undefined` for\n * verbatim (`preserveComments === true`, which always wins) / strip / no\n * explicit style (including when nothing was requested at all).\n */\nfunction requestedCommentStyle(\n options: CommentOptions | undefined\n): 'c-style' | 'cdn-style' | undefined {\n if (options?.preserveComments === true) return undefined;\n if (typeof options?.preserveComments === 'string')\n return options.preserveComments;\n const style = options?.comments;\n return style === 'strip' ? undefined : style;\n}\n\n/** How a node should render under `preserveAppPrefix`. */\nexport type AppSeqRenderDecision =\n 'verbatim' | 'adjusted' | 'source' | 'structural' | 'normal';\n\n/**\n * Decide how an extension result node — from a `prefix'...'` /\n * `` prefix`...` `` / `prefix<<...>>` source, or (for a tag-wrapper node\n * that also has a generic `CborTag` fallback to delegate to) a raw tag\n * literal `N(...)` — should render under `ToCDNOptions.preserveAppPrefix`.\n *\n * A raw-tag source is recognised by `ednSource !== undefined`: the parser\n * only ever sets a tag-wrapper's `ednSource` (the tag *number's* digit\n * spelling) when it was reached via `N(...)`, never via one of the\n * app-string/-sequence forms. Leaf (non-tag-wrapper) nodes have no raw-tag\n * form at all — always pass `undefined` for `ednSource` there.\n *\n * Returns:\n * - `'verbatim'`: re-emit `appSeqSource` as-is. Only reachable for a\n * raw-tag source: its encoding-indicator suffixes are nested at two\n * independent positions (tag number and inner content), so this is only\n * safe in `'auto'` mode with no relevant sibling option overridden.\n * - `'source'`: keep a raw-tag source structurally verbatim, applying\n * comment and encoding-indicator changes by their captured source spans.\n * This avoids changing unrelated literal spelling or layout.\n * - `'adjusted'`: for an app-string/-sequence source, strip whatever\n * *outer* indicator suffix is already at the end of `appSeqSource` (or,\n * under `'never'`, also an *inner* one immediately before `<<...>>`'s\n * closing `>>` — the app-sequence's sole item's own indicator) and let\n * the caller append one recomputed via `resolveEiSuffix`/`floatSuffix`\n * for the current mode via `adjustAppSeqIndicator` — correct in every\n * mode, without losing the source's notation family. (An inner indicator\n * can only be *stripped*, not *recomputed*: the item's own encoding\n * width isn't tracked once resolved to a plain date/address string, so\n * `'always'` cannot add a missing one — it is left absent.)\n * - `'structural'`: keep the raw-tag notation *family* (as opposed to\n * upgrading to `prefix'...'`) but re-derive it structurally — via the\n * node's own `CborTag` rendering — instead of using `appSeqSource`\n * verbatim. Needed whenever verbatim text would ignore a sibling option\n * that must apply per nested node: an explicit `preserveNumberFormat` /\n * `preserveByteString` / `preserveTextString` / `preserveRawString` /\n * `preserveConcatenation` override.\n * Verbatim raw-tag text inherently contains the nested literal spelling.\n * - `'normal'`: fall through to the class's own notation regeneration\n * (`prefix'...'`), unaffected by `preserveAppPrefix`. For `<<...>>`,\n * this is also used when replaying its sole inner item would defeat an\n * explicitly disabled, relevant literal-preservation option.\n *\n * `editsComplete` (from `CborItem.appSeqEncodingEditsComplete`, raw-tag\n * sources only) is `false` when the tag's content contains a node type\n * `collectContentEncodingEdits` doesn't cover (e.g. a `CborMap` nested in an\n * `ip` array's raw-tag content). `'source'` relies on those edits to apply\n * `encodingIndicators: 'always'`/`'never'`, so incomplete coverage would\n * silently leave the uncovered node's own indicator unchanged; `'structural'`\n * is used instead, since it re-derives every nested indicator recursively.\n */\nexport function decideTaggedAppSeqRendering(\n options: ToCDNOptions | undefined,\n appSeqSource: string | undefined,\n ednSource: string | undefined,\n sourceFeatures?: AppSeqSourceFeatures,\n editsComplete?: boolean\n): AppSeqRenderDecision {\n if (!options?.preserveAppPrefix || appSeqSource === undefined)\n return 'normal';\n if (resolveIndent(options) === null && /[\\r\\n]/.test(appSeqSource))\n return 'normal';\n const isRawTagSource = ednSource !== undefined;\n // App-string/-sequence sources carry relative comment spans, so their\n // spelling can stay intact while adjustAppSeqIndicator converts or removes\n // comments. Raw tags instead have a structural CborTag fallback that\n // applies comment formatting together with all other nested-node options.\n if (!isRawTagSource) {\n const innerSourceOverridden =\n (sourceFeatures?.byteString && options?.preserveByteString === false) ||\n (sourceFeatures?.textString && options?.preserveTextString === false) ||\n (sourceFeatures?.rawString && options?.preserveRawString === false) ||\n (sourceFeatures?.concatenation &&\n options?.preserveConcatenation === false);\n return innerSourceOverridden ? 'normal' : 'adjusted';\n }\n const commentsNeedEditing =\n wantsCommentsStripped(options) ||\n requestedCommentStyle(options) !== undefined ||\n (options?.preserveComments === true && resolveIndent(options) === null);\n const mode = options?.encodingIndicators ?? 'auto';\n const siblingOverridden =\n options?.preserveNumberFormat === false ||\n (sourceFeatures?.byteString && options?.preserveByteString === false) ||\n (sourceFeatures?.textString && options?.preserveTextString === false) ||\n (sourceFeatures?.rawString && options?.preserveRawString === false) ||\n (sourceFeatures?.concatenation && options?.preserveConcatenation === false);\n if (siblingOverridden) return 'structural';\n if (mode !== 'auto' && editsComplete === false) return 'structural';\n return mode !== 'auto' || commentsNeedEditing ? 'source' : 'verbatim';\n}\n\n/**\n * Replacement text for a comment being stripped entirely (not converted):\n * empty, unless removing it would fuse two otherwise-separate tokens\n * together — e.g. \"24/x/h'...'\" would become \"24h'...'\", which the parser\n * rejects as two array items with no separator between them. A single\n * space keeps the tokens apart in that case, the same concern\n * `sourceSuffixEdit`'s own separator handles for an inserted indicator.\n *\n * The two neighbouring characters are checked generically (any non-space,\n * non-comma character needs a separator), not just \"word\" characters —\n * `24/x/'abc'` needs the same space as `24/x/h'...'` even though `'` isn't\n * itself part of a token that could lexically fuse with `24`: the parser's\n * \"array items must be separated\" check is purely positional (are the two\n * tokens flush against each other), not about what those tokens are. A\n * comma on either side never needs a separator of its own, since it's\n * already a valid separator by itself.\n *\n * `text`/`start`/`end` share one coordinate space (the source being edited\n * and the comment's offsets within it).\n */\nfunction stripCommentReplacement(\n text: string,\n start: number,\n end: number\n): string {\n const before = start > 0 ? text[start - 1]! : '';\n const after = end < text.length ? text[end]! : '';\n const needsSeparator = (ch: string) => ch !== '' && !/[\\s,]/.test(ch);\n return needsSeparator(before) && needsSeparator(after) ? ' ' : '';\n}\n\nfunction rewriteAppSeqComments(\n appSeqSource: string,\n options: ToCDNOptions | undefined,\n comments: readonly CborComment[] | undefined,\n removedAt?: number\n): string {\n if (!hasExplicitCommentRequest(options) || !comments?.length)\n return appSeqSource;\n const stripComments =\n wantsCommentsStripped(options) || resolveIndent(options) === null;\n const style = requestedCommentStyle(options);\n let text = appSeqSource;\n // Apply replacements from right to left so an earlier comment's offsets\n // are unaffected by a later replacement. Account for characters already\n // removed before a following comment.\n const ordered = [...comments].sort((a, b) => b.start - a.start);\n for (const comment of ordered) {\n const shift =\n removedAt !== undefined && comment.start >= removedAt ? -2 : 0;\n const start = comment.start + shift;\n const end = comment.end + shift;\n const replacement = stripComments\n ? stripCommentReplacement(text, start, end)\n : convertCommentText(comment, style);\n text = text.slice(0, start) + replacement + text.slice(end);\n }\n return text;\n}\n\n/** Apply comment/EI options directly to a preserved raw-tag source. */\nexport function adjustRawAppSeqSource(\n appSeqSource: string,\n options: ToCDNOptions | undefined,\n comments: readonly CborComment[] | undefined,\n encodingEdits: readonly AppSeqEncodingEdit[] | undefined\n): string {\n const replacements: {\n start: number;\n end: number;\n replacement: string;\n }[] = [];\n if (hasExplicitCommentRequest(options) && comments?.length) {\n const stripComments =\n wantsCommentsStripped(options) || resolveIndent(options) === null;\n const style = requestedCommentStyle(options);\n for (const comment of comments)\n replacements.push({\n start: comment.start,\n end: comment.end,\n replacement: stripComments\n ? stripCommentReplacement(appSeqSource, comment.start, comment.end)\n : convertCommentText(comment, style),\n });\n }\n const mode = options?.encodingIndicators ?? 'auto';\n if (mode !== 'auto' && encodingEdits)\n for (const edit of encodingEdits)\n replacements.push({\n start: edit.start,\n end: edit.end,\n replacement: mode === 'always' ? edit.always : edit.never,\n });\n\n // Right-to-left edits keep every stored source offset valid. At the same\n // offset, replace a non-empty span before performing a zero-width insert.\n replacements.sort((a, b) => b.start - a.start || b.end - a.end);\n let text = appSeqSource;\n for (const edit of replacements)\n text = text.slice(0, edit.start) + edit.replacement + text.slice(edit.end);\n return text;\n}\n\n/**\n * Adjust an `'adjusted'` app-string/-sequence source: apply requested comment\n * conversion/removal by captured source span, strip the existing\n * encoding-indicator suffix(es), then append `newSuffix` (the outer/wrapper\n * indicator recomputed for the current mode) — see\n * `decideTaggedAppSeqRendering`.\n *\n * Under `encodingIndicators: 'never'`, an inner (item-level) indicator is\n * also stripped, using\n * `innerItemEnd` (see `CborItem.appSeqInnerEnd`) to find it by its actual\n * parsed position rather than by pattern-matching text near the closing\n * `>>` — whitespace, a trailing comma, and/or a comment can all separate\n * the two, in any combination, so a position-based cut is the only fully\n * reliable way to locate it.\n */\nexport function adjustAppSeqIndicator(\n appSeqSource: string,\n newSuffix: string,\n options: ToCDNOptions | undefined,\n innerItemEnd: number | undefined,\n comments: readonly CborComment[] | undefined\n): string {\n let text = appSeqSource;\n let removedInnerAt: number | undefined;\n if (\n (options?.encodingIndicators ?? 'auto') === 'never' &&\n innerItemEnd !== undefined\n ) {\n const beforeInner = text.slice(0, innerItemEnd);\n if (/_[0-3i]$/.test(beforeInner)) {\n removedInnerAt = innerItemEnd - 2;\n text = beforeInner.slice(0, -2) + text.slice(innerItemEnd);\n }\n }\n\n text = rewriteAppSeqComments(text, options, comments, removedInnerAt);\n return text.replace(/_[0-3i]$/, '') + newSuffix;\n}\n"],"mappings":"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"}
|