@bcts/dcbor 1.0.0-alpha.16 → 1.0.0-alpha.18
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.md +1 -1
- package/dist/index.cjs +789 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -23
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +160 -23
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +789 -474
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +797 -490
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/bignum.ts +334 -0
- package/src/byte-string.ts +17 -17
- package/src/date.ts +11 -11
- package/src/index.ts +10 -0
- package/src/map.ts +23 -23
- package/src/prelude.ts +3 -0
- package/src/set.ts +9 -9
- package/src/tags-store.ts +17 -17
- package/src/tags.ts +46 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bcts/dcbor",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Blockchain Commons Deterministic CBOR (dCBOR) for TypeScript",
|
|
6
6
|
"license": "BSD-2-Clause-Patent",
|
|
@@ -71,15 +71,15 @@
|
|
|
71
71
|
"@bcts/tsconfig": "^0.1.0",
|
|
72
72
|
"@eslint/js": "^9.39.2",
|
|
73
73
|
"@types/collections": "^5.1.5",
|
|
74
|
-
"@types/node": "^25.0
|
|
75
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
76
|
-
"@typescript-eslint/parser": "^8.
|
|
74
|
+
"@types/node": "^25.2.0",
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
76
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
77
77
|
"eslint": "^9.39.2",
|
|
78
78
|
"ts-node": "^10.9.2",
|
|
79
|
-
"tsdown": "^0.
|
|
80
|
-
"typedoc": "^0.28.
|
|
79
|
+
"tsdown": "^0.20.1",
|
|
80
|
+
"typedoc": "^0.28.16",
|
|
81
81
|
"typescript": "^5.9.3",
|
|
82
|
-
"vitest": "^4.0.
|
|
82
|
+
"vitest": "^4.0.18"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"byte-data": "^19.0.1",
|
package/src/bignum.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBOR bignum (tags 2 and 3) support.
|
|
3
|
+
*
|
|
4
|
+
* This module provides conversion between CBOR and JavaScript BigInt types,
|
|
5
|
+
* implementing RFC 8949 §3.4.3 (Bignums) with dCBOR/CDE canonical encoding rules.
|
|
6
|
+
*
|
|
7
|
+
* Encoding:
|
|
8
|
+
* - `biguintToCbor` always encodes as tag 2 (positive bignum) with a byte
|
|
9
|
+
* string content.
|
|
10
|
+
* - `bigintToCbor` encodes as tag 2 for non-negative values or tag 3
|
|
11
|
+
* (negative bignum) for negative values.
|
|
12
|
+
* - No numeric reduction is performed: values are always encoded as bignums,
|
|
13
|
+
* even if they would fit in normal CBOR integers.
|
|
14
|
+
*
|
|
15
|
+
* Decoding:
|
|
16
|
+
* - Accepts CBOR integers (major types 0 and 1) and converts them to bigints.
|
|
17
|
+
* - Accepts tag 2 (positive bignum) and tag 3 (negative bignum) with byte
|
|
18
|
+
* string content.
|
|
19
|
+
* - Enforces shortest-form canonical representation for bignum magnitudes.
|
|
20
|
+
* - Rejects floating-point values.
|
|
21
|
+
*
|
|
22
|
+
* @module bignum
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { type Cbor, MajorType, toTaggedValue } from "./cbor";
|
|
26
|
+
import { CborError } from "./error";
|
|
27
|
+
|
|
28
|
+
// CBOR tag values (local constants matching tags.ts, avoiding circular import)
|
|
29
|
+
const TAG_2_POSITIVE_BIGNUM = 2;
|
|
30
|
+
const TAG_3_NEGATIVE_BIGNUM = 3;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Validates that a bignum magnitude byte string is in shortest canonical form.
|
|
34
|
+
*
|
|
35
|
+
* Matches Rust's `validate_bignum_magnitude()`.
|
|
36
|
+
*
|
|
37
|
+
* Rules:
|
|
38
|
+
* - For positive bignums (tag 2): empty byte string represents zero;
|
|
39
|
+
* non-empty must not have leading zero bytes.
|
|
40
|
+
* - For negative bignums (tag 3): byte string must not be empty
|
|
41
|
+
* (magnitude zero is encoded as `0x00`); must not have leading zero bytes
|
|
42
|
+
* except when the magnitude is zero (single `0x00`).
|
|
43
|
+
*
|
|
44
|
+
* @param bytes - The magnitude byte string to validate
|
|
45
|
+
* @param isNegative - Whether this is for a negative bignum (tag 3)
|
|
46
|
+
* @throws CborError with type NonCanonicalNumeric on validation failure
|
|
47
|
+
*/
|
|
48
|
+
export function validateBignumMagnitude(bytes: Uint8Array, isNegative: boolean): void {
|
|
49
|
+
if (isNegative) {
|
|
50
|
+
// Tag 3: byte string must not be empty
|
|
51
|
+
if (bytes.length === 0) {
|
|
52
|
+
throw new CborError({ type: "NonCanonicalNumeric" });
|
|
53
|
+
}
|
|
54
|
+
// No leading zeros unless the entire magnitude is zero (single 0x00 byte)
|
|
55
|
+
if (bytes.length > 1 && bytes[0] === 0) {
|
|
56
|
+
throw new CborError({ type: "NonCanonicalNumeric" });
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
// Tag 2: empty byte string is valid (represents zero)
|
|
60
|
+
// Non-empty must not have leading zeros
|
|
61
|
+
if (bytes.length > 0 && bytes[0] === 0) {
|
|
62
|
+
throw new CborError({ type: "NonCanonicalNumeric" });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Strips leading zero bytes from a byte array, returning the minimal
|
|
69
|
+
* representation.
|
|
70
|
+
*
|
|
71
|
+
* Matches Rust's `strip_leading_zeros()`.
|
|
72
|
+
*
|
|
73
|
+
* @param bytes - The byte array to strip
|
|
74
|
+
* @returns A subarray with leading zeros removed
|
|
75
|
+
*/
|
|
76
|
+
export function stripLeadingZeros(bytes: Uint8Array): Uint8Array {
|
|
77
|
+
let start = 0;
|
|
78
|
+
while (start < bytes.length && bytes[start] === 0) {
|
|
79
|
+
start++;
|
|
80
|
+
}
|
|
81
|
+
return bytes.subarray(start);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Convert a non-negative bigint to a big-endian byte array.
|
|
86
|
+
*
|
|
87
|
+
* Zero returns an empty Uint8Array.
|
|
88
|
+
*
|
|
89
|
+
* @param value - A non-negative bigint value
|
|
90
|
+
* @returns Big-endian byte representation
|
|
91
|
+
*/
|
|
92
|
+
export function bigintToBytes(value: bigint): Uint8Array {
|
|
93
|
+
if (value === 0n) return new Uint8Array(0);
|
|
94
|
+
const hex = value.toString(16);
|
|
95
|
+
const padded = hex.length % 2 !== 0 ? `0${hex}` : hex;
|
|
96
|
+
const bytes = new Uint8Array(padded.length / 2);
|
|
97
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
98
|
+
bytes[i] = parseInt(padded.substring(i * 2, i * 2 + 2), 16);
|
|
99
|
+
}
|
|
100
|
+
return bytes;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Convert a big-endian byte array to a bigint.
|
|
105
|
+
*
|
|
106
|
+
* Empty array returns 0n.
|
|
107
|
+
*
|
|
108
|
+
* @param bytes - Big-endian byte representation
|
|
109
|
+
* @returns The bigint value
|
|
110
|
+
*/
|
|
111
|
+
export function bytesToBigint(bytes: Uint8Array): bigint {
|
|
112
|
+
if (bytes.length === 0) return 0n;
|
|
113
|
+
let result = 0n;
|
|
114
|
+
for (const byte of bytes) {
|
|
115
|
+
result = (result << 8n) | BigInt(byte);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Encode a non-negative bigint as a CBOR tag 2 (positive bignum).
|
|
122
|
+
*
|
|
123
|
+
* Matches Rust's `From<BigUint> for CBOR`.
|
|
124
|
+
*
|
|
125
|
+
* The value is always encoded as a bignum regardless of size.
|
|
126
|
+
* Zero is encoded as tag 2 with an empty byte string.
|
|
127
|
+
*
|
|
128
|
+
* @param value - A non-negative bigint (must be >= 0n)
|
|
129
|
+
* @returns CBOR tagged value
|
|
130
|
+
* @throws CborError with type OutOfRange if value is negative
|
|
131
|
+
*/
|
|
132
|
+
export function biguintToCbor(value: bigint): Cbor {
|
|
133
|
+
if (value < 0n) {
|
|
134
|
+
throw new CborError({ type: "OutOfRange" });
|
|
135
|
+
}
|
|
136
|
+
const bytes = bigintToBytes(value);
|
|
137
|
+
const stripped = stripLeadingZeros(bytes);
|
|
138
|
+
return toTaggedValue(TAG_2_POSITIVE_BIGNUM, stripped);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Encode a bigint as a CBOR tag 2 or tag 3 bignum.
|
|
143
|
+
*
|
|
144
|
+
* Matches Rust's `From<BigInt> for CBOR`.
|
|
145
|
+
*
|
|
146
|
+
* - Non-negative values use tag 2 (positive bignum).
|
|
147
|
+
* - Negative values use tag 3 (negative bignum), where the encoded
|
|
148
|
+
* magnitude is `|value| - 1` per RFC 8949.
|
|
149
|
+
*
|
|
150
|
+
* @param value - Any bigint value
|
|
151
|
+
* @returns CBOR tagged value
|
|
152
|
+
*/
|
|
153
|
+
export function bigintToCbor(value: bigint): Cbor {
|
|
154
|
+
if (value >= 0n) {
|
|
155
|
+
return biguintToCbor(value);
|
|
156
|
+
}
|
|
157
|
+
// Negative: use tag 3 with magnitude = |value| - 1
|
|
158
|
+
// For value = -1, magnitude = 1, so n = 0 -> encode as 0x00
|
|
159
|
+
// For value = -2, magnitude = 2, so n = 1 -> encode as 0x01
|
|
160
|
+
const magnitude = -value;
|
|
161
|
+
const n = magnitude - 1n;
|
|
162
|
+
const bytes = bigintToBytes(n);
|
|
163
|
+
const stripped = stripLeadingZeros(bytes);
|
|
164
|
+
// For n = 0 (value = -1), bigintToBytes returns empty, but we need 0x00
|
|
165
|
+
const contentBytes = stripped.length === 0 ? new Uint8Array([0]) : stripped;
|
|
166
|
+
return toTaggedValue(TAG_3_NEGATIVE_BIGNUM, contentBytes);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Decode a BigUint from an untagged CBOR byte string.
|
|
171
|
+
*
|
|
172
|
+
* Matches Rust's `biguint_from_untagged_cbor()`.
|
|
173
|
+
*
|
|
174
|
+
* This function is intended for use in tag summarizers where the tag has
|
|
175
|
+
* already been stripped. It expects a CBOR byte string representing the
|
|
176
|
+
* big-endian magnitude of a positive bignum (tag 2 content).
|
|
177
|
+
*
|
|
178
|
+
* Enforces canonical encoding: no leading zero bytes (except empty for zero).
|
|
179
|
+
*
|
|
180
|
+
* @param cbor - A CBOR value that should be a byte string
|
|
181
|
+
* @returns Non-negative bigint
|
|
182
|
+
* @throws CborError with type WrongType if not a byte string
|
|
183
|
+
* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
|
|
184
|
+
*/
|
|
185
|
+
export function biguintFromUntaggedCbor(cbor: Cbor): bigint {
|
|
186
|
+
if (cbor.type !== MajorType.ByteString) {
|
|
187
|
+
throw new CborError({ type: "WrongType" });
|
|
188
|
+
}
|
|
189
|
+
const bytes = cbor.value;
|
|
190
|
+
validateBignumMagnitude(bytes, false);
|
|
191
|
+
return bytesToBigint(bytes);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Decode a BigInt from an untagged CBOR byte string for a negative bignum.
|
|
196
|
+
*
|
|
197
|
+
* Matches Rust's `bigint_from_negative_untagged_cbor()`.
|
|
198
|
+
*
|
|
199
|
+
* This function is intended for use in tag summarizers where the tag has
|
|
200
|
+
* already been stripped. It expects a CBOR byte string representing `n` where
|
|
201
|
+
* the actual value is `-1 - n` (tag 3 content per RFC 8949).
|
|
202
|
+
*
|
|
203
|
+
* Enforces canonical encoding: no leading zero bytes (except single `0x00`
|
|
204
|
+
* for -1).
|
|
205
|
+
*
|
|
206
|
+
* @param cbor - A CBOR value that should be a byte string
|
|
207
|
+
* @returns Negative bigint
|
|
208
|
+
* @throws CborError with type WrongType if not a byte string
|
|
209
|
+
* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical
|
|
210
|
+
*/
|
|
211
|
+
export function bigintFromNegativeUntaggedCbor(cbor: Cbor): bigint {
|
|
212
|
+
if (cbor.type !== MajorType.ByteString) {
|
|
213
|
+
throw new CborError({ type: "WrongType" });
|
|
214
|
+
}
|
|
215
|
+
const bytes = cbor.value;
|
|
216
|
+
validateBignumMagnitude(bytes, true);
|
|
217
|
+
const n = bytesToBigint(bytes);
|
|
218
|
+
const magnitude = n + 1n;
|
|
219
|
+
return -magnitude;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Convert CBOR to a non-negative bigint.
|
|
224
|
+
*
|
|
225
|
+
* Matches Rust's `TryFrom<CBOR> for BigUint`.
|
|
226
|
+
*
|
|
227
|
+
* Accepts:
|
|
228
|
+
* - Major type 0 (unsigned integer)
|
|
229
|
+
* - Tag 2 (positive bignum) with canonical byte string
|
|
230
|
+
*
|
|
231
|
+
* Rejects:
|
|
232
|
+
* - Major type 1 (negative integer) -> OutOfRange
|
|
233
|
+
* - Tag 3 (negative bignum) -> OutOfRange
|
|
234
|
+
* - Floating-point values -> WrongType
|
|
235
|
+
* - Non-canonical bignum encodings -> NonCanonicalNumeric
|
|
236
|
+
*
|
|
237
|
+
* @param cbor - The CBOR value to convert
|
|
238
|
+
* @returns Non-negative bigint
|
|
239
|
+
* @throws CborError
|
|
240
|
+
*/
|
|
241
|
+
export function cborToBiguint(cbor: Cbor): bigint {
|
|
242
|
+
switch (cbor.type) {
|
|
243
|
+
case MajorType.Unsigned:
|
|
244
|
+
return BigInt(cbor.value);
|
|
245
|
+
case MajorType.Negative:
|
|
246
|
+
throw new CborError({ type: "OutOfRange" });
|
|
247
|
+
case MajorType.Tagged: {
|
|
248
|
+
const tagValue = Number(cbor.tag);
|
|
249
|
+
if (tagValue === TAG_2_POSITIVE_BIGNUM) {
|
|
250
|
+
const inner = cbor.value;
|
|
251
|
+
if (inner.type !== MajorType.ByteString) {
|
|
252
|
+
throw new CborError({ type: "WrongType" });
|
|
253
|
+
}
|
|
254
|
+
const bytes = inner.value;
|
|
255
|
+
validateBignumMagnitude(bytes, false);
|
|
256
|
+
return bytesToBigint(bytes);
|
|
257
|
+
} else if (tagValue === TAG_3_NEGATIVE_BIGNUM) {
|
|
258
|
+
throw new CborError({ type: "OutOfRange" });
|
|
259
|
+
}
|
|
260
|
+
throw new CborError({ type: "WrongType" });
|
|
261
|
+
}
|
|
262
|
+
case MajorType.ByteString:
|
|
263
|
+
case MajorType.Text:
|
|
264
|
+
case MajorType.Array:
|
|
265
|
+
case MajorType.Map:
|
|
266
|
+
case MajorType.Simple:
|
|
267
|
+
throw new CborError({ type: "WrongType" });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Convert CBOR to a bigint (any sign).
|
|
273
|
+
*
|
|
274
|
+
* Matches Rust's `TryFrom<CBOR> for BigInt`.
|
|
275
|
+
*
|
|
276
|
+
* Accepts:
|
|
277
|
+
* - Major type 0 (unsigned integer)
|
|
278
|
+
* - Major type 1 (negative integer)
|
|
279
|
+
* - Tag 2 (positive bignum) with canonical byte string
|
|
280
|
+
* - Tag 3 (negative bignum) with canonical byte string
|
|
281
|
+
*
|
|
282
|
+
* Rejects:
|
|
283
|
+
* - Floating-point values -> WrongType
|
|
284
|
+
* - Non-canonical bignum encodings -> NonCanonicalNumeric
|
|
285
|
+
*
|
|
286
|
+
* @param cbor - The CBOR value to convert
|
|
287
|
+
* @returns A bigint value
|
|
288
|
+
* @throws CborError
|
|
289
|
+
*/
|
|
290
|
+
export function cborToBigint(cbor: Cbor): bigint {
|
|
291
|
+
switch (cbor.type) {
|
|
292
|
+
case MajorType.Unsigned:
|
|
293
|
+
return BigInt(cbor.value);
|
|
294
|
+
case MajorType.Negative: {
|
|
295
|
+
// CBOR negative: value stored is n where actual = -1 - n
|
|
296
|
+
const n = BigInt(cbor.value);
|
|
297
|
+
const magnitude = n + 1n;
|
|
298
|
+
return -magnitude;
|
|
299
|
+
}
|
|
300
|
+
case MajorType.Tagged: {
|
|
301
|
+
const tagValue = Number(cbor.tag);
|
|
302
|
+
if (tagValue === TAG_2_POSITIVE_BIGNUM) {
|
|
303
|
+
const inner = cbor.value;
|
|
304
|
+
if (inner.type !== MajorType.ByteString) {
|
|
305
|
+
throw new CborError({ type: "WrongType" });
|
|
306
|
+
}
|
|
307
|
+
const bytes = inner.value;
|
|
308
|
+
validateBignumMagnitude(bytes, false);
|
|
309
|
+
const mag = bytesToBigint(bytes);
|
|
310
|
+
if (mag === 0n) {
|
|
311
|
+
return 0n;
|
|
312
|
+
}
|
|
313
|
+
return mag;
|
|
314
|
+
} else if (tagValue === TAG_3_NEGATIVE_BIGNUM) {
|
|
315
|
+
const inner = cbor.value;
|
|
316
|
+
if (inner.type !== MajorType.ByteString) {
|
|
317
|
+
throw new CborError({ type: "WrongType" });
|
|
318
|
+
}
|
|
319
|
+
const bytes = inner.value;
|
|
320
|
+
validateBignumMagnitude(bytes, true);
|
|
321
|
+
const n = bytesToBigint(bytes);
|
|
322
|
+
const magnitude = n + 1n;
|
|
323
|
+
return -magnitude;
|
|
324
|
+
}
|
|
325
|
+
throw new CborError({ type: "WrongType" });
|
|
326
|
+
}
|
|
327
|
+
case MajorType.ByteString:
|
|
328
|
+
case MajorType.Text:
|
|
329
|
+
case MajorType.Array:
|
|
330
|
+
case MajorType.Map:
|
|
331
|
+
case MajorType.Simple:
|
|
332
|
+
throw new CborError({ type: "WrongType" });
|
|
333
|
+
}
|
|
334
|
+
}
|
package/src/byte-string.ts
CHANGED
|
@@ -44,7 +44,7 @@ import { CborError } from "./error";
|
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
46
|
export class ByteString {
|
|
47
|
-
|
|
47
|
+
private _data: Uint8Array;
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Creates a new `ByteString` from a Uint8Array or array of bytes.
|
|
@@ -62,9 +62,9 @@ export class ByteString {
|
|
|
62
62
|
*/
|
|
63
63
|
constructor(data: Uint8Array | number[]) {
|
|
64
64
|
if (Array.isArray(data)) {
|
|
65
|
-
this
|
|
65
|
+
this._data = new Uint8Array(data);
|
|
66
66
|
} else {
|
|
67
|
-
this
|
|
67
|
+
this._data = new Uint8Array(data);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -103,7 +103,7 @@ export class ByteString {
|
|
|
103
103
|
* ```
|
|
104
104
|
*/
|
|
105
105
|
data(): Uint8Array {
|
|
106
|
-
return this
|
|
106
|
+
return this._data;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
/**
|
|
@@ -121,7 +121,7 @@ export class ByteString {
|
|
|
121
121
|
* ```
|
|
122
122
|
*/
|
|
123
123
|
len(): number {
|
|
124
|
-
return this
|
|
124
|
+
return this._data.length;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
@@ -139,7 +139,7 @@ export class ByteString {
|
|
|
139
139
|
* ```
|
|
140
140
|
*/
|
|
141
141
|
isEmpty(): boolean {
|
|
142
|
-
return this
|
|
142
|
+
return this._data.length === 0;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/**
|
|
@@ -160,10 +160,10 @@ export class ByteString {
|
|
|
160
160
|
*/
|
|
161
161
|
extend(other: Uint8Array | number[]): void {
|
|
162
162
|
const otherArray = Array.isArray(other) ? new Uint8Array(other) : other;
|
|
163
|
-
const newData = new Uint8Array(this
|
|
164
|
-
newData.set(this
|
|
165
|
-
newData.set(otherArray, this
|
|
166
|
-
this
|
|
163
|
+
const newData = new Uint8Array(this._data.length + otherArray.length);
|
|
164
|
+
newData.set(this._data, 0);
|
|
165
|
+
newData.set(otherArray, this._data.length);
|
|
166
|
+
this._data = newData;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
@@ -184,7 +184,7 @@ export class ByteString {
|
|
|
184
184
|
* ```
|
|
185
185
|
*/
|
|
186
186
|
toUint8Array(): Uint8Array {
|
|
187
|
-
return new Uint8Array(this
|
|
187
|
+
return new Uint8Array(this._data);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
|
@@ -211,7 +211,7 @@ export class ByteString {
|
|
|
211
211
|
* ```
|
|
212
212
|
*/
|
|
213
213
|
iter(): Iterator<number> {
|
|
214
|
-
return this
|
|
214
|
+
return this._data.values();
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
/**
|
|
@@ -233,7 +233,7 @@ export class ByteString {
|
|
|
233
233
|
* ```
|
|
234
234
|
*/
|
|
235
235
|
toCbor(): Cbor {
|
|
236
|
-
return toCbor(this
|
|
236
|
+
return toCbor(this._data);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
/**
|
|
@@ -272,7 +272,7 @@ export class ByteString {
|
|
|
272
272
|
* @returns Byte at index or undefined
|
|
273
273
|
*/
|
|
274
274
|
at(index: number): number | undefined {
|
|
275
|
-
return this
|
|
275
|
+
return this._data[index];
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/**
|
|
@@ -282,9 +282,9 @@ export class ByteString {
|
|
|
282
282
|
* @returns true if equal
|
|
283
283
|
*/
|
|
284
284
|
equals(other: ByteString): boolean {
|
|
285
|
-
if (this
|
|
286
|
-
for (let i = 0; i < this
|
|
287
|
-
if (this
|
|
285
|
+
if (this._data.length !== other._data.length) return false;
|
|
286
|
+
for (let i = 0; i < this._data.length; i++) {
|
|
287
|
+
if (this._data[i] !== other._data[i]) return false;
|
|
288
288
|
}
|
|
289
289
|
return true;
|
|
290
290
|
}
|
package/src/date.ts
CHANGED
|
@@ -67,7 +67,7 @@ import { CborError } from "./error";
|
|
|
67
67
|
* ```
|
|
68
68
|
*/
|
|
69
69
|
export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDecodable<CborDate> {
|
|
70
|
-
|
|
70
|
+
private _datetime: Date;
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Creates a new `CborDate` from the given JavaScript `Date`.
|
|
@@ -87,7 +87,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
87
87
|
*/
|
|
88
88
|
static fromDatetime(dateTime: Date): CborDate {
|
|
89
89
|
const instance = new CborDate();
|
|
90
|
-
instance
|
|
90
|
+
instance._datetime = new Date(dateTime);
|
|
91
91
|
return instance;
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -265,7 +265,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
265
265
|
* ```
|
|
266
266
|
*/
|
|
267
267
|
datetime(): Date {
|
|
268
|
-
return new Date(this
|
|
268
|
+
return new Date(this._datetime);
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/**
|
|
@@ -285,8 +285,8 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
285
285
|
* ```
|
|
286
286
|
*/
|
|
287
287
|
timestamp(): number {
|
|
288
|
-
const wholeSecondsSinceUnixEpoch = Math.trunc(this
|
|
289
|
-
const msecs = this
|
|
288
|
+
const wholeSecondsSinceUnixEpoch = Math.trunc(this._datetime.getTime() / 1000);
|
|
289
|
+
const msecs = this._datetime.getTime() % 1000;
|
|
290
290
|
return wholeSecondsSinceUnixEpoch + msecs / 1000.0;
|
|
291
291
|
}
|
|
292
292
|
|
|
@@ -430,7 +430,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
const date = CborDate.fromTimestamp(timestamp);
|
|
433
|
-
this
|
|
433
|
+
this._datetime = date._datetime;
|
|
434
434
|
return this;
|
|
435
435
|
}
|
|
436
436
|
|
|
@@ -495,7 +495,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
495
495
|
* ```
|
|
496
496
|
*/
|
|
497
497
|
toString(): string {
|
|
498
|
-
const dt = this
|
|
498
|
+
const dt = this._datetime;
|
|
499
499
|
// Check only hours, minutes, and seconds (not milliseconds) to match Rust behavior
|
|
500
500
|
const hasTime = dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0;
|
|
501
501
|
|
|
@@ -521,7 +521,7 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
521
521
|
* @returns true if dates represent the same moment in time
|
|
522
522
|
*/
|
|
523
523
|
equals(other: CborDate): boolean {
|
|
524
|
-
return this
|
|
524
|
+
return this._datetime.getTime() === other._datetime.getTime();
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
/**
|
|
@@ -531,8 +531,8 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
531
531
|
* @returns -1 if this < other, 0 if equal, 1 if this > other
|
|
532
532
|
*/
|
|
533
533
|
compare(other: CborDate): number {
|
|
534
|
-
const thisTime = this
|
|
535
|
-
const otherTime = other
|
|
534
|
+
const thisTime = this._datetime.getTime();
|
|
535
|
+
const otherTime = other._datetime.getTime();
|
|
536
536
|
if (thisTime < otherTime) return -1;
|
|
537
537
|
if (thisTime > otherTime) return 1;
|
|
538
538
|
return 0;
|
|
@@ -548,6 +548,6 @@ export class CborDate implements CborTagged, CborTaggedEncodable, CborTaggedDeco
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
private constructor() {
|
|
551
|
-
this
|
|
551
|
+
this._datetime = new Date();
|
|
552
552
|
}
|
|
553
553
|
}
|
package/src/index.ts
CHANGED
|
@@ -88,6 +88,16 @@ export { type Error, type Result, Ok, Err, errorMsg, errorToString, CborError }
|
|
|
88
88
|
// Note: conveniences.ts is an internal module (not exported in Rust either)
|
|
89
89
|
// The main convenience functions are exported from cbor.ts above
|
|
90
90
|
|
|
91
|
+
// BigNum support (CBOR tags 2/3, RFC 8949 §3.4.3)
|
|
92
|
+
export {
|
|
93
|
+
biguintToCbor,
|
|
94
|
+
bigintToCbor,
|
|
95
|
+
cborToBiguint,
|
|
96
|
+
cborToBigint,
|
|
97
|
+
biguintFromUntaggedCbor,
|
|
98
|
+
bigintFromNegativeUntaggedCbor,
|
|
99
|
+
} from "./bignum";
|
|
100
|
+
|
|
91
101
|
// Float utilities
|
|
92
102
|
export { hasFractionalPart } from "./float";
|
|
93
103
|
|