cborg 4.5.8 → 5.0.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/.github/dependabot.yml +4 -0
- package/.github/workflows/test-and-release.yml +2 -4
- package/CHANGELOG.md +50 -0
- package/README.md +213 -9
- package/cborg.js +5 -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 +8 -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
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test vectors for cborg/extended tag encoders/decoders
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - RFC 8949 Appendix A (Date tags 0, 1)
|
|
8
|
+
* - RFC 8746 (TypedArray tags 64-87)
|
|
9
|
+
* - CBOR Sets Spec: https://github.com/input-output-hk/cbor-sets-spec (Tag 258)
|
|
10
|
+
* - CBOR Map Spec: https://github.com/shanewholloway/js-cbor-codec (Tag 259)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as chai from 'chai'
|
|
14
|
+
import { encode, decode } from '../lib/extended/extended.js'
|
|
15
|
+
import { fromHex, toHex } from '../lib/byte-utils.js'
|
|
16
|
+
|
|
17
|
+
const { assert } = chai
|
|
18
|
+
|
|
19
|
+
describe('cborg/extended test vectors', () => {
|
|
20
|
+
describe('Tag 1 - Date (RFC 8949 Appendix A)', () => {
|
|
21
|
+
it('decodes epoch integer: c11a514b67b0 → Date(1363896240000)', () => {
|
|
22
|
+
// From RFC 8949 Appendix A: 1(1363896240)
|
|
23
|
+
const bytes = fromHex('c11a514b67b0')
|
|
24
|
+
const result = decode(bytes)
|
|
25
|
+
assert.ok(result instanceof Date)
|
|
26
|
+
assert.strictEqual(result.getTime(), 1363896240000)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('decodes epoch float: c1fb41d452d9ec200000 → Date(1363896240500)', () => {
|
|
30
|
+
// From RFC 8949 Appendix A: 1(1363896240.5)
|
|
31
|
+
const bytes = fromHex('c1fb41d452d9ec200000')
|
|
32
|
+
const result = decode(bytes)
|
|
33
|
+
assert.ok(result instanceof Date)
|
|
34
|
+
assert.strictEqual(result.getTime(), 1363896240500)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('round-trips date with millisecond precision', () => {
|
|
38
|
+
const date = new Date(1363896240500) // 2013-03-21T20:04:00.500Z
|
|
39
|
+
const encoded = encode(date)
|
|
40
|
+
const decoded = decode(encoded)
|
|
41
|
+
assert.strictEqual(decoded.getTime(), date.getTime())
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('Tag 2/3 - BigInt (RFC 8949)', () => {
|
|
46
|
+
it('decodes positive bigint: c249010000000000000000 → 2^64', () => {
|
|
47
|
+
// Tag 2 with bytes for 2^64
|
|
48
|
+
const bytes = fromHex('c249010000000000000000')
|
|
49
|
+
const result = decode(bytes)
|
|
50
|
+
assert.strictEqual(typeof result, 'bigint')
|
|
51
|
+
assert.strictEqual(result, BigInt('18446744073709551616'))
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('decodes negative bigint: c349010000000000000000 → -(2^64 + 1)', () => {
|
|
55
|
+
// Tag 3 with bytes for -(2^64 + 1)
|
|
56
|
+
const bytes = fromHex('c349010000000000000000')
|
|
57
|
+
const result = decode(bytes)
|
|
58
|
+
assert.strictEqual(typeof result, 'bigint')
|
|
59
|
+
assert.strictEqual(result, BigInt('-18446744073709551617'))
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('round-trips large positive bigint', () => {
|
|
63
|
+
const n = BigInt('18446744073709551616') // 2^64
|
|
64
|
+
const encoded = encode(n)
|
|
65
|
+
// Verify it uses tag 2
|
|
66
|
+
assert.strictEqual(encoded[0], 0xc2) // Tag 2
|
|
67
|
+
const decoded = decode(encoded)
|
|
68
|
+
assert.strictEqual(decoded, n)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('round-trips large negative bigint', () => {
|
|
72
|
+
const n = BigInt('-18446744073709551617') // -(2^64 + 1)
|
|
73
|
+
const encoded = encode(n)
|
|
74
|
+
// Verify it uses tag 3
|
|
75
|
+
assert.strictEqual(encoded[0], 0xc3) // Tag 3
|
|
76
|
+
const decoded = decode(encoded)
|
|
77
|
+
assert.strictEqual(decoded, n)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('Tag 258 - Set (IANA Registry)', () => {
|
|
82
|
+
it('decodes official vector: d9010283010203 → Set([1, 2, 3])', () => {
|
|
83
|
+
// From https://github.com/input-output-hk/cbor-sets-spec
|
|
84
|
+
const bytes = fromHex('d9010283010203')
|
|
85
|
+
const result = decode(bytes)
|
|
86
|
+
assert.ok(result instanceof Set)
|
|
87
|
+
assert.strictEqual(result.size, 3)
|
|
88
|
+
assert.ok(result.has(1))
|
|
89
|
+
assert.ok(result.has(2))
|
|
90
|
+
assert.ok(result.has(3))
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('encodes Set([1, 2, 3]) with tag 258', () => {
|
|
94
|
+
const set = new Set([1, 2, 3])
|
|
95
|
+
const encoded = encode(set)
|
|
96
|
+
// First two bytes should be d9 0102 (tag 258)
|
|
97
|
+
assert.strictEqual(encoded[0], 0xd9)
|
|
98
|
+
assert.strictEqual(encoded[1], 0x01)
|
|
99
|
+
assert.strictEqual(encoded[2], 0x02)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('round-trips empty set', () => {
|
|
103
|
+
const set = new Set()
|
|
104
|
+
const encoded = encode(set)
|
|
105
|
+
const decoded = decode(encoded)
|
|
106
|
+
assert.ok(decoded instanceof Set)
|
|
107
|
+
assert.strictEqual(decoded.size, 0)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('Tag 259 - Map (IANA Registry)', () => {
|
|
112
|
+
it('decodes official vector: d90103a2626b31627631626b32627632 → Map', () => {
|
|
113
|
+
// From https://github.com/shanewholloway/js-cbor-codec
|
|
114
|
+
// Map with string keys: {k1: v1, k2: v2}
|
|
115
|
+
const bytes = fromHex('d90103a2626b31627631626b32627632')
|
|
116
|
+
const result = decode(bytes)
|
|
117
|
+
assert.ok(result instanceof Map)
|
|
118
|
+
assert.strictEqual(result.get('k1'), 'v1')
|
|
119
|
+
assert.strictEqual(result.get('k2'), 'v2')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('encodes Map with tag 259', () => {
|
|
123
|
+
const map = new Map([['k1', 'v1'], ['k2', 'v2']])
|
|
124
|
+
const encoded = encode(map)
|
|
125
|
+
// First two bytes should be d9 0103 (tag 259)
|
|
126
|
+
assert.strictEqual(encoded[0], 0xd9)
|
|
127
|
+
assert.strictEqual(encoded[1], 0x01)
|
|
128
|
+
assert.strictEqual(encoded[2], 0x03)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('round-trips map with non-string keys', () => {
|
|
132
|
+
const map = new Map([[42, 'answer'], [true, 'yes']])
|
|
133
|
+
const encoded = encode(map)
|
|
134
|
+
const decoded = decode(encoded)
|
|
135
|
+
assert.ok(decoded instanceof Map)
|
|
136
|
+
assert.strictEqual(decoded.get(42), 'answer')
|
|
137
|
+
assert.strictEqual(decoded.get(true), 'yes')
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe('Tags 64-87 - TypedArrays (RFC 8746)', () => {
|
|
142
|
+
// RFC 8746 defines tags for typed arrays
|
|
143
|
+
// We use little-endian tags (69, 70, 71, 77, 78, 79, 85, 86) for multi-byte types
|
|
144
|
+
|
|
145
|
+
it('Tag 64: Uint8Array round-trips', () => {
|
|
146
|
+
const arr = new Uint8Array([1, 2, 3, 255])
|
|
147
|
+
const encoded = encode(arr)
|
|
148
|
+
assert.strictEqual(encoded[0], 0xd8) // 1-byte tag
|
|
149
|
+
assert.strictEqual(encoded[1], 64) // Tag 64
|
|
150
|
+
const decoded = decode(encoded)
|
|
151
|
+
assert.ok(decoded instanceof Uint8Array)
|
|
152
|
+
assert.deepStrictEqual([...decoded], [1, 2, 3, 255])
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('Tag 68: Uint8ClampedArray round-trips', () => {
|
|
156
|
+
const arr = new Uint8ClampedArray([0, 128, 255])
|
|
157
|
+
const encoded = encode(arr)
|
|
158
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
159
|
+
assert.strictEqual(encoded[1], 68)
|
|
160
|
+
const decoded = decode(encoded)
|
|
161
|
+
assert.ok(decoded instanceof Uint8ClampedArray)
|
|
162
|
+
assert.deepStrictEqual([...decoded], [0, 128, 255])
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('Tag 72: Int8Array round-trips', () => {
|
|
166
|
+
const arr = new Int8Array([-128, 0, 127])
|
|
167
|
+
const encoded = encode(arr)
|
|
168
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
169
|
+
assert.strictEqual(encoded[1], 72)
|
|
170
|
+
const decoded = decode(encoded)
|
|
171
|
+
assert.ok(decoded instanceof Int8Array)
|
|
172
|
+
assert.deepStrictEqual([...decoded], [-128, 0, 127])
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('Tag 69: Uint16Array (LE) round-trips', () => {
|
|
176
|
+
const arr = new Uint16Array([0, 256, 65535])
|
|
177
|
+
const encoded = encode(arr)
|
|
178
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
179
|
+
assert.strictEqual(encoded[1], 69)
|
|
180
|
+
const decoded = decode(encoded)
|
|
181
|
+
assert.ok(decoded instanceof Uint16Array)
|
|
182
|
+
assert.deepStrictEqual([...decoded], [0, 256, 65535])
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('Tag 77: Int16Array (LE) round-trips', () => {
|
|
186
|
+
const arr = new Int16Array([-32768, 0, 32767])
|
|
187
|
+
const encoded = encode(arr)
|
|
188
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
189
|
+
assert.strictEqual(encoded[1], 77)
|
|
190
|
+
const decoded = decode(encoded)
|
|
191
|
+
assert.ok(decoded instanceof Int16Array)
|
|
192
|
+
assert.deepStrictEqual([...decoded], [-32768, 0, 32767])
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('Tag 70: Uint32Array (LE) round-trips', () => {
|
|
196
|
+
const arr = new Uint32Array([0, 65536, 4294967295])
|
|
197
|
+
const encoded = encode(arr)
|
|
198
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
199
|
+
assert.strictEqual(encoded[1], 70)
|
|
200
|
+
const decoded = decode(encoded)
|
|
201
|
+
assert.ok(decoded instanceof Uint32Array)
|
|
202
|
+
assert.deepStrictEqual([...decoded], [0, 65536, 4294967295])
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('Tag 78: Int32Array (LE) round-trips', () => {
|
|
206
|
+
const arr = new Int32Array([-2147483648, 0, 2147483647])
|
|
207
|
+
const encoded = encode(arr)
|
|
208
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
209
|
+
assert.strictEqual(encoded[1], 78)
|
|
210
|
+
const decoded = decode(encoded)
|
|
211
|
+
assert.ok(decoded instanceof Int32Array)
|
|
212
|
+
assert.deepStrictEqual([...decoded], [-2147483648, 0, 2147483647])
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('Tag 85: Float32Array (LE) round-trips', () => {
|
|
216
|
+
const arr = new Float32Array([1.5, -2.5, 0])
|
|
217
|
+
const encoded = encode(arr)
|
|
218
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
219
|
+
assert.strictEqual(encoded[1], 85)
|
|
220
|
+
const decoded = decode(encoded)
|
|
221
|
+
assert.ok(decoded instanceof Float32Array)
|
|
222
|
+
assert.strictEqual(decoded[0], 1.5)
|
|
223
|
+
assert.strictEqual(decoded[1], -2.5)
|
|
224
|
+
assert.strictEqual(decoded[2], 0)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('Tag 86: Float64Array (LE) round-trips', () => {
|
|
228
|
+
const arr = new Float64Array([Math.PI, -Math.E, Infinity])
|
|
229
|
+
const encoded = encode(arr)
|
|
230
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
231
|
+
assert.strictEqual(encoded[1], 86)
|
|
232
|
+
const decoded = decode(encoded)
|
|
233
|
+
assert.ok(decoded instanceof Float64Array)
|
|
234
|
+
assert.strictEqual(decoded[0], Math.PI)
|
|
235
|
+
assert.strictEqual(decoded[1], -Math.E)
|
|
236
|
+
assert.strictEqual(decoded[2], Infinity)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
it('Tag 71: BigUint64Array (LE) round-trips', () => {
|
|
240
|
+
const arr = new BigUint64Array([0n, 1n, BigInt('18446744073709551615')])
|
|
241
|
+
const encoded = encode(arr)
|
|
242
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
243
|
+
assert.strictEqual(encoded[1], 71)
|
|
244
|
+
const decoded = decode(encoded)
|
|
245
|
+
assert.ok(decoded instanceof BigUint64Array)
|
|
246
|
+
assert.deepStrictEqual([...decoded], [0n, 1n, BigInt('18446744073709551615')])
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('Tag 79: BigInt64Array (LE) round-trips', () => {
|
|
250
|
+
const arr = new BigInt64Array([BigInt('-9223372036854775808'), 0n, BigInt('9223372036854775807')])
|
|
251
|
+
const encoded = encode(arr)
|
|
252
|
+
assert.strictEqual(encoded[0], 0xd8)
|
|
253
|
+
assert.strictEqual(encoded[1], 79)
|
|
254
|
+
const decoded = decode(encoded)
|
|
255
|
+
assert.ok(decoded instanceof BigInt64Array)
|
|
256
|
+
assert.deepStrictEqual([...decoded], [BigInt('-9223372036854775808'), 0n, BigInt('9223372036854775807')])
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
describe('cross-implementation compatibility', () => {
|
|
261
|
+
it('generates deterministic output for Set', () => {
|
|
262
|
+
// Sets should encode consistently
|
|
263
|
+
const set = new Set([1, 2, 3])
|
|
264
|
+
const encoded1 = encode(set)
|
|
265
|
+
const encoded2 = encode(set)
|
|
266
|
+
assert.strictEqual(toHex(encoded1), toHex(encoded2))
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('generates deterministic output for Map', () => {
|
|
270
|
+
// Maps should encode with consistent key ordering
|
|
271
|
+
const map = new Map([['b', 2], ['a', 1]])
|
|
272
|
+
const encoded1 = encode(map)
|
|
273
|
+
const encoded2 = encode(map)
|
|
274
|
+
assert.strictEqual(toHex(encoded1), toHex(encoded2))
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('handles nested tagged values', () => {
|
|
278
|
+
// A Set containing a Map containing a Date
|
|
279
|
+
const nested = new Set([
|
|
280
|
+
new Map([['created', new Date('2024-01-01T00:00:00Z')]])
|
|
281
|
+
])
|
|
282
|
+
const encoded = encode(nested)
|
|
283
|
+
const decoded = decode(encoded)
|
|
284
|
+
|
|
285
|
+
assert.ok(decoded instanceof Set)
|
|
286
|
+
const innerMap = [...decoded][0]
|
|
287
|
+
assert.ok(innerMap instanceof Map)
|
|
288
|
+
const date = innerMap.get('created')
|
|
289
|
+
assert.ok(date instanceof Date)
|
|
290
|
+
assert.strictEqual(date.toISOString(), '2024-01-01T00:00:00.000Z')
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
})
|