@cbortech/cbor 0.26.8 → 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 +193 -28
- package/README.md +196 -29
- package/dist/ast/CborAppSeqResult.d.ts +58 -3
- package/dist/ast/CborArray.d.ts +2 -2
- package/dist/ast/CborByteString.d.ts +17 -1
- package/dist/ast/CborEmbeddedCBOR.d.ts +2 -2
- package/dist/ast/CborFloat.d.ts +2 -2
- package/dist/ast/CborIndefiniteByteString.d.ts +25 -1
- package/dist/ast/CborIndefiniteTextString.d.ts +17 -1
- package/dist/ast/CborItem.d.ts +340 -10
- package/dist/ast/CborMap.d.ts +2 -2
- package/dist/ast/CborNint.d.ts +1 -1
- package/dist/ast/CborTag.d.ts +30 -3
- package/dist/ast/CborTextString.d.ts +3 -2
- package/dist/ast/CborUint.d.ts +1 -1
- package/dist/ast/CborUnresolvedAppExt.d.ts +2 -2
- package/dist/ast/index.cjs +1 -1
- package/dist/ast/index.js +2 -2
- package/dist/cddl/index.cjs +1 -1
- package/dist/cddl/index.js +1 -1
- package/dist/cdn/index.cjs +2 -2
- package/dist/cdn/index.cjs.map +1 -1
- package/dist/cdn/index.js +18 -18
- package/dist/cdn/index.js.map +1 -1
- package/dist/cdn/serialize-utils.d.ts +237 -10
- package/dist/cdn/tokenizer.d.ts +12 -11
- package/dist/extensions/builtins.d.ts +5 -5
- package/dist/extensions/cri.d.ts +4 -4
- package/dist/extensions/dt.d.ts +4 -4
- package/dist/extensions/ip.d.ts +4 -4
- package/dist/extensions/types.d.ts +44 -5
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +158 -158
- package/dist/index.js.map +1 -1
- package/dist/{mapEntries-Ci_dppP6.js → mapEntries-CCLaJSaJ.js} +1599 -1275
- 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-y8G5mDIS.js → schema-DN9inJny.js} +294 -294
- package/dist/{schema-y8G5mDIS.js.map → schema-DN9inJny.js.map} +1 -1
- package/dist/schema-zsg5yCPK.cjs +63 -0
- package/dist/{schema-DgnkH0P6.cjs.map → schema-zsg5yCPK.cjs.map} +1 -1
- package/dist/serialize-utils-DhlW61ZX.cjs +37 -0
- package/dist/serialize-utils-DhlW61ZX.cjs.map +1 -0
- package/dist/{tokenizer-N-vAvRdj.js → serialize-utils-h-CVB9rg.js} +636 -358
- package/dist/serialize-utils-h-CVB9rg.js.map +1 -0
- package/dist/types.d.ts +508 -58
- package/dist/utils/base64.d.ts +1 -1
- package/dist/utils/hexfloat.d.ts +11 -3
- package/dist/utils/strip-comments.d.ts +1 -1
- package/package.json +13 -12
- package/dist/mapEntries-BJzyBUH5.cjs +0 -13
- package/dist/mapEntries-BJzyBUH5.cjs.map +0 -1
- package/dist/mapEntries-Ci_dppP6.js.map +0 -1
- package/dist/schema-DgnkH0P6.cjs +0 -63
- package/dist/tokenizer-BD08xbyd.cjs +0 -36
- package/dist/tokenizer-BD08xbyd.cjs.map +0 -1
- package/dist/tokenizer-N-vAvRdj.js.map +0 -1
package/README.md
CHANGED
|
@@ -392,19 +392,23 @@ CBOR.format("h'68' + b64'aQ'", {
|
|
|
392
392
|
// b64'aQ'
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
-
|
|
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
|
-
(
|
|
399
|
-
`prefix<<...>>` (
|
|
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. `
|
|
409
|
+
gets rewritten too. `preserveAppPrefix` keeps the original spelling
|
|
406
410
|
instead — whichever form was used. It has no effect when
|
|
407
|
-
`
|
|
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)', {
|
|
421
|
+
CBOR.format('1(1749772800)', { preserveAppPrefix: true });
|
|
418
422
|
// "1(1749772800)"
|
|
419
423
|
|
|
420
|
-
CBOR.format("DT<<'1969-07-21T02:56:16Z'>>", {
|
|
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`', {
|
|
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
|
|
@@ -681,10 +719,85 @@ console.log(text);
|
|
|
681
719
|
// DT'2026-05-06T00:00:00Z'
|
|
682
720
|
```
|
|
683
721
|
|
|
722
|
+
### Per-item option overrides
|
|
723
|
+
|
|
724
|
+
`itemOptions` on `toJS()` is called for every node before it is converted, so
|
|
725
|
+
one part of a document can be converted differently from the rest. Return a
|
|
726
|
+
partial options object to override options for that node and its descendants,
|
|
727
|
+
or `undefined` to leave them unchanged. `ctx.path` identifies the node as a
|
|
728
|
+
sequence of array indices and map keys, empty at the root.
|
|
729
|
+
|
|
730
|
+
It can be called more than once for the same node — when a `reviver` is also
|
|
731
|
+
present, arrays and object-mode maps convert each child at least twice: once
|
|
732
|
+
to build a value visible to an earlier sibling's own `reviver` call, and once
|
|
733
|
+
more for the value that's actually kept. Write it as a pure function of
|
|
734
|
+
`node`/`ctx`, not relying on how many times it runs.
|
|
735
|
+
|
|
736
|
+
```ts
|
|
737
|
+
import { CBOR } from '@cbortech/cbor';
|
|
738
|
+
|
|
739
|
+
const item = CBOR.fromCDN(
|
|
740
|
+
`{"date1": DT'2026-08-23T00:00:00Z', "date2": DT'2026-08-23T00:00:00Z'}`
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
const value = item.toJS({
|
|
744
|
+
stripTags: true,
|
|
745
|
+
itemOptions: (_node, ctx) =>
|
|
746
|
+
ctx.path.length === 1 && ctx.path[0] === 'date1'
|
|
747
|
+
? { extensions: [CBOR.dt_as_Date] }
|
|
748
|
+
: undefined,
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
console.log(value);
|
|
752
|
+
// { date1: Date(...), date2: 1787443200 }
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
`extensions` on `ToJSOptions` also works on its own, without `itemOptions`, to
|
|
756
|
+
reinterpret an entire tree: a value parsed with the default `dt` extension can
|
|
757
|
+
still be converted with `dt_as_Date` (or vice versa) by passing `extensions`
|
|
758
|
+
directly to `toJS()`.
|
|
759
|
+
|
|
760
|
+
`ctx.options` carries the options already in effect for the node — the root
|
|
761
|
+
options merged with whatever an ancestor's `itemOptions` already returned —
|
|
762
|
+
so a callback can build on the current value of an option instead of
|
|
763
|
+
overriding it outright:
|
|
764
|
+
|
|
765
|
+
```ts
|
|
766
|
+
itemOptions: (_node, ctx) => ({
|
|
767
|
+
extensions: [...(ctx.options.extensions ?? []), CBOR.dt_as_Date],
|
|
768
|
+
});
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
`toCDN()` takes the same `itemOptions` option, formatting one part of a
|
|
772
|
+
document differently from the rest:
|
|
773
|
+
|
|
774
|
+
```ts
|
|
775
|
+
import { CBOR } from '@cbortech/cbor';
|
|
776
|
+
|
|
777
|
+
const item = CBOR.fromCDN('{"raw": 255, "count": 255}');
|
|
778
|
+
|
|
779
|
+
const text = item.toCDN({
|
|
780
|
+
itemOptions: (_node, ctx) =>
|
|
781
|
+
ctx.path.length === 1 && ctx.path[0] === 'raw'
|
|
782
|
+
? { intFormat: 'hex' }
|
|
783
|
+
: undefined,
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
console.log(text);
|
|
787
|
+
// {"raw":0xff,"count":255}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
There is no `reviver` for `toCDN()`, so it can't be called more than once for
|
|
791
|
+
that reason — but it can still be called more than once for a node that's
|
|
792
|
+
also a `toCDN()` layout decision (`inlineLeafContainers`'s one-line collapse
|
|
793
|
+
check, or a tag/app-sequence value's own multi-word check re-render an entry
|
|
794
|
+
purely to answer that question before the real render). Write it as a pure
|
|
795
|
+
function here too.
|
|
796
|
+
|
|
684
797
|
## String Concatenation and Indefinite-Length Strings
|
|
685
798
|
|
|
686
|
-
The `t1` / `b1` / `ilbs` / `ilts`
|
|
687
|
-
draft-ietf-cbor-edn-literals-
|
|
799
|
+
The `t1` / `b1` / `ilbs` / `ilts` app-extensions from
|
|
800
|
+
draft-ietf-cbor-edn-literals-27 (§3.5 / §3.6) are enabled by default.
|
|
688
801
|
|
|
689
802
|
`t1<<...>>` and `b1<<...>>` join (text or byte) string arguments from left to
|
|
690
803
|
right into a single text string (`t1`) or byte string (`b1`). Arguments may
|
|
@@ -694,11 +807,11 @@ also be ellipses (`...`) to elide parts of a string.
|
|
|
694
807
|
import { CBOR } from '@cbortech/cbor';
|
|
695
808
|
|
|
696
809
|
const text = CBOR.fromCDN('t1<<"Hello ", "world">>');
|
|
697
|
-
console.log(text.toCDN({
|
|
810
|
+
console.log(text.toCDN({ appPrefix: false }));
|
|
698
811
|
// "Hello world"
|
|
699
812
|
|
|
700
813
|
const bytes = CBOR.fromCDN("b1<<'Hello ', h'776f726c64'>>");
|
|
701
|
-
console.log(bytes.toCDN({
|
|
814
|
+
console.log(bytes.toCDN({ appPrefix: false }));
|
|
702
815
|
// 'Hello world'
|
|
703
816
|
```
|
|
704
817
|
|
|
@@ -711,29 +824,81 @@ documents; this library keeps accepting the legacy syntax on input.
|
|
|
711
824
|
import { CBOR } from '@cbortech/cbor';
|
|
712
825
|
|
|
713
826
|
const v = CBOR.fromCDN("ilbs<<'Hello ', 'world'>>");
|
|
714
|
-
console.log(v.toCDN({
|
|
827
|
+
console.log(v.toCDN({ appPrefix: false }));
|
|
715
828
|
// (_ 'Hello ','world')
|
|
716
829
|
```
|
|
717
830
|
|
|
831
|
+
### Emitting `t1`/`b1`/`ilbs`/`ilts` notation
|
|
832
|
+
|
|
833
|
+
Parsing already accepts `t1`/`b1`/`ilbs`/`ilts` notation, but by default
|
|
834
|
+
`toCDN()`/`CBOR.format()` never emit it on their own: a preserved
|
|
835
|
+
concatenation (`preserveConcatenation`) still renders as `+`, and an
|
|
836
|
+
indefinite-length string still renders as the legacy `(_ ...)` streamstring
|
|
837
|
+
form. `modernConcat` and `modernStreamSyntax` opt into emitting the draft-27
|
|
838
|
+
notation instead — both default to `false` (the legacy syntax), and both fall
|
|
839
|
+
back to it when `appPrefix` is `false`.
|
|
840
|
+
|
|
841
|
+
```ts
|
|
842
|
+
import { CBOR } from '@cbortech/cbor';
|
|
843
|
+
|
|
844
|
+
CBOR.format('"a" + "b"', {
|
|
845
|
+
indent: 2,
|
|
846
|
+
preserveConcatenation: true,
|
|
847
|
+
modernConcat: true,
|
|
848
|
+
});
|
|
849
|
+
// t1<<"a", "b">>
|
|
850
|
+
|
|
851
|
+
CBOR.format('(_ "a", "b")', { modernStreamSyntax: true });
|
|
852
|
+
// ilts<<"a","b">>
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
`modernConcat` also applies within a `...` elision chain (§5.2), rendering
|
|
856
|
+
`"a" + ... + "b"` as `t1<<"a", ..., "b">>` — unlike plain concatenation, this
|
|
857
|
+
happens regardless of `preserveConcatenation`, since an elision chain has no
|
|
858
|
+
single-literal collapsed form to fall back to in the first place.
|
|
859
|
+
|
|
860
|
+
> [!NOTE]
|
|
861
|
+
> Neither option converts `t1`/`b1`/`ilbs`/`ilts` source back to the
|
|
862
|
+
> legacy notation: a value parsed from `t1<<...>>` (or `ilbs<<...>>`, etc.)
|
|
863
|
+
> keeps that exact spelling on output regardless of `modernConcat` /
|
|
864
|
+
> `modernStreamSyntax` — as long as `appPrefix` is not `false`,
|
|
865
|
+
> `encodingIndicators` is `'auto'` (both defaults), and the source is either
|
|
866
|
+
> single-line or being rendered with `indent` enabled. `encodingIndicators:
|
|
867
|
+
'always'`/`'never'` or `appPrefix: false` still normalize it like any
|
|
868
|
+
> other app-string value (e.g. `t1<<"a", "b">>` becomes `"ab"_i`
|
|
869
|
+
> under `encodingIndicators: 'always'`), and a multi-line source falls back
|
|
870
|
+
> to normalized output in single-line mode (that layout can't be reproduced
|
|
871
|
+
> without `indent`):
|
|
872
|
+
>
|
|
873
|
+
> ```ts
|
|
874
|
+
> CBOR.format('t1<<\n "a",\n "b"\n>>');
|
|
875
|
+
> // '"ab"' — falls back: multi-line source, no `indent`
|
|
876
|
+
> CBOR.format('t1<<\n "a",\n "b"\n>>', { indent: 2 });
|
|
877
|
+
> // 't1<<\n "a",\n "b"\n>>' — kept verbatim
|
|
878
|
+
> ```
|
|
879
|
+
>
|
|
880
|
+
> Both options only affect how a value reconstructed from a `+` chain or a
|
|
881
|
+
> `(_ ...)` chunk list is _newly_ rendered.
|
|
882
|
+
|
|
718
883
|
> [!NOTE]
|
|
719
|
-
> The identifiers `t1` and `b1` are explicitly provisional in draft-
|
|
884
|
+
> The identifiers `t1` and `b1` are explicitly provisional in draft-27 and
|
|
720
885
|
> may be renamed by the CBOR working group.
|
|
721
886
|
|
|
722
887
|
## float
|
|
723
888
|
|
|
724
889
|
Interprets a hex bit-pattern as an IEEE 754 floating-point value
|
|
725
|
-
(draft-ietf-cbor-edn-literals-
|
|
890
|
+
(draft-ietf-cbor-edn-literals-27 §3.8). Enabled by default.
|
|
726
891
|
|
|
727
892
|
```ts
|
|
728
893
|
import { CBOR } from '@cbortech/cbor';
|
|
729
894
|
|
|
730
895
|
const v = CBOR.fromCDN("float'7e00'");
|
|
731
|
-
console.log(v.toCDN({
|
|
896
|
+
console.log(v.toCDN({ appPrefix: false }));
|
|
732
897
|
// NaN
|
|
733
898
|
|
|
734
899
|
// Interpret bytes as float bits
|
|
735
900
|
const v2 = CBOR.fromCDN("float<<h'3f800000'>>");
|
|
736
|
-
console.log(v2.toCDN({
|
|
901
|
+
console.log(v2.toCDN({ appPrefix: false }));
|
|
737
902
|
// 1.0_2
|
|
738
903
|
```
|
|
739
904
|
|
|
@@ -747,7 +912,7 @@ default. Import what you need and pass it through the `extensions` option.
|
|
|
747
912
|
Byte-string literals using [RFC 4648](https://www.rfc-editor.org/rfc/rfc4648)
|
|
748
913
|
Base32 encoding. These prefixes are described in §8 of
|
|
749
914
|
[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/
|
|
915
|
+
[draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/).
|
|
751
916
|
|
|
752
917
|
- `b32` — §6 Base32 (`A–Z 2–7` alphabet)
|
|
753
918
|
- `h32` — §7 Base32Hex (`0–9 A–V` alphabet)
|
|
@@ -756,11 +921,11 @@ Base32 encoding. These prefixes are described in §8 of
|
|
|
756
921
|
import { CBOR, b32, h32 } from '@cbortech/cbor';
|
|
757
922
|
|
|
758
923
|
const v1 = CBOR.fromCDN("b32'AEBAGBA'", { extensions: [b32] });
|
|
759
|
-
console.log(v1.toCDN({
|
|
924
|
+
console.log(v1.toCDN({ appPrefix: false }));
|
|
760
925
|
// h'01020304'
|
|
761
926
|
|
|
762
927
|
const v2 = CBOR.fromCDN("h32'00P00'", { extensions: [h32] });
|
|
763
|
-
console.log(v2.toCDN({
|
|
928
|
+
console.log(v2.toCDN({ appPrefix: false }));
|
|
764
929
|
// h'003200'
|
|
765
930
|
```
|
|
766
931
|
|
|
@@ -774,24 +939,24 @@ identical CBOR bytes and returns the first item. This extension is described in
|
|
|
774
939
|
import { CBOR, same } from '@cbortech/cbor';
|
|
775
940
|
|
|
776
941
|
const v = CBOR.fromCDN("same<<h'0102', h'0102'>>", { extensions: [same] });
|
|
777
|
-
console.log(v.toCDN({
|
|
942
|
+
console.log(v.toCDN({ appPrefix: false }));
|
|
778
943
|
// h'0102'
|
|
779
944
|
|
|
780
945
|
// A single-item sequence always passes
|
|
781
946
|
const v2 = CBOR.fromCDN('same<<42>>', { extensions: [same] });
|
|
782
|
-
console.log(v2.toCDN({
|
|
947
|
+
console.log(v2.toCDN({ appPrefix: false }));
|
|
783
948
|
// 42
|
|
784
949
|
```
|
|
785
950
|
|
|
786
951
|
---
|
|
787
952
|
|
|
788
|
-
Additional
|
|
953
|
+
Additional app-extensions are published as separate packages. Install
|
|
789
954
|
the ones you need and pass them through the `extensions` option.
|
|
790
955
|
|
|
791
956
|
### hash
|
|
792
957
|
|
|
793
|
-
`hash` is an
|
|
794
|
-
[draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/
|
|
958
|
+
`hash` is an app-extension defined in §3.4 of
|
|
959
|
+
[draft-ietf-cbor-edn-literals](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/).
|
|
795
960
|
It represents cryptographic hash values in the form `hash'algorithm:value'`.
|
|
796
961
|
Because it requires an external cryptographic library, it is provided separately
|
|
797
962
|
as [@cbortech/hash-extension](https://www.npmjs.com/package/@cbortech/hash-extension).
|
|
@@ -816,7 +981,7 @@ const digest = cbor.parse(
|
|
|
816
981
|
|
|
817
982
|
### uuid
|
|
818
983
|
|
|
819
|
-
`uuid` is a library-specific
|
|
984
|
+
`uuid` is a library-specific app-extension, provided separately as
|
|
820
985
|
[@cbortech/uuid-extension](https://www.npmjs.com/package/@cbortech/uuid-extension).
|
|
821
986
|
|
|
822
987
|
```bash
|
|
@@ -835,7 +1000,7 @@ const id = cbor.parse("uuid'550e8400-e29b-41d4-a716-446655440000'");
|
|
|
835
1000
|
|
|
836
1001
|
### set / map
|
|
837
1002
|
|
|
838
|
-
`SET` and `MAP` are library-specific
|
|
1003
|
+
`SET` and `MAP` are library-specific app-extensions for tagged Set and
|
|
839
1004
|
Map values. They are provided together as
|
|
840
1005
|
[@cbortech/set-map-extensions](https://www.npmjs.com/package/@cbortech/set-map-extensions).
|
|
841
1006
|
`SET<<[...]>>` produces CBOR tag 258 over an array, and `MAP<<{...}>>` produces
|
|
@@ -1093,9 +1258,11 @@ types).
|
|
|
1093
1258
|
|
|
1094
1259
|
- CBOR
|
|
1095
1260
|
- [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949)
|
|
1261
|
+
- CBOR Sequences
|
|
1262
|
+
- [RFC 8742](https://www.rfc-editor.org/rfc/rfc8742)
|
|
1096
1263
|
- CDN (CBOR-EDN)
|
|
1097
1264
|
- [draft-ietf-cbor-edn-literals-25](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/25/)
|
|
1098
|
-
- [draft-ietf-cbor-edn-literals-
|
|
1265
|
+
- [draft-ietf-cbor-edn-literals-27](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/27/)
|
|
1099
1266
|
- CDDL
|
|
1100
1267
|
- [RFC 8610](https://www.rfc-editor.org/rfc/rfc8610)
|
|
1101
1268
|
- [RFC 9682](https://www.rfc-editor.org/rfc/rfc9682)
|
|
@@ -1103,7 +1270,7 @@ types).
|
|
|
1103
1270
|
|
|
1104
1271
|
Implementation notes:
|
|
1105
1272
|
|
|
1106
|
-
- CDN follows draft-
|
|
1273
|
+
- CDN follows draft-27 while retaining draft-25's `(_ ...)` streamstring syntax
|
|
1107
1274
|
and `+` string-concatenation syntax.
|
|
1108
1275
|
- CDDL implements every RFC 8610 control operator, plus RFC 9165's `.plus`,
|
|
1109
1276
|
`.cat`, and `.feature`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToCDNOptions, ToCBOROptions, ToJSOptions } from '../types';
|
|
2
|
-
import { CborItem } from './CborItem';
|
|
2
|
+
import { CborItem, Occurrence } from './CborItem';
|
|
3
3
|
import { CborWriter } from '../cbor/encode';
|
|
4
4
|
/**
|
|
5
5
|
* Wraps a resolved app-sequence result and preserves the original EDN source
|
|
@@ -13,6 +13,39 @@ import { CborWriter } from '../cbor/encode';
|
|
|
13
13
|
* lines also delegates to the inner item, since it cannot be re-emitted
|
|
14
14
|
* without breaking the single-line guarantee.
|
|
15
15
|
*
|
|
16
|
+
* When `toCDN()`'s `itemOptions` is configured (see `needsCdnItemDispatch`),
|
|
17
|
+
* the verbatim `ednSource` fast path alone can't be trusted: it was produced
|
|
18
|
+
* without ever visiting `this.inner`'s own descendants, so an override
|
|
19
|
+
* targeting one of them (e.g. one chunk of an `ilbs<<...>>`) would otherwise
|
|
20
|
+
* never even be offered the chance to apply. But merely *having* `itemOptions`
|
|
21
|
+
* configured must not by itself change the output — many callers set it
|
|
22
|
+
* without it ever matching anything in this particular subtree, and
|
|
23
|
+
* `itemOptions` returning `undefined` everywhere is documented to mean "no
|
|
24
|
+
* change" (see `CdnItemContext`). So this renders through the normal
|
|
25
|
+
* recursive path while tracking, via `CDN_OVERRIDE_TRACKER` (an out-of-band
|
|
26
|
+
* symbol key, *not* a wrapped `itemOptions` — wrapping it would make
|
|
27
|
+
* `ctx.options.itemOptions` a different function for every descendant here
|
|
28
|
+
* than everywhere else in the tree, observable even to a pure callback),
|
|
29
|
+
* whether any call in the subtree actually returned an override, and only
|
|
30
|
+
* swaps in that freshly rendered text when one did; otherwise the exact
|
|
31
|
+
* preserved `ednSource` is still returned.
|
|
32
|
+
*
|
|
33
|
+
* Each `_toCDN()` call installs its *own fresh* tracker box before
|
|
34
|
+
* recursing, rather than reusing whatever tracker it was handed — reusing
|
|
35
|
+
* one directly would let an override applied by some unrelated part of the
|
|
36
|
+
* tree that merely happens to share the same ambient `options` object (a
|
|
37
|
+
* later sibling reached through the same `itemOptions`, say) falsely mark
|
|
38
|
+
* *this* wrapper's own verbatim source as stale. But a genuinely *nested*
|
|
39
|
+
* app-sequence (e.g. a custom `wrap<<ilbs<<h'61'>>>>` extension wrapping an
|
|
40
|
+
* `ilbs<<...>>` result) must still have its own outer verbatim source
|
|
41
|
+
* abandoned when the inner wrapper's own tracked render found something to
|
|
42
|
+
* apply — an inner override changes what the outer source would need to
|
|
43
|
+
* embed too. So once this call's own local tracker comes back `applied`,
|
|
44
|
+
* that fact is additionally bubbled up to whichever ancestor tracker (if
|
|
45
|
+
* any) this call itself received via `options` — the exact wrapper this
|
|
46
|
+
* call is nested inside, never a sibling reached only through shared
|
|
47
|
+
* top-level `options`.
|
|
48
|
+
*
|
|
16
49
|
* CBOR encoding and JS conversion always delegate to the inner item so the
|
|
17
50
|
* wrapper is fully transparent for those operations.
|
|
18
51
|
*/
|
|
@@ -21,7 +54,29 @@ export declare class CborAppSeqResult extends CborItem {
|
|
|
21
54
|
readonly ednSource: string;
|
|
22
55
|
constructor(inner: CborItem, ednSource: string);
|
|
23
56
|
get _containsCdnContainer(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Same approach as `CborTag`: tokenize this wrapper's own `_toCDN()`
|
|
59
|
+
* output rather than delegating to `this.inner._isMultiWordText()`.
|
|
60
|
+
* Delegating to `this.inner` was tried and found wrong: for
|
|
61
|
+
* `ilbs<<h'68656c6c6f20776f726c64'>>`, the chunk's raw bytes decode to
|
|
62
|
+
* printable "hello world", so `this.inner`'s own semantic check reports
|
|
63
|
+
* it as multi-word — but the *actual* rendering is the preserved
|
|
64
|
+
* `ilbs<<...>>` app-sequence spelling, where that chunk appears as a
|
|
65
|
+
* `h'...'` literal, never as decoded text; the semantic prediction and
|
|
66
|
+
* the real output disagree. Tokenizing `this._toCDN()` directly sees
|
|
67
|
+
* whichever one actually happens: the preserved `ednSource` verbatim
|
|
68
|
+
* (`isMultiWordRenderedLiteral` peels the `prefix<<...>>` wrapper and
|
|
69
|
+
* checks each item under the loose rule, same as `<<...>>` — a
|
|
70
|
+
* multi-word text item like `ilts<<"two words">>` still always counts,
|
|
71
|
+
* a prefixed-literal item like `ilbs<<h'00'>>` does not) or, in the
|
|
72
|
+
* 'always'/'never' `encodingIndicators` modes, a pure passthrough to
|
|
73
|
+
* `this.inner._toCDN()` with no extra wrapping (any node needing that to
|
|
74
|
+
* be caught, like a self-disqualifying `CborIndefiniteByteString`, has
|
|
75
|
+
* already produced a `\n` in that string, which the caller's own
|
|
76
|
+
* `s.includes('\n')` check picks up independently either way).
|
|
77
|
+
*/
|
|
78
|
+
_isMultiWordText(options: ToCDNOptions | undefined, strict?: boolean, path?: readonly unknown[]): boolean;
|
|
24
79
|
_encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
|
|
25
|
-
_toCDN(options: ToCDNOptions | undefined, depth: number): string;
|
|
26
|
-
_toJS(options?: ToJSOptions): unknown;
|
|
80
|
+
_toCDN(options: ToCDNOptions | undefined, depth: number, path?: readonly unknown[]): string;
|
|
81
|
+
_toJS(options?: ToJSOptions, path?: readonly unknown[], occurrence?: Occurrence): unknown;
|
|
27
82
|
}
|
package/dist/ast/CborArray.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare class CborArray extends CborItem {
|
|
|
12
12
|
});
|
|
13
13
|
get _containsCdnContainer(): boolean;
|
|
14
14
|
_encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
|
|
15
|
-
_toCDN(options: ToCDNOptions | undefined, depth: number): string;
|
|
15
|
+
_toCDN(options: ToCDNOptions | undefined, depth: number, path?: readonly unknown[]): string;
|
|
16
16
|
_toHexDump(depth: number, options?: ToCDNOptions): AnnotatedLine[];
|
|
17
|
-
_toJS(options?: ToJSOptions): unknown;
|
|
17
|
+
_toJS(options?: ToJSOptions, path?: readonly unknown[], occurrence?: readonly unknown[]): unknown;
|
|
18
18
|
}
|
|
@@ -48,7 +48,23 @@ 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, _path?: readonly unknown[]): boolean;
|
|
51
67
|
_encodeTo(writer: CborWriter, _options?: ToCBOROptions): void;
|
|
52
|
-
_toCDN(options: ToCDNOptions | undefined, _depth: number): string;
|
|
68
|
+
_toCDN(options: ToCDNOptions | undefined, _depth: number, _path?: readonly unknown[]): string;
|
|
53
69
|
_toJS(_options?: ToJSOptions): unknown;
|
|
54
70
|
}
|
|
@@ -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
|
+
* 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.
|
|
@@ -21,7 +21,7 @@ export declare class CborEmbeddedCBOR extends CborItem {
|
|
|
21
21
|
/** The raw concatenated CBOR bytes of all contained items. */
|
|
22
22
|
private _content;
|
|
23
23
|
_encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
|
|
24
|
-
_toCDN(options: ToCDNOptions | undefined, depth: number): string;
|
|
24
|
+
_toCDN(options: ToCDNOptions | undefined, depth: number, path?: readonly unknown[]): string;
|
|
25
25
|
_toHexDump(depth: number, options?: ToCDNOptions): AnnotatedLine[];
|
|
26
26
|
_toJS(_options?: ToJSOptions): unknown;
|
|
27
27
|
}
|
package/dist/ast/CborFloat.d.ts
CHANGED
|
@@ -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 `
|
|
25
|
+
* to round-trip the literal when `appPrefix` is not false.
|
|
26
26
|
*/
|
|
27
27
|
ednSource?: string;
|
|
28
28
|
/**
|
|
@@ -48,6 +48,6 @@ export declare class CborFloat extends CborItem {
|
|
|
48
48
|
literalSource?: string;
|
|
49
49
|
});
|
|
50
50
|
_encodeTo(writer: CborWriter, _options?: ToCBOROptions): void;
|
|
51
|
-
_toCDN(options: ToCDNOptions | undefined, _depth: number): string;
|
|
51
|
+
_toCDN(options: ToCDNOptions | undefined, _depth: number, _path?: readonly unknown[]): string;
|
|
52
52
|
_toJS(_options?: ToJSOptions): unknown;
|
|
53
53
|
}
|
|
@@ -8,7 +8,31 @@ export declare class CborIndefiniteByteString extends CborItem {
|
|
|
8
8
|
readonly chunks: CborByteString[];
|
|
9
9
|
constructor(chunks: CborByteString[]);
|
|
10
10
|
_encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* True when any chunk's own decoded content, if it renders as bare sqstr
|
|
13
|
+
* text, has two or more words. Reachable when this node is a *direct*
|
|
14
|
+
* entry of another container (`[(_ "two words")]`) — though even then,
|
|
15
|
+
* its own `_toCDN()` already self-disqualifies internally in that case
|
|
16
|
+
* (a multi-word chunk forces a multi-line self-render), which the
|
|
17
|
+
* ordinary "entry's own rendering has a line break" check would catch
|
|
18
|
+
* regardless of what this method answers, so this mostly exists for
|
|
19
|
+
* robustness/consistency with `CborTextString`/`CborByteString` rather
|
|
20
|
+
* than because some case is otherwise unreachable.
|
|
21
|
+
*
|
|
22
|
+
* `CborAppSeqResult`, which wraps this node for results like
|
|
23
|
+
* `ilbs<<...>>`, does *not* delegate to this method — it tokenizes its
|
|
24
|
+
* own rendered output directly instead (`isMultiWordRenderedLiteral`),
|
|
25
|
+
* which is exactly why `ilbs<<h'00'>>` stays an ordinary leaf (checked
|
|
26
|
+
* under the loose rule, matching `<<...>>`) while `[h'00']`/`(_ h'00')`
|
|
27
|
+
* still always disqualify — this method's own `_strict` (always `true`,
|
|
28
|
+
* matching how a chunk renders when this container *is* regenerated
|
|
29
|
+
* directly) plays no part in that distinction anymore, and a byte string
|
|
30
|
+
* chunk's own `_isMultiWordText` doesn't consult `strict` at all
|
|
31
|
+
* regardless (see `CborByteString`'s doc — its "prefixed literal" case
|
|
32
|
+
* was removed there too).
|
|
33
|
+
*/
|
|
34
|
+
_isMultiWordText(options: ToCDNOptions | undefined, _strict?: boolean): boolean;
|
|
35
|
+
_toCDN(options: ToCDNOptions | undefined, depth: number, path?: readonly unknown[]): string;
|
|
12
36
|
_toHexDump(depth: number, options?: ToCDNOptions): AnnotatedLine[];
|
|
13
37
|
_toJS(_options?: ToJSOptions): unknown;
|
|
14
38
|
}
|
|
@@ -8,7 +8,23 @@ export declare class CborIndefiniteTextString extends CborItem {
|
|
|
8
8
|
readonly chunks: CborTextString[];
|
|
9
9
|
constructor(chunks: CborTextString[]);
|
|
10
10
|
_encodeTo(writer: CborWriter, options?: ToCBOROptions): void;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* True when any chunk is multi-word. Reachable when this node is a
|
|
13
|
+
* *direct* entry of another container (`[(_ "two words")]`) — though even
|
|
14
|
+
* then, its own `_toCDN()` already self-disqualifies internally in that
|
|
15
|
+
* case, producing a multi-line self-render that the ordinary "entry's own
|
|
16
|
+
* rendering has a line break" check would catch regardless of what this
|
|
17
|
+
* method answers, so this mostly exists for robustness/consistency with
|
|
18
|
+
* `CborTextString`/`CborByteString` rather than because some case is
|
|
19
|
+
* otherwise unreachable. (`CborAppSeqResult`, which wraps this node for
|
|
20
|
+
* results like `ilts<<...>>`, does *not* delegate to this method — it
|
|
21
|
+
* tokenizes its own rendered output directly instead; see its doc for
|
|
22
|
+
* why that turned out to be necessary.) `_strict` is intentionally
|
|
23
|
+
* unused: a chunk is always CborTextString, whose own word count doesn't
|
|
24
|
+
* depend on it.
|
|
25
|
+
*/
|
|
26
|
+
_isMultiWordText(options: ToCDNOptions | undefined, _strict?: boolean): boolean;
|
|
27
|
+
_toCDN(options: ToCDNOptions | undefined, depth: number, path?: readonly unknown[]): string;
|
|
12
28
|
_toHexDump(depth: number, options?: ToCDNOptions): AnnotatedLine[];
|
|
13
29
|
_toJS(_options?: ToJSOptions): unknown;
|
|
14
30
|
}
|