@cbortech/cbor 0.26.6 → 0.26.8

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.
Files changed (49) hide show
  1. package/README.ja.md +125 -0
  2. package/README.md +124 -0
  3. package/dist/ast/CborByteString.d.ts +25 -0
  4. package/dist/ast/CborEllipsis.d.ts +94 -2
  5. package/dist/ast/CborFloat.d.ts +10 -0
  6. package/dist/ast/CborItem.d.ts +93 -4
  7. package/dist/ast/CborNint.d.ts +9 -0
  8. package/dist/ast/CborSimple.d.ts +11 -2
  9. package/dist/ast/CborTag.d.ts +8 -0
  10. package/dist/ast/CborTextString.d.ts +36 -0
  11. package/dist/ast/CborUint.d.ts +8 -0
  12. package/dist/ast/index.cjs +1 -1
  13. package/dist/ast/index.d.ts +1 -0
  14. package/dist/ast/index.js +2 -2
  15. package/dist/cddl/index.cjs +1 -1
  16. package/dist/cddl/index.js +1 -1
  17. package/dist/cdn/index.cjs +2 -2
  18. package/dist/cdn/index.cjs.map +1 -1
  19. package/dist/cdn/index.d.ts +2 -0
  20. package/dist/cdn/index.js +26 -26
  21. package/dist/cdn/index.js.map +1 -1
  22. package/dist/cdn/serialize-utils.d.ts +208 -9
  23. package/dist/extensions/dt.d.ts +3 -0
  24. package/dist/extensions/types.d.ts +31 -9
  25. package/dist/index.cjs +6 -6
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +62 -99
  29. package/dist/index.js.map +1 -1
  30. package/dist/mapEntries-BJzyBUH5.cjs +13 -0
  31. package/dist/mapEntries-BJzyBUH5.cjs.map +1 -0
  32. package/dist/{mapEntries-Czxt-cmd.js → mapEntries-Ci_dppP6.js} +1499 -1219
  33. package/dist/mapEntries-Ci_dppP6.js.map +1 -0
  34. package/dist/{schema-BmGsaEaW.cjs → schema-DgnkH0P6.cjs} +5 -5
  35. package/dist/{schema-BmGsaEaW.cjs.map → schema-DgnkH0P6.cjs.map} +1 -1
  36. package/dist/{schema-BxkgvUY6.js → schema-y8G5mDIS.js} +248 -248
  37. package/dist/{schema-BxkgvUY6.js.map → schema-y8G5mDIS.js.map} +1 -1
  38. package/dist/tokenizer-BD08xbyd.cjs +36 -0
  39. package/dist/tokenizer-BD08xbyd.cjs.map +1 -0
  40. package/dist/{tokenizer-CeuixxXi.js → tokenizer-N-vAvRdj.js} +350 -14
  41. package/dist/tokenizer-N-vAvRdj.js.map +1 -0
  42. package/dist/types.d.ts +176 -7
  43. package/package.json +2 -3
  44. package/dist/mapEntries-BhMlCwYo.cjs +0 -15
  45. package/dist/mapEntries-BhMlCwYo.cjs.map +0 -1
  46. package/dist/mapEntries-Czxt-cmd.js.map +0 -1
  47. package/dist/tokenizer-CeuixxXi.js.map +0 -1
  48. package/dist/tokenizer-EciPlN0n.cjs +0 -30
  49. package/dist/tokenizer-EciPlN0n.cjs.map +0 -1
