@bcts/dcbor 1.0.0-alpha.10

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 (45) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +9151 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +3107 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +3107 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +9155 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +9027 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +80 -0
  14. package/src/.claude-flow/metrics/agent-metrics.json +1 -0
  15. package/src/.claude-flow/metrics/performance.json +87 -0
  16. package/src/.claude-flow/metrics/task-metrics.json +10 -0
  17. package/src/byte-string.ts +300 -0
  18. package/src/cbor-codable.ts +170 -0
  19. package/src/cbor-tagged-codable.ts +72 -0
  20. package/src/cbor-tagged-decodable.ts +184 -0
  21. package/src/cbor-tagged-encodable.ts +138 -0
  22. package/src/cbor-tagged.ts +104 -0
  23. package/src/cbor.ts +869 -0
  24. package/src/conveniences.ts +840 -0
  25. package/src/date.ts +553 -0
  26. package/src/decode.ts +276 -0
  27. package/src/diag.ts +462 -0
  28. package/src/dump.ts +277 -0
  29. package/src/error.ts +259 -0
  30. package/src/exact.ts +714 -0
  31. package/src/float.ts +279 -0
  32. package/src/global.d.ts +34 -0
  33. package/src/globals.d.ts +0 -0
  34. package/src/index.ts +180 -0
  35. package/src/map.ts +308 -0
  36. package/src/prelude.ts +70 -0
  37. package/src/set.ts +515 -0
  38. package/src/simple.ts +153 -0
  39. package/src/stdlib.ts +55 -0
  40. package/src/string-util.ts +55 -0
  41. package/src/tag.ts +53 -0
  42. package/src/tags-store.ts +294 -0
  43. package/src/tags.ts +231 -0
  44. package/src/varint.ts +124 -0
  45. package/src/walk.ts +516 -0
