@bcts/dcbor 1.0.0-alpha.8 → 1.0.0-beta.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/src/global.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * Global type declarations for cross-platform APIs
3
7
  */
4
8
 
package/src/globals.d.ts CHANGED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ */
package/src/index.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * BC-DCBOR TypeScript Library
3
7
  *
4
8
  * A TypeScript implementation of Blockchain Commons' Deterministic CBOR (dCBOR).
@@ -27,31 +31,52 @@ export {
27
31
  export { type Simple, simpleName, isNaN } from "./simple";
28
32
 
29
33
  // Encoding/Decoding
30
- export { cbor, cborData } from "./cbor";
34
+ export { cbor, cborData, cborEquals } from "./cbor";
31
35
  export { decodeCbor } from "./decode";
32
36
 
33
- // Factory functions (static creators)
34
- export { toByteString, toByteStringFromHex, toTaggedValue } from "./cbor";
37
+ // Factory functions (static creators).
38
+ // `cborFalse`, `cborTrue`, `cborNull`, `cborNaN` mirror Rust
39
+ // `CBOR::r#false()`, `CBOR::r#true()`, `CBOR::null()`, `CBOR::nan()`.
40
+ export {
41
+ toByteString,
42
+ toByteStringFromHex,
43
+ toTaggedValue,
44
+ cborFalse,
45
+ cborTrue,
46
+ cborNull,
47
+ cborNaN,
48
+ } from "./cbor";
35
49
 
36
50
  // Map and Set
37
51
  export { CborMap, type MapEntry } from "./map";
38
52
  export { CborSet } from "./set";
39
53
 
40
54
  // Tags and Tagged values
41
- export { type Tag, createTag } from "./tag";
55
+ export {
56
+ type Tag,
57
+ type TagValue,
58
+ createTag,
59
+ tagWithValue,
60
+ tagWithStaticName,
61
+ tagsEqual,
62
+ } from "./tag";
42
63
  export {
43
64
  type CborTagged,
44
65
  type CborTaggedEncodable,
45
66
  type CborTaggedDecodable,
46
67
  type CborTaggedCodable,
47
68
  createTaggedCbor,
69
+ taggedCborData,
48
70
  validateTag,
49
71
  extractTaggedContent,
72
+ fromTaggedCborData,
73
+ fromUntaggedCborData,
50
74
  } from "./cbor-tagged";
51
75
  export {
52
76
  TagsStore,
53
77
  type TagsStoreTrait,
54
78
  type CborSummarizer,
79
+ type SummarizerResult,
55
80
  getGlobalTagsStore,
56
81
  } from "./tags-store";
57
82
  export * from "./tags";
@@ -61,10 +86,17 @@ export { registerTags, registerTagsIn, tagsForValues } from "./tags";
61
86
  export { CborDate } from "./date";
62
87
 
63
88
  // Diagnostic formatting
64
- export { diagnosticOpt, summary, type DiagFormatOpts } from "./diag";
89
+ export {
90
+ diagnostic,
91
+ diagnosticAnnotated,
92
+ diagnosticFlat,
93
+ diagnosticOpt,
94
+ summary,
95
+ type DiagFormatOpts,
96
+ } from "./diag";
65
97
 
66
98
  // Hex formatting
67
- export { hexOpt, hexToBytes, bytesToHex, type HexFormatOpts } from "./dump";
99
+ export { hex, hexOpt, hexAnnotated, hexToBytes, bytesToHex, type HexFormatOpts } from "./dump";
68
100
 
69
101
  // Walk/Traversal functionality
70
102
  export {
@@ -72,15 +104,10 @@ export {
72
104
  type EdgeTypeVariant,
73
105
  type WalkElement,
74
106
  type Visitor,
107
+ walk,
75
108
  asSingle,
76
109
  asKeyValue,
77
110
  edgeLabel,
78
- // Helper functions
79
- countElements,
80
- collectAtLevel,
81
- findFirst,
82
- collectAllText,
83
- maxDepth,
84
111
  } from "./walk";
85
112
 
86
113
  // Codable interfaces
@@ -92,6 +119,19 @@ export { type Error, type Result, Ok, Err, errorMsg, errorToString, CborError }
92
119
  // Note: conveniences.ts is an internal module (not exported in Rust either)
93
120
  // The main convenience functions are exported from cbor.ts above
94
121
 
122
+ // BigNum support (CBOR tags 2/3, RFC 8949 §3.4.3)
123
+ export {
124
+ biguintToCbor,
125
+ bigintToCbor,
126
+ cborToBiguint,
127
+ cborToBigint,
128
+ biguintFromUntaggedCbor,
129
+ bigintFromNegativeUntaggedCbor,
130
+ } from "./bignum";
131
+
132
+ // CBOR-encoding-based array sorting (Rust `array.rs::CBORSortable`).
133
+ export { sortArrayByCborEncoding, arraySortable, setSortable, type CBORSortable } from "./sortable";
134
+
95
135
  // Float utilities
96
136
  export { hasFractionalPart } from "./float";
97
137
 
@@ -169,7 +209,19 @@ export {
169
209
  // Extract native JavaScript value from CBOR
170
210
  export { extractCbor } from "./conveniences";
171
211
 
172
- // Envelope compatibility functions
212
+ // =============================================================================
213
+ // Envelope compatibility helpers (TS-only, no Rust counterpart)
214
+ //
215
+ // These wrappers expose `dcbor` types to `@bcts/envelope`'s decode pipeline
216
+ // in the shape it expects — mostly thin renames around the convenience
217
+ // functions above. They have no equivalents in `bc-dcbor-rust` (Rust
218
+ // envelope decoding goes through `TryFrom<CBOR>` directly).
219
+ //
220
+ // Down-stream callers wanting strict Rust parity should prefer the
221
+ // canonical names (`asTagged` / `asBytes` / `asArray` / `asMap`,
222
+ // `isNumber` is just a type guard). Kept here for backwards compatibility
223
+ // with older Envelope code; do not extend.
224
+ // =============================================================================
173
225
  export {
174
226
  asTaggedValue,
175
227
  asByteString,
package/src/map.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * Map Support in dCBOR
3
7
  *
4
8
  * A deterministic CBOR map implementation that ensures maps with the same
@@ -44,14 +48,14 @@ export interface MapEntry {
44
48
  * encoded CBOR representation, ensuring deterministic encoding.
45
49
  */
46
50
  export class CborMap {
47
- #dict: SortedMap<MapKey, MapEntry>;
51
+ private _dict: SortedMap<MapKey, MapEntry>;
48
52
 
49
53
  /**
50
54
  * Creates a new, empty CBOR Map.
51
55
  * Optionally initializes from a JavaScript Map.
52
56
  */
53
57
  constructor(map?: Map<unknown, unknown>) {
54
- this.#dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
58
+ this._dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
55
59
 
56
60
  if (map !== undefined) {
57
61
  for (const [key, value] of map.entries()) {
@@ -76,7 +80,7 @@ export class CborMap {
76
80
  const keyCbor = cbor(key);
77
81
  const valueCbor = cbor(value);
78
82
  const keyData = cborData(keyCbor);
79
- this.#dict.set(keyData, { key: keyCbor, value: valueCbor });
83
+ this._dict.set(keyData, { key: keyCbor, value: valueCbor });
80
84
  }
81
85
 
82
86
  /**
@@ -86,7 +90,7 @@ export class CborMap {
86
90
  this.set(key, value);
87
91
  }
88
92
 
89
- #makeKey<K extends CborInput>(key: K): MapKey {
93
+ private _makeKey<K extends CborInput>(key: K): MapKey {
90
94
  const keyCbor = cbor(key);
91
95
  return cborData(keyCbor);
92
96
  }
@@ -97,8 +101,8 @@ export class CborMap {
97
101
  * Matches Rust's Map::get().
98
102
  */
99
103
  get<K extends CborInput, V>(key: K): V | undefined {
100
- const keyData = this.#makeKey(key);
101
- const value = this.#dict.get(keyData);
104
+ const keyData = this._makeKey(key);
105
+ const value = this._dict.get(keyData);
102
106
  if (value === undefined) {
103
107
  return undefined;
104
108
  }
@@ -124,24 +128,24 @@ export class CborMap {
124
128
  * Matches Rust's Map::contains_key().
125
129
  */
126
130
  containsKey<K extends CborInput>(key: K): boolean {
127
- const keyData = this.#makeKey(key);
128
- return this.#dict.has(keyData);
131
+ const keyData = this._makeKey(key);
132
+ return this._dict.has(keyData);
129
133
  }
130
134
 
131
135
  delete<K extends CborInput>(key: K): boolean {
132
- const keyData = this.#makeKey(key);
133
- const existed = this.#dict.has(keyData);
134
- this.#dict.delete(keyData);
136
+ const keyData = this._makeKey(key);
137
+ const existed = this._dict.has(keyData);
138
+ this._dict.delete(keyData);
135
139
  return existed;
136
140
  }
137
141
 
138
142
  has<K extends CborInput>(key: K): boolean {
139
- const keyData = this.#makeKey(key);
140
- return this.#dict.has(keyData);
143
+ const keyData = this._makeKey(key);
144
+ return this._dict.has(keyData);
141
145
  }
142
146
 
143
147
  clear(): void {
144
- this.#dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
148
+ this._dict = new SortedMap(null, areBytesEqual, lexicographicallyCompareBytes);
145
149
  }
146
150
 
147
151
  /**
@@ -149,7 +153,7 @@ export class CborMap {
149
153
  * Matches Rust's Map::len().
150
154
  */
151
155
  get length(): number {
152
- return this.#dict.length;
156
+ return this._dict.length;
153
157
  }
154
158
 
155
159
  /**
@@ -157,7 +161,7 @@ export class CborMap {
157
161
  * Also matches Rust's Map::len().
158
162
  */
159
163
  get size(): number {
160
- return this.#dict.length;
164
+ return this._dict.length;
161
165
  }
162
166
 
163
167
  /**
@@ -165,7 +169,7 @@ export class CborMap {
165
169
  * Matches Rust's Map::len().
166
170
  */
167
171
  len(): number {
168
- return this.#dict.length;
172
+ return this._dict.length;
169
173
  }
170
174
 
171
175
  /**
@@ -173,7 +177,7 @@ export class CborMap {
173
177
  * Matches Rust's Map::is_empty().
174
178
  */
175
179
  isEmpty(): boolean {
176
- return this.#dict.length === 0;
180
+ return this._dict.length === 0;
177
181
  }
178
182
 
179
183
  /**
@@ -181,7 +185,7 @@ export class CborMap {
181
185
  * Keys are sorted in lexicographic order of their encoded CBOR bytes.
182
186
  */
183
187
  get entriesArray(): MapEntry[] {
184
- return this.#dict.map((value: MapEntry, _key: MapKey) => ({
188
+ return this._dict.map((value: MapEntry, _key: MapKey) => ({
185
189
  key: value.key,
186
190
  value: value.value,
187
191
  }));
@@ -213,21 +217,21 @@ export class CborMap {
213
217
  * Matches Rust's Map::insert_next().
214
218
  */
215
219
  setNext<K extends CborInput, V extends CborInput>(key: K, value: V): void {
216
- const lastEntry = this.#dict.max();
220
+ const lastEntry = this._dict.max();
217
221
  if (lastEntry === undefined) {
218
222
  this.set(key, value);
219
223
  return;
220
224
  }
221
225
  const keyCbor = cbor(key);
222
226
  const newKey = cborData(keyCbor);
223
- if (this.#dict.has(newKey)) {
227
+ if (this._dict.has(newKey)) {
224
228
  throw new CborError({ type: "DuplicateMapKey" });
225
229
  }
226
- const lastEntryKey = this.#makeKey(lastEntry.key);
230
+ const lastEntryKey = this._makeKey(lastEntry.key);
227
231
  if (lexicographicallyCompareBytes(newKey, lastEntryKey) <= 0) {
228
232
  throw new CborError({ type: "MisorderedMapKey" });
229
233
  }
230
- this.#dict.set(newKey, { key: keyCbor, value: cbor(value) });
234
+ this._dict.set(newKey, { key: keyCbor, value: cbor(value) });
231
235
  }
232
236
 
233
237
  get debug(): string {
package/src/prelude.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * Prelude module - Re-exports commonly used types and classes.
3
7
  *
4
8
  * This module provides a curated set of imports matching Rust's prelude.rs.
@@ -51,8 +55,8 @@ export { ByteString } from "./byte-string";
51
55
  export { CborDate } from "./date";
52
56
 
53
57
  // Tag handling
54
- export type { Tag } from "./tag";
55
- export { createTag } from "./tag";
58
+ export type { Tag, TagValue } from "./tag";
59
+ export { createTag, tagWithValue, tagWithStaticName, tagsEqual } from "./tag";
56
60
  export { TagsStore, getGlobalTagsStore, withTags, withTagsMut } from "./tags-store";
57
61
  export type { TagsStoreTrait } from "./tags-store";
58
62
  export { tagsForValues } from "./tags";
@@ -65,6 +69,12 @@ export type { HexFormatOpts } from "./dump";
65
69
  export { EdgeType } from "./walk";
66
70
  export type { WalkElement, EdgeTypeVariant, Visitor } from "./walk";
67
71
 
72
+ // BigNum support
73
+ export { biguintToCbor, bigintToCbor, cborToBiguint, cborToBigint } from "./bignum";
74
+
75
+ // CBOR-encoding-based array sorting (Rust `prelude.rs::CBORSortable`).
76
+ export { sortArrayByCborEncoding, arraySortable, setSortable, type CBORSortable } from "./sortable";
77
+
68
78
  // Error handling
69
79
  export type { Error, Result } from "./error";
70
80
  export { Ok, Err, errorMsg, errorToString, CborError } from "./error";
package/src/set.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * Set data structure for CBOR with tag(258) encoding.
3
7
  *
4
8
  * A Set is encoded as an array with no duplicate elements,
@@ -47,10 +51,10 @@ import { CborError } from "./error";
47
51
  * ```
48
52
  */
49
53
  export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet> {
50
- readonly #map: CborMap;
54
+ private readonly _map: CborMap;
51
55
 
52
56
  constructor() {
53
- this.#map = new CborMap();
57
+ this._map = new CborMap();
54
58
  }
55
59
 
56
60
  // =========================================================================
@@ -127,7 +131,27 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
127
131
  insert(value: CborInput): void {
128
132
  const cborValue = encodeCborValue(value);
129
133
  // In a set, key and value are the same
130
- this.#map.set(cborValue, cborValue);
134
+ this._map.set(cborValue, cborValue);
135
+ }
136
+
137
+ /**
138
+ * Insert an element into the set, requiring it to be strictly greater
139
+ * (in canonical CBOR-encoded byte order) than every previously-inserted
140
+ * element. Used by the decoder to reject misordered or duplicate
141
+ * elements in tag-258 set encodings.
142
+ *
143
+ * Mirrors Rust `Set::insert_next` (`pub(crate)`); exposed here because
144
+ * TypeScript doesn't have a crate-private visibility level.
145
+ *
146
+ * @throws CborError of type `MisorderedMap` if `value` would not preserve
147
+ * strict ascending CBOR-byte order, or `DuplicateMapKey` for an exact
148
+ * repeat.
149
+ */
150
+ insertNext(value: CborInput): void {
151
+ const cborValue = encodeCborValue(value);
152
+ // Set is `Map<key=value, value>` in Rust. `Map::insert_next` enforces
153
+ // strict ascending order on the encoded key bytes.
154
+ this._map.setNext(cborValue, cborValue);
131
155
  }
132
156
 
133
157
  /**
@@ -145,7 +169,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
145
169
  */
146
170
  contains(value: CborInput): boolean {
147
171
  const cborValue = encodeCborValue(value);
148
- return this.#map.has(cborValue);
172
+ return this._map.has(cborValue);
149
173
  }
150
174
 
151
175
  /**
@@ -163,14 +187,14 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
163
187
  */
164
188
  delete(value: CborInput): boolean {
165
189
  const cborValue = encodeCborValue(value);
166
- return this.#map.delete(cborValue);
190
+ return this._map.delete(cborValue);
167
191
  }
168
192
 
169
193
  /**
170
194
  * Remove all elements from the set.
171
195
  */
172
196
  clear(): void {
173
- this.#map.clear();
197
+ this._map.clear();
174
198
  }
175
199
 
176
200
  /**
@@ -179,7 +203,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
179
203
  * @returns Number of elements
180
204
  */
181
205
  get size(): number {
182
- return this.#map.size;
206
+ return this._map.size;
183
207
  }
184
208
 
185
209
  /**
@@ -188,7 +212,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
188
212
  * @returns true if set has no elements
189
213
  */
190
214
  isEmpty(): boolean {
191
- return this.#map.size === 0;
215
+ return this._map.size === 0;
192
216
  }
193
217
 
194
218
  // =========================================================================
@@ -313,7 +337,7 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
313
337
  * ```
314
338
  */
315
339
  *[Symbol.iterator](): Iterator<Cbor> {
316
- for (const [_, value] of this.#map) {
340
+ for (const [_, value] of this._map) {
317
341
  yield value;
318
342
  }
319
343
  }
@@ -376,8 +400,11 @@ export class CborSet implements CborTaggedEncodable, CborTaggedDecodable<CborSet
376
400
  }
377
401
 
378
402
  this.clear();
403
+ // Mirrors Rust `Set::try_from_vec` which calls `insert_next` per item:
404
+ // a tag-258 wire encoding must already be in strict ascending CBOR-byte
405
+ // order with no duplicates.
379
406
  for (const value of c.value) {
380
- this.insert(extractCbor(value) as CborInput);
407
+ this.insertNext(extractCbor(value) as CborInput);
381
408
  }
382
409
 
383
410
  return this;
package/src/simple.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * CBOR Simple Values (Major Type 7).
3
7
  *
4
8
  * @module simple
@@ -120,10 +124,19 @@ export const simpleEquals = (a: Simple, b: Simple): boolean => {
120
124
  /**
121
125
  * Hash a Simple value.
122
126
  *
123
- * Matches Rust's Hash trait implementation.
127
+ * **Cross-language note.** Rust derives `Hash` on `Simple` via
128
+ * `f64::to_bits().hash(state)` through `DefaultHasher` (SipHash). JS
129
+ * doesn't expose SipHash, so this implementation uses FNV-1a — a fast
130
+ * non-cryptographic hash. The hash codes therefore **differ between
131
+ * Rust and TS at runtime**; this is intentional and harmless because
132
+ * `Hash` is only used to drive per-runtime hash tables (e.g. dedup in
133
+ * `HashSet<Simple>`). It is **not** part of the deterministic CBOR wire
134
+ * format, which uses bytewise lex on the encoded CBOR (see
135
+ * `lexicographicallyCompareBytes`). Do not rely on these hash values
136
+ * across implementations.
124
137
  */
125
138
  export const simpleHash = (simple: Simple): number => {
126
- // Simple FNV-1a hash
139
+ // FNV-1a hash. (See doc-comment above for why this differs from Rust.)
127
140
  let hash = 2166136261;
128
141
 
129
142
  switch (simple.type) {
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
6
+ * CBOR-encoding-based array sorting helpers.
7
+ *
8
+ * Ported from `bc-dcbor-rust/src/array.rs` (`sort_array_by_cbor_encoding` +
9
+ * `CBORSortable<T>` trait). dCBOR / CDE deterministic ordering is bytewise
10
+ * lexicographic over the CBOR encoding of each element — this is the same
11
+ * comparator that `Map`/`Set` use internally for key ordering.
12
+ *
13
+ * @module sortable
14
+ */
15
+
16
+ import { type CborInput, cbor } from "./cbor";
17
+ import { lexicographicallyCompareBytes } from "./stdlib";
18
+
19
+ /**
20
+ * Return a new array sorted by the bytewise lexicographic order of each
21
+ * element's CBOR encoding.
22
+ *
23
+ * Mirrors Rust `pub fn sort_array_by_cbor_encoding<T>(array)`.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const sorted = sortArrayByCborEncoding([3, 1, 2]); // [1, 2, 3]
28
+ * ```
29
+ */
30
+ export function sortArrayByCborEncoding<T extends CborInput>(array: readonly T[]): T[] {
31
+ const annotated: { encoding: Uint8Array; item: T }[] = array.map((item) => ({
32
+ encoding: cbor(item).toData(),
33
+ item,
34
+ }));
35
+ annotated.sort((a, b) => lexicographicallyCompareBytes(a.encoding, b.encoding));
36
+ return annotated.map((entry) => entry.item);
37
+ }
38
+
39
+ /**
40
+ * Sortable-by-CBOR-encoding trait shape.
41
+ *
42
+ * Mirrors Rust `pub trait CBORSortable<T> { fn sort_by_cbor_encoding(&self)
43
+ * -> Vec<T>; }` with blanket implementations for `Vec<T>`, `&[T]`,
44
+ * `HashSet<T>`. In TypeScript we expose a narrow interface plus
45
+ * `arraySortable` / `setSortable` helpers that wrap any iterable into a
46
+ * `CBORSortable` view.
47
+ */
48
+ export interface CBORSortable<T extends CborInput> {
49
+ sortByCborEncoding(): T[];
50
+ }
51
+
52
+ /**
53
+ * Wrap a readonly array as a {@link CBORSortable}. Equivalent to Rust's
54
+ * blanket `impl CBORSortable<T> for Vec<T>` / `for &[T]`.
55
+ */
56
+ export function arraySortable<T extends CborInput>(array: readonly T[]): CBORSortable<T> {
57
+ return {
58
+ sortByCborEncoding: () => sortArrayByCborEncoding(array),
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Wrap a `Set<T>` as a {@link CBORSortable}. Equivalent to Rust's
64
+ * `impl CBORSortable<T> for HashSet<T>`.
65
+ */
66
+ export function setSortable<T extends CborInput>(set: ReadonlySet<T>): CBORSortable<T> {
67
+ return {
68
+ sortByCborEncoding: () => sortArrayByCborEncoding(Array.from(set)),
69
+ };
70
+ }
package/src/stdlib.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * Standard library re-exports and compatibility layer.
3
7
  *
4
8
  * In Rust, this handles std/no_std feature flags.
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * String utilities for dCBOR, including Unicode normalization.
3
7
  *
4
8
  * @module string-util
package/src/tag.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  /**
2
+ * Copyright © 2023-2026 Blockchain Commons, LLC
3
+ * Copyright © 2025-2026 Parity Technologies
4
+ *
5
+ *
2
6
  * CBOR Tag support for semantic tagging of values.
3
7
  *
4
8
  * Tags provide semantic information about CBOR data items.
@@ -9,14 +13,29 @@
9
13
 
10
14
  import type { CborNumber } from "./cbor";
11
15
 
16
+ /**
17
+ * Numeric tag value type alias.
18
+ *
19
+ * Mirrors Rust `pub type TagValue = u64`. Where Rust narrows to u64, TS
20
+ * accepts the broader `CborNumber` (`number | bigint`) since JavaScript
21
+ * has no native u64 — the runtime guards in `encodeVarInt` enforce the
22
+ * 0..=2^64-1 range.
23
+ */
24
+ export type TagValue = CborNumber;
25
+
12
26
  /**
13
27
  * A CBOR tag with an optional name.
14
28
  *
15
29
  * Tags consist of a numeric value and an optional human-readable name.
30
+ *
31
+ * Note on equality: Rust derives `PartialEq` on `Tag` keyed on `value`
32
+ * only — two tags with the same value but different names compare equal.
33
+ * Use {@link tagsEqual} to mirror that behaviour from TypeScript; raw
34
+ * `===` on `Tag` objects compares by reference.
16
35
  */
17
36
  export interface Tag {
18
37
  /** The numeric tag value */
19
- readonly value: CborNumber;
38
+ readonly value: TagValue;
20
39
  /** Optional human-readable name for the tag */
21
40
  readonly name?: string;
22
41
  }
@@ -34,13 +53,43 @@ export interface Tag {
34
53
  * const customTag = createTag(12345, 'myCustomTag');
35
54
  * ```
36
55
  */
37
- export const createTag = (value: CborNumber, name?: string): Tag => {
56
+ export const createTag = (value: TagValue, name?: string): Tag => {
38
57
  if (name !== undefined) {
39
58
  return { value, name };
40
59
  }
41
60
  return { value };
42
61
  };
43
62
 
63
+ /**
64
+ * Create a Tag from just its numeric value, no name attached.
65
+ *
66
+ * Mirrors Rust's `Tag::with_value(v: TagValue)`.
67
+ */
68
+ export const tagWithValue = (value: TagValue): Tag => ({ value });
69
+
70
+ /**
71
+ * Create a Tag with a static (string) name.
72
+ *
73
+ * In Rust this distinguishes `Tag::Static(&'static str)` from
74
+ * `Tag::Dynamic(String)`. TypeScript has no compile-time equivalent — both
75
+ * variants collapse to the same `{ value, name }` object — but the
76
+ * function name is preserved for API parity.
77
+ *
78
+ * Mirrors Rust's `Tag::with_static_name(v, name)`.
79
+ */
80
+ export const tagWithStaticName = (value: TagValue, name: string): Tag => ({ value, name });
81
+
82
+ /**
83
+ * Compare two tags for equality. Mirrors Rust's `PartialEq for Tag`, which
84
+ * compares by `value` only and ignores the optional `name`.
85
+ */
86
+ export const tagsEqual = (a: Tag, b: Tag): boolean => {
87
+ if (typeof a.value === "bigint" || typeof b.value === "bigint") {
88
+ return BigInt(a.value) === BigInt(b.value);
89
+ }
90
+ return a.value === b.value;
91
+ };
92
+
44
93
  /**
45
94
  * Get the string representation of a tag.
46
95
  * Internal function used for error messages.