@cbortech/cbor 0.23.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.
- package/LICENSE +201 -0
- package/README.ja.md +479 -0
- package/README.md +488 -0
- package/dist/index.cjs +32 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +695 -0
- package/dist/index.js +4052 -0
- package/dist/index.js.map +1 -0
- package/package.json +85 -0
package/README.md
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# @cbortech/cbor
|
|
2
|
+
|
|
3
|
+
TypeScript library for converting between [CBOR](#specifications),
|
|
4
|
+
[CBOR-EDN](#specifications), and JavaScript values.
|
|
5
|
+
|
|
6
|
+
This package currently exposes a small public API centered on the `CBOR` facade.
|
|
7
|
+
Lower-level parser, encoder, and AST classes are intentionally not part of the
|
|
8
|
+
documented public API yet.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @cbortech/cbor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Import
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { CBOR } from '@cbortech/cbor';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Default import is also supported:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import CBOR from '@cbortech/cbor';
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Examples
|
|
29
|
+
|
|
30
|
+
### JavaScript to CBOR bytes
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { CBOR } from '@cbortech/cbor';
|
|
34
|
+
|
|
35
|
+
const bytes = CBOR.encode({ hello: 'world', n: 42 });
|
|
36
|
+
|
|
37
|
+
console.log(bytes);
|
|
38
|
+
// Uint8Array(...)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### CBOR bytes to JavaScript
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { CBOR } from '@cbortech/cbor';
|
|
45
|
+
|
|
46
|
+
const value = CBOR.decode(
|
|
47
|
+
new Uint8Array([
|
|
48
|
+
0xa2, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x65, 0x77, 0x6f, 0x72, 0x6c,
|
|
49
|
+
0x64, 0x61, 0x6e, 0x18, 0x2a,
|
|
50
|
+
])
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
console.log(value);
|
|
54
|
+
// { hello: 'world', n: 42 }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### CBOR bytes to CBOR-EDN
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { CBOR } from '@cbortech/cbor';
|
|
61
|
+
|
|
62
|
+
const text = CBOR.cborToCborEdn(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
|
|
63
|
+
|
|
64
|
+
console.log(text);
|
|
65
|
+
// [1,2,3]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### CBOR-EDN to CBOR bytes
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { CBOR } from '@cbortech/cbor';
|
|
72
|
+
|
|
73
|
+
const bytes = CBOR.cborEdnToCbor('[1, 2, 3]');
|
|
74
|
+
|
|
75
|
+
console.log(bytes);
|
|
76
|
+
// Uint8Array([0x83, 0x01, 0x02, 0x03])
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### JavaScript to CBOR-EDN
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { CBOR } from '@cbortech/cbor';
|
|
83
|
+
|
|
84
|
+
const text = CBOR.stringify({ a: 1, b: true, c: null });
|
|
85
|
+
|
|
86
|
+
console.log(text);
|
|
87
|
+
// {"a":1,"b":true,"c":null}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Pretty CBOR-EDN
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { CBOR } from '@cbortech/cbor';
|
|
94
|
+
|
|
95
|
+
const text = CBOR.stringify({ items: [1, 2, 3], ok: true }, { indent: 2 });
|
|
96
|
+
|
|
97
|
+
console.log(text);
|
|
98
|
+
// {
|
|
99
|
+
// "items": [
|
|
100
|
+
// 1,
|
|
101
|
+
// 2,
|
|
102
|
+
// 3
|
|
103
|
+
// ],
|
|
104
|
+
// "ok": true
|
|
105
|
+
// }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### CBOR-EDN to JavaScript
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { CBOR } from '@cbortech/cbor';
|
|
112
|
+
|
|
113
|
+
const value = CBOR.parse("[1, h'deadbeef', true, null]");
|
|
114
|
+
|
|
115
|
+
console.log(value);
|
|
116
|
+
// [1, Uint8Array(...), true, null]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Normalize CBOR-EDN
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { CBOR } from '@cbortech/cbor';
|
|
123
|
+
|
|
124
|
+
const text = CBOR.format('{ "b" : [ 1,2 ], "a" : true }', { indent: 2 });
|
|
125
|
+
|
|
126
|
+
console.log(text);
|
|
127
|
+
// {
|
|
128
|
+
// "b": [
|
|
129
|
+
// 1,
|
|
130
|
+
// 2
|
|
131
|
+
// ],
|
|
132
|
+
// "a": true
|
|
133
|
+
// }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Split text strings while formatting
|
|
137
|
+
|
|
138
|
+
`textStringFormat` can split long text strings with EDN string concatenation.
|
|
139
|
+
It is applied when `indent` is specified.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { CBOR } from '@cbortech/cbor';
|
|
143
|
+
|
|
144
|
+
const text = CBOR.format('{"text": "line1\\nline2\\nline3"}', {
|
|
145
|
+
indent: 2,
|
|
146
|
+
textStringFormat: ['newline'],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
console.log(text);
|
|
150
|
+
// {
|
|
151
|
+
// "text": "line1\n" +
|
|
152
|
+
// "line2\n" +
|
|
153
|
+
// "line3"
|
|
154
|
+
// }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
For strings that contain CBOR-EDN or JSON-like content, use `cboredn`.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { CBOR } from '@cbortech/cbor';
|
|
161
|
+
|
|
162
|
+
const text = CBOR.format('{"edn": "[1,2,3]"}', {
|
|
163
|
+
indent: 2,
|
|
164
|
+
textStringFormat: ['cboredn'],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
console.log(text);
|
|
168
|
+
// {
|
|
169
|
+
// "edn": "[" +
|
|
170
|
+
// "1," +
|
|
171
|
+
// "2," +
|
|
172
|
+
// "3" +
|
|
173
|
+
// "]"
|
|
174
|
+
// }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Working With The AST
|
|
178
|
+
|
|
179
|
+
`CBOR.fromCBOR()`, `CBOR.fromEDN()`, and `CBOR.fromJS()` return a CBOR item.
|
|
180
|
+
The concrete node classes are not documented as public API yet, but every item
|
|
181
|
+
supports these methods:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { CBOR } from '@cbortech/cbor';
|
|
185
|
+
|
|
186
|
+
const item = CBOR.fromEDN('{ "x": 1 }');
|
|
187
|
+
|
|
188
|
+
const bytes = item.toCBOR();
|
|
189
|
+
const text = item.toEDN();
|
|
190
|
+
const value = item.toJS();
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Parse to AST, then serialize
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import { CBOR } from '@cbortech/cbor';
|
|
197
|
+
|
|
198
|
+
const item = CBOR.fromEDN('[_ 1, 2, 3]');
|
|
199
|
+
|
|
200
|
+
console.log(item.toEDN());
|
|
201
|
+
// [_ 1,2,3]
|
|
202
|
+
|
|
203
|
+
console.log(item.toCBOR());
|
|
204
|
+
// Uint8Array(...)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Decode to AST, then inspect as EDN
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { CBOR } from '@cbortech/cbor';
|
|
211
|
+
|
|
212
|
+
const item = CBOR.fromCBOR(new Uint8Array([0x83, 0x01, 0x02, 0x03]));
|
|
213
|
+
|
|
214
|
+
console.log(item.toEDN());
|
|
215
|
+
// [1,2,3]
|
|
216
|
+
|
|
217
|
+
console.log(item.toJS());
|
|
218
|
+
// [1, 2, 3]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## JSON-like API
|
|
222
|
+
|
|
223
|
+
`CBOR.parse()` and `CBOR.stringify()` intentionally feel similar to
|
|
224
|
+
`JSON.parse()` and `JSON.stringify()`.
|
|
225
|
+
|
|
226
|
+
Unlike JSON, CBOR can represent `undefined` as a value. Use `CBOR.OMIT` from a
|
|
227
|
+
reviver or replacer when you want to remove an object entry or map entry
|
|
228
|
+
explicitly, instead of producing an `undefined` value.
|
|
229
|
+
|
|
230
|
+
### Reviver function
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { CBOR } from '@cbortech/cbor';
|
|
234
|
+
|
|
235
|
+
const value = CBOR.parse(
|
|
236
|
+
'{"createdAt": "2026-05-06T00:00:00Z"}',
|
|
237
|
+
(key, value) => {
|
|
238
|
+
if (key === 'createdAt') return new Date(value);
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
console.log(value);
|
|
244
|
+
// { createdAt: 2026-05-06T00:00:00.000Z }
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Replacer function
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { CBOR } from '@cbortech/cbor';
|
|
251
|
+
|
|
252
|
+
const text = CBOR.stringify({ id: 1, password: 'secret' }, (key, value) =>
|
|
253
|
+
key === 'password' ? CBOR.OMIT : value
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
console.log(text);
|
|
257
|
+
// {"id":1}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Replacer key list
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import { CBOR } from '@cbortech/cbor';
|
|
264
|
+
|
|
265
|
+
const text = CBOR.stringify(
|
|
266
|
+
{ id: 1, name: 'Alice', password: 'secret' },
|
|
267
|
+
['id', 'name'],
|
|
268
|
+
2
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
console.log(text);
|
|
272
|
+
// {
|
|
273
|
+
// "id": 1,
|
|
274
|
+
// "name": "Alice"
|
|
275
|
+
// }
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Default Options
|
|
279
|
+
|
|
280
|
+
Create a `CBOR` instance when you want to reuse the same options.
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import { CBOR } from '@cbortech/cbor';
|
|
284
|
+
|
|
285
|
+
const cbor = new CBOR({
|
|
286
|
+
extensions: [CBOR.dt_as_Date],
|
|
287
|
+
indent: 2,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const value = cbor.parse("DT'2026-05-06T00:00:00Z'");
|
|
291
|
+
|
|
292
|
+
console.log(value);
|
|
293
|
+
// Date(...)
|
|
294
|
+
|
|
295
|
+
console.log(cbor.stringify({ value }));
|
|
296
|
+
// {
|
|
297
|
+
// "value": DT'2026-05-06T00:00:00Z'
|
|
298
|
+
// }
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Dates
|
|
302
|
+
|
|
303
|
+
CBOR-EDN `dt'...'` and `DT'...'` literals are parsed by default. Add `CBOR.dt_as_Date`
|
|
304
|
+
when you want JavaScript `Date` objects.
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
import { CBOR } from '@cbortech/cbor';
|
|
308
|
+
|
|
309
|
+
const value = CBOR.parse("DT'2026-05-06T00:00:00Z'", {
|
|
310
|
+
extensions: [CBOR.dt_as_Date],
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
console.log(value instanceof Date);
|
|
314
|
+
// true
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import { CBOR } from '@cbortech/cbor';
|
|
319
|
+
|
|
320
|
+
const text = CBOR.stringify(new Date('2026-05-06T00:00:00Z'), {
|
|
321
|
+
extensions: [CBOR.dt_as_Date],
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
console.log(text);
|
|
325
|
+
// DT'2026-05-06T00:00:00Z'
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Tags
|
|
329
|
+
|
|
330
|
+
Use `CBOR.Tag` for CBOR tagged values in JavaScript.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
import { CBOR } from '@cbortech/cbor';
|
|
334
|
+
|
|
335
|
+
const tagged = CBOR.Tag.set('hello', 42n);
|
|
336
|
+
const text = CBOR.stringify(tagged);
|
|
337
|
+
|
|
338
|
+
console.log(text);
|
|
339
|
+
// 42("hello")
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import { CBOR } from '@cbortech/cbor';
|
|
344
|
+
|
|
345
|
+
const value = CBOR.parse('42("hello")');
|
|
346
|
+
|
|
347
|
+
console.log(CBOR.Tag.get(value));
|
|
348
|
+
// 42n
|
|
349
|
+
|
|
350
|
+
console.log(CBOR.Tag.getValue(value));
|
|
351
|
+
// "hello"
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Simple Values
|
|
355
|
+
|
|
356
|
+
Use `CBOR.Simple` for CBOR simple values other than `false`, `true`, `null`, and
|
|
357
|
+
`undefined`.
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
import { CBOR } from '@cbortech/cbor';
|
|
361
|
+
|
|
362
|
+
const text = CBOR.stringify(new CBOR.Simple(16));
|
|
363
|
+
|
|
364
|
+
console.log(text);
|
|
365
|
+
// simple(16)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import { CBOR } from '@cbortech/cbor';
|
|
370
|
+
|
|
371
|
+
const value = CBOR.parse('simple(16)');
|
|
372
|
+
|
|
373
|
+
console.log(value instanceof CBOR.Simple);
|
|
374
|
+
// true
|
|
375
|
+
|
|
376
|
+
console.log(value.value);
|
|
377
|
+
// 16
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Maps
|
|
381
|
+
|
|
382
|
+
By default, CBOR maps with text keys become plain JavaScript objects.
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
import { CBOR } from '@cbortech/cbor';
|
|
386
|
+
|
|
387
|
+
const value = CBOR.parse('{"a": 1, "b": 2}');
|
|
388
|
+
|
|
389
|
+
console.log(value);
|
|
390
|
+
// { a: 1, b: 2 }
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Use `mapAs: 'entries'` when you need to preserve non-string keys or duplicate
|
|
394
|
+
keys.
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
import { CBOR } from '@cbortech/cbor';
|
|
398
|
+
|
|
399
|
+
const entries = CBOR.parse('{1: "one", 1: "uno"}', {
|
|
400
|
+
mapAs: 'entries',
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
console.log(entries instanceof CBOR.MapEntries);
|
|
404
|
+
// true
|
|
405
|
+
|
|
406
|
+
console.log(entries);
|
|
407
|
+
// [[1, "one"], [1, "uno"]]
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`CBOR.MapEntries` can be passed back to `CBOR.stringify()` or `CBOR.encode()`.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { CBOR } from '@cbortech/cbor';
|
|
414
|
+
|
|
415
|
+
const entries = new CBOR.MapEntries([1, 'one'], [1, 'uno']);
|
|
416
|
+
|
|
417
|
+
console.log(CBOR.stringify(entries));
|
|
418
|
+
// {1:"one",1:"uno"}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Hex Dumps
|
|
422
|
+
|
|
423
|
+
CBOR items can produce and parse annotated hex dumps.
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
import { CBOR } from '@cbortech/cbor';
|
|
427
|
+
|
|
428
|
+
const item = CBOR.fromEDN('[_ 1, [2, 3]]');
|
|
429
|
+
const dump = item.toHexDump();
|
|
430
|
+
|
|
431
|
+
console.log(dump);
|
|
432
|
+
// 9F -- Start indefinite-length array
|
|
433
|
+
// ...
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
```ts
|
|
437
|
+
import { CBOR } from '@cbortech/cbor';
|
|
438
|
+
|
|
439
|
+
const item = CBOR.fromHexDump(`
|
|
440
|
+
83 -- Array of length 3
|
|
441
|
+
01 -- 1
|
|
442
|
+
02 -- 2
|
|
443
|
+
03 -- 3
|
|
444
|
+
`);
|
|
445
|
+
|
|
446
|
+
console.log(item.toEDN());
|
|
447
|
+
// [1,2,3]
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Public API
|
|
451
|
+
|
|
452
|
+
The documented public export is:
|
|
453
|
+
|
|
454
|
+
- `CBOR`
|
|
455
|
+
|
|
456
|
+
The `CBOR` facade also exposes:
|
|
457
|
+
|
|
458
|
+
- `CBOR.Tag`
|
|
459
|
+
- `CBOR.Simple`
|
|
460
|
+
- `CBOR.MapEntries`
|
|
461
|
+
- `CBOR.dt_as_Date`
|
|
462
|
+
- `CBOR.OMIT`
|
|
463
|
+
|
|
464
|
+
## Specifications
|
|
465
|
+
|
|
466
|
+
This library targets:
|
|
467
|
+
|
|
468
|
+
- [CBOR, RFC 8949](https://www.rfc-editor.org/rfc/rfc8949)
|
|
469
|
+
- [CBOR Extended Diagnostic Notation (CBOR-EDN), draft-ietf-cbor-edn-literals-23](https://datatracker.ietf.org/doc/draft-ietf-cbor-edn-literals/23/)
|
|
470
|
+
|
|
471
|
+
CBOR-EDN is a human-readable text notation for CBOR data. It is useful for
|
|
472
|
+
examples, test vectors, debugging, fixtures, and configuration-like files where
|
|
473
|
+
raw CBOR bytes would be hard to read.
|
|
474
|
+
|
|
475
|
+
It looks similar to JSON for ordinary arrays, maps, strings, numbers, booleans,
|
|
476
|
+
and null values, but it can also represent CBOR-specific features such as byte
|
|
477
|
+
strings, tags, simple values, indefinite-length items, non-string map keys, and
|
|
478
|
+
application literals like `dt'2026-05-06T00:00:00Z'`.
|
|
479
|
+
|
|
480
|
+
CBOR-EDN is a superset of JSON and JSONC, so ordinary JSON data and
|
|
481
|
+
commented JSON-style data can be parsed and formatted as CBOR-EDN without
|
|
482
|
+
special handling.
|
|
483
|
+
|
|
484
|
+
CBOR-EDN is still an Internet-Draft rather than a widely deployed RFC.
|
|
485
|
+
|
|
486
|
+
## License
|
|
487
|
+
|
|
488
|
+
Apache-2.0
|