cborg 4.5.7 → 5.0.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 (76) hide show
  1. package/.github/dependabot.yml +4 -0
  2. package/.github/workflows/test-and-release.yml +2 -4
  3. package/CHANGELOG.md +51 -0
  4. package/README.md +213 -9
  5. package/cborg.js +4 -4
  6. package/example-extended.js +122 -0
  7. package/interface.ts +15 -3
  8. package/lib/0uint.js +2 -2
  9. package/lib/1negint.js +2 -2
  10. package/lib/2bytes.js +2 -2
  11. package/lib/3string.js +2 -2
  12. package/lib/4array.js +2 -2
  13. package/lib/5map.js +2 -2
  14. package/lib/6tag.js +2 -2
  15. package/lib/7float.js +5 -4
  16. package/lib/decode.js +94 -4
  17. package/lib/diagnostic.js +10 -3
  18. package/lib/encode.js +7 -7
  19. package/lib/extended/extended.js +250 -0
  20. package/lib/json/decode.js +2 -2
  21. package/lib/json/encode.js +3 -3
  22. package/lib/jump.js +1 -1
  23. package/lib/length.js +3 -3
  24. package/lib/taglib.js +452 -0
  25. package/package.json +23 -18
  26. package/test/common.js +2 -1
  27. package/test/node-test-bin.js +26 -9
  28. package/test/test-6tag.js +2 -1
  29. package/test/test-cbor-vectors.js +14 -6
  30. package/test/test-extended-vectors.js +293 -0
  31. package/test/test-extended.js +684 -0
  32. package/test/test-taglib.js +634 -0
  33. package/tsconfig.json +7 -11
  34. package/types/cborg.d.ts +4 -4
  35. package/types/cborg.d.ts.map +1 -1
  36. package/types/interface.d.ts +14 -3
  37. package/types/interface.d.ts.map +1 -1
  38. package/types/lib/0uint.d.ts +4 -4
  39. package/types/lib/0uint.d.ts.map +1 -1
  40. package/types/lib/1negint.d.ts +4 -4
  41. package/types/lib/1negint.d.ts.map +1 -1
  42. package/types/lib/2bytes.d.ts +2 -2
  43. package/types/lib/2bytes.d.ts.map +1 -1
  44. package/types/lib/3string.d.ts +2 -2
  45. package/types/lib/3string.d.ts.map +1 -1
  46. package/types/lib/4array.d.ts +2 -2
  47. package/types/lib/4array.d.ts.map +1 -1
  48. package/types/lib/5map.d.ts +2 -2
  49. package/types/lib/5map.d.ts.map +1 -1
  50. package/types/lib/6tag.d.ts +4 -4
  51. package/types/lib/6tag.d.ts.map +1 -1
  52. package/types/lib/7float.d.ts +6 -6
  53. package/types/lib/7float.d.ts.map +1 -1
  54. package/types/lib/byte-utils.d.ts +5 -2
  55. package/types/lib/byte-utils.d.ts.map +1 -1
  56. package/types/lib/decode.d.ts +4 -3
  57. package/types/lib/decode.d.ts.map +1 -1
  58. package/types/lib/diagnostic.d.ts.map +1 -1
  59. package/types/lib/encode.d.ts +8 -8
  60. package/types/lib/encode.d.ts.map +1 -1
  61. package/types/lib/extended/extended.d.ts +78 -0
  62. package/types/lib/extended/extended.d.ts.map +1 -0
  63. package/types/lib/json/decode.d.ts +5 -5
  64. package/types/lib/json/decode.d.ts.map +1 -1
  65. package/types/lib/json/encode.d.ts +3 -3
  66. package/types/lib/json/encode.d.ts.map +1 -1
  67. package/types/lib/jump.d.ts +1 -1
  68. package/types/lib/jump.d.ts.map +1 -1
  69. package/types/lib/length.d.ts +3 -3
  70. package/types/lib/length.d.ts.map +1 -1
  71. package/types/lib/taglib.d.ts +143 -0
  72. package/types/lib/taglib.d.ts.map +1 -0
  73. package/types/tsconfig.tsbuildinfo +1 -1
  74. package/taglib.js +0 -73
  75. package/types/taglib.d.ts +0 -18
  76. package/types/taglib.d.ts.map +0 -1
