@cbortech/cbor 0.26.8 → 0.27.0

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 (54) hide show
  1. package/README.ja.md +120 -28
  2. package/README.md +121 -29
  3. package/dist/ast/CborAppSeqResult.d.ts +22 -0
  4. package/dist/ast/CborByteString.d.ts +16 -0
  5. package/dist/ast/CborEmbeddedCBOR.d.ts +1 -1
  6. package/dist/ast/CborFloat.d.ts +1 -1
  7. package/dist/ast/CborIndefiniteByteString.d.ts +24 -0
  8. package/dist/ast/CborIndefiniteTextString.d.ts +16 -0
  9. package/dist/ast/CborItem.d.ts +44 -4
  10. package/dist/ast/CborTag.d.ts +27 -0
  11. package/dist/ast/CborTextString.d.ts +2 -1
  12. package/dist/ast/CborUnresolvedAppExt.d.ts +2 -2
  13. package/dist/ast/index.cjs +1 -1
  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.js +18 -18
  20. package/dist/cdn/index.js.map +1 -1
  21. package/dist/cdn/serialize-utils.d.ts +207 -8
  22. package/dist/cdn/tokenizer.d.ts +12 -11
  23. package/dist/extensions/builtins.d.ts +5 -5
  24. package/dist/extensions/cri.d.ts +2 -2
  25. package/dist/extensions/ip.d.ts +1 -1
  26. package/dist/extensions/types.d.ts +4 -4
  27. package/dist/index.cjs +3 -3
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.js +158 -158
  30. package/dist/index.js.map +1 -1
  31. package/dist/mapEntries-C1f7G0AM.cjs +13 -0
  32. package/dist/mapEntries-C1f7G0AM.cjs.map +1 -0
  33. package/dist/{mapEntries-Ci_dppP6.js → mapEntries-CvLdiN0h.js} +1362 -1219
  34. package/dist/mapEntries-CvLdiN0h.js.map +1 -0
  35. package/dist/{schema-y8G5mDIS.js → schema-CNfrVRYp.js} +294 -294
  36. package/dist/{schema-y8G5mDIS.js.map → schema-CNfrVRYp.js.map} +1 -1
  37. package/dist/schema-iXpYtKQl.cjs +63 -0
  38. package/dist/{schema-DgnkH0P6.cjs.map → schema-iXpYtKQl.cjs.map} +1 -1
  39. package/dist/{tokenizer-N-vAvRdj.js → serialize-utils-BuIZPaUc.js} +626 -358
  40. package/dist/serialize-utils-BuIZPaUc.js.map +1 -0
  41. package/dist/serialize-utils-CjTqQivB.cjs +37 -0
  42. package/dist/serialize-utils-CjTqQivB.cjs.map +1 -0
  43. package/dist/types.d.ts +235 -58
  44. package/dist/utils/base64.d.ts +1 -1
  45. package/dist/utils/hexfloat.d.ts +1 -1
  46. package/dist/utils/strip-comments.d.ts +1 -1
  47. package/package.json +8 -6
  48. package/dist/mapEntries-BJzyBUH5.cjs +0 -13
  49. package/dist/mapEntries-BJzyBUH5.cjs.map +0 -1
  50. package/dist/mapEntries-Ci_dppP6.js.map +0 -1
  51. package/dist/schema-DgnkH0P6.cjs +0 -63
  52. package/dist/tokenizer-BD08xbyd.cjs +0 -36
  53. package/dist/tokenizer-BD08xbyd.cjs.map +0 -1
  54. package/dist/tokenizer-N-vAvRdj.js.map +0 -1