package/src/float.ts ADDED
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Float encoding and conversion utilities for dCBOR.
3
+ *
4
+ * # Floating Point Number Support in dCBOR
5
+ *
6
+ * dCBOR provides canonical encoding for floating point values.
7
+ *
8
+ * Per the dCBOR specification, the canonical encoding rules ensure
9
+ * deterministic representation:
10
+ *
11
+ * - Numeric reduction: Floating point values with zero fractional part in
12
+ * range [-2^63, 2^64-1] are automatically encoded as integers (e.g., 42.0
13
+ * becomes 42)
14
+ * - Values are encoded in the smallest possible representation that preserves
15
+ * their value
16
+ * - All NaN values are canonicalized to a single representation: 0xf97e00
17
+ * - Positive/negative infinity are canonicalized to half-precision
18
+ * representations
19
+ *
20
+ * @module float
21
+ */
22
+
23
+ import * as byteData from "byte-data";
24
+ import { encodeVarInt } from "./varint";
25
+ import { MajorType } from "./cbor";
26
+ import { ExactU64, ExactU32, ExactU16, ExactI128 } from "./exact";
27
+ import { CborError } from "./error";
28
+
29
+ /**
30
+ * Canonical NaN representation in CBOR: 0xf97e00
31
+ */
32
+ export const CBOR_NAN = new Uint8Array([0xf9, 0x7e, 0x00]);
33
+
34
+ /**
35
+ * Check if a number has a fractional part.
36
+ */
37
+ export const hasFractionalPart = (n: number): boolean => n !== Math.floor(n);
38
+
39
+ /**
40
+ * Convert 64-bit binary to number.
41
+ * @internal
42
+ */
43
+ export const binary64ToNumber = (data: Uint8Array): number => {
44
+ return byteData.unpack(data, { bits: 64, fp: true, be: true });
45
+ };
46
+
47
+ /**
48
+ * Convert number to 32-bit float binary (big-endian).
49
+ */
50
+ export const numberToBinary32 = (n: number): Uint8Array => {
51
+ const data = new Uint8Array(4);
52
+ byteData.packTo(n, { bits: 32, fp: true, be: true }, data);
53
+ return data;
54
+ };
55
+
56
+ /**
57
+ * Convert 32-bit binary to number.
58
+ */
59
+ export const binary32ToNumber = (data: Uint8Array): number => {
60
+ return byteData.unpack(data, { bits: 32, fp: true, be: true });
61
+ };
62
+
63
+ /**
64
+ * Convert number to 16-bit float binary (big-endian).
65
+ */
66
+ export const numberToBinary16 = (n: number): Uint8Array => {
67
+ const data = new Uint8Array(2);
68
+ byteData.packTo(n, { bits: 16, fp: true, be: true }, data);
69
+ return data;
70
+ };
71
+
72
+ /**
73
+ * Convert 16-bit binary to number.
74
+ */
75
+ export const binary16ToNumber = (data: Uint8Array): number => {
76
+ return byteData.unpack(data, { bits: 16, fp: true, be: true });
77
+ };
78
+
79
+ /**
80
+ * Encode f64 value to CBOR data bytes.
81
+ * Implements numeric reduction and canonical encoding rules.
82
+ * Matches Rust's f64_cbor_data function.
83
+ * @internal
84
+ */
85
+ export const f64CborData = (value: number): Uint8Array => {
86
+ const n = value;
87
+
88
+ // Try to reduce to f32 first
89
+ const f32Bytes = numberToBinary32(n);
90
+ const f = binary32ToNumber(f32Bytes);
91
+ if (f === n) {
92
+ return f32CborData(f);
93
+ }
94
+
95
+ // Try numeric reduction to negative integer
96
+ if (n < 0.0) {
97
+ const i128 = ExactI128.exactFromF64(n);
98
+ if (i128 !== undefined) {
99
+ const i = ExactU64.exactFromI128(-1n - i128);
100
+ if (i !== undefined) {
101
+ // Encode as a negative integer
102
+ const num = typeof i === "bigint" ? Number(i) : i;
103
+ return encodeVarInt(num, MajorType.Negative);
104
+ }
105
+ }
106
+ }
107
+
108
+ // Try numeric reduction to unsigned integer
109
+ const u = ExactU64.exactFromF64(n);
110
+ if (u !== undefined) {
111
+ const num = typeof u === "bigint" ? Number(u) : u;
112
+ return encodeVarInt(num, MajorType.Unsigned);
113
+ }
114
+
115
+ // Canonical NaN
116
+ if (Number.isNaN(value)) {
117
+ return CBOR_NAN;
118
+ }
119
+
120
+ // Encode as f64 - create binary manually (always 8 bytes with 0xfb prefix)
121
+ const buffer = new ArrayBuffer(8);
122
+ const view = new DataView(buffer);
123
+ view.setFloat64(0, n, false); // big-endian
124
+ const bytes = new Uint8Array(buffer);
125
+ const majorByte = 0xfb; // 0x1b | (MajorType.Simple << 5) = 0x1b | 0xe0 = 0xfb
126
+ return new Uint8Array([majorByte, ...bytes]);
127
+ };
128
+
129
+ /**
130
+ * Validate canonical encoding for f64.
131
+ * Matches Rust's validate_canonical_f64 function.
132
+ *
133
+ * TODO: Check if this is legacy code
134
+ */
135
+ export const validateCanonicalF64 = (n: number): void => {
136
+ const f32Bytes = numberToBinary32(n);
137
+ const f32 = binary32ToNumber(f32Bytes);
138
+
139
+ if (n === f32 || n === Math.trunc(n) || Number.isNaN(n)) {
140
+ throw new CborError({ type: "NonCanonicalNumeric" });
141
+ }
142
+ };
143
+
144
+ /**
145
+ * Encode f32 value to CBOR data bytes.
146
+ * Implements numeric reduction and canonical encoding rules.
147
+ * Matches Rust's f32_cbor_data function.
148
+ * @internal
149
+ */
150
+ export const f32CborData = (value: number): Uint8Array => {
151
+ const n = value;
152
+
153
+ // Try to reduce to f16
154
+ const f16Bytes = numberToBinary16(n);
155
+ const f = binary16ToNumber(f16Bytes);
156
+ if (f === n) {
157
+ return f16CborData(f);
158
+ }
159
+
160
+ // Try numeric reduction to negative integer
161
+ if (n < 0.0) {
162
+ const u = ExactU64.exactFromF32(-1.0 - n);
163
+ if (u !== undefined) {
164
+ const num = typeof u === "bigint" ? Number(u) : u;
165
+ return encodeVarInt(num, MajorType.Negative);
166
+ }
167
+ }
168
+
169
+ // Try numeric reduction to unsigned integer
170
+ const u = ExactU32.exactFromF32(n);
171
+ if (u !== undefined) {
172
+ return encodeVarInt(u, MajorType.Unsigned);
173
+ }
174
+
175
+ // Canonical NaN
176
+ if (Number.isNaN(value)) {
177
+ return CBOR_NAN;
178
+ }
179
+
180
+ // Encode as f32 - always use 0xfa prefix with 4 bytes
181
+ const bytes = numberToBinary32(n);
182
+ return new Uint8Array([0xfa, ...bytes]);
183
+ };
184
+
185
+ /**
186
+ * Validate canonical encoding for f32.
187
+ * Matches Rust's validate_canonical_f32 function.
188
+ *
189
+ * TODO: Check if this is legacy code
190
+ */
191
+ export const validateCanonicalF32 = (n: number): void => {
192
+ const f16Bytes = numberToBinary16(n);
193
+ const f16 = binary16ToNumber(f16Bytes);
194
+
195
+ if (n === f16 || n === Math.trunc(n) || Number.isNaN(n)) {
196
+ throw new CborError({ type: "NonCanonicalNumeric" });
197
+ }
198
+ };
199
+
200
+ /**
201
+ * Encode f16 value to CBOR data bytes.
202
+ * Implements numeric reduction and canonical encoding rules.
203
+ * Matches Rust's f16_cbor_data function.
204
+ * @internal
205
+ */
206
+ export const f16CborData = (value: number): Uint8Array => {
207
+ const n = value;
208
+
209
+ // Try numeric reduction to negative integer
210
+ if (n < 0.0) {
211
+ const u = ExactU64.exactFromF64(-1.0 - n);
212
+ if (u !== undefined) {
213
+ const num = typeof u === "bigint" ? Number(u) : u;
214
+ return encodeVarInt(num, MajorType.Negative);
215
+ }
216
+ }
217
+
218
+ // Try numeric reduction to unsigned integer
219
+ const u = ExactU16.exactFromF64(n);
220
+ if (u !== undefined) {
221
+ return encodeVarInt(u, MajorType.Unsigned);
222
+ }
223
+
224
+ // Canonical NaN
225
+ if (Number.isNaN(value)) {
226
+ return CBOR_NAN;
227
+ }
228
+
229
+ // Encode as f16 - always use 0xf9 prefix with 2 bytes
230
+ const bytes = numberToBinary16(value);
231
+ return new Uint8Array([0xf9, ...bytes]);
232
+ };
233
+
234
+ /**
235
+ * Validate canonical encoding for f16.
236
+ * Matches Rust's validate_canonical_f16 function.
237
+ *
238
+ * TODO: Check if this is legacy code
239
+ */
240
+ export const validateCanonicalF16 = (value: number): void => {
241
+ const n = value;
242
+ const f = n;
243
+
244
+ const f16Bytes = numberToBinary16(value);
245
+ const bits = new DataView(f16Bytes.buffer).getUint16(0, false);
246
+
247
+ if (f === Math.trunc(f) || (Number.isNaN(value) && bits !== 0x7e00)) {
248
+ throw new CborError({ type: "NonCanonicalNumeric" });
249
+ }
250
+ };
251
+
252
+ /**
253
+ * Convert the smallest possible float binary representation to number.
254
+ * This is the canonical decoder - validates that larger representations
255
+ * are not reducible to smaller ones.
256
+ * @internal
257
+ */
258
+ export const numberToBinary = (n: number): Uint8Array => {
259
+ if (Number.isNaN(n)) {
260
+ return new Uint8Array([0x7e, 0x00]);
261
+ }
262
+
263
+ const n32 = numberToBinary32(n);
264
+ const f32 = binary32ToNumber(n32);
265
+ if (f32 === n) {
266
+ const n16 = numberToBinary16(n);
267
+ const f16 = binary16ToNumber(n16);
268
+ if (f16 === n) {
269
+ return n16;
270
+ }
271
+ return n32;
272
+ }
273
+
274
+ // Create a 64-bit float binary inline
275
+ const buffer = new ArrayBuffer(8);
276
+ const view = new DataView(buffer);
277
+ view.setFloat64(0, n, false); // big-endian
278
+ return new Uint8Array(buffer);
279
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Global type declarations for cross-platform APIs
3
+ */
4
+
5
+ declare global {
6
+ /**
7
+ * TextEncoder encodes a string into a Uint8Array of UTF-8 bytes.
8
+ * Available in Node.js 11.0.0+ and all modern browsers.
9
+ */
10
+ interface TextEncoder {
11
+ encode(input: string): Uint8Array;
12
+ }
13
+
14
+ /**
15
+ * TextDecoder decodes a Uint8Array of UTF-8 bytes into a string.
16
+ * Available in Node.js 11.0.0+ and all modern browsers.
17
+ */
18
+ interface TextDecoder {
19
+ decode(input: Uint8Array | ArrayBuffer | null | undefined): string;
20
+ }
21
+
22
+ type TextEncoderConstructor = new () => TextEncoder;
23
+ type TextDecoderConstructor = new (label?: string, options?: TextDecoderOptions) => TextDecoder;
24
+
25
+ interface TextDecoderOptions {
26
+ fatal?: boolean;
27
+ ignoreBOM?: boolean;
28
+ }
29
+
30
+ const TextEncoder: TextEncoderConstructor;
31
+ const TextDecoder: TextDecoderConstructor;
32
+ }
33
+
34
+ export {};
File without changes
package/src/index.ts ADDED
@@ -0,0 +1,180 @@
1
+ /**
2
+ * BC-DCBOR TypeScript Library
3
+ *
4
+ * A TypeScript implementation of Blockchain Commons' Deterministic CBOR (dCBOR).
5
+ *
6
+ * @module bc-dcbor
7
+ */
8
+
9
+ // Core CBOR types and encoding/decoding
10
+ export {
11
+ Cbor,
12
+ type CborInput,
13
+ type CborNumber,
14
+ type CborMethods,
15
+ MajorType,
16
+ type CborUnsignedType,
17
+ type CborNegativeType,
18
+ type CborByteStringType,
19
+ type CborTextType,
20
+ type CborArrayType,
21
+ type CborMapType,
22
+ type CborTaggedType,
23
+ type CborSimpleType,
24
+ } from "./cbor";
25
+
26
+ // Simple value types
27
+ export { type Simple, simpleName, isNaN } from "./simple";
28
+
29
+ // Encoding/Decoding
30
+ export { cbor, cborData } from "./cbor";
31
+ export { decodeCbor } from "./decode";
32
+
33
+ // Factory functions (static creators)
34
+ export { toByteString, toByteStringFromHex, toTaggedValue } from "./cbor";
35
+
36
+ // Map and Set
37
+ export { CborMap, type MapEntry } from "./map";
38
+ export { CborSet } from "./set";
39
+
40
+ // Tags and Tagged values
41
+ export { type Tag, createTag } from "./tag";
42
+ export {
43
+ type CborTagged,
44
+ type CborTaggedEncodable,
45
+ type CborTaggedDecodable,
46
+ type CborTaggedCodable,
47
+ createTaggedCbor,
48
+ validateTag,
49
+ extractTaggedContent,
50
+ } from "./cbor-tagged";
51
+ export {
52
+ TagsStore,
53
+ type TagsStoreTrait,
54
+ type CborSummarizer,
55
+ getGlobalTagsStore,
56
+ } from "./tags-store";
57
+ export * from "./tags";
58
+ export { registerTags, registerTagsIn, tagsForValues } from "./tags";
59
+
60
+ // Date utilities
61
+ export { CborDate } from "./date";
62
+
63
+ // Diagnostic formatting
64
+ export { diagnosticOpt, summary, type DiagFormatOpts } from "./diag";
65
+
66
+ // Hex formatting
67
+ export { hexOpt, hexToBytes, bytesToHex, type HexFormatOpts } from "./dump";
68
+
69
+ // Walk/Traversal functionality
70
+ export {
71
+ type EdgeType,
72
+ type EdgeTypeVariant,
73
+ type WalkElement,
74
+ type Visitor,
75
+ asSingle,
76
+ asKeyValue,
77
+ edgeLabel,
78
+ // Helper functions
79
+ countElements,
80
+ collectAtLevel,
81
+ findFirst,
82
+ collectAllText,
83
+ maxDepth,
84
+ } from "./walk";
85
+
86
+ // Codable interfaces
87
+ export { type CborCodable, type CborEncodable, type CborDecodable } from "./cbor-codable";
88
+
89
+ // Error types (matches Rust's Error enum)
90
+ export { type Error, type Result, Ok, Err, errorMsg, errorToString, CborError } from "./error";
91
+
92
+ // Note: conveniences.ts is an internal module (not exported in Rust either)
93
+ // The main convenience functions are exported from cbor.ts above
94
+
95
+ // Float utilities
96
+ export { hasFractionalPart } from "./float";
97
+
98
+ // Varint utilities
99
+ export { encodeVarInt, decodeVarInt, decodeVarIntData } from "./varint";
100
+
101
+ // Type utilities
102
+ export { ByteString } from "./byte-string";
103
+
104
+ // Convenience utilities - type guards
105
+ export {
106
+ isUnsigned,
107
+ isNegative,
108
+ isInteger,
109
+ isBytes,
110
+ isText,
111
+ isArray,
112
+ isMap,
113
+ isTagged,
114
+ isSimple,
115
+ isBoolean,
116
+ isNull,
117
+ isFloat,
118
+ } from "./conveniences";
119
+
120
+ // Convenience utilities - safe extraction (returns undefined on type mismatch)
121
+ export {
122
+ asUnsigned,
123
+ asNegative,
124
+ asInteger,
125
+ asBytes,
126
+ asText,
127
+ asArray,
128
+ asMap,
129
+ asBoolean,
130
+ asFloat,
131
+ asNumber,
132
+ } from "./conveniences";
133
+
134
+ // Convenience utilities - expectations (throw on type mismatch)
135
+ export {
136
+ expectUnsigned,
137
+ expectNegative,
138
+ expectInteger,
139
+ expectBytes,
140
+ expectText,
141
+ expectArray,
142
+ expectMap,
143
+ expectBoolean,
144
+ expectFloat,
145
+ expectNumber,
146
+ // Aliases for envelope compatibility
147
+ expectText as tryIntoText,
148
+ expectBoolean as tryIntoBool,
149
+ expectBytes as tryIntoByteString,
150
+ } from "./conveniences";
151
+
152
+ // Convenience utilities - array operations
153
+ export { arrayItem, arrayLength, arrayIsEmpty } from "./conveniences";
154
+
155
+ // Convenience utilities - map operations
156
+ export { mapValue, mapHas, mapKeys, mapValues, mapSize, mapIsEmpty } from "./conveniences";
157
+
158
+ // Convenience utilities - tagged value operations
159
+ export {
160
+ tagValue,
161
+ tagContent,
162
+ hasTag,
163
+ getTaggedContent,
164
+ expectTaggedContent,
165
+ // Alias for envelope compatibility
166
+ expectTaggedContent as tryExpectedTaggedValue,
167
+ } from "./conveniences";
168
+
169
+ // Extract native JavaScript value from CBOR
170
+ export { extractCbor } from "./conveniences";
171
+
172
+ // Envelope compatibility functions
173
+ export {
174
+ asTaggedValue,
175
+ asByteString,
176
+ asCborArray,
177
+ type CborArrayWrapper,
178
+ asCborMap,
179
+ isNumber,
180
+ } from "./conveniences";