package/lib/taglib.js ADDED
@@ -0,0 +1,452 @@
1
+ import { Token, Type } from '../cborg.js'
2
+ import { objectToTokens, Ref } from './encode.js'
3
+
4
+ /*
5
+ A collection of standard CBOR tags for extended JavaScript type support.
6
+
7
+ There are no tags included by default in the cborg encoder or decoder, you have
8
+ to include them by passing options. `typeEncoders` for encode() and `tags` for
9
+ decode().
10
+
11
+ The encoders here can be included with these options (see the tests for how this
12
+ can be done), or as examples for writing additional tags.
13
+
14
+ For convenience, cborg/extended provides a pre-configured encode/decode that
15
+ includes all of these, with type support similar to the browser's structured
16
+ clone algorithm.
17
+ */
18
+
19
+ // =============================================================================
20
+ // Tag Constants
21
+ // =============================================================================
22
+
23
+ // Standard Tags (RFC 8949)
24
+ export const TAG_DATE_STRING = 0 // RFC 3339 date/time string
25
+ export const TAG_DATE_EPOCH = 1 // Epoch-based date/time (integer or float)
26
+ export const TAG_BIGINT_POS = 2 // Unsigned bignum
27
+ export const TAG_BIGINT_NEG = 3 // Negative bignum
28
+
29
+ // TypedArray Tags (RFC 8746) - Single-byte arrays (no endianness)
30
+ export const TAG_UINT8_ARRAY = 64
31
+ export const TAG_UINT8_CLAMPED_ARRAY = 68
32
+ export const TAG_INT8_ARRAY = 72
33
+
34
+ // TypedArray Tags (RFC 8746) - Little-endian multi-byte arrays
35
+ export const TAG_UINT16_ARRAY_LE = 69
36
+ export const TAG_UINT32_ARRAY_LE = 70
37
+ export const TAG_BIGUINT64_ARRAY_LE = 71
38
+ export const TAG_INT16_ARRAY_LE = 77
39
+ export const TAG_INT32_ARRAY_LE = 78
40
+ export const TAG_BIGINT64_ARRAY_LE = 79
41
+ export const TAG_FLOAT32_ARRAY_LE = 85
42
+ export const TAG_FLOAT64_ARRAY_LE = 86
43
+
44
+ // Generic Object Tag (IANA Registry)
45
+ export const TAG_OBJECT_CLASS = 27 // Serialised object with class name and constructor arguments
46
+
47
+ // Extended Tags (IANA Registry)
48
+ export const TAG_SET = 258 // Mathematical finite set
49
+ export const TAG_MAP = 259 // Map datatype
50
+ export const TAG_REGEXP = 21066 // ECMAScript RegExp
51
+
52
+ // =============================================================================
53
+ // BigInt (Tags 2/3) - RFC 8949 Section 3.4.3
54
+ // =============================================================================
55
+
56
+ const neg1b = BigInt(-1)
57
+ const pos1b = BigInt(1)
58
+ const zerob = BigInt(0)
59
+ const eightb = BigInt(8)
60
+
61
+ /**
62
+ * Decode a positive bignum from bytes (Tag 2)
63
+ * @param {import('../interface.js').TagDecodeControl} decode
64
+ * @returns {bigint}
65
+ */
66
+ export function bigIntDecoder (decode) {
67
+ const bytes = /** @type {Uint8Array} */ (decode())
68
+ let bi = zerob
69
+ for (let ii = 0; ii < bytes.length; ii++) {
70
+ bi = (bi << eightb) + BigInt(bytes[ii])
71
+ }
72
+ return bi
73
+ }
74
+
75
+ /**
76
+ * Convert a BigInt to bytes
77
+ * @param {bigint} bi
78
+ * @returns {Uint8Array}
79
+ */
80
+ const ffb = BigInt(0xff)
81
+ /**
82
+ * @param {bigint} bi
83
+ */
84
+ function fromBigInt (bi) {
85
+ const buf = []
86
+ while (bi > 0) {
87
+ // Use BigInt operations to avoid Number precision loss
88
+ buf.unshift(Number(bi & ffb))
89
+ bi >>= eightb
90
+ }
91
+ return Uint8Array.from(buf.length ? buf : [0])
92
+ }
93
+
94
+ // For IPLD compatibility: only tag BigInts outside 64-bit range
95
+ const maxSafeBigInt = BigInt('18446744073709551615') // 2^64 - 1
96
+ const minSafeBigInt = BigInt('-18446744073709551616') // -2^64
97
+
98
+ /**
99
+ * Encode a BigInt, only using tags for values outside 64-bit range (IPLD compatible)
100
+ * @param {bigint} obj
101
+ * @returns {Token[]|null}
102
+ */
103
+ export function bigIntEncoder (obj) {
104
+ if (obj >= minSafeBigInt && obj <= maxSafeBigInt) {
105
+ return null // null = encode as native CBOR integer
106
+ }
107
+ return [
108
+ new Token(Type.tag, obj >= zerob ? TAG_BIGINT_POS : TAG_BIGINT_NEG),
109
+ new Token(Type.bytes, fromBigInt(obj >= zerob ? obj : obj * neg1b - pos1b))
110
+ ]
111
+ }
112
+
113
+ /**
114
+ * Encode a BigInt, always using tags 2/3 (for extended mode, full round-trip fidelity)
115
+ * @param {bigint} obj
116
+ * @returns {Token[]}
117
+ */
118
+ export function structBigIntEncoder (obj) {
119
+ return [
120
+ new Token(Type.tag, obj >= zerob ? TAG_BIGINT_POS : TAG_BIGINT_NEG),
121
+ new Token(Type.bytes, fromBigInt(obj >= zerob ? obj : obj * neg1b - pos1b))
122
+ ]
123
+ }
124
+
125
+ /**
126
+ * Decode a negative bignum from bytes (Tag 3)
127
+ * @param {import('../interface.js').TagDecodeControl} decode
128
+ * @returns {bigint}
129
+ */
130
+ export function bigNegIntDecoder (decode) {
131
+ const bytes = /** @type {Uint8Array} */ (decode())
132
+ let bi = zerob
133
+ for (let ii = 0; ii < bytes.length; ii++) {
134
+ bi = (bi << eightb) + BigInt(bytes[ii])
135
+ }
136
+ return neg1b - bi
137
+ }
138
+
139
+ // =============================================================================
140
+ // Date (Tag 1) - RFC 8949 Section 3.4.2
141
+ // =============================================================================
142
+
143
+ /**
144
+ * Encode a Date as Tag 1 (epoch seconds as float)
145
+ * @param {Date} date
146
+ * @returns {Token[]}
147
+ */
148
+ export function dateEncoder (date) {
149
+ // Use float for millisecond precision
150
+ const seconds = date.getTime() / 1000
151
+ return [
152
+ new Token(Type.tag, TAG_DATE_EPOCH),
153
+ new Token(Type.float, seconds)
154
+ ]
155
+ }
156
+
157
+ /**
158
+ * Decode Tag 1 (epoch seconds) to a Date
159
+ * @param {import('../interface.js').TagDecodeControl} decode
160
+ * @returns {Date}
161
+ */
162
+ export function dateDecoder (decode) {
163
+ const seconds = /** @type {number} */ (decode())
164
+ return new Date(seconds * 1000)
165
+ }
166
+
167
+ // =============================================================================
168
+ // RegExp (Tag 21066) - IANA Registry
169
+ // =============================================================================
170
+
171
+ /**
172
+ * Encode a RegExp as Tag 21066
173
+ * @param {RegExp} re
174
+ * @returns {Token[]}
175
+ */
176
+ export function regExpEncoder (re) {
177
+ if (re.flags) {
178
+ return [
179
+ new Token(Type.tag, TAG_REGEXP),
180
+ new Token(Type.array, 2),
181
+ new Token(Type.string, re.source),
182
+ new Token(Type.string, re.flags)
183
+ ]
184
+ }
185
+ return [
186
+ new Token(Type.tag, TAG_REGEXP),
187
+ new Token(Type.array, 1),
188
+ new Token(Type.string, re.source)
189
+ ]
190
+ }
191
+
192
+ /**
193
+ * Decode Tag 21066 to a RegExp
194
+ * @param {import('../interface.js').TagDecodeControl} decode
195
+ * @returns {RegExp}
196
+ */
197
+ export function regExpDecoder (decode) {
198
+ const val = /** @type {string[]|string} */ (decode())
199
+ if (Array.isArray(val)) {
200
+ return new RegExp(val[0], val[1] || '')
201
+ }
202
+ return new RegExp(val)
203
+ }
204
+
205
+ // =============================================================================
206
+ // Set (Tag 258) - IANA Registry
207
+ // =============================================================================
208
+
209
+ /**
210
+ * Encode a Set as Tag 258 + array
211
+ * This is a typeEncoder, receives (obj, typ, options, refStack)
212
+ * @param {Set<any>} set
213
+ * @param {string} _typ
214
+ * @param {import('../interface.js').EncodeOptions} options
215
+ * @param {import('../interface.js').Reference} [refStack]
216
+ * @returns {import('../interface.js').TokenOrNestedTokens[]}
217
+ */
218
+ export function setEncoder (set, _typ, options, refStack) {
219
+ if (set.size === 0) {
220
+ return [
221
+ new Token(Type.tag, TAG_SET),
222
+ new Token(Type.array, 0)
223
+ ]
224
+ }
225
+
226
+ refStack = Ref.createCheck(refStack, set)
227
+ const values = []
228
+ for (const v of set) {
229
+ values.push(objectToTokens(v, options, refStack))
230
+ }
231
+
232
+ return [
233
+ new Token(Type.tag, TAG_SET),
234
+ new Token(Type.array, set.size),
235
+ values
236
+ ]
237
+ }
238
+
239
+ /**
240
+ * Decode Tag 258 to a Set
241
+ * @param {import('../interface.js').TagDecodeControl} decode
242
+ * @returns {Set<any>}
243
+ */
244
+ export function setDecoder (decode) {
245
+ const val = /** @type {any[]} */ (decode())
246
+ return new Set(val)
247
+ }
248
+
249
+ // =============================================================================
250
+ // Map (Tag 259) - IANA Registry
251
+ // Tag 259 wraps a CBOR map to indicate it should decode as a JS Map
252
+ // =============================================================================
253
+
254
+ /**
255
+ * Encode a Map as Tag 259 + CBOR map
256
+ * This is a typeEncoder, receives (obj, typ, options, refStack)
257
+ * @param {Map<any, any>} map
258
+ * @param {string} _typ
259
+ * @param {import('../interface.js').EncodeOptions} options
260
+ * @param {import('../interface.js').Reference} [refStack]
261
+ * @returns {import('../interface.js').TokenOrNestedTokens[]}
262
+ */
263
+ export function mapEncoder (map, _typ, options, refStack) {
264
+ if (map.size === 0) {
265
+ return [
266
+ new Token(Type.tag, TAG_MAP),
267
+ new Token(Type.map, 0)
268
+ ]
269
+ }
270
+
271
+ refStack = Ref.createCheck(refStack, map)
272
+ const entries = []
273
+ for (const [key, value] of map) {
274
+ entries.push([
275
+ objectToTokens(key, options, refStack),
276
+ objectToTokens(value, options, refStack)
277
+ ])
278
+ }
279
+
280
+ // Sort entries if mapSorter is provided (for deterministic encoding)
281
+ if (options.mapSorter) {
282
+ entries.sort(options.mapSorter)
283
+ }
284
+
285
+ return [
286
+ new Token(Type.tag, TAG_MAP),
287
+ new Token(Type.map, map.size),
288
+ entries
289
+ ]
290
+ }
291
+
292
+ /**
293
+ * Decode Tag 259 to a Map
294
+ * Uses decode.entries() to preserve key types (integers, etc.) regardless of useMaps setting
295
+ * @param {import('../interface.js').TagDecodeControl} decode
296
+ * @returns {Map<any, any>}
297
+ */
298
+ export function mapDecoder (decode) {
299
+ return new Map(decode.entries())
300
+ }
301
+
302
+ // =============================================================================
303
+ // TypedArrays (Tags 64-87) - RFC 8746
304
+ // Uses little-endian tags for multi-byte arrays (JS native byte order)
305
+ // =============================================================================
306
+
307
+ /**
308
+ * Helper to create a TypedArray from an ArrayBuffer
309
+ * @template {ArrayBufferView} T
310
+ * @param {new (buffer: ArrayBuffer) => T} TypedArrayClass
311
+ * @returns {(decode: import('../interface.js').TagDecodeControl) => T}
312
+ */
313
+ function createTypedArrayDecoder (TypedArrayClass) {
314
+ return function (decode) {
315
+ const bytes = /** @type {Uint8Array} */ (decode())
316
+ // bytes is a Uint8Array, need to get properly sliced ArrayBuffer
317
+ const buffer = /** @type {ArrayBuffer} */ (bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength))
318
+ return new TypedArrayClass(buffer)
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Helper to create a TypedArray encoder
324
+ * @param {number} tag
325
+ * @returns {(arr: ArrayBufferView) => Token[]}
326
+ */
327
+ function createTypedArrayEncoder (tag) {
328
+ return function (arr) {
329
+ // Get the bytes from the TypedArray's underlying buffer
330
+ const bytes = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength)
331
+ return [
332
+ new Token(Type.tag, tag),
333
+ new Token(Type.bytes, bytes)
334
+ ]
335
+ }
336
+ }
337
+
338
+ // Uint8Array (Tag 64), no endianness concerns
339
+ export const uint8ArrayEncoder = createTypedArrayEncoder(TAG_UINT8_ARRAY)
340
+ export const uint8ArrayDecoder = createTypedArrayDecoder(Uint8Array)
341
+
342
+ // Uint8ClampedArray (Tag 68), no endianness concerns
343
+ export const uint8ClampedArrayEncoder = createTypedArrayEncoder(TAG_UINT8_CLAMPED_ARRAY)
344
+ export const uint8ClampedArrayDecoder = createTypedArrayDecoder(Uint8ClampedArray)
345
+
346
+ // Int8Array (Tag 72), no endianness concerns
347
+ export const int8ArrayEncoder = createTypedArrayEncoder(TAG_INT8_ARRAY)
348
+ export const int8ArrayDecoder = createTypedArrayDecoder(Int8Array)
349
+
350
+ // Uint16Array (Tag 69, little endian)
351
+ export const uint16ArrayEncoder = createTypedArrayEncoder(TAG_UINT16_ARRAY_LE)
352
+ export const uint16ArrayDecoder = createTypedArrayDecoder(Uint16Array)
353
+
354
+ // Uint32Array (Tag 70, little endian)
355
+ export const uint32ArrayEncoder = createTypedArrayEncoder(TAG_UINT32_ARRAY_LE)
356
+ export const uint32ArrayDecoder = createTypedArrayDecoder(Uint32Array)
357
+
358
+ // BigUint64Array (Tag 71, little endian)
359
+ export const bigUint64ArrayEncoder = createTypedArrayEncoder(TAG_BIGUINT64_ARRAY_LE)
360
+ export const bigUint64ArrayDecoder = createTypedArrayDecoder(BigUint64Array)
361
+
362
+ // Int16Array (Tag 77, little endian)
363
+ export const int16ArrayEncoder = createTypedArrayEncoder(TAG_INT16_ARRAY_LE)
364
+ export const int16ArrayDecoder = createTypedArrayDecoder(Int16Array)
365
+
366
+ // Int32Array (Tag 78, little endian)
367
+ export const int32ArrayEncoder = createTypedArrayEncoder(TAG_INT32_ARRAY_LE)
368
+ export const int32ArrayDecoder = createTypedArrayDecoder(Int32Array)
369
+
370
+ // BigInt64Array (Tag 79, little endian)
371
+ export const bigInt64ArrayEncoder = createTypedArrayEncoder(TAG_BIGINT64_ARRAY_LE)
372
+ export const bigInt64ArrayDecoder = createTypedArrayDecoder(BigInt64Array)
373
+
374
+ // Float32Array (Tag 85, little endian)
375
+ export const float32ArrayEncoder = createTypedArrayEncoder(TAG_FLOAT32_ARRAY_LE)
376
+ export const float32ArrayDecoder = createTypedArrayDecoder(Float32Array)
377
+
378
+ // Float64Array (Tag 86, little endian)
379
+ export const float64ArrayEncoder = createTypedArrayEncoder(TAG_FLOAT64_ARRAY_LE)
380
+ export const float64ArrayDecoder = createTypedArrayDecoder(Float64Array)
381
+
382
+ // =============================================================================
383
+ // Error (Tag 27) - IANA "object with class name and constructor arguments"
384
+ // Format: Tag 27: [className, message, options?]
385
+ // =============================================================================
386
+
387
+ /**
388
+ * Known JavaScript Error constructors
389
+ * @type {Record<string, ErrorConstructor>}
390
+ */
391
+ const errorConstructors = {
392
+ Error,
393
+ EvalError,
394
+ RangeError,
395
+ ReferenceError,
396
+ SyntaxError,
397
+ TypeError,
398
+ URIError
399
+ }
400
+
401
+ /**
402
+ * Encode an Error as Tag 27: [className, message]
403
+ * @param {Error} err
404
+ * @returns {Token[]}
405
+ */
406
+ export function errorEncoder (err) {
407
+ const className = err.name
408
+ // Only encode name and message (not stack, which is environment-specific)
409
+ return [
410
+ new Token(Type.tag, TAG_OBJECT_CLASS),
411
+ new Token(Type.array, 2),
412
+ new Token(Type.string, className),
413
+ new Token(Type.string, err.message)
414
+ ]
415
+ }
416
+
417
+ /**
418
+ * Decode Tag 27 to an Error (or Error subclass)
419
+ * @param {import('../interface.js').TagDecodeControl} decode
420
+ * @returns {Error}
421
+ */
422
+ export function errorDecoder (decode) {
423
+ const arr = /** @type {[string, string]} */ (decode())
424
+ const [className, message] = arr
425
+ const Ctor = errorConstructors[className] || Error
426
+ const err = new Ctor(message)
427
+ // If the constructor doesn't match (e.g., custom error name), set the name
428
+ if (err.name !== className && className in errorConstructors) {
429
+ err.name = className
430
+ }
431
+ return err
432
+ }
433
+
434
+ // =============================================================================
435
+ // Negative Zero (-0) Support
436
+ // CBOR can represent -0 as a float, but by default numbers encode as integers.
437
+ // This encoder ensures -0 is preserved by encoding it as a float.
438
+ // =============================================================================
439
+
440
+ /**
441
+ * Encode a number, preserving -0 as a float
442
+ * Use this as a typeEncoder for 'number' to preserve -0 fidelity
443
+ * @param {number} num
444
+ * @returns {Token[] | null}
445
+ */
446
+ export function negativeZeroEncoder (num) {
447
+ if (Object.is(num, -0)) {
448
+ return [new Token(Type.float, -0)]
449
+ }
450
+ // Return null to fall through to default number encoding
451
+ return null
452
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cborg",
3
- "version": "4.5.7",
3
+ "version": "5.0.0",
4
4
  "description": "Fast CBOR with a focus on strictness",
5
5
  "main": "cborg.js",
6
6
  "type": "module",
@@ -13,8 +13,9 @@
13
13
  "build:types": "tsc --build",
14
14
  "prepublishOnly": "npm run build",
15
15
  "test:node": "c8 --check-coverage --exclude=test/** mocha test/test-*.js",
16
+ "test:node-bin": "mocha test/node-test-bin.js",
16
17
  "test:browser": "polendina --cleanup test/test-*.js",
17
- "test": "npm run lint && npm run build && npm run test:node && npm run test:browser",
18
+ "test": "npm run lint && npm run build && npm run test:node && npm run test:node-bin && npm run test:browser",
18
19
  "test:ci": "npm run test",
19
20
  "coverage": "c8 --reporter=html --reporter=text mocha test/test-*.js && npx st -d coverage -p 8888"
20
21
  },