package/README.ja.md CHANGED
@@ -385,18 +385,22 @@ CBOR.format("h'68' + b64'aQ'", {
385
385
  // b64'aQ'
386
386
  ```
387
387
 
388
- ### application-string / -sequence 記法を保持する
388
+ 保持した連結を `+` ではなく draft-27 の `t1<<...>>` / `b1<<...>>` 記法で
389
+ 出力するには、[文字列連結と不定長文字列](#文字列連結と不定長文字列) の
390
+ `modernConcat` を参照してください。
391
+
392
+ ### app-string / -sequence 記法を保持する
389
393
 
390
394
  一部の組み込み拡張(`dt`/`DT`、`ip`/`IP`)は同じ値に対して `prefix'...'`
391
- (application string)、`` prefix`...` ``(backtick application string)、
392
- `prefix<<...>>`(application sequence)、生のタグリテラル(`N(...)`)の
395
+ (app-string)、`` prefix`...` ``(backtick app-string)、
396
+ `prefix<<...>>`(app-sequence)、生のタグリテラル(`N(...)`)の
393
397
  いずれの記法もサポートしていますが、デフォルトでは `CBOR.format()` を呼ぶ
394
398
  たびに解決済みの値から `prefix'...'` を再生成します。そのため
395
399
  `` DT`1969-07-21T02:56:16Z` `` も `DT<<'1969-07-21T02:56:16Z'>>` も、生の
396
400
  タグ記法 `1(1749772800)` さえも、すべて `DT'...'` 記法に正規化され、さら
397
401
  に非正規な `DT'...'` の表記(例えば `Z` の代わりに `+00:00` を使った場合
398
- など)も書き換えられます。`preserveAppSequence` を指定すると、実際に使わ
399
- れていた表記のまま保持します。`appStrings: false` を同時に指定した場合は
402
+ など)も書き換えられます。`preserveAppPrefix` を指定すると、実際に使わ
403
+ れていた表記のまま保持します。`appPrefix: false` を同時に指定した場合は
400
404
  効果がありません(どちらにせよ元の表記に関わらず生のタグ記法になるため)。
401
405
  これらの記法からパースされていない値にも効果はありません。
402
406
 
@@ -406,16 +410,50 @@ import { CBOR } from '@cbortech/cbor';
406
410
  CBOR.format('1(1749772800)');
407
411
  // "DT'2025-06-13T00:00:00Z'"
408
412
 
409
- CBOR.format('1(1749772800)', { preserveAppSequence: true });
413
+ CBOR.format('1(1749772800)', { preserveAppPrefix: true });
410
414
  // "1(1749772800)"
411
415
 
412
- CBOR.format("DT<<'1969-07-21T02:56:16Z'>>", { preserveAppSequence: true });
416
+ CBOR.format("DT<<'1969-07-21T02:56:16Z'>>", { preserveAppPrefix: true });
413
417
  // "DT<<'1969-07-21T02:56:16Z'>>"
414
418
 
415
- CBOR.format('DT`1969-07-21T02:56:16Z`', { preserveAppSequence: true });
419
+ CBOR.format('DT`1969-07-21T02:56:16Z`', { preserveAppPrefix: true });
416
420
  // "DT`1969-07-21T02:56:16Z`"
417
421
  ```
418
422
 
423
+ ### コメントを保持する
424
+
425
+ デフォルトでは、`CBOR.fromCDN()` はコメントを破棄し、`CBOR.format()` も
426
+ コメントを出力しません。`preserveComments: true` を指定すると、パース時に
427
+ コメントを取り込み、元々書かれていたマーカー(`#`・`//`・`/* */`・`/ /`)の
428
+ まま再出力します。
429
+
430
+ ```ts
431
+ import { CBOR } from '@cbortech/cbor';
432
+
433
+ const text = '{ "a": 1 } # trailing comment';
434
+
435
+ CBOR.format(text, { indent: 2 });
436
+ // '{\n "a": 1\n}'
437
+
438
+ CBOR.format(text, { indent: 2, preserveComments: true });
439
+ // '{\n "a": 1\n} # trailing comment'
440
+ ```
441
+
442
+ 書かれていたマーカーを混在させたまま保持するのではなく、すべてのコメントの
443
+ マーカーを正規化したい場合は `comments` を使います — `'c-style'` は
444
+ `//` と `/* */`、`'cdn-style'` は `#` と `/ /` に正規化します。
445
+ `preserveComments: true` が指定されている場合は効果がありません(verbatim
446
+ が優先されます)。コメントを完全に削除するには `comments: 'strip'` を
447
+ 明示的に指定するか(あるいは両方とも未指定のままにするか)します。
448
+
449
+ ```ts
450
+ CBOR.format(text, { indent: 2, comments: 'c-style' });
451
+ // '{\n "a": 1\n} // trailing comment'
452
+ ```
453
+
454
+ `indent` を指定して整形出力する場合のみ効果があります。1 行出力では改行で
455
+ 終端する必要がある行コメントの性質上、コメントは常に取り除かれます。
456
+
419
457
  ### 空行を保持する
420
458
 
421
459
  デフォルトでは、`CBOR.format()` は配列・マップの要素間(および `(_ ...)`
@@ -672,7 +710,7 @@ console.log(text);
672
710
 
673
711
  ## 文字列連結と不定長文字列
674
712
 
675
- draft-ietf-cbor-edn-literals-26(§3.4 / §3.5)の application extension
713
+ draft-ietf-cbor-edn-literals-27(§3.5 / §3.6)の app-extension
676
714
  `t1` / `b1` / `ilbs` / `ilts` は、デフォルトで有効です。
677
715
 
678
716
  `t1<<...>>` と `b1<<...>>` は、(テキストまたはバイト)文字列の引数を左から
@@ -683,11 +721,11 @@ draft-ietf-cbor-edn-literals-26(§3.4 / §3.5)の application extension
683
721
  import { CBOR } from '@cbortech/cbor';
684
722
 
685
723
  const text = CBOR.fromCDN('t1<<"Hello ", "world">>');
686
- console.log(text.toCDN({ appStrings: false }));
724
+ console.log(text.toCDN({ appPrefix: false }));
687
725
  // "Hello world"
688
726
 
689
727
  const bytes = CBOR.fromCDN("b1<<'Hello ', h'776f726c64'>>");
690
- console.log(bytes.toCDN({ appStrings: false }));
728
+ console.log(bytes.toCDN({ appPrefix: false }));
691
729
  // 'Hello world'
692
730
  ```
693
731
 
@@ -701,29 +739,82 @@ streamstring 構文の置き換えですが、本ライブラリは従来構文
701
739
  import { CBOR } from '@cbortech/cbor';
702
740
 
703
741
  const v = CBOR.fromCDN("ilbs<<'Hello ', 'world'>>");
704
- console.log(v.toCDN({ appStrings: false }));
742
+ console.log(v.toCDN({ appPrefix: false }));
705
743
  // (_ 'Hello ','world')
706
744
  ```
707
745
 
746
+ ### `t1`/`b1`/`ilbs`/`ilts` 記法を出力する
747
+
748
+ パース側はすでに `t1`/`b1`/`ilbs`/`ilts` 記法を受理しますが、`toCDN()` /
749
+ `CBOR.format()` はデフォルトではこれらを自ら出力しません。保持した連結
750
+ (`preserveConcatenation`)は従来どおり `+` で、不定長文字列は従来どおり
751
+ `(_ ...)` streamstring 形式でレンダリングされます。`modernConcat` と
752
+ `modernStreamSyntax` を `true` にすると draft-27 の記法での出力を選択でき
753
+ ます。どちらもデフォルトは `false`(従来構文)で、`appPrefix` が `false`
754
+ の場合は従来構文にフォールバックします。
755
+
756
+ ```ts
757
+ import { CBOR } from '@cbortech/cbor';
758
+
759
+ CBOR.format('"a" + "b"', {
760
+ indent: 2,
761
+ preserveConcatenation: true,
762
+ modernConcat: true,
763
+ });
764
+ // t1<<"a", "b">>
765
+
766
+ CBOR.format('(_ "a", "b")', { modernStreamSyntax: true });
767
+ // ilts<<"a","b">>
768
+ ```
769
+
770
+ `modernConcat` は `...` による省略連結(§5.2)にも適用され、
771
+ `"a" + ... + "b"` は `t1<<"a", ..., "b">>` としてレンダリングされます。
772
+ 通常の連結と異なり、これは `preserveConcatenation` の値に関わらず適用され
773
+ ます — 省略連結にはそもそも1つのリテラルに畳み込んだ状態が存在しないため
774
+ です。
775
+
776
+ > [!NOTE]
777
+ > どちらのオプションも `t1`/`b1`/`ilbs`/`ilts` のソースを従来記法に
778
+ > 変換するものではありません。`t1<<...>>`(や `ilbs<<...>>` など)
779
+ > からパースされた値は、`appPrefix` が `false` でなく、
780
+ > `encodingIndicators` が `'auto'`(どちらもデフォルト)であり、かつ
781
+ > ソースが単一行、または `indent` 指定時であれば、`modernConcat` /
782
+ > `modernStreamSyntax` の値に関わらずそのままの記法で出力されます。
783
+ > `encodingIndicators: 'always'`/`'never'` や `appPrefix: false` を指定
784
+ > した場合は、他の app-string 値と同様に正規化されます(例:
785
+ > `encodingIndicators: 'always'` では `t1<<"a", "b">>` が `"ab"_i` に
786
+ > なります)。また、複数行のソースは `indent` 未指定(1行出力)の場合、
787
+ > そのレイアウトを再現できないため正規化されます:
788
+ >
789
+ > ```ts
790
+ > CBOR.format('t1<<\n "a",\n "b"\n>>');
791
+ > // '"ab"' — indent未指定のため正規化される
792
+ > CBOR.format('t1<<\n "a",\n "b"\n>>', { indent: 2 });
793
+ > // 't1<<\n "a",\n "b"\n>>' — そのまま保持される
794
+ > ```
795
+ >
796
+ > 両オプションが影響するのは `+` チェーンや `(_ ...)` チャンク列から
797
+ > 再構築された値の出力のみです。
798
+
708
799
  > [!NOTE]
709
- > `t1` / `b1` という識別子は draft-26 で暫定(provisional)と明記されて
800
+ > `t1` / `b1` という識別子は draft-27 でも暫定(provisional)と明記されて
710
801
  > おり、CBOR ワーキンググループにより改名される可能性があります。
711
802
 
712
803
  ## float
713
804
 
714
805
  16 進数のビットパターンを IEEE 754 浮動小数点値として解釈します
715
- (draft-ietf-cbor-edn-literals-26 §3.7)。デフォルトで有効です。
806
+ (draft-ietf-cbor-edn-literals-27 §3.8)。デフォルトで有効です。
716
807
 
717
808
  ```ts
718
809
  import { CBOR } from '@cbortech/cbor';
719
810
 
720
811
  const v = CBOR.fromCDN("float'7e00'");
721
- console.log(v.toCDN({ appStrings: false }));
812
+ console.log(v.toCDN({ appPrefix: false }));
722
813
  // NaN
723
814
 
724
815
  // バイト列から解釈する場合
725
816
  const v2 = CBOR.fromCDN("float<<h'3f800000'>>");
726
- console.log(v2.toCDN({ appStrings: false }));
817
+ console.log(v2.toCDN({ appPrefix: false }));
727
818
  // 1.0_2
728
819
  ```
729
820
 
@@ -736,7 +827,7 @@ extension があります。必要なものを `import` し、
736
827
  ### b32 / h32
737
828
 
738
829
  [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648) の Base32 エンコードによるバイト列リテラルです。
739
- [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949) §8 に記載があり、[draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/) でも触れられています。
830
+ [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949) §8 に記載があり、[draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/) でも触れられています。
740
831
 
741
832
  - `b32` — §6 Base32(`A–Z 2–7` アルファベット)
742
833
  - `h32` — §7 Base32Hex(`0–9 A–V` アルファベット)
@@ -745,11 +836,11 @@ extension があります。必要なものを `import` し、
745
836
  import { CBOR, b32, h32 } from '@cbortech/cbor';
746
837
 
747
838
  const v1 = CBOR.fromCDN("b32'AEBAGBA'", { extensions: [b32] });
748
- console.log(v1.toCDN({ appStrings: false }));
839
+ console.log(v1.toCDN({ appPrefix: false }));
749
840
  // h'01020304'
750
841
 
751
842
  const v2 = CBOR.fromCDN("h32'00P00'", { extensions: [h32] });
752
- console.log(v2.toCDN({ appStrings: false }));
843
+ console.log(v2.toCDN({ appPrefix: false }));
753
844
  // h'003200'
754
845
  ```
755
846
 
@@ -763,25 +854,24 @@ console.log(v2.toCDN({ appStrings: false }));
763
854
  ```ts
764
855
  import { CBOR, same } from '@cbortech/cbor';
765
856
 
766
- // すべての要素が同じバイト列かを検証し、最初の要素を返す
767
857
  const v = CBOR.fromCDN("same<<h'0102', h'0102'>>", { extensions: [same] });
768
- console.log(v.toCDN({ appStrings: false }));
858
+ console.log(v.toCDN({ appPrefix: false }));
769
859
  // h'0102'
770
860
 
771
861
  // 要素が 1 つでも有効(常にパスする)
772
862
  const v2 = CBOR.fromCDN('same<<42>>', { extensions: [same] });
773
- console.log(v2.toCDN({ appStrings: false }));
863
+ console.log(v2.toCDN({ appPrefix: false }));
774
864
  // 42
775
865
  ```
776
866
 
777
867
  ---
778
868
 
779
- 追加の application extension は別パッケージとして公開されています。必要なものを
869
+ 追加の app-extension は別パッケージとして公開されています。必要なものを
780
870
  インストールし、`extensions` オプションに渡して使います。
781
871
 
782
872
  ### hash
783
873
 
784
- `hash` は [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/) §3.3 で定義された標準の application extension です。
874
+ `hash` は [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/) §3.4 で定義された標準の app-extension です。
785
875
  ハッシュアルゴリズムと値を `hash'algorithm:value'` の形式で表現します。
786
876
  実装には外部の暗号ライブラリが必要なため、[@cbortech/hash-extension](https://www.npmjs.com/package/@cbortech/hash-extension) として
787
877
  別パッケージで提供しています。
@@ -806,7 +896,7 @@ const digest = cbor.parse(
806
896
 
807
897
  ### uuid
808
898
 
809
- `uuid` はこのライブラリ独自の application extension です。
899
+ `uuid` はこのライブラリ独自の app-extension です。
810
900
  [@cbortech/uuid-extension](https://www.npmjs.com/package/@cbortech/uuid-extension) として別パッケージで提供しています。
811
901
 
812
902
  ```bash
@@ -826,7 +916,7 @@ const id = cbor.parse("uuid'550e8400-e29b-41d4-a716-446655440000'");
826
916
  ### set / map
827
917
 
828
918
  `SET` と `MAP` は、タグ付きの Set / Map 値を扱うための、このライブラリ独自の
829
- application extension です。
919
+ app-extension です。
830
920
  [@cbortech/set-map-extensions](https://www.npmjs.com/package/@cbortech/set-map-extensions)
831
921
  としてまとめて別パッケージで提供しています。`SET<<[...]>>` は配列に CBOR tag
832
922
  258 を付けた値、`MAP<<{...}>>` は map に CBOR tag 259 を付けた値を生成します。
@@ -1083,9 +1173,11 @@ CDDL コンパイラは `@cbortech/cbor/cddl`
1083
1173
 
1084
1174
  - CBOR
1085
1175
  - [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949)
1176
+ - CBOR Sequences
1177
+ - [RFC 8742](https://www.rfc-editor.org/rfc/rfc8742)
1086
1178
  - CDN (CBOR-EDN)
1087
1179
  - [draft-ietf-cbor-edn-literals-25](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/)
1088
- - [draft-ietf-cbor-edn-literals-26](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/26/)
1180
+ - [draft-ietf-cbor-edn-literals-27](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/)
1089
1181
  - CDDL
1090
1182
  - [RFC 8610](https://www.rfc-editor.org/rfc/rfc8610)
1091
1183
  - [RFC 9682](https://www.rfc-editor.org/rfc/rfc9682)
@@ -1093,7 +1185,7 @@ CDDL コンパイラは `@cbortech/cbor/cddl`
1093
1185
 
1094
1186
  補足:
1095
1187
 
1096
- - CDN は draft-26 に準拠しつつ、draft-25 の `(_ ...)` streamstring 構文と
1188
+ - CDN は draft-27 に準拠しつつ、draft-25 の `(_ ...)` streamstring 構文と
1097
1189
  `+` による文字列連結構文も引き続きサポートしています。
1098
1190
  - CDDL は RFC 8610 のすべての control operator と、RFC 9165 の `.plus`、
1099
1191
  `.cat`、`.feature` をサポートしています。
package/README.md CHANGED
@@ -392,19 +392,23 @@ CBOR.format("h'68' + b64'aQ'", {
392
392
  // b64'aQ'
393
393
  ```
394
394
 
395
- ### Preserve application-string/-sequence notation
395
+ To render the preserved concatenation using draft-27's `t1<<...>>` /
396
+ `b1<<...>>` notation instead of `+`, see `modernConcat` in
397
+ [String Concatenation and Indefinite-Length Strings](#string-concatenation-and-indefinite-length-strings).
398
+
399
+ ### Preserve app-string/-sequence notation
396
400
 
397
401
  Some built-in extensions (`dt`/`DT`, `ip`/`IP`) support `prefix'...'`
398
- (application string), `` prefix`...` `` (backtick application string),
399
- `prefix<<...>>` (application sequence), and a raw tag literal (`N(...)`)
402
+ (app-string), `` prefix`...` `` (backtick app-string),
403
+ `prefix<<...>>` (app-sequence), and a raw tag literal (`N(...)`)
400
404
  notation for the same value, and by default regenerate `prefix'...'` from
401
405
  the resolved value on every `CBOR.format()` call — so
402
406
  `` DT`1969-07-21T02:56:16Z` ``, `DT<<'1969-07-21T02:56:16Z'>>`, and even the
403
407
  raw tag form `1(1749772800)` all normalize to `DT'...'` notation, and a
404
408
  non-canonical `DT'...'` spelling (e.g. a `+00:00` offset instead of `Z`)
405
- gets rewritten too. `preserveAppSequence` keeps the original spelling
409
+ gets rewritten too. `preserveAppPrefix` keeps the original spelling
406
410
  instead — whichever form was used. It has no effect when
407
- `appStrings: false` is also set (raw tag notation is used either way
411
+ `appPrefix: false` is also set (raw tag notation is used either way
408
412
  regardless of the original spelling), or on values not parsed from one of
409
413
  these forms.
410
414
 
@@ -414,16 +418,50 @@ import { CBOR } from '@cbortech/cbor';
414
418
  CBOR.format('1(1749772800)');
415
419
  // "DT'2025-06-13T00:00:00Z'"
416
420
 
417
- CBOR.format('1(1749772800)', { preserveAppSequence: true });
421
+ CBOR.format('1(1749772800)', { preserveAppPrefix: true });
418
422
  // "1(1749772800)"
419
423
 
420
- CBOR.format("DT<<'1969-07-21T02:56:16Z'>>", { preserveAppSequence: true });
424
+ CBOR.format("DT<<'1969-07-21T02:56:16Z'>>", { preserveAppPrefix: true });
421
425
  // "DT<<'1969-07-21T02:56:16Z'>>"
422
426
 
423
- CBOR.format('DT`1969-07-21T02:56:16Z`', { preserveAppSequence: true });
427
+ CBOR.format('DT`1969-07-21T02:56:16Z`', { preserveAppPrefix: true });
424
428
  // "DT`1969-07-21T02:56:16Z`"
425
429
  ```
426
430
 
431
+ ### Preserve comments
432
+
433
+ By default, `CBOR.fromCDN()` discards comments and `CBOR.format()` emits
434
+ none. `preserveComments: true` captures them while parsing and re-emits each
435
+ comment verbatim, with whichever marker (`#`, `//`, `/* */`, `/ /`) it was
436
+ originally written with.
437
+
438
+ ```ts
439
+ import { CBOR } from '@cbortech/cbor';
440
+
441
+ const text = '{ "a": 1 } # trailing comment';
442
+
443
+ CBOR.format(text, { indent: 2 });
444
+ // '{\n "a": 1\n}'
445
+
446
+ CBOR.format(text, { indent: 2, preserveComments: true });
447
+ // '{\n "a": 1\n} # trailing comment'
448
+ ```
449
+
450
+ To normalize every comment's marker instead of keeping the mix as originally
451
+ written, use `comments` — `'c-style'` for `//` and `/* */`, or
452
+ `'cdn-style'` for `#` and `/ /`. It has no effect when `preserveComments` is
453
+ `true` (verbatim wins); explicitly set `comments: 'strip'` (or leave
454
+ both options unset) to drop comments entirely.
455
+
456
+ ```ts
457
+ CBOR.format(text, { indent: 2, comments: 'c-style' });
458
+ // '{\n "a": 1\n} // trailing comment'
459
+ ```
460
+
461
+ Only effective when `indent` enables pretty-printing: single-line output
462
+ strips all comments regardless, since line comments can only be terminated
463
+ by a newline.
464
+
427
465
  ### Preserve blank lines
428
466
 
429
467
  By default, `CBOR.format()` drops blank lines between array/map entries (and
@@ -683,8 +721,8 @@ console.log(text);
683
721
 
684
722
  ## String Concatenation and Indefinite-Length Strings
685
723
 
686
- The `t1` / `b1` / `ilbs` / `ilts` application extensions from
687
- draft-ietf-cbor-edn-literals-26 (§3.4 / §3.5) are enabled by default.
724
+ The `t1` / `b1` / `ilbs` / `ilts` app-extensions from
725
+ draft-ietf-cbor-edn-literals-27 (§3.5 / §3.6) are enabled by default.
688
726
 
689
727
  `t1<<...>>` and `b1<<...>>` join (text or byte) string arguments from left to
690
728
  right into a single text string (`t1`) or byte string (`b1`). Arguments may
@@ -694,11 +732,11 @@ also be ellipses (`...`) to elide parts of a string.
694
732
  import { CBOR } from '@cbortech/cbor';
695
733
 
696
734
  const text = CBOR.fromCDN('t1<<"Hello ", "world">>');
697
- console.log(text.toCDN({ appStrings: false }));
735
+ console.log(text.toCDN({ appPrefix: false }));
698
736
  // "Hello world"
699
737
 
700
738
  const bytes = CBOR.fromCDN("b1<<'Hello ', h'776f726c64'>>");
701
- console.log(bytes.toCDN({ appStrings: false }));
739
+ console.log(bytes.toCDN({ appPrefix: false }));
702
740
  // 'Hello world'
703
741
  ```
704
742
 
@@ -711,29 +749,81 @@ documents; this library keeps accepting the legacy syntax on input.
711
749
  import { CBOR } from '@cbortech/cbor';
712
750
 
713
751
  const v = CBOR.fromCDN("ilbs<<'Hello ', 'world'>>");
714
- console.log(v.toCDN({ appStrings: false }));
752
+ console.log(v.toCDN({ appPrefix: false }));
715
753
  // (_ 'Hello ','world')
716
754
  ```
717
755
 
756
+ ### Emitting `t1`/`b1`/`ilbs`/`ilts` notation
757
+
758
+ Parsing already accepts `t1`/`b1`/`ilbs`/`ilts` notation, but by default
759
+ `toCDN()`/`CBOR.format()` never emit it on their own: a preserved
760
+ concatenation (`preserveConcatenation`) still renders as `+`, and an
761
+ indefinite-length string still renders as the legacy `(_ ...)` streamstring
762
+ form. `modernConcat` and `modernStreamSyntax` opt into emitting the draft-27
763
+ notation instead — both default to `false` (the legacy syntax), and both fall
764
+ back to it when `appPrefix` is `false`.
765
+
766
+ ```ts
767
+ import { CBOR } from '@cbortech/cbor';
768
+
769
+ CBOR.format('"a" + "b"', {
770
+ indent: 2,
771
+ preserveConcatenation: true,
772
+ modernConcat: true,
773
+ });
774
+ // t1<<"a", "b">>
775
+
776
+ CBOR.format('(_ "a", "b")', { modernStreamSyntax: true });
777
+ // ilts<<"a","b">>
778
+ ```
779
+
780
+ `modernConcat` also applies within a `...` elision chain (§5.2), rendering
781
+ `"a" + ... + "b"` as `t1<<"a", ..., "b">>` — unlike plain concatenation, this
782
+ happens regardless of `preserveConcatenation`, since an elision chain has no
783
+ single-literal collapsed form to fall back to in the first place.
784
+
785
+ > [!NOTE]
786
+ > Neither option converts `t1`/`b1`/`ilbs`/`ilts` source back to the
787
+ > legacy notation: a value parsed from `t1<<...>>` (or `ilbs<<...>>`, etc.)
788
+ > keeps that exact spelling on output regardless of `modernConcat` /
789
+ > `modernStreamSyntax` — as long as `appPrefix` is not `false`,
790
+ > `encodingIndicators` is `'auto'` (both defaults), and the source is either
791
+ > single-line or being rendered with `indent` enabled. `encodingIndicators:
792
+ 'always'`/`'never'` or `appPrefix: false` still normalize it like any
793
+ > other app-string value (e.g. `t1<<"a", "b">>` becomes `"ab"_i`
794
+ > under `encodingIndicators: 'always'`), and a multi-line source falls back
795
+ > to normalized output in single-line mode (that layout can't be reproduced
796
+ > without `indent`):
797
+ >
798
+ > ```ts
799
+ > CBOR.format('t1<<\n "a",\n "b"\n>>');
800
+ > // '"ab"' — falls back: multi-line source, no `indent`
801
+ > CBOR.format('t1<<\n "a",\n "b"\n>>', { indent: 2 });
802
+ > // 't1<<\n "a",\n "b"\n>>' — kept verbatim
803
+ > ```
804
+ >
805
+ > Both options only affect how a value reconstructed from a `+` chain or a
806
+ > `(_ ...)` chunk list is _newly_ rendered.
807
+
718
808
  > [!NOTE]
719
- > The identifiers `t1` and `b1` are explicitly provisional in draft-26 and
809
+ > The identifiers `t1` and `b1` are explicitly provisional in draft-27 and
720
810
  > may be renamed by the CBOR working group.
721
811
 
722
812
  ## float
723
813
 
724
814
  Interprets a hex bit-pattern as an IEEE 754 floating-point value
725
- (draft-ietf-cbor-edn-literals-26 §3.7). Enabled by default.
815
+ (draft-ietf-cbor-edn-literals-27 §3.8). Enabled by default.
726
816
 
727
817
  ```ts
728
818
  import { CBOR } from '@cbortech/cbor';
729
819
 
730
820
  const v = CBOR.fromCDN("float'7e00'");
731
- console.log(v.toCDN({ appStrings: false }));
821
+ console.log(v.toCDN({ appPrefix: false }));
732
822
  // NaN
733
823
 
734
824
  // Interpret bytes as float bits
735
825
  const v2 = CBOR.fromCDN("float<<h'3f800000'>>");
736
- console.log(v2.toCDN({ appStrings: false }));
826
+ console.log(v2.toCDN({ appPrefix: false }));
737
827
  // 1.0_2
738
828
  ```
739
829
 
@@ -747,7 +837,7 @@ default. Import what you need and pass it through the `extensions` option.
747
837
  Byte-string literals using [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648)
748
838
  Base32 encoding. These prefixes are described in §8 of
749
839
  [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949) and also mentioned in
750
- [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/).
840
+ [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/).
751
841
 
752
842
  - `b32` — §6 Base32 (`A–Z 2–7` alphabet)
753
843
  - `h32` — §7 Base32Hex (`0–9 A–V` alphabet)
@@ -756,11 +846,11 @@ Base32 encoding. These prefixes are described in §8 of
756
846
  import { CBOR, b32, h32 } from '@cbortech/cbor';
757
847
 
758
848
  const v1 = CBOR.fromCDN("b32'AEBAGBA'", { extensions: [b32] });
759
- console.log(v1.toCDN({ appStrings: false }));
849
+ console.log(v1.toCDN({ appPrefix: false }));
760
850
  // h'01020304'
761
851
 
762
852
  const v2 = CBOR.fromCDN("h32'00P00'", { extensions: [h32] });
763
- console.log(v2.toCDN({ appStrings: false }));
853
+ console.log(v2.toCDN({ appPrefix: false }));
764
854
  // h'003200'
765
855
  ```
766
856
 
@@ -774,24 +864,24 @@ identical CBOR bytes and returns the first item. This extension is described in
774
864
  import { CBOR, same } from '@cbortech/cbor';
775
865
 
776
866
  const v = CBOR.fromCDN("same<<h'0102', h'0102'>>", { extensions: [same] });
777
- console.log(v.toCDN({ appStrings: false }));
867
+ console.log(v.toCDN({ appPrefix: false }));
778
868
  // h'0102'
779
869
 
780
870
  // A single-item sequence always passes
781
871
  const v2 = CBOR.fromCDN('same<<42>>', { extensions: [same] });
782
- console.log(v2.toCDN({ appStrings: false }));
872
+ console.log(v2.toCDN({ appPrefix: false }));
783
873
  // 42
784
874
  ```
785
875
 
786
876
  ---
787
877
 
788
- Additional application extensions are published as separate packages. Install
878
+ Additional app-extensions are published as separate packages. Install
789
879
  the ones you need and pass them through the `extensions` option.
790
880
 
791
881
  ### hash
792
882
 
793
- `hash` is an application extension defined in §3.3 of
794
- [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/).
883
+ `hash` is an app-extension defined in §3.4 of
884
+ [draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/).
795
885
  It represents cryptographic hash values in the form `hash'algorithm:value'`.
796
886
  Because it requires an external cryptographic library, it is provided separately
797
887
  as [@cbortech/hash-extension](https://www.npmjs.com/package/@cbortech/hash-extension).
@@ -816,7 +906,7 @@ const digest = cbor.parse(
816
906
 
817
907
  ### uuid
818
908
 
819
- `uuid` is a library-specific application extension, provided separately as
909
+ `uuid` is a library-specific app-extension, provided separately as
820
910
  [@cbortech/uuid-extension](https://www.npmjs.com/package/@cbortech/uuid-extension).
821
911
 
822
912
  ```bash
@@ -835,7 +925,7 @@ const id = cbor.parse("uuid'550e8400-e29b-41d4-a716-446655440000'");
835
925
 
836
926
  ### set / map
837
927
 
838
- `SET` and `MAP` are library-specific application extensions for tagged Set and
928
+ `SET` and `MAP` are library-specific app-extensions for tagged Set and
839
929
  Map values. They are provided together as
840
930
  [@cbortech/set-map-extensions](https://www.npmjs.com/package/@cbortech/set-map-extensions).
841
931
  `SET<<[...]>>` produces CBOR tag 258 over an array, and `MAP<<{...}>>` produces
@@ -1093,9 +1183,11 @@ types).
1093
1183
 
1094
1184
  - CBOR
1095
1185
  - [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949)
1186
+ - CBOR Sequences
1187
+ - [RFC 8742](https://www.rfc-editor.org/rfc/rfc8742)
1096
1188
  - CDN (CBOR-EDN)
1097
1189
  - [draft-ietf-cbor-edn-literals-25](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/)
1098
- - [draft-ietf-cbor-edn-literals-26](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/26/)
1190
+ - [draft-ietf-cbor-edn-literals-27](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/)
1099
1191
  - CDDL
1100
1192
  - [RFC 8610](https://www.rfc-editor.org/rfc/rfc8610)
1101
1193
  - [RFC 9682](https://www.rfc-editor.org/rfc/rfc9682)
@@ -1103,7 +1195,7 @@ types).
1103
1195
 
1104
1196
  Implementation notes:
1105
1197
 
1106
- - CDN follows draft-26 while retaining draft-25's `(_ ...)` streamstring syntax
1198
+ - CDN follows draft-27 while retaining draft-25's `(_ ...)` streamstring syntax
1107
1199
  and `+` string-concatenation syntax.
1108
1200
  - CDDL implements every RFC 8610 control operator, plus RFC 9165's `.plus`,
1109
1201
  `.cat`, and `.feature`.
@@ -21,6 +21,28 @@ export declare class CborAppSeqResult extends CborItem {
21
21
  readonly ednSource: string;
22
22
  constructor(inner: CborItem, ednSource: string);
23
23
  get _containsCdnContainer(): boolean;
24
+ /**
25
+ * Same approach as `CborTag`: tokenize this wrapper's own `_toCDN()`
26
+ * output rather than delegating to `this.inner._isMultiWordText()`.
27
+ * Delegating to `this.inner` was tried and found wrong: for
28
+ * `ilbs<<h'68656c6c6f20776f726c64'>>`, the chunk's raw bytes decode to
29
+ * printable "hello world", so `this.inner`'s own semantic check reports
30
+ * it as multi-word — but the *actual* rendering is the preserved
31
+ * `ilbs<<...>>` app-sequence spelling, where that chunk appears as a
32
+ * `h'...'` literal, never as decoded text; the semantic prediction and
33
+ * the real output disagree. Tokenizing `this._toCDN()` directly sees
34
+ * whichever one actually happens: the preserved `ednSource` verbatim
35
+ * (`isMultiWordRenderedLiteral` peels the `prefix<<...>>` wrapper and
36
+ * checks each item under the loose rule, same as `<<...>>` — a
37
+ * multi-word text item like `ilts<<"two words">>` still always counts,
38
+ * a prefixed-literal item like `ilbs<<h'00'>>` does not) or, in the
39
+ * 'always'/'never' `encodingIndicators` modes, a pure passthrough to
40
+ * `this.inner._toCDN()` with no extra wrapping (any node needing that to
41
+ * be caught, like a self-disqualifying `CborIndefiniteByteString`, has
42
+ * already produced a `\n` in that string, which the caller's own
43
+ * `s.includes('\n')` check picks up independently either way).
44
+ */
45
+ _isMultiWordText(options: ToCDNOptions | undefined, strict?: boolean): boolean;
24
46
  _encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
25
47
  _toCDN(options: ToCDNOptions | undefined, depth: number): string;
26
48
  _toJS(options?: ToJSOptions): unknown;
@@ -48,6 +48,22 @@ export declare class CborByteString extends CborItem {
48
48
  ednCommentSyntax?: ByteCommentSyntax;
49
49
  ednParts?: readonly CborByteStringPart[];
50
50
  });
51
+ /**
52
+ * Only the "bare sqstr text with 2+ words" case — the "is this a
53
+ * prefixed literal" question is deliberately *not* predicted here from
54
+ * raw bytes at all (a subclass like `CborIpExt` might override `_toCDN()`
55
+ * to render something else entirely, e.g. a preserved
56
+ * `ip<<'192.0.2.42'>>` app-sequence spelling, that raw-byte prediction
57
+ * knows nothing about — see `isMultiWordByteString`'s doc). That
58
+ * question is instead answered from the *actual rendering*: for a bare
59
+ * entry, `serializeContainer`'s own `isPrefixedLiteralText(s)` check
60
+ * already covers it (this node's render *is* `s`, unobscured); for one
61
+ * wrapped in a `CborTag`, `CborTag._isMultiWordText`'s
62
+ * `isMultiWordRenderedLiteral` check covers it instead. `strict` isn't
63
+ * needed here at all now — it's accepted purely for interface
64
+ * consistency with the base class.
65
+ */
66
+ _isMultiWordText(options: ToCDNOptions | undefined, _strict?: boolean): boolean;
51
67
  _encodeTo(writer: CborWriter, _options?: ToCBOROptions): void;
52
68
  _toCDN(options: ToCDNOptions | undefined, _depth: number): string;
53
69
  _toJS(_options?: ToJSOptions): unknown;
@@ -2,7 +2,7 @@ import { ToCDNOptions, ToJSOptions, ToCBOROptions } from '../types';
2
2
  import { CborItem, AnnotatedLine } from './CborItem';
3
3
  import { CborWriter, EncodingWidth } from '../cbor/encode';
4
4
  /**
5
- * CBOR Sequence Literal (§2.5.6) — `<<item, item, ...>>`.
5
+ * CBOR Sequence Literal (§2.3.4) — `<<item, item, ...>>`.
6
6
  *
7
7
  * Encodes as a definite-length byte string whose value is the concatenation
8
8
  * of the CBOR encodings of the contained items.
@@ -22,7 +22,7 @@ export declare class CborFloat extends CborItem {
22
22
  /**
23
23
  * Original app-string source (e.g. `float'7e00'`), set by the parser when
24
24
  * this float is the result of a `float'...'` app-string. Used by toCDN()
25
- * to round-trip the literal when `appStrings` is not false.
25
+ * to round-trip the literal when `appPrefix` is not false.
26
26
  */
27
27
  ednSource?: string;
28
28
  /**