@@ -10,16 +10,52 @@ export declare class CborTextString extends CborItem {
10
10
  readonly ednParts: readonly string[] | undefined;
11
11
  /** Original raw-string source text, when parsed from a single backtick literal. */
12
12
  readonly ednSource: string | undefined;
13
+ /**
14
+ * Original double-quoted source text (including its escape sequences),
15
+ * when parsed from a single non-concatenated `"..."` literal. Used by
16
+ * `_toCDN()` to round-trip the literal's exact spelling when
17
+ * `preserveTextString` is set.
18
+ */
19
+ readonly quotedEdnSource: string | undefined;
13
20
  /**
14
21
  * Original source text per `ednParts` entry, aligned by index; `undefined`
15
22
  * for parts that were not raw backtick literals.
16
23
  */
17
24
  readonly ednPartSources: readonly (string | undefined)[] | undefined;
25
+ /**
26
+ * `true` at index `i`, aligned with `ednParts`, when that part came from a
27
+ * byte-string literal on the right of a text-leading `+` concatenation
28
+ * (decoded as UTF-8 and merged in per §5.1) rather than a double-quoted
29
+ * `"..."` literal. Both cases leave `ednPartSources[i]` `undefined` (byte
30
+ * strings have no preserved raw source here, same as an unpreserved
31
+ * double-quoted literal), so this is what lets `appSeqSourceFeatures`
32
+ * attribute the part to `byteString` instead of the unpreservable
33
+ * `textString`.
34
+ */
35
+ readonly ednPartIsByteString: readonly boolean[] | undefined;
36
+ /**
37
+ * Source span of each `ednParts` entry's own literal token, aligned by
38
+ * index — used to place a comment sitting between two `+`-joined parts at
39
+ * the right gap instead of dropping it (there is no per-part AST node for
40
+ * such a comment to attach to; it lands as `dangling` on this whole node
41
+ * instead — see `CborByteString.ednParts`'s equivalent doc). `undefined`
42
+ * for a node not parsed from a `+` chain at all.
43
+ */
44
+ readonly ednPartSpans: readonly {
45
+ start: number;
46
+ end: number;
47
+ }[] | undefined;
18
48
  constructor(value: string, options?: {
19
49
  encodingWidth?: EncodingWidth;
20
50
  ednParts?: readonly string[];
21
51
  ednSource?: string;
52
+ quotedEdnSource?: string;
22
53
  ednPartSources?: readonly (string | undefined)[];
54
+ ednPartIsByteString?: readonly boolean[];
55
+ ednPartSpans?: readonly {
56
+ start: number;
57
+ end: number;
58
+ }[];
23
59
  });
24
60
  _encodeTo(writer: CborWriter, _options?: ToCBOROptions): void;
25
61
  _toCDN(options: ToCDNOptions | undefined, depth: number): string;
@@ -5,8 +5,16 @@ import { CborWriter, EncodingWidth } from '../cbor/encode';
5
5
  export declare class CborUint extends CborItem {
6
6
  readonly value: bigint;
7
7
  encodingWidth: EncodingWidth | undefined;
8
+ /**
9
+ * Original CDN digit spelling (base + digits, without the encoding-
10
+ * indicator suffix), set by the parser when this value came from CDN
11
+ * text. Used by `_toCDN()` to round-trip the literal's base (`0xff`,
12
+ * `0o377`, `0b101`, decimal) when `preserveNumberFormat` is set.
13
+ */
14
+ readonly ednSource?: string;
8
15
  constructor(value: number | bigint, options?: {
9
16
  encodingWidth?: EncodingWidth;
17
+ ednSource?: string;
10
18
  });
11
19
  _encodeTo(writer: CborWriter, _options?: ToCBOROptions): void;
12
20
  _toCDN(options: ToCDNOptions | undefined, _depth: number): string;
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../mapEntries-BhMlCwYo.cjs");exports.CborArray=e.E,exports.CborBigNint=e.v,exports.CborBigUint=e.y,exports.CborByteString=e.k,exports.CborEmbeddedCBOR=e.C,exports.CborFloat=e.j,exports.CborIndefiniteByteString=e.O,exports.CborIndefiniteTextString=e.D,exports.CborItem=e.F,exports.CborMap=e.T,exports.CborNint=e.N,exports.CborSimple=e.w,exports.CborTag=e.A,exports.CborTextString=e.g,exports.CborUint=e.P;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../mapEntries-BJzyBUH5.cjs");exports.CborArray=e.D,exports.CborBigNint=e._,exports.CborBigUint=e.v,exports.CborByteString=e.A,exports.CborEmbeddedCBOR=e.w,exports.CborFloat=e.M,exports.CborIndefiniteByteString=e.k,exports.CborIndefiniteTextString=e.O,exports.CborItem=e.I,exports.CborMap=e.E,exports.CborNint=e.P,exports.CborSimple=e.T,exports.CborTag=e.j,exports.CborTextString=e.h,exports.CborUint=e.F;
@@ -1,4 +1,5 @@
1
1
  export { CborItem } from './CborItem';
2
+ export type { AppSeqEncodingEdit, AppSeqSourceFeatures } from './CborItem';
2
3
  export { CborUint } from './CborUint';
3
4
  export { CborBigUint, CborBigNint } from './CborBignum';
4
5
  export { CborNint } from './CborNint';
package/dist/ast/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as e, C as t, D as n, E as r, F as i, N as a, O as o, P as s, T as c, g as l, j as u, k as d, v as f, w as p, y as m } from "../mapEntries-Czxt-cmd.js";
2
- export { r as CborArray, f as CborBigNint, m as CborBigUint, d as CborByteString, t as CborEmbeddedCBOR, u as CborFloat, o as CborIndefiniteByteString, n as CborIndefiniteTextString, i as CborItem, c as CborMap, a as CborNint, p as CborSimple, e as CborTag, l as CborTextString, s as CborUint };
1
+ import { A as e, D as t, E as n, F as r, I as i, M as a, O as o, P as s, T as c, _ as l, h as u, j as d, k as f, v as p, w as m } from "../mapEntries-Ci_dppP6.js";
2
+ export { t as CborArray, l as CborBigNint, p as CborBigUint, e as CborByteString, m as CborEmbeddedCBOR, a as CborFloat, f as CborIndefiniteByteString, o as CborIndefiniteTextString, i as CborItem, n as CborMap, s as CborNint, c as CborSimple, d as CborTag, u as CborTextString, r as CborUint };
@@ -1,3 +1,3 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../schema-BmGsaEaW.cjs");function t(e,t){let n=Math.max(0,Math.min(t,e.length)),r=1,i=0;for(let t=0;t<n;t++)e.charCodeAt(t)===10&&(r++,i=t+1);return{line:r,column:n-i+1}}var n=class{static compile(t,n){return e.n(t,n)}};function r(t){let n=new e.o(t),r=[];for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}function i(t){let n=new e.o(t),r=[];try{for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}catch(i){let a=i instanceof e.l?i:new e.l(i instanceof Error?i.message:String(i)),o=n.lastEndOffset;if(o<t.length){let e=1,n=1;for(let r=0;r<o;r++)t[r]===`
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../schema-DgnkH0P6.cjs");function t(e,t){let n=Math.max(0,Math.min(t,e.length)),r=1,i=0;for(let t=0;t<n;t++)e.charCodeAt(t)===10&&(r++,i=t+1);return{line:r,column:n-i+1}}var n=class{static compile(t,n){return e.n(t,n)}};function r(t){let n=new e.o(t),r=[];for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}function i(t){let n=new e.o(t),r=[];try{for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}catch(i){let a=i instanceof e.l?i:new e.l(i instanceof Error?i.message:String(i)),o=n.lastEndOffset;if(o<t.length){let e=1,n=1;for(let r=0;r<o;r++)t[r]===`
2
2
  `?(e++,n=1):n++;r.push({type:`ERROR`,value:t.slice(o),raw:t.slice(o),line:e,col:n,offset:o,endOffset:t.length})}return{tokens:r,comments:n.comments,error:a}}}exports.CDDL=n,exports.default=n,exports.CddlMismatchError=e.s,exports.CddlSchema=e.t,exports.CddlSemanticError=e.c,exports.CddlSyntaxError=e.l,exports.PRELUDE_CDDL=e.r,exports.getPreludeRules=e.i,exports.parseCDDL=e.a,exports.positionAt=t,exports.tokenize=r,exports.tokenizeLenient=i;
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1,4 +1,4 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "../schema-BxkgvUY6.js";
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c } from "../schema-y8G5mDIS.js";
2
2
  //#region src/cddl/position.ts
3
3
  function l(e, t) {
4
4
  let n = Math.max(0, Math.min(t, e.length)), r = 1, i = 0;
@@ -1,3 +1,3 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../tokenizer-EciPlN0n.cjs");function t(t){let n=new e.t(t),r=[];for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}function n(t){let n=new e.t(t),r=[];try{for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}catch(i){let a=i instanceof e.o?i:new e.o(i instanceof Error?i.message:String(i)),o=n.lastEndOffset;if(o<t.length){let e=1,n=1;for(let r=0;r<o;r++)t[r]===`
2
- `?(e++,n=1):n++;r.push({type:`ERROR`,value:t.slice(o),raw:t.slice(o),line:e,col:n,offset:o,endOffset:t.length})}return{tokens:r,comments:n.comments,error:a}}}exports.CdnSyntaxError=e.o,exports.tokenize=t,exports.tokenizeLenient=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../tokenizer-BD08xbyd.cjs");function t(t){let n=new e.t(t),r=[];for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}function n(t){let n=new e.t(t),r=[];try{for(;;){let e=n.consume();if(e.type===`EOF`)break;r.push(e)}return{tokens:r,comments:n.comments}}catch(i){let a=i instanceof e.D?i:new e.D(i instanceof Error?i.message:String(i)),o=n.lastEndOffset;if(o<t.length){let e=1,n=1;for(let r=0;r<o;r++)t[r]===`
2
+ `?(e++,n=1):n++;r.push({type:`ERROR`,value:t.slice(o),raw:t.slice(o),line:e,col:n,offset:o,endOffset:t.length})}return{tokens:r,comments:n.comments,error:a}}}exports.CdnSyntaxError=e.D,exports.adjustAppSeqIndicator=e.n,exports.adjustRawAppSeqSource=e.r,exports.canonicalEncodingWidth=e.i,exports.decideTaggedAppSeqRendering=e.s,exports.resolveEiSuffix=e._,exports.tokenize=t,exports.tokenizeLenient=n;
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/cdn/index.ts"],"sourcesContent":["/**\n * Public lower-level CDN tokenization API (`@cbortech/cbor/cdn`).\n *\n * Exposes the same lexer the parser uses, so tooling such as syntax\n * highlighters stays in exact agreement with parsing behavior.\n */\n\nimport { Tokenizer, type Token, type EdnComment } from './tokenizer';\nimport { CdnSyntaxError } from './errors';\n\nexport type { Token, TokenType, EdnComment } from './tokenizer';\nexport { CdnSyntaxError } from './errors';\n\nexport interface TokenizeResult {\n /** Scanned tokens in source order, excluding the final EOF token. */\n tokens: Token[];\n /** Comments encountered while scanning, in source order. */\n comments: EdnComment[];\n}\n\nexport interface TokenizeLenientResult extends TokenizeResult {\n /**\n * The scan failure, if any. When set, `tokens` ends with a synthetic\n * `ERROR` token covering the source from the last clean token to the end\n * of the input.\n */\n error?: CdnSyntaxError;\n}\n\n/**\n * Tokenize CDN text. Throws {@link CdnSyntaxError} on invalid input.\n */\nexport function tokenize(text: string): TokenizeResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n}\n\n/**\n * Error-tolerant tokenization for editors and highlighters: never throws on\n * invalid input. Tokens before the failure are returned as scanned; the\n * remainder of the input is covered by a single synthetic `ERROR` token and\n * the failure is reported in `error`.\n */\nexport function tokenizeLenient(text: string): TokenizeLenientResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n try {\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n } catch (e) {\n const error =\n e instanceof CdnSyntaxError\n ? e\n : new CdnSyntaxError(e instanceof Error ? e.message : String(e));\n const start = tokenizer.lastEndOffset;\n if (start < text.length) {\n let line = 1;\n let col = 1;\n for (let i = 0; i < start; i++) {\n if (text[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n tokens.push({\n type: 'ERROR',\n value: text.slice(start),\n raw: text.slice(start),\n line,\n col,\n offset: start,\n endOffset: text.length,\n });\n }\n return { tokens, comments: tokenizer.comments, error };\n }\n}\n"],"mappings":"gHAgCA,SAAgB,EAAS,EAA8B,CACrD,IAAM,EAAY,IAAI,EAAA,EAAU,CAAI,EAC9B,EAAkB,CAAC,EACzB,OAAS,CACP,IAAM,EAAM,EAAU,QAAQ,EAC9B,GAAI,EAAI,OAAS,MAAO,MACxB,EAAO,KAAK,CAAG,CACjB,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,QAAS,CAChD,CAQA,SAAgB,EAAgB,EAAqC,CACnE,IAAM,EAAY,IAAI,EAAA,EAAU,CAAI,EAC9B,EAAkB,CAAC,EACzB,GAAI,CACF,OAAS,CACP,IAAM,EAAM,EAAU,QAAQ,EAC9B,GAAI,EAAI,OAAS,MAAO,MACxB,EAAO,KAAK,CAAG,CACjB,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,QAAS,CAChD,OAAS,EAAG,CACV,IAAM,EACJ,aAAa,EAAA,EACT,EACA,IAAI,EAAA,EAAe,aAAa,MAAQ,EAAE,QAAU,OAAO,CAAC,CAAC,EAC7D,EAAQ,EAAU,cACxB,GAAI,EAAQ,EAAK,OAAQ,CACvB,IAAI,EAAO,EACP,EAAM,EACV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,IACrB,EAAK,KAAO;GACd,IACA,EAAM,GAEN,IAGJ,EAAO,KAAK,CACV,KAAM,QACN,MAAO,EAAK,MAAM,CAAK,EACvB,IAAK,EAAK,MAAM,CAAK,EACrB,OACA,MACA,OAAQ,EACR,UAAW,EAAK,MAClB,CAAC,CACH,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,SAAU,OAAM,CACvD,CACF"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/cdn/index.ts"],"sourcesContent":["/**\n * Public lower-level CDN tokenization and serialization API\n * (`@cbortech/cbor/cdn`).\n *\n * Exposes the same lexer the parser uses, so tooling such as syntax\n * highlighters stays in exact agreement with parsing behavior. Also exposes\n * the `preserveAppSequence` source-preservation primitives that the built-in\n * `dt`/`ip`/`cri` extensions use, so a third-party `CborExtension` whose\n * result has its own dedicated notation (regenerated from a resolved value,\n * the way `dt'...'`/`ip'...'`/`cri'...'` do) can support `preserveAppSequence`\n * too, instead of always discarding the original `` prefix`...` ``,\n * non-canonical `prefix'...'`, or raw-tag `N(...)` source spelling. See the\n * `dt`/`ip`/`cri` extension sources for the pattern these are meant to be\n * used in.\n */\n\nimport { Tokenizer, type Token, type EdnComment } from './tokenizer';\nimport { CdnSyntaxError } from './errors';\n\nexport type { Token, TokenType, EdnComment } from './tokenizer';\nexport { CdnSyntaxError } from './errors';\n\nexport {\n resolveEiSuffix,\n canonicalEncodingWidth,\n decideTaggedAppSeqRendering,\n adjustRawAppSeqSource,\n adjustAppSeqIndicator,\n} from './serialize-utils';\nexport type { AppSeqRenderDecision } from './serialize-utils';\n\nexport interface TokenizeResult {\n /** Scanned tokens in source order, excluding the final EOF token. */\n tokens: Token[];\n /** Comments encountered while scanning, in source order. */\n comments: EdnComment[];\n}\n\nexport interface TokenizeLenientResult extends TokenizeResult {\n /**\n * The scan failure, if any. When set, `tokens` ends with a synthetic\n * `ERROR` token covering the source from the last clean token to the end\n * of the input.\n */\n error?: CdnSyntaxError;\n}\n\n/**\n * Tokenize CDN text. Throws {@link CdnSyntaxError} on invalid input.\n */\nexport function tokenize(text: string): TokenizeResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n}\n\n/**\n * Error-tolerant tokenization for editors and highlighters: never throws on\n * invalid input. Tokens before the failure are returned as scanned; the\n * remainder of the input is covered by a single synthetic `ERROR` token and\n * the failure is reported in `error`.\n */\nexport function tokenizeLenient(text: string): TokenizeLenientResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n try {\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n } catch (e) {\n const error =\n e instanceof CdnSyntaxError\n ? e\n : new CdnSyntaxError(e instanceof Error ? e.message : String(e));\n const start = tokenizer.lastEndOffset;\n if (start < text.length) {\n let line = 1;\n let col = 1;\n for (let i = 0; i < start; i++) {\n if (text[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n tokens.push({\n type: 'ERROR',\n value: text.slice(start),\n raw: text.slice(start),\n line,\n col,\n offset: start,\n endOffset: text.length,\n });\n }\n return { tokens, comments: tokenizer.comments, error };\n }\n}\n"],"mappings":"gHAkDA,SAAgB,EAAS,EAA8B,CACrD,IAAM,EAAY,IAAI,EAAA,EAAU,CAAI,EAC9B,EAAkB,CAAC,EACzB,OAAS,CACP,IAAM,EAAM,EAAU,QAAQ,EAC9B,GAAI,EAAI,OAAS,MAAO,MACxB,EAAO,KAAK,CAAG,CACjB,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,QAAS,CAChD,CAQA,SAAgB,EAAgB,EAAqC,CACnE,IAAM,EAAY,IAAI,EAAA,EAAU,CAAI,EAC9B,EAAkB,CAAC,EACzB,GAAI,CACF,OAAS,CACP,IAAM,EAAM,EAAU,QAAQ,EAC9B,GAAI,EAAI,OAAS,MAAO,MACxB,EAAO,KAAK,CAAG,CACjB,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,QAAS,CAChD,OAAS,EAAG,CACV,IAAM,EACJ,aAAa,EAAA,EACT,EACA,IAAI,EAAA,EAAe,aAAa,MAAQ,EAAE,QAAU,OAAO,CAAC,CAAC,EAC7D,EAAQ,EAAU,cACxB,GAAI,EAAQ,EAAK,OAAQ,CACvB,IAAI,EAAO,EACP,EAAM,EACV,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,IACrB,EAAK,KAAO;GACd,IACA,EAAM,GAEN,IAGJ,EAAO,KAAK,CACV,KAAM,QACN,MAAO,EAAK,MAAM,CAAK,EACvB,IAAK,EAAK,MAAM,CAAK,EACrB,OACA,MACA,OAAQ,EACR,UAAW,EAAK,MAClB,CAAC,CACH,CACA,MAAO,CAAE,SAAQ,SAAU,EAAU,SAAU,OAAM,CACvD,CACF"}
@@ -2,6 +2,8 @@ import { Token, EdnComment } from './tokenizer';
2
2
  import { CdnSyntaxError } from './errors';
3
3
  export type { Token, TokenType, EdnComment } from './tokenizer';
4
4
  export { CdnSyntaxError } from './errors';
5
+ export { resolveEiSuffix, canonicalEncodingWidth, decideTaggedAppSeqRendering, adjustRawAppSeqSource, adjustAppSeqIndicator, } from './serialize-utils';
6
+ export type { AppSeqRenderDecision } from './serialize-utils';
5
7
  export interface TokenizeResult {
6
8
  /** Scanned tokens in source order, excluding the final EOF token. */
7
9
  tokens: Token[];
package/dist/cdn/index.js CHANGED
@@ -1,52 +1,52 @@
1
- import { o as e, t } from "../tokenizer-CeuixxXi.js";
1
+ import { D as e, _ as t, i as n, n as r, r as i, s as a, t as o } from "../tokenizer-N-vAvRdj.js";
2
2
  //#region src/cdn/index.ts
3
- function n(e) {
4
- let n = new t(e), r = [];
3
+ function s(e) {
4
+ let t = new o(e), n = [];
5
5
  for (;;) {
6
- let e = n.consume();
6
+ let e = t.consume();
7
7
  if (e.type === "EOF") break;
8
- r.push(e);
8
+ n.push(e);
9
9
  }
10
10
  return {
11
- tokens: r,
12
- comments: n.comments
11
+ tokens: n,
12
+ comments: t.comments
13
13
  };
14
14
  }
15
- function r(n) {
16
- let r = new t(n), i = [];
15
+ function c(t) {
16
+ let n = new o(t), r = [];
17
17
  try {
18
18
  for (;;) {
19
- let e = r.consume();
19
+ let e = n.consume();
20
20
  if (e.type === "EOF") break;
21
- i.push(e);
21
+ r.push(e);
22
22
  }
23
23
  return {
24
- tokens: i,
25
- comments: r.comments
24
+ tokens: r,
25
+ comments: n.comments
26
26
  };
27
- } catch (t) {
28
- let a = t instanceof e ? t : new e(t instanceof Error ? t.message : String(t)), o = r.lastEndOffset;
29
- if (o < n.length) {
30
- let e = 1, t = 1;
31
- for (let r = 0; r < o; r++) n[r] === "\n" ? (e++, t = 1) : t++;
32
- i.push({
27
+ } catch (i) {
28
+ let a = i instanceof e ? i : new e(i instanceof Error ? i.message : String(i)), o = n.lastEndOffset;
29
+ if (o < t.length) {
30
+ let e = 1, n = 1;
31
+ for (let r = 0; r < o; r++) t[r] === "\n" ? (e++, n = 1) : n++;
32
+ r.push({
33
33
  type: "ERROR",
34
- value: n.slice(o),
35
- raw: n.slice(o),
34
+ value: t.slice(o),
35
+ raw: t.slice(o),
36
36
  line: e,
37
- col: t,
37
+ col: n,
38
38
  offset: o,
39
- endOffset: n.length
39
+ endOffset: t.length
40
40
  });
41
41
  }
42
42
  return {
43
- tokens: i,
44
- comments: r.comments,
43
+ tokens: r,
44
+ comments: n.comments,
45
45
  error: a
46
46
  };
47
47
  }
48
48
  }
49
49
  //#endregion
50
- export { e as CdnSyntaxError, n as tokenize, r as tokenizeLenient };
50
+ export { e as CdnSyntaxError, r as adjustAppSeqIndicator, i as adjustRawAppSeqSource, n as canonicalEncodingWidth, a as decideTaggedAppSeqRendering, t as resolveEiSuffix, s as tokenize, c as tokenizeLenient };
51
51
 
52
52
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cdn/index.ts"],"sourcesContent":["/**\n * Public lower-level CDN tokenization API (`@cbortech/cbor/cdn`).\n *\n * Exposes the same lexer the parser uses, so tooling such as syntax\n * highlighters stays in exact agreement with parsing behavior.\n */\n\nimport { Tokenizer, type Token, type EdnComment } from './tokenizer';\nimport { CdnSyntaxError } from './errors';\n\nexport type { Token, TokenType, EdnComment } from './tokenizer';\nexport { CdnSyntaxError } from './errors';\n\nexport interface TokenizeResult {\n /** Scanned tokens in source order, excluding the final EOF token. */\n tokens: Token[];\n /** Comments encountered while scanning, in source order. */\n comments: EdnComment[];\n}\n\nexport interface TokenizeLenientResult extends TokenizeResult {\n /**\n * The scan failure, if any. When set, `tokens` ends with a synthetic\n * `ERROR` token covering the source from the last clean token to the end\n * of the input.\n */\n error?: CdnSyntaxError;\n}\n\n/**\n * Tokenize CDN text. Throws {@link CdnSyntaxError} on invalid input.\n */\nexport function tokenize(text: string): TokenizeResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n}\n\n/**\n * Error-tolerant tokenization for editors and highlighters: never throws on\n * invalid input. Tokens before the failure are returned as scanned; the\n * remainder of the input is covered by a single synthetic `ERROR` token and\n * the failure is reported in `error`.\n */\nexport function tokenizeLenient(text: string): TokenizeLenientResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n try {\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n } catch (e) {\n const error =\n e instanceof CdnSyntaxError\n ? e\n : new CdnSyntaxError(e instanceof Error ? e.message : String(e));\n const start = tokenizer.lastEndOffset;\n if (start < text.length) {\n let line = 1;\n let col = 1;\n for (let i = 0; i < start; i++) {\n if (text[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n tokens.push({\n type: 'ERROR',\n value: text.slice(start),\n raw: text.slice(start),\n line,\n col,\n offset: start,\n endOffset: text.length,\n });\n }\n return { tokens, comments: tokenizer.comments, error };\n }\n}\n"],"mappings":";;AAgCA,SAAgB,EAAS,GAA8B;CACrD,IAAM,IAAY,IAAI,EAAU,CAAI,GAC9B,IAAkB,CAAC;CACzB,SAAS;EACP,IAAM,IAAM,EAAU,QAAQ;EAC9B,IAAI,EAAI,SAAS,OAAO;EACxB,EAAO,KAAK,CAAG;CACjB;CACA,OAAO;EAAE;EAAQ,UAAU,EAAU;CAAS;AAChD;AAQA,SAAgB,EAAgB,GAAqC;CACnE,IAAM,IAAY,IAAI,EAAU,CAAI,GAC9B,IAAkB,CAAC;CACzB,IAAI;EACF,SAAS;GACP,IAAM,IAAM,EAAU,QAAQ;GAC9B,IAAI,EAAI,SAAS,OAAO;GACxB,EAAO,KAAK,CAAG;EACjB;EACA,OAAO;GAAE;GAAQ,UAAU,EAAU;EAAS;CAChD,SAAS,GAAG;EACV,IAAM,IACJ,aAAa,IACT,IACA,IAAI,EAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,GAC7D,IAAQ,EAAU;EACxB,IAAI,IAAQ,EAAK,QAAQ;GACvB,IAAI,IAAO,GACP,IAAM;GACV,KAAK,IAAI,IAAI,GAAG,IAAI,GAAO,KACzB,AAAI,EAAK,OAAO,QACd,KACA,IAAM,KAEN;GAGJ,EAAO,KAAK;IACV,MAAM;IACN,OAAO,EAAK,MAAM,CAAK;IACvB,KAAK,EAAK,MAAM,CAAK;IACrB;IACA;IACA,QAAQ;IACR,WAAW,EAAK;GAClB,CAAC;EACH;EACA,OAAO;GAAE;GAAQ,UAAU,EAAU;GAAU;EAAM;CACvD;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/cdn/index.ts"],"sourcesContent":["/**\n * Public lower-level CDN tokenization and serialization API\n * (`@cbortech/cbor/cdn`).\n *\n * Exposes the same lexer the parser uses, so tooling such as syntax\n * highlighters stays in exact agreement with parsing behavior. Also exposes\n * the `preserveAppSequence` source-preservation primitives that the built-in\n * `dt`/`ip`/`cri` extensions use, so a third-party `CborExtension` whose\n * result has its own dedicated notation (regenerated from a resolved value,\n * the way `dt'...'`/`ip'...'`/`cri'...'` do) can support `preserveAppSequence`\n * too, instead of always discarding the original `` prefix`...` ``,\n * non-canonical `prefix'...'`, or raw-tag `N(...)` source spelling. See the\n * `dt`/`ip`/`cri` extension sources for the pattern these are meant to be\n * used in.\n */\n\nimport { Tokenizer, type Token, type EdnComment } from './tokenizer';\nimport { CdnSyntaxError } from './errors';\n\nexport type { Token, TokenType, EdnComment } from './tokenizer';\nexport { CdnSyntaxError } from './errors';\n\nexport {\n resolveEiSuffix,\n canonicalEncodingWidth,\n decideTaggedAppSeqRendering,\n adjustRawAppSeqSource,\n adjustAppSeqIndicator,\n} from './serialize-utils';\nexport type { AppSeqRenderDecision } from './serialize-utils';\n\nexport interface TokenizeResult {\n /** Scanned tokens in source order, excluding the final EOF token. */\n tokens: Token[];\n /** Comments encountered while scanning, in source order. */\n comments: EdnComment[];\n}\n\nexport interface TokenizeLenientResult extends TokenizeResult {\n /**\n * The scan failure, if any. When set, `tokens` ends with a synthetic\n * `ERROR` token covering the source from the last clean token to the end\n * of the input.\n */\n error?: CdnSyntaxError;\n}\n\n/**\n * Tokenize CDN text. Throws {@link CdnSyntaxError} on invalid input.\n */\nexport function tokenize(text: string): TokenizeResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n}\n\n/**\n * Error-tolerant tokenization for editors and highlighters: never throws on\n * invalid input. Tokens before the failure are returned as scanned; the\n * remainder of the input is covered by a single synthetic `ERROR` token and\n * the failure is reported in `error`.\n */\nexport function tokenizeLenient(text: string): TokenizeLenientResult {\n const tokenizer = new Tokenizer(text);\n const tokens: Token[] = [];\n try {\n for (;;) {\n const tok = tokenizer.consume();\n if (tok.type === 'EOF') break;\n tokens.push(tok);\n }\n return { tokens, comments: tokenizer.comments };\n } catch (e) {\n const error =\n e instanceof CdnSyntaxError\n ? e\n : new CdnSyntaxError(e instanceof Error ? e.message : String(e));\n const start = tokenizer.lastEndOffset;\n if (start < text.length) {\n let line = 1;\n let col = 1;\n for (let i = 0; i < start; i++) {\n if (text[i] === '\\n') {\n line++;\n col = 1;\n } else {\n col++;\n }\n }\n tokens.push({\n type: 'ERROR',\n value: text.slice(start),\n raw: text.slice(start),\n line,\n col,\n offset: start,\n endOffset: text.length,\n });\n }\n return { tokens, comments: tokenizer.comments, error };\n }\n}\n"],"mappings":";;AAkDA,SAAgB,EAAS,GAA8B;CACrD,IAAM,IAAY,IAAI,EAAU,CAAI,GAC9B,IAAkB,CAAC;CACzB,SAAS;EACP,IAAM,IAAM,EAAU,QAAQ;EAC9B,IAAI,EAAI,SAAS,OAAO;EACxB,EAAO,KAAK,CAAG;CACjB;CACA,OAAO;EAAE;EAAQ,UAAU,EAAU;CAAS;AAChD;AAQA,SAAgB,EAAgB,GAAqC;CACnE,IAAM,IAAY,IAAI,EAAU,CAAI,GAC9B,IAAkB,CAAC;CACzB,IAAI;EACF,SAAS;GACP,IAAM,IAAM,EAAU,QAAQ;GAC9B,IAAI,EAAI,SAAS,OAAO;GACxB,EAAO,KAAK,CAAG;EACjB;EACA,OAAO;GAAE;GAAQ,UAAU,EAAU;EAAS;CAChD,SAAS,GAAG;EACV,IAAM,IACJ,aAAa,IACT,IACA,IAAI,EAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,GAC7D,IAAQ,EAAU;EACxB,IAAI,IAAQ,EAAK,QAAQ;GACvB,IAAI,IAAO,GACP,IAAM;GACV,KAAK,IAAI,IAAI,GAAG,IAAI,GAAO,KACzB,AAAI,EAAK,OAAO,QACd,KACA,IAAM,KAEN;GAGJ,EAAO,KAAK;IACV,MAAM;IACN,OAAO,EAAK,MAAM,CAAK;IACvB,KAAK,EAAK,MAAM,CAAK;IACrB;IACA;IACA,QAAQ;IACR,WAAW,EAAK;GAClB,CAAC;EACH;EACA,OAAO;GAAE;GAAQ,UAAU,EAAU;GAAU;EAAM;CACvD;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { CborComment, CborComments, ToCDNOptions } from '../types';
2
2
  import { EncodingWidth } from '../cbor/encode';
3
+ import { AppSeqEncodingEdit, AppSeqSourceFeatures } from '../ast/CborItem';
3
4
  /** Resolve indent option to a string, or null for single-line output. */
4
5
  export declare function resolveIndent(options: ToCDNOptions | undefined): string | null;
5
6
  /** Build the indent prefix for a given depth. */
@@ -9,10 +10,18 @@ export declare function indentOf(indentStr: string, depth: number): string;
9
10
  *
10
11
  * Single-line (` + `) when indent is disabled; otherwise each continuation
11
12
  * part starts on its own line, indented one level deeper than the owner.
13
+ *
14
+ * `midComments`, when given, holds already-converted comment lines for each
15
+ * gap between two consecutive parts (`midComments[i]` sits between
16
+ * `literals[i]` and `literals[i + 1]`) — e.g. a comment between two
17
+ * `+`-joined byte-string literals, which has nowhere else to attach since
18
+ * there is no per-part AST node. Ignored in single-line mode, matching every
19
+ * other comment kind.
12
20
  */
13
- export declare function joinConcatParts(literals: readonly string[], indentStr: string | null, depth: number): string;
21
+ export declare function joinConcatParts(literals: readonly string[], indentStr: string | null, depth: number, midComments?: readonly (readonly string[])[]): string;
14
22
  export interface Commented {
15
23
  comments?: CborComments;
24
+ blankLineBefore?: boolean;
16
25
  }
17
26
  export declare function hasPreservedComments(item: Commented): boolean;
18
27
  export declare function hasContainerLayoutComments(item: Commented): boolean;
@@ -29,7 +38,49 @@ export declare function hasContainerLayoutComments(item: Commented): boolean;
29
38
  * this (e.g. `/**…*\/` → `/ *…/`).
30
39
  */