@@ -29,23 +30,23 @@
29
30
  "license": "Apache-2.0",
30
31
  "devDependencies": {
31
32
  "@semantic-release/changelog": "^6.0.3",
32
- "@semantic-release/commit-analyzer": "^13.0.0",
33
+ "@semantic-release/commit-analyzer": "^13.0.1",
33
34
  "@semantic-release/git": "^10.0.1",
34
- "@semantic-release/github": "^12.0.0",
35
- "@semantic-release/npm": "^13.0.0",
36
- "@semantic-release/release-notes-generator": "^14.0.1",
37
- "@types/chai": "^5.0.0",
38
- "@types/mocha": "^10.0.8",
39
- "@types/node": "^25.0.0",
40
- "c8": "^10.1.2",
41
- "chai": "^6.0.1",
42
- "conventional-changelog-conventionalcommits": "^9.0.0",
35
+ "@semantic-release/github": "^12.0.6",
36
+ "@semantic-release/npm": "^13.1.5",
37
+ "@semantic-release/release-notes-generator": "^14.1.0",
38
+ "@types/chai": "^5.2.3",
39
+ "@types/mocha": "^10.0.10",
40
+ "@types/node": "^25.5.0",
41
+ "c8": "^11.0.0",
42
+ "chai": "^6.2.2",
43
+ "conventional-changelog-conventionalcommits": "^9.3.0",
43
44
  "ipld-garbage": "^5.0.0",
44
- "mocha": "^11.0.1",
45
- "polendina": "^3.2.2",
46
- "semantic-release": "^25.0.0",
45
+ "mocha": "^11.7.5",
46
+ "polendina": "^3.2.20",
47
+ "semantic-release": "^25.0.3",
47
48
  "standard": "^17.1.2",
48
- "typescript": "^5.6.2"
49
+ "typescript": "^6.0.2"
49
50
  },
