cborg 4.5.8 → 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.
- package/.github/dependabot.yml +4 -0
- package/.github/workflows/test-and-release.yml +2 -4
- package/CHANGELOG.md +44 -0
- package/README.md +213 -9
- package/cborg.js +4 -4
- package/example-extended.js +122 -0
- package/interface.ts +15 -3
- package/lib/0uint.js +2 -2
- package/lib/1negint.js +2 -2
- package/lib/2bytes.js +2 -2
- package/lib/3string.js +2 -2
- package/lib/4array.js +2 -2
- package/lib/5map.js +2 -2
- package/lib/6tag.js +2 -2
- package/lib/7float.js +5 -4
- package/lib/decode.js +94 -4
- package/lib/encode.js +7 -7
- package/lib/extended/extended.js +250 -0
- package/lib/json/decode.js +2 -2
- package/lib/json/encode.js +3 -3
- package/lib/jump.js +1 -1
- package/lib/length.js +3 -3
- package/lib/taglib.js +452 -0
- package/package.json +21 -17
- package/test/common.js +2 -1
- package/test/test-6tag.js +2 -1
- package/test/test-cbor-vectors.js +14 -6
- package/test/test-extended-vectors.js +293 -0
- package/test/test-extended.js +684 -0
- package/test/test-taglib.js +634 -0
- package/tsconfig.json +7 -11
- package/types/cborg.d.ts +4 -4
- package/types/cborg.d.ts.map +1 -1
- package/types/interface.d.ts +14 -3
- package/types/interface.d.ts.map +1 -1
- package/types/lib/0uint.d.ts +4 -4
- package/types/lib/0uint.d.ts.map +1 -1
- package/types/lib/1negint.d.ts +4 -4
- package/types/lib/1negint.d.ts.map +1 -1
- package/types/lib/2bytes.d.ts +2 -2
- package/types/lib/2bytes.d.ts.map +1 -1
- package/types/lib/3string.d.ts +2 -2
- package/types/lib/3string.d.ts.map +1 -1
- package/types/lib/4array.d.ts +2 -2
- package/types/lib/4array.d.ts.map +1 -1
- package/types/lib/5map.d.ts +2 -2
- package/types/lib/5map.d.ts.map +1 -1
- package/types/lib/6tag.d.ts +4 -4
- package/types/lib/6tag.d.ts.map +1 -1
- package/types/lib/7float.d.ts +6 -6
- package/types/lib/7float.d.ts.map +1 -1
- package/types/lib/byte-utils.d.ts +5 -2
- package/types/lib/byte-utils.d.ts.map +1 -1
- package/types/lib/decode.d.ts +4 -3
- package/types/lib/decode.d.ts.map +1 -1
- package/types/lib/encode.d.ts +8 -8
- package/types/lib/encode.d.ts.map +1 -1
- package/types/lib/extended/extended.d.ts +78 -0
- package/types/lib/extended/extended.d.ts.map +1 -0
- package/types/lib/json/decode.d.ts +5 -5
- package/types/lib/json/decode.d.ts.map +1 -1
- package/types/lib/json/encode.d.ts +3 -3
- package/types/lib/json/encode.d.ts.map +1 -1
- package/types/lib/jump.d.ts +1 -1
- package/types/lib/jump.d.ts.map +1 -1
- package/types/lib/length.d.ts +3 -3
- package/types/lib/length.d.ts.map +1 -1
- package/types/lib/taglib.d.ts +143 -0
- package/types/lib/taglib.d.ts.map +1 -0
- package/types/tsconfig.tsbuildinfo +1 -1
- package/taglib.js +0 -73
- package/types/taglib.d.ts +0 -18
- 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": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Fast CBOR with a focus on strictness",
|
|
5
5
|
"main": "cborg.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,23 +30,23 @@
|
|
|
30
30
|
"license": "Apache-2.0",
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@semantic-release/changelog": "^6.0.3",
|
|
33
|
-
"@semantic-release/commit-analyzer": "^13.0.
|
|
33
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
34
34
|
"@semantic-release/git": "^10.0.1",
|
|
35
|
-
"@semantic-release/github": "^12.0.
|
|
36
|
-
"@semantic-release/npm": "^13.
|
|
37
|
-
"@semantic-release/release-notes-generator": "^14.0
|
|
38
|
-
"@types/chai": "^5.
|
|
39
|
-
"@types/mocha": "^10.0.
|
|
40
|
-
"@types/node": "^25.
|
|
41
|
-
"c8": "^
|
|
42
|
-
"chai": "^6.
|
|
43
|
-
"conventional-changelog-conventionalcommits": "^9.
|
|
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",
|
|
44
44
|
"ipld-garbage": "^5.0.0",
|
|
45
|
-
"mocha": "^11.
|
|
46
|
-
"polendina": "^3.2.
|
|
47
|
-
"semantic-release": "^25.0.
|
|
45
|
+
"mocha": "^11.7.5",
|
|
46
|
+
"polendina": "^3.2.20",
|
|
47
|
+
"semantic-release": "^25.0.3",
|
|
48
48
|
"standard": "^17.1.2",
|
|
49
|
-
"typescript": "^
|
|
49
|
+
"typescript": "^6.0.2"
|
|
50
50
|
},
|
|
51
51
|
"exports": {
|
|
52
52
|
".": {
|
|
@@ -58,13 +58,17 @@
|
|
|
58
58
|
"types": "./types/lib/length.d.ts"
|
|
59
59
|
},
|
|
60
60
|
"./taglib": {
|
|
61
|
-
"import": "./taglib.js",
|
|
62
|
-
"types": "./types/taglib.d.ts"
|
|
61
|
+
"import": "./lib/taglib.js",
|
|
62
|
+
"types": "./types/lib/taglib.d.ts"
|
|
63
63
|
},
|
|
64
64
|
"./json": {
|
|
65
65
|
"import": "./lib/json/json.js",
|
|
66
66
|
"types": "./types/lib/json/json.d.ts"
|
|
67
67
|
},
|
|
68
|
+
"./extended": {
|
|
69
|
+
"import": "./lib/extended/extended.js",
|
|
70
|
+
"types": "./types/lib/extended/extended.d.ts"
|
|
71
|
+
},
|
|
68
72
|
"./interface": {
|
|
69
73
|
"types": "./types/interface.d.ts"
|
|
70
74
|
}
|
package/test/common.js
CHANGED
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
51
|
-
|
|
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 (
|
|
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
|
}
|