31
40
  export declare function convertCommentText(comment: CborComment, style: 'c-style' | 'cdn-style' | undefined): string;
32
- export declare function formatLeadingComments(item: Commented, indent: string, style?: 'c-style' | 'cdn-style' | undefined): string[];
41
+ /**
42
+ * Bucket a flat, source-ordered list of comments (typically a node's own
43
+ * `comments.dangling`) by which gap between two consecutive `parts` each
44
+ * one's offset falls into — `result[i]` sits between `parts[i]` and
45
+ * `parts[i + 1]`, already converted to the requested marker style.
46
+ *
47
+ * Used for a comment that sits between two `+`-joined fragments merged into
48
+ * a single value with no per-fragment AST node of its own to attach to (a
49
+ * concatenated `CborByteString`'s own `ednParts`, or — inside a bytes
50
+ * elision — a `CborEllipsis` item's `ednParts`): `attachComments` can only
51
+ * land such a comment on the merged node as a whole, as `dangling`, so this
52
+ * re-derives which specific gap it belongs in from each part's own
53
+ * `start`/`end` span. A comment is dropped (as it already was before this
54
+ * function existed) when either neighbouring part lacks a known span — a
55
+ * part merged from a single elided literal's own internal segments, which
56
+ * cannot have a comment between them anyway (see `_elidedHexAtoms`).
57
+ *
58
+ * Returns `undefined` (rather than an all-empty array) when nothing landed
59
+ * in any gap, so callers can cheaply skip the mid-comment rendering path
60
+ * entirely in the common case.
61
+ */
62
+ export declare function danglingCommentsByGap(dangling: readonly CborComment[] | undefined, parts: readonly {
63
+ start?: number;
64
+ end?: number;
65
+ }[] | undefined, style: 'c-style' | 'cdn-style' | undefined): string[][] | undefined;
66
+ /**
67
+ * Split an item's leading comments into ones that get their own line above
68
+ * it, and a trailing run of comments the parser found on the same source
69
+ * line as the item itself (`CborComment.sameLine`) — e.g.
70
+ * `/ protected / << ... >>,` in an RFC 9052-style annotated array. Since
71
+ * comments and the item they lead up to appear in strictly increasing
72
+ * source order, `sameLine` comments always form a contiguous run at the end
73
+ * of the list (nothing can sit between a same-line comment and the item
74
+ * without itself being on that same line).
75
+ *
76
+ * `ownLines` renders like `formatLeadingComments` used to; `inlinePrefix` is
77
+ * meant to be prepended directly to the item's own rendered line (already
78
+ * includes a trailing space per comment, or `''` when there is none).
79
+ */
80
+ export declare function splitLeadingComments(item: Commented, indent: string, style?: 'c-style' | 'cdn-style' | undefined): {
81
+ ownLines: string[];
82
+ inlinePrefix: string;
83
+ };
33
84
  export declare function formatTrailingComments(item: Commented, style?: 'c-style' | 'cdn-style' | undefined): string;