50
51
  "exports": {
51
52
  ".": {
@@ -57,13 +58,17 @@
57
58
  "types": "./types/lib/length.d.ts"
58
59
  },
59
60
  "./taglib": {
60
- "import": "./taglib.js",
61
- "types": "./types/taglib.d.ts"
61
+ "import": "./lib/taglib.js",
62
+ "types": "./types/lib/taglib.d.ts"
62
63
  },
63
64
  "./json": {
64
65
  "import": "./lib/json/json.js",
65
66
  "types": "./types/lib/json/json.d.ts"
66
67
  },
68
+ "./extended": {
69
+ "import": "./lib/extended/extended.js",
70
+ "types": "./types/lib/extended/extended.d.ts"
71
+ },
67
72
  "./interface": {
68
73
  "types": "./types/interface.d.ts"
69
74
  }
package/test/common.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Token, Type } from '../lib/token.js'
2
2
 
3
- export function dateDecoder (obj) {
3
+ export function dateDecoder (decode) {
4
+ const obj = decode()
4
5
  if (typeof obj !== 'string') {
5
6
  throw new Error('expected string for tag 1')
6
7
  }
@@ -97,17 +97,17 @@ describe('Bin', () => {
97
97
  assert.strictEqual(e.stderr,
98
98
  `Usage: cborg <command> <args>
99
99
  Valid commands:
100
- \tbin2diag [binary input]
100
+ \tbin2diag [--width <width>] [binary input]
101
101
  \tbin2hex [binary input]
102
102
  \tbin2json [--pretty] [binary input]
103
103
  \tdiag2bin [diagnostic input]
104
104
  \tdiag2hex [diagnostic input]
105
105
  \tdiag2json [--pretty] [diagnostic input]
106
106
  \thex2bin [hex input]
107
- \thex2diag [hex input]
107
+ \thex2diag [--width <width>] [hex input]
108
108
  \thex2json [--pretty] [hex input]
109
109
  \tjson2bin '[json input]'
110
- \tjson2diag '[json input]'
110
+ \tjson2diag [--width <width>] '[json input]'
111
111
  \tjson2hex '[json input]'
112
112
  Input may either be supplied as an argument or piped via stdin
113
113
  `)
@@ -124,17 +124,17 @@ Input may either be supplied as an argument or piped via stdin
124
124
  `Unknown command: 'blip'
125
125
  Usage: cborg <command> <args>
126
126
  Valid commands:
127
- \tbin2diag [binary input]
127
+ \tbin2diag [--width <width>] [binary input]
128
128
  \tbin2hex [binary input]
129
129
  \tbin2json [--pretty] [binary input]
130
130
  \tdiag2bin [diagnostic input]
131
131
  \tdiag2hex [diagnostic input]
132
132
  \tdiag2json [--pretty] [diagnostic input]
133
133
  \thex2bin [hex input]
134
- \thex2diag [hex input]
134
+ \thex2diag [--width <width>] [hex input]
135
135
  \thex2json [--pretty] [hex input]
136
136
  \tjson2bin '[json input]'
137
- \tjson2diag '[json input]'
137
+ \tjson2diag [--width <width>] '[json input]'
138
138
  \tjson2hex '[json input]'
139
139
  Input may either be supplied as an argument or piped via stdin
140
140
  `)
@@ -147,17 +147,17 @@ Input may either be supplied as an argument or piped via stdin
147
147
  assert.strictEqual(stderr,
148
148
  `Usage: cborg <command> <args>
149
149
  Valid commands:
150
- \tbin2diag [binary input]
150
+ \tbin2diag [--width <width>] [binary input]
151
151
  \tbin2hex [binary input]
152
152
  \tbin2json [--pretty] [binary input]
153
153
  \tdiag2bin [diagnostic input]
154
154
  \tdiag2hex [diagnostic input]
155
155
  \tdiag2json [--pretty] [diagnostic input]
156
156
  \thex2bin [hex input]
157
- \thex2diag [hex input]
157
+ \thex2diag [--width <width>] [hex input]
158
158
  \thex2json [--pretty] [hex input]
159
159
  \tjson2bin '[json input]'
160
- \tjson2diag '[json input]'
160
+ \tjson2diag [--width <width>] '[json input]'
161
161
  \tjson2hex '[json input]'
162
162
  Input may either be supplied as an argument or piped via stdin
163
163
  `)
@@ -341,6 +341,23 @@ Input may either be supplied as an argument or piped via stdin
341
341
  })
342
342
 
343
343
  describe('diag length bytes', () => {
344
+ // issue #137 - array and map length bytes were missing for lengths >= 24
345
+ it('array with 24 elements', async () => {
346
+ // 98 18 = array(24), then 24 uint(1) values
347
+ const hex = '9818' + '01'.repeat(24)
348
+ const { stdout, stderr } = await execBin(`hex2diag ${hex}`)
349
+ assert.strictEqual(stderr, '')
350
+ assert.ok(stdout.startsWith('98 18 # array(24)\n'))
351
+ })
352
+
353
+ it('map with 24 entries', async () => {
354
+ // b8 18 = map(24), then 24 pairs of string('a')=uint(1)
355
+ const hex = 'b818' + '616101'.repeat(24)
356
+ const { stdout, stderr } = await execBin(`hex2diag ${hex}`)
357
+ assert.strictEqual(stderr, '')
358
+ assert.ok(stdout.startsWith('b8 18 # map(24)\n'))
359
+ })
360
+
344
361
  it('compact', async () => {
345
362
  const { stdout, stderr } = await execBin('json2diag', '"aaaaaaaaaaaaaaaaaaaaaaa"')
346
363
  assert.strictEqual(stderr, '')
package/test/test-6tag.js CHANGED
@@ -17,7 +17,8 @@ const encodeIntoBytes = (data, dest, options) => {
17
17
 
18
18
  const fixedDest = new Uint8Array(1024)
19
19
 
20
- function Uint16ArrayDecoder (obj) {
20
+ function Uint16ArrayDecoder (decode) {
21
+ const obj = decode()
21
22
  if (typeof obj !== 'string') {
22
23
  throw new Error('expected string for tag 23')
23
24
  }
@@ -21,14 +21,16 @@ const fixedDest = new Uint8Array(1024)
21
21
  const tags = []
22
22
  const typeEncoders = {}
23
23
 
24
- tags[0] = function (obj) {
24
+ tags[0] = function (decode) {
25
+ const obj = decode()
25
26
  if (typeof obj !== 'string') {
26
27
  throw new Error('expected string for tag 1')
27
28
  }
28
29
  return `0("${new Date(obj).toISOString().replace(/\.000Z$/, 'Z')}")`
29
30
  }
30
31
 
31
- tags[1] = function (obj) {
32
+ tags[1] = function (decode) {
33
+ const obj = decode()
32
34
  if (typeof obj !== 'number') {
33
35
  throw new Error('expected number for tag 1')
34
36
  }
@@ -39,19 +41,25 @@ tags[2] = taglib.bigIntDecoder
39
41
  typeEncoders.bigint = taglib.bigIntEncoder
40
42
  tags[3] = taglib.bigNegIntDecoder
41
43
 
42
- tags[23] = function (obj) {
44
+ tags[23] = function (decode) {
43
45
  // expected conversion to base16
46
+ const obj = decode()
44
47
  if (!(obj instanceof Uint8Array)) {
45
48
  throw new Error('expected byte array for tag 23')
46
49
  }
47
50
  return `23(h'${toHex(obj)}')`
48
51
  }
49
52
 
50
- tags[24] = function (obj) { // embedded cbor, oh my
51
- return tags[23](obj).replace(/^23/, '24')
53
+ tags[24] = function (decode) { // embedded cbor, oh my
54
+ const obj = decode()
55
+ if (!(obj instanceof Uint8Array)) {
56
+ throw new Error('expected byte array for tag 24')
57
+ }
58
+ return `24(h'${toHex(obj)}')`
52
59
  }
53
60
 
54
- tags[32] = function (obj) { // url
61
+ tags[32] = function (decode) { // url
62
+ const obj = decode()
55
63
  if (typeof obj !== 'string') {
56
64
  throw new Error('expected string for tag 32')
57
65
  }