34
85
  export declare function formatDanglingComments(item: Commented, indent: string, style?: 'c-style' | 'cdn-style' | undefined): string[];
35
86
  /**
@@ -59,26 +110,46 @@ export declare function resolveSeparators(options: ToCDNOptions | undefined, com
59
110
  * comments — line comments can only be terminated by a newline.
60
111
  *
61
112
  * Entries are accessed through per-index callbacks (not materialised entry
62
- * objects) so the common no-comments path allocates nothing per entry.
63
- * `hasEntryComments`, `entryLeadingNode`, and `entryTrailing` are consulted
64
- * only when `preserveComments` is set. `renderEntry` receives the resolved
65
- * `colSep` (': ' or ':' depending on compact mode) for rendering map pairs.
113
+ * objects) so the common no-comments/no-blank-line path allocates nothing
114
+ * per entry. `hasEntryComments` and `entryTrailing` are consulted only when
115
+ * `preserveComments` is set; `entryLeadingNode` is also consulted when
116
+ * `preserveBlankLines` is set, independently of `preserveComments`, to read
117
+ * its `blankLineBefore` flag. `renderEntry` receives the resolved `colSep`
118
+ * (': ' or ':' depending on compact mode) for rendering map pairs.
66
119
  */
67
120
  export declare function serializeContainer(p: {
68
121
  node: Commented;
69
122
  options: ToCDNOptions | undefined;
70
123
  depth: number;
71
- openChar: '[' | '{' | '(';
72
- closeChar: ']' | '}' | ')';
124
+ openChar: string;
125
+ closeChar: string;
73
126
  count: number;
74
127
  indefiniteLength: boolean;
75
128
  encodingWidth: EncodingWidth | undefined;
129
+ /**
130
+ * Where the resolved encoding-indicator suffix is placed.
131
+ * - `'open'` (default): right after `openChar`, before the content
132
+ * (`[_2 1,2,3]`) — the head this indicator describes encodes entry count.
133
+ * - `'close'`: right after `closeChar`, with no separating space
134
+ * (`<<1,2>>_1`) — for `CborEmbeddedCBOR`, whose byte-string head encodes
135
+ * content byte length, not entry count.
136
+ */
137
+ eiPosition?: 'open' | 'close';
138
+ /**
139
+ * Basis for canonical-encoding-width detection (`encodingIndicators:
140
+ * 'auto'`/`'always'` with no explicit `encodingWidth`). Defaults to
141
+ * `count`, matching the CBOR array/map head. `CborEmbeddedCBOR` overrides
142
+ * this to its encoded content's byte length instead.
143
+ */
144
+ canonicalCount?: () => bigint;
76
145
  hasEntryComments: () => boolean;
77
146
  /** Render entry `i` at child depth (`item` or `key: value`). */
78
147
  renderEntry: (i: number, colSep: string) => string;
79
148
  /**
80
149
  * Whether entry `i` contains no nested array/map, so it may stay on the
81
- * container's line under `inlineLeafContainers`. Omitted = always a leaf.
150
+ * container's line under `inlineLeafContainers`. Omitted = always a leaf
151
+ * (used by `CborEmbeddedCBOR`, where an entry that is itself a container
152
+ * still inlines as long as its own rendering fits on one line).
82
153
  */
83
154
  entryIsLeaf?: (i: number) => boolean;
84
155
  /** Node whose leading comments are emitted above entry `i` (item / map key). */
@@ -86,7 +157,63 @@ export declare function serializeContainer(p: {
86
157
  /** Pre-formatted trailing comment text for entry `i` (starts with ' ', or ''). */
87
158
  entryTrailing: (i: number, style: 'c-style' | 'cdn-style' | undefined) => string;
88
159
  }): string;
160
+ /**
161
+ * Single-child counterpart to `serializeContainer`, for a wrapper that
162
+ * holds exactly one child inside `openChar`/`closeChar` (currently just
163
+ * `CborTag`'s `(content)`) rather than a comma-separated list of entries.
164
+ *
165
+ * Emits the child's own leading/trailing comments, and the wrapper node's
166
+ * `dangling` comments (a comment positioned after the child but still
167
+ * inside the brackets, with nothing following it to attach to as leading —
168
+ * mirroring how `serializeContainer` handles a container's own dangling
169
+ * comments). Falls back to the plain single-line `(content)` form — the
170
+ * common, zero-allocation-beyond-string-concat path — when comments aren't
171
+ * requested/applicable (no indent, no `preserveComments`, or neither the
172
+ * child nor the wrapper has any).
173
+ *
174
+ * `renderChild` is called with the child's depth exactly once, resolved
175
+ * *before* calling it: `depth + 1` when comments force multi-line
176
+ * rendering, `depth` otherwise (matching a plain value's existing
177
+ * "transparent" nesting — `tag(content)` doesn't indent `content` an extra
178
+ * level when there's nothing to justify going multi-line for).
179
+ */
180
+ export declare function renderSingleChildWithComments(child: Commented, wrapper: Commented, options: ToCDNOptions | undefined, depth: number, renderChild: (childDepth: number) => string, openChar: '(', closeChar: ')'): string;
89
181
  export declare function serializeBytes(bytes: Uint8Array, encoding?: 'hex' | 'base64' | 'base64url' | 'base32' | 'base32hex', sqstr?: 'printable-string' | 'string' | 'none'): string;
182
+ /**
183
+ * Which comment syntax a byte-string literal's raw source recognizes —
184
+ * `undefined` when it has none at all (its content is data, not a comment
185
+ * host). Set once, at parse time, by whoever actually knows the literal's
186
+ * real origin (the tokenizer for `h'...'`/`b64'...'`/bare sqstr, or the
187
+ * parser comparing the resolved extension against the specific built-in
188
+ * `b32`/`h32` objects by reference — never guessed later from the prefix
189
+ * string, since a user extension can register under any prefix, including
190
+ * one a built-in also uses; see `CborByteString.ednCommentSyntax`).
191
+ * - `'full'`: `#`, `//`, `/* *\/`, and `/ /` (§5.2.1/§5.3.3) — `h'...'`
192
+ * and its backtick form, and the built-in `b32'...'`/`h32'...'`
193
+ * extensions, which share hex's comment syntax (`utils/strip-comments.ts`).
194
+ * - `'hash-only'`: only `#` line comments — standard base64 (`b64'...'`),
195
+ * where `/` is valid data (e.g. `//8=` decodes to 0xFFFF), never a
196
+ * comment marker (see Tokenizer._readByteContent, §5.2.2).
197
+ */
198
+ export type ByteCommentSyntax = 'full' | 'hash-only';
199
+ /**
200
+ * Strip comments from inside a preserved byte-string literal's raw source,
201
+ * keeping everything else — case, whitespace, `...` — untouched. Used when
202
+ * `preserveByteString` is set but `preserveComments` is not: the preserved
203
+ * spelling should still drop comments, the same as an unpreserved literal
204
+ * re-derived from its decoded value would. `syntax` selects the comment
205
+ * rules to apply (see `ByteCommentSyntax`); the caller is responsible for
206
+ * knowing which one is correct — this function does not guess from `raw`.
207
+ *
208
+ * Only scans the quote-delimited content (not the prefix or a trailing
209
+ * encoding-indicator suffix), and mirrors the tokenizer's own
210
+ * comment-recognition closely enough for realistic input; a comment
211
+ * containing a literal copy of the delimiter quote character is not
212
+ * specially handled (the input is already known-valid, so at worst this
213
+ * shifts where the content/comment boundary is drawn, never produces
214
+ * unparseable output).
215
+ */
216
+ export declare function stripByteLiteralComments(raw: string, syntax: ByteCommentSyntax): string;
90
217
  /**
91
218
  * Produce a single-quoted EDN app-string content `'...'` from a string value.
92
219
  * Exported for use by app-extension `_toCDN` implementations.
@@ -114,3 +241,75 @@ export declare function canonicalEncodingWidth(n: bigint): EncodingWidth;
114
241
  * @param getCanonical - lazily compute the canonical width (only called in 'always' mode)
115
242
  */
116
243
  export declare function resolveEiSuffix(options: ToCDNOptions | undefined, encodingWidth: EncodingWidth | undefined, getCanonical: () => EncodingWidth): string;
244
+ /** How a node should render under `preserveAppSequence`. */
245
+ export type AppSeqRenderDecision = 'verbatim' | 'adjusted' | 'source' | 'structural' | 'normal';
246
+ /**
247
+ * Decide how an extension result node — from a `prefix'...'` /
248
+ * `` prefix`...` `` / `prefix<<...>>` source, or (for a tag-wrapper node
249
+ * that also has a generic `CborTag` fallback to delegate to) a raw tag
250
+ * literal `N(...)` — should render under `ToCDNOptions.preserveAppSequence`.
251
+ *
252
+ * A raw-tag source is recognised by `ednSource !== undefined`: the parser
253
+ * only ever sets a tag-wrapper's `ednSource` (the tag *number's* digit
254
+ * spelling) when it was reached via `N(...)`, never via one of the
255
+ * app-string/-sequence forms. Leaf (non-tag-wrapper) nodes have no raw-tag
256
+ * form at all — always pass `undefined` for `ednSource` there.
257
+ *
258
+ * Returns:
259
+ * - `'verbatim'`: re-emit `appSeqSource` as-is. Only reachable for a
260
+ * raw-tag source: its encoding-indicator suffixes are nested at two
261
+ * independent positions (tag number and inner content), so this is only
262
+ * safe in `'auto'` mode with no relevant sibling option overridden.
263
+ * - `'source'`: keep a raw-tag source structurally verbatim, applying
264
+ * comment and encoding-indicator changes by their captured source spans.
265
+ * This avoids changing unrelated literal spelling or layout.
266
+ * - `'adjusted'`: for an app-string/-sequence source, strip whatever
267
+ * *outer* indicator suffix is already at the end of `appSeqSource` (or,
268
+ * under `'never'`, also an *inner* one immediately before `<<...>>`'s
269
+ * closing `>>` — the app-sequence's sole item's own indicator) and let
270
+ * the caller append one recomputed via `resolveEiSuffix`/`floatSuffix`
271
+ * for the current mode via `adjustAppSeqIndicator` — correct in every
272
+ * mode, without losing the source's notation family. (An inner indicator
273
+ * can only be *stripped*, not *recomputed*: the item's own encoding
274
+ * width isn't tracked once resolved to a plain date/address string, so
275
+ * `'always'` cannot add a missing one — it is left absent.)
276
+ * - `'structural'`: keep the raw-tag notation *family* (as opposed to
277
+ * upgrading to `prefix'...'`) but re-derive it structurally — via the
278
+ * node's own `CborTag` rendering — instead of using `appSeqSource`
279
+ * verbatim. Needed whenever verbatim text would ignore a sibling option
280
+ * that must apply per nested node: an explicit `preserveNumberFormat` /
281
+ * `preserveByteString` / `preserveTextString` / `preserveRawString` /
282
+ * `preserveConcatenation` override.
283
+ * Verbatim raw-tag text inherently contains the nested literal spelling.
284
+ * - `'normal'`: fall through to the class's own notation regeneration
285
+ * (`prefix'...'`), unaffected by `preserveAppSequence`. For `<<...>>`,
286
+ * this is also used when replaying its sole inner item would defeat an
287
+ * explicitly disabled, relevant literal-preservation option.
288
+ *
289
+ * `editsComplete` (from `CborItem.appSeqEncodingEditsComplete`, raw-tag
290
+ * sources only) is `false` when the tag's content contains a node type
291
+ * `collectContentEncodingEdits` doesn't cover (e.g. a `CborMap` nested in an
292
+ * `ip` array's raw-tag content). `'source'` relies on those edits to apply
293
+ * `encodingIndicators: 'always'`/`'never'`, so incomplete coverage would
294
+ * silently leave the uncovered node's own indicator unchanged; `'structural'`
295
+ * is used instead, since it re-derives every nested indicator recursively.
296
+ */
297
+ export declare function decideTaggedAppSeqRendering(options: ToCDNOptions | undefined, appSeqSource: string | undefined, ednSource: string | undefined, sourceFeatures?: AppSeqSourceFeatures, editsComplete?: boolean): AppSeqRenderDecision;
298
+ /** Apply comment/EI options directly to a preserved raw-tag source. */
299
+ export declare function adjustRawAppSeqSource(appSeqSource: string, options: ToCDNOptions | undefined, comments: readonly CborComment[] | undefined, encodingEdits: readonly AppSeqEncodingEdit[] | undefined): string;
300
+ /**
301
+ * Adjust an `'adjusted'` app-string/-sequence source: apply requested comment
302
+ * conversion/removal by captured source span, strip the existing
303
+ * encoding-indicator suffix(es), then append `newSuffix` (the outer/wrapper
304
+ * indicator recomputed for the current mode) — see
305
+ * `decideTaggedAppSeqRendering`.
306
+ *
307
+ * Under `encodingIndicators: 'never'`, an inner (item-level) indicator is
308
+ * also stripped, using
309
+ * `innerItemEnd` (see `CborItem.appSeqInnerEnd`) to find it by its actual
310
+ * parsed position rather than by pattern-matching text near the closing
311
+ * `>>` — whitespace, a trailing comma, and/or a comment can all separate
312
+ * the two, in any combination, so a position-based cut is the only fully
313
+ * reliable way to locate it.
314
+ */
315
+ export declare function adjustAppSeqIndicator(appSeqSource: string, newSuffix: string, options: ToCDNOptions | undefined, innerItemEnd: number | undefined, comments: readonly CborComment[] | undefined): string;
@@ -30,6 +30,7 @@ export declare const TAG_EPOCH = 1n;
30
30
  export declare class CborEpochDtExtUint extends CborUint {
31
31
  constructor(value: number | bigint, options?: {
32
32
  encodingWidth?: EncodingWidth;
33
+ ednSource?: string;
33
34
  });
34
35
  _toCDN(options: ToCDNOptions | undefined, _depth: number): string;
35
36
  }
@@ -40,6 +41,7 @@ export declare class CborEpochDtExtUint extends CborUint {
40
41
  export declare class CborEpochDtExtNint extends CborNint {
41
42
  constructor(value: number | bigint, options?: {
42
43
  encodingWidth?: EncodingWidth;
44
+ ednSource?: string;
43
45
  });
44
46
  _toCDN(options: ToCDNOptions | undefined, _depth: number): string;
45
47
  }
@@ -50,6 +52,7 @@ export declare class CborEpochDtExtNint extends CborNint {
50
52
  export declare class CborEpochDtExtFloat extends CborFloat {
51
53
  constructor(value: number, options?: {
52
54
  precision?: 'half' | 'single' | 'double';
55
+ literalSource?: string;
53
56
  });
54
57
  _toCDN(options: ToCDNOptions | undefined, _depth: number): string;
55
58
  }
@@ -52,17 +52,39 @@ export interface CborExtension {
52
52
  */
53
53
  parseAppSequence?(prefix: string, items: CborItem[], onError?: (msg: string) => void): CborItem;
54
54
  /**
55
- * When `true`, the CDN parser wraps the result of `parseAppSequence` in a
56
- * `CborAppSeqResult` so that `toCDN()` round-trips the original
57
- * `prefix<<...>>` notation when `appStrings !== false`. In single-line
58
- * output (no `indent`), a source spelling that spans multiple lines falls
59
- * back to serializing the resolved item instead.
55
+ * Controls how the CDN parser preserves the original application-string
56
+ * / -sequence / raw-tag source text — `prefix'...'`, `` prefix`...` ``,
57
+ * `prefix<<...>>`, or a raw tag literal `N(...)` resolved via `parseTag`
58
+ * for round-tripping through `toCDN()`.
60
59
  *
61
- * Extensions whose result is already a subclass that handles source
62
- * preservation itself (e.g. `CborFloat` via its `ednSource` property) should
63
- * leave this unset.
60
+ * - `true`: the parser wraps the result of `parseAppSequence` (only —
61
+ * `parseAppString` and `parseTag` results are unaffected) in a
62
+ * `CborAppSeqResult`, which round-trips the original `<<...>>` notation
63
+ * unconditionally whenever `appStrings !== false` (no extra option
64
+ * needed). Use this when the result has no dedicated subclass whose
65
+ * identity callers rely on (e.g. `instanceof` checks) — the wrapper
66
+ * changes the returned node's type.
67
+ * - `'optional'`: for `parseAppString`, `parseAppSequence`, and `parseTag`
68
+ * results alike, the parser instead sets `appSeqSource` directly on the
69
+ * *same* result node (preserving its class/identity) and leaves it to
70
+ * the node's own `_toCDN()` override to decide whether to use it — by
71
+ * convention, only when `ToCDNOptions.preserveAppSequence` is set, so
72
+ * the default output keeps regenerating `prefix'...'` form from the
73
+ * resolved value. This covers a `` prefix`...` `` (backtick) source, a
74
+ * non-canonically-spelled `prefix'...'` source, and a raw tag literal
75
+ * (e.g. `1(1749772800)`) that would otherwise be upgraded to
76
+ * `prefix'...'` notation — not just `<<...>>`. Use this when the result
77
+ * is a dedicated subclass whose default behavior is to regenerate its
78
+ * notation from the resolved value on every call.
79
+ * - `undefined` (default): neither happens. Extensions whose result
80
+ * already handles source preservation itself (e.g. `CborFloat` via its
81
+ * own `ednSource` property) should leave this unset.
82
+ *
83
+ * In single-line output (no `indent`), a source spelling that spans
84
+ * multiple lines always falls back to serializing the resolved item,
85
+ * regardless of mode.
64
86
  */
65
- readonly preserveAppSeqSource?: boolean;
87
+ readonly preserveAppSeqSource?: boolean | 'optional';
66
88
  /**
67
89
  * Called when a `CborTag` is encountered during CBOR decode (`fromCBOR`)
68
90
  * or EDN integer-tag parsing (`fromCDN`).