microcbor 1.1.0 → 1.2.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/README.md CHANGED
@@ -68,7 +68,15 @@ console.log(decode(data))
68
68
  ### CBOR Values
69
69
 
70
70
  ```ts
71
- declare type CBORValue = undefined | null | boolean | number | string | Uint8Array | CBORArray | CBORMap
71
+ declare type CBORValue =
72
+ | undefined
73
+ | null
74
+ | boolean
75
+ | number
76
+ | string
77
+ | Uint8Array
78
+ | CBORArray
79
+ | CBORMap
72
80
 
73
81
  interface CBORArray extends Array<CBORValue> {}
74
82
  interface CBORMap {
@@ -82,6 +90,12 @@ interface CBORMap {
82
90
 
83
91
  ```ts
84
92
  export interface EncodeOptions {
93
+ /**
94
+ * Allow `undefined`
95
+ * @default true
96
+ */
97
+ allowUndefined?: boolean
98
+
85
99
  /**
86
100
  * Re-use the same underlying ArrayBuffer for all yielded chunks.
87
101
  * If this is enabled, the consumer must copy each chunk content
@@ -113,7 +127,10 @@ export interface EncodeOptions {
113
127
  * Calculate the byte length that a value will encode into
114
128
  * without actually allocating anything.
115
129
  */
116
- declare function encodingLength(value: CBORValue): number
130
+ declare function encodingLength(
131
+ value: CBORValue,
132
+ options?: EncodeOptions,
133
+ ): number
117
134
  ```
118
135
 
119
136
  #### `encode`
@@ -123,7 +140,7 @@ declare function encodingLength(value: CBORValue): number
123
140
  * Encode a single CBOR value.
124
141
  * options.chunkRecycling has no effect here.
125
142
  */
126
- export function encode(value: CBORValue, options: EncodeOptions = {}): Uint8Array
143
+ export function encode(value: CBORValue, options?: EncodeOptions): Uint8Array
127
144
  ```
128
145
 
129
146
  #### `encodeIterable`
@@ -132,7 +149,7 @@ export function encode(value: CBORValue, options: EncodeOptions = {}): Uint8Arra
132
149
  /** Encode an iterable of CBOR values into an iterable of Uint8Array chunks */
133
150
  export function* encodeIterable(
134
151
  source: Iterable<CBORValue>,
135
- options: EncodeOptions = {},
152
+ options?: EncodeOptions,
136
153
  ): IterableIterator<Uint8Array>
137
154
 
138
155
  ```
@@ -143,7 +160,7 @@ export function* encodeIterable(
143
160
  /** Encode an async iterable of CBOR values into an async iterable of Uint8Array chunks */
144
161
  export async function* encodeAsyncIterable(
145
162
  source: AsyncIterable<CBORValue>,
146
- options: EncodeOptions = {},
163
+ options?: EncodeOptions,
147
164
  ): AsyncIterableIterator<Uint8Array>
148
165
 
149
166
  ```
@@ -156,17 +173,38 @@ export async function* encodeAsyncIterable(
156
173
  * options.chunkRecycling has no effect here.
157
174
  */
158
175
  export class CBOREncoderStream extends TransformStream<CBORValue, Uint8Array> {
159
- public constructor(options: EncodeOptions = {})
176
+ public constructor(options?: EncodeOptions)
160
177
  }
161
178
  ```
162
179
 
163
180
  ### Decoding
164
181
 
182
+ #### `DecodeOptions`
183
+
184
+ ```ts
185
+ export interface DecodeOptions {
186
+ /**
187
+ * Allow `undefined`
188
+ * @default true
189
+ */
190
+ allowUndefined?: boolean
191
+
192
+ /**
193
+ * Minimum bitsize for floating-point numbers: 16, 32, or 64
194
+ * @default 16
195
+ */
196
+ minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize]
197
+ }
198
+ ```
199
+
165
200
  #### `decode`
166
201
 
167
202
  ```ts
168
203
  /** Decode a single CBOR value. */
169
- export function decode<T extends CBORValue = CBORValue>(data: Uint8Array): T
204
+ export function decode<T extends CBORValue = CBORValue>(
205
+ data: Uint8Array,
206
+ options?: DecodeOptions,
207
+ ): T
170
208
  ```
171
209
 
172
210
  #### `decodeIterable`
@@ -175,8 +213,8 @@ export function decode<T extends CBORValue = CBORValue>(data: Uint8Array): T
175
213
  /** Decode an iterable of Uint8Array chunks into an iterable of CBOR values */
176
214
  export function* decodeIterable<T extends CBORValue = CBORValue>(
177
215
  source: Iterable<Uint8Array>,
216
+ options?: DecodeOptions,
178
217
  ): IterableIterator<T>
179
-
180
218
  ```
181
219
 
182
220
  #### `decodeAsyncIterable`
@@ -185,6 +223,7 @@ export function* decodeIterable<T extends CBORValue = CBORValue>(
185
223
  /** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
186
224
  export async function* decodeAsyncIterable<T extends CBORValue = CBORValue>(
187
225
  source: AsyncIterable<Uint8Array>,
226
+ options?: DecodeOptions,
188
227
  ): AsyncIterable<CBORValue>
189
228
  ```
190
229
 
@@ -192,7 +231,9 @@ export async function* decodeAsyncIterable<T extends CBORValue = CBORValue>(
192
231
 
193
232
  ```ts
194
233
  /** Decode a Web Streams API ReadableStream. */
195
- export class CBORDecoderStream<T extends CBORValue = CBORValue> extends TransformStream<Uint8Array, T> {
234
+ export class CBORDecoderStream<
235
+ T extends CBORValue = CBORValue,
236
+ > extends TransformStream<Uint8Array, T> {
196
237
  public constructor()
197
238
  }
198
239
  ```
@@ -1,5 +1,6 @@
1
+ import { DecodeOptions } from "./options.js";
1
2
  import { CBORValue } from "./types.js";
2
3
  /** Decode a Web Streams API ReadableStream */
3
4
  export declare class CBORDecoderStream<T extends CBORValue = CBORValue> extends TransformStream<Uint8Array, T> {
4
- constructor();
5
+ constructor(options?: DecodeOptions);
5
6
  }
@@ -1,7 +1,7 @@
1
1
  import { Decoder } from "./decodeAsyncIterable.js";
2
2
  /** Decode a Web Streams API ReadableStream */
3
3
  export class CBORDecoderStream extends TransformStream {
4
- constructor() {
4
+ constructor(options = {}) {
5
5
  let readableController;
6
6
  const readable = new ReadableStream({
7
7
  start(controller) {
@@ -13,6 +13,7 @@ export class CBORDecoderStream extends TransformStream {
13
13
  const chunks = new WeakMap();
14
14
  async function pipe(controller) {
15
15
  const decoder = new Decoder(readable.values(), {
16
+ ...options,
16
17
  onFree: (chunk) => chunks.get(chunk)?.resolve(),
17
18
  });
18
19
  for await (const value of decoder) {
@@ -1,5 +1,5 @@
1
1
  import { CBORValue } from "./types.js";
2
- import { EncodeOptions } from "./Encoder.js";
2
+ import { EncodeOptions } from "./options.js";
3
3
  /**
4
4
  * Encode a Web Streams API ReadableStream.
5
5
  * options.chunkRecycling has no effect here.
package/lib/Decoder.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import type { CBORValue } from "./types.js";
2
+ import type { DecodeOptions, FloatSize } from "./options.js";
2
3
  export declare class Decoder {
3
4
  #private;
4
5
  private readonly data;
5
- constructor(data: Uint8Array);
6
+ readonly allowUndefined: boolean;
7
+ readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
8
+ constructor(data: Uint8Array, options?: DecodeOptions);
6
9
  getOffset(): number;
7
10
  private constant;
8
11
  private float16;
@@ -18,4 +21,4 @@ export declare class Decoder {
18
21
  decodeValue(): CBORValue;
19
22
  }
20
23
  /** Decode a single CBOR value */
21
- export declare function decode<T extends CBORValue = CBORValue>(data: Uint8Array): T;
24
+ export declare function decode<T extends CBORValue = CBORValue>(data: Uint8Array, options?: DecodeOptions): T;
package/lib/Decoder.js CHANGED
@@ -13,7 +13,7 @@ var _Decoder_offset, _Decoder_view;
13
13
  import { getFloat16 } from "fp16";
14
14
  import { UnsafeIntegerError, maxSafeInteger, minSafeInteger } from "./utils.js";
15
15
  export class Decoder {
16
- constructor(data) {
16
+ constructor(data, options = {}) {
17
17
  this.data = data;
18
18
  _Decoder_offset.set(this, void 0);
19
19
  _Decoder_view.set(this, void 0);
@@ -31,6 +31,8 @@ export class Decoder {
31
31
  this.uint64 = this.constant(8, () => __classPrivateFieldGet(this, _Decoder_view, "f").getBigUint64(__classPrivateFieldGet(this, _Decoder_offset, "f")));
32
32
  __classPrivateFieldSet(this, _Decoder_offset, 0, "f");
33
33
  __classPrivateFieldSet(this, _Decoder_view, new DataView(data.buffer, data.byteOffset, data.byteLength), "f");
34
+ this.allowUndefined = options.allowUndefined ?? true;
35
+ this.minFloatSize = options.minFloatSize ?? 16;
34
36
  }
35
37
  getOffset() {
36
38
  return __classPrivateFieldGet(this, _Decoder_offset, "f");
@@ -133,13 +135,28 @@ export class Decoder {
133
135
  case 22:
134
136
  return null;
135
137
  case 23:
136
- return undefined;
138
+ if (this.allowUndefined) {
139
+ return undefined;
140
+ }
141
+ else {
142
+ throw new TypeError("`undefined` not allowed");
143
+ }
137
144
  case 24:
138
145
  throw new Error("microcbor does not support decoding unassigned simple values");
139
146
  case 25:
140
- return this.float16();
147
+ if (this.minFloatSize <= 16) {
148
+ return this.float16();
149
+ }
150
+ else {
151
+ throw new Error("cannot decode float16 type - below provided minFloatSize");
152
+ }
141
153
  case 26:
142
- return this.float32();
154
+ if (this.minFloatSize <= 32) {
155
+ return this.float32();
156
+ }
157
+ else {
158
+ throw new Error("cannot decode float32 type - below provided minFloatSize");
159
+ }
143
160
  case 27:
144
161
  return this.float64();
145
162
  case 31:
@@ -155,6 +172,6 @@ export class Decoder {
155
172
  }
156
173
  _Decoder_offset = new WeakMap(), _Decoder_view = new WeakMap();
157
174
  /** Decode a single CBOR value */
158
- export function decode(data) {
159
- return new Decoder(data).decodeValue();
175
+ export function decode(data, options = {}) {
176
+ return new Decoder(data, options).decodeValue();
160
177
  }
package/lib/Encoder.d.ts CHANGED
@@ -1,33 +1,9 @@
1
1
  import type { CBORValue } from "./types.js";
2
- export declare const FloatSize: {
3
- f16: number;
4
- f32: number;
5
- f64: number;
6
- };
7
- export interface EncodeOptions {
8
- /**
9
- * Re-use the same underlying ArrayBuffer for all yielded chunks.
10
- * If this is enabled, the consumer must copy each chunk content
11
- * themselves to a new buffer if they wish to keep it.
12
- * This mode is useful for efficiently hashing objects without
13
- * ever allocating memory for the entire encoded result.
14
- * @default false
15
- */
16
- chunkRecycling?: boolean;
17
- /**
18
- * Maximum chunk size
19
- * @default 4096
20
- */
21
- chunkSize?: number;
22
- /**
23
- * Minimum bitsize for floating-point numbers: 16, 32, or 64
24
- * @default 16
25
- */
26
- minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
27
- }
2
+ import { EncodeOptions, FloatSize } from "./options.js";
28
3
  export declare class Encoder {
29
4
  #private;
30
5
  static defaultChunkSize: number;
6
+ readonly allowUndefined: boolean;
31
7
  readonly chunkRecycling: boolean;
32
8
  readonly chunkSize: number;
33
9
  readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
package/lib/Encoder.js CHANGED
@@ -11,17 +11,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
11
11
  };
12
12
  var _Encoder_instances, _Encoder_closed, _Encoder_flush;
13
13
  import { Precision, getFloat16Precision, getFloat32Precision, setFloat16 } from "fp16";
14
+ import { FloatSize } from "./options.js";
14
15
  import { assert } from "./utils.js";
15
- export const FloatSize = {
16
- f16: 16,
17
- f32: 32,
18
- f64: 64,
19
- };
20
16
  export class Encoder {
21
17
  constructor(options = {}) {
22
18
  _Encoder_instances.add(this);
23
19
  _Encoder_closed.set(this, void 0);
24
20
  this.encoder = new TextEncoder();
21
+ this.allowUndefined = options.allowUndefined ?? true;
25
22
  this.minFloatSize = options.minFloatSize ?? 16;
26
23
  this.chunkRecycling = options.chunkRecycling ?? false;
27
24
  this.chunkSize = options.chunkSize ?? Encoder.defaultChunkSize;
@@ -175,7 +172,12 @@ export class Encoder {
175
172
  yield* this.uint8(0xf6);
176
173
  }
177
174
  else if (value === undefined) {
178
- yield* this.uint8(0xf7);
175
+ if (this.allowUndefined) {
176
+ yield* this.uint8(0xf7);
177
+ }
178
+ else {
179
+ throw new TypeError("`undefined` is not allowed");
180
+ }
179
181
  }
180
182
  else if (typeof value === "number") {
181
183
  yield* this.encodeNumber(value);
@@ -1,5 +1,11 @@
1
1
  import type { CBORValue } from "./types.js";
2
+ import { DecodeOptions, FloatSize } from "./options.js";
3
+ export interface AsyncDecodeOptions extends DecodeOptions {
4
+ onFree?: (chunk: Uint8Array) => void;
5
+ }
2
6
  export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIterableIterator<T> {
7
+ readonly allowUndefined: boolean;
8
+ readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
3
9
  private offset;
4
10
  private byteLength;
5
11
  private readonly chunks;
@@ -7,9 +13,9 @@ export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIt
7
13
  private readonly constantView;
8
14
  private readonly iter;
9
15
  private readonly onFree?;
10
- constructor(source: AsyncIterable<Uint8Array>, options?: {
11
- onFree?: (chunk: Uint8Array) => void;
12
- });
16
+ private readonly touchedChunks;
17
+ private readonly freedChunks;
18
+ constructor(source: AsyncIterable<Uint8Array>, options?: AsyncDecodeOptions);
13
19
  [Symbol.asyncIterator]: () => this;
14
20
  private allocate;
15
21
  private fill;
@@ -34,4 +40,4 @@ export declare class Decoder<T extends CBORValue = CBORValue> implements AsyncIt
34
40
  private decodeValue;
35
41
  }
36
42
  /** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
37
- export declare function decodeAsyncIterable(source: AsyncIterable<Uint8Array>): AsyncIterableIterator<CBORValue>;
43
+ export declare function decodeAsyncIterable(source: AsyncIterable<Uint8Array>, options?: AsyncDecodeOptions): AsyncIterableIterator<CBORValue>;
@@ -8,6 +8,8 @@ export class Decoder {
8
8
  this.chunks = [];
9
9
  this.constantBuffer = new ArrayBuffer(8);
10
10
  this.constantView = new DataView(this.constantBuffer);
11
+ this.touchedChunks = new WeakSet();
12
+ this.freedChunks = new WeakSet();
11
13
  this[_a] = () => this;
12
14
  this.constant = (size, f) => {
13
15
  return async () => {
@@ -24,10 +26,22 @@ export class Decoder {
24
26
  this.uint16 = this.constant(2, (view) => view.getUint16(0));
25
27
  this.uint32 = this.constant(4, (view) => view.getUint32(0));
26
28
  this.uint64 = this.constant(8, (view) => view.getBigUint64(0));
27
- this.iter = source[Symbol.asyncIterator]();
28
29
  this.onFree = options.onFree;
30
+ this.allowUndefined = options.allowUndefined ?? true;
31
+ this.minFloatSize = options.minFloatSize ?? 16;
32
+ this.iter = source[Symbol.asyncIterator]();
29
33
  }
30
34
  async allocate(size) {
35
+ // If we need more data, first call onFree for all touched chunks
36
+ // This allows the transform stream to provide more chunks
37
+ if (this.byteLength < size && this.onFree !== undefined) {
38
+ for (const chunk of this.chunks) {
39
+ if (this.touchedChunks.has(chunk) && !this.freedChunks.has(chunk)) {
40
+ this.freedChunks.add(chunk);
41
+ this.onFree(chunk);
42
+ }
43
+ }
44
+ }
31
45
  while (this.byteLength < size) {
32
46
  const { done, value } = await this.iter.next();
33
47
  if (done) {
@@ -36,6 +50,12 @@ export class Decoder {
36
50
  else {
37
51
  this.chunks.push(value);
38
52
  this.byteLength += value.byteLength;
53
+ // If we still need more data after adding this chunk,
54
+ // immediately call onFree to allow the next chunk to flow
55
+ if (this.byteLength < size && this.onFree !== undefined && !this.freedChunks.has(value)) {
56
+ this.freedChunks.add(value);
57
+ this.onFree(value);
58
+ }
39
59
  }
40
60
  }
41
61
  }
@@ -47,6 +67,10 @@ export class Decoder {
47
67
  let deleteCount = 0;
48
68
  for (let i = 0; byteLength < target.byteLength; i++) {
49
69
  const chunk = this.chunks[i];
70
+ // Track which chunks we touched
71
+ if (!this.touchedChunks.has(chunk)) {
72
+ this.touchedChunks.add(chunk);
73
+ }
50
74
  const capacity = target.byteLength - byteLength;
51
75
  const length = chunk.byteLength - this.offset;
52
76
  if (length <= capacity) {
@@ -65,9 +89,14 @@ export class Decoder {
65
89
  this.byteLength -= capacity;
66
90
  }
67
91
  }
92
+ // Call onFree for chunks that are being removed (fully consumed)
68
93
  if (this.onFree !== undefined) {
69
94
  for (let i = 0; i < deleteCount; i++) {
70
- this.onFree(this.chunks[i]);
95
+ const chunk = this.chunks[i];
96
+ if (!this.freedChunks.has(chunk)) {
97
+ this.freedChunks.add(chunk);
98
+ this.onFree(chunk);
99
+ }
71
100
  }
72
101
  }
73
102
  this.chunks.splice(0, deleteCount);
@@ -185,13 +214,28 @@ export class Decoder {
185
214
  case 22:
186
215
  return null;
187
216
  case 23:
188
- return undefined;
217
+ if (this.allowUndefined) {
218
+ return undefined;
219
+ }
220
+ else {
221
+ throw new TypeError("`undefined` not allowed");
222
+ }
189
223
  case 24:
190
224
  throw new Error("microcbor does not support decoding unassigned simple values");
191
225
  case 25:
192
- return await this.float16();
226
+ if (this.minFloatSize <= 16) {
227
+ return this.float16();
228
+ }
229
+ else {
230
+ throw new Error("cannot decode float16 type - below provided minFloatSize");
231
+ }
193
232
  case 26:
194
- return await this.float32();
233
+ if (this.minFloatSize <= 32) {
234
+ return this.float32();
235
+ }
236
+ else {
237
+ throw new Error("cannot decode float32 type - below provided minFloatSize");
238
+ }
195
239
  case 27:
196
240
  return await this.float64();
197
241
  case 31:
@@ -207,6 +251,6 @@ export class Decoder {
207
251
  }
208
252
  _a = Symbol.asyncIterator;
209
253
  /** Decode an async iterable of Uint8Array chunks into an async iterable of CBOR values */
210
- export async function* decodeAsyncIterable(source) {
211
- yield* new Decoder(source);
254
+ export async function* decodeAsyncIterable(source, options = {}) {
255
+ yield* new Decoder(source, options);
212
256
  }
@@ -1,3 +1,37 @@
1
1
  import type { CBORValue } from "./types.js";
2
+ import type { DecodeOptions, FloatSize } from "./options.js";
3
+ export declare class Decoder<T extends CBORValue = CBORValue> implements IterableIterator<T> {
4
+ readonly allowUndefined: boolean;
5
+ readonly minFloatSize: (typeof FloatSize)[keyof typeof FloatSize];
6
+ private offset;
7
+ private byteLength;
8
+ private readonly chunks;
9
+ private readonly constantBuffer;
10
+ private readonly constantView;
11
+ private readonly iter;
12
+ constructor(source: Iterable<Uint8Array>, options?: DecodeOptions);
13
+ [Symbol.iterator]: () => this;
14
+ private allocate;
15
+ private fill;
16
+ private constant;
17
+ private float16;
18
+ private float32;
19
+ private float64;
20
+ private uint8;
21
+ private uint16;
22
+ private uint32;
23
+ private uint64;
24
+ private decodeBytes;
25
+ private decodeString;
26
+ private getArgument;
27
+ next(): {
28
+ done: true;
29
+ value: undefined;
30
+ } | {
31
+ done: false;
32
+ value: T;
33
+ };
34
+ private decodeValue;
35
+ }
2
36
  /** Decode an iterable of Uint8Array chunks into an iterable of CBOR values */
3
37
  export declare function decodeIterable(source: Iterable<Uint8Array>): IterableIterator<CBORValue>;
@@ -1,8 +1,8 @@
1
1
  var _a;
2
2
  import { getFloat16 } from "fp16";
3
3
  import { UnsafeIntegerError, maxSafeInteger, minSafeInteger } from "./utils.js";
4
- class Decoder {
5
- constructor(source) {
4
+ export class Decoder {
5
+ constructor(source, options = {}) {
6
6
  this.offset = 0;
7
7
  this.byteLength = 0;
8
8
  this.chunks = [];
@@ -24,6 +24,8 @@ class Decoder {
24
24
  this.uint16 = this.constant(2, (view) => view.getUint16(0));
25
25
  this.uint32 = this.constant(4, (view) => view.getUint32(0));
26
26
  this.uint64 = this.constant(8, (view) => view.getBigUint64(0));
27
+ this.allowUndefined = options.allowUndefined ?? true;
28
+ this.minFloatSize = options.minFloatSize ?? 16;
27
29
  this.iter = source[Symbol.iterator]();
28
30
  }
29
31
  allocate(size) {
@@ -179,13 +181,28 @@ class Decoder {
179
181
  case 22:
180
182
  return null;
181
183
  case 23:
182
- return undefined;
184
+ if (this.allowUndefined) {
185
+ return undefined;
186
+ }
187
+ else {
188
+ throw new TypeError("`undefined` not allowed");
189
+ }
183
190
  case 24:
184
191
  throw new Error("microcbor does not support decoding unassigned simple values");
185
192
  case 25:
186
- return this.float16();
193
+ if (this.minFloatSize <= 16) {
194
+ return this.float16();
195
+ }
196
+ else {
197
+ throw new Error("cannot decode float16 type - below provided minFloatSize");
198
+ }
187
199
  case 26:
188
- return this.float32();
200
+ if (this.minFloatSize <= 32) {
201
+ return this.float32();
202
+ }
203
+ else {
204
+ throw new Error("cannot decode float32 type - below provided minFloatSize");
205
+ }
189
206
  case 27:
190
207
  return this.float64();
191
208
  case 31:
@@ -1,4 +1,4 @@
1
1
  import type { CBORValue } from "./types.js";
2
- import { EncodeOptions } from "./Encoder.js";
2
+ import { EncodeOptions } from "./options.js";
3
3
  /** Encode an async iterable of CBOR values into an async iterable of Uint8Array chunks */
4
4
  export declare function encodeAsyncIterable(source: AsyncIterable<CBORValue>, options?: EncodeOptions): AsyncIterableIterator<Uint8Array>;
@@ -1,4 +1,4 @@
1
1
  import type { CBORValue } from "./types.js";
2
- import { EncodeOptions } from "./Encoder.js";
2
+ import { EncodeOptions } from "./options.js";
3
3
  /** Encode an iterable of CBOR values into an iterable of Uint8Array chunks */
4
4
  export declare function encodeIterable(source: Iterable<CBORValue>, options?: EncodeOptions): IterableIterator<Uint8Array>;
@@ -1,6 +1,7 @@
1
1
  import { CBORValue } from "./types.js";
2
+ import { EncodeOptions } from "./options.js";
2
3
  /**
3
4
  * Calculate the byte length that a value will encode into
4
5
  * without actually allocating anything.
5
6
  */
6
- export declare function encodingLength(value: CBORValue): number;
7
+ export declare function encodingLength(value: CBORValue, options?: EncodeOptions): number;
@@ -4,7 +4,7 @@ import { getByteLength } from "./utils.js";
4
4
  * Calculate the byte length that a value will encode into
5
5
  * without actually allocating anything.
6
6
  */
7
- export function encodingLength(value) {
7
+ export function encodingLength(value, options = {}) {
8
8
  if (value === false) {
9
9
  return 1;
10
10
  }
@@ -15,10 +15,15 @@ export function encodingLength(value) {
15
15
  return 1;
16
16
  }
17
17
  else if (value === undefined) {
18
- return 1;
18
+ if (options.allowUndefined ?? true) {
19
+ return 1;
20
+ }
21
+ else {
22
+ throw new Error("`undefined` is not allowed");
23
+ }
19
24
  }
20
25
  else if (typeof value === "number") {
21
- return numberEncodingLength(value);
26
+ return numberEncodingLength(value, options);
22
27
  }
23
28
  else if (typeof value === "string") {
24
29
  return stringEncodingLength(value);
@@ -29,7 +34,7 @@ export function encodingLength(value) {
29
34
  else if (Array.isArray(value)) {
30
35
  let length = argumentEncodingLength(value.length);
31
36
  for (const element of value) {
32
- length += encodingLength(element);
37
+ length += encodingLength(element, options);
33
38
  }
34
39
  return length;
35
40
  }
@@ -39,7 +44,7 @@ export function encodingLength(value) {
39
44
  for (const key of keys) {
40
45
  if (typeof key === "string") {
41
46
  length += stringEncodingLength(key);
42
- length += encodingLength(value[key]);
47
+ length += encodingLength(value[key], options);
43
48
  }
44
49
  else {
45
50
  throw new Error("object keys must be strings");
@@ -68,18 +73,18 @@ function argumentEncodingLength(argument) {
68
73
  return 1 + 8;
69
74
  }
70
75
  }
71
- function numberEncodingLength(value) {
76
+ function numberEncodingLength(value, options) {
72
77
  if (Object.is(value, 0)) {
73
78
  return integerEncodingLength(value);
74
79
  }
75
80
  else if (Object.is(value, -0)) {
76
- return floatEncodingLength(value);
81
+ return floatEncodingLength(value, options);
77
82
  }
78
83
  else if (Math.floor(value) === value && Number.MIN_SAFE_INTEGER <= value && value <= Number.MAX_SAFE_INTEGER) {
79
84
  return integerEncodingLength(value);
80
85
  }
81
86
  else {
82
- return floatEncodingLength(value);
87
+ return floatEncodingLength(value, options);
83
88
  }
84
89
  }
85
90
  function integerEncodingLength(value) {
@@ -90,11 +95,12 @@ function integerEncodingLength(value) {
90
95
  return argumentEncodingLength(value);
91
96
  }
92
97
  }
93
- function floatEncodingLength(value) {
94
- if (getFloat16Precision(value) === Precision.Exact) {
98
+ function floatEncodingLength(value, options) {
99
+ const { minFloatSize = 16 } = options;
100
+ if (minFloatSize <= 16 && getFloat16Precision(value) === Precision.Exact) {
95
101
  return 1 + 2;
96
102
  }
97
- else if (getFloat32Precision(value) === Precision.Exact) {
103
+ else if (minFloatSize <= 32 && getFloat32Precision(value) === Precision.Exact) {
98
104
  return 1 + 4;
99
105
  }
100
106
  else {
@@ -0,0 +1,43 @@
1
+ export declare const FloatSize: {
2
+ f16: number;
3
+ f32: number;
4
+ f64: number;
5
+ };
6
+ export interface EncodeOptions {
7
+ /**
8
+ * Allow `undefined`
9
+ * @default true
10
+ */
11
+ allowUndefined?: boolean;
12
+ /**
13
+ * Re-use the same underlying ArrayBuffer for all yielded chunks.
14
+ * If this is enabled, the consumer must copy each chunk content
15
+ * themselves to a new buffer if they wish to keep it.
16
+ * This mode is useful for efficiently hashing objects without
17
+ * ever allocating memory for the entire encoded result.
18
+ * @default false
19
+ */
20
+ chunkRecycling?: boolean;
21
+ /**
22
+ * Maximum chunk size
23
+ * @default 4096
24
+ */
25
+ chunkSize?: number;
26
+ /**
27
+ * Minimum bitsize for floating-point numbers: 16, 32, or 64
28
+ * @default 16
29
+ */
30
+ minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
31
+ }
32
+ export interface DecodeOptions {
33
+ /**
34
+ * Allow `undefined`
35
+ * @default true
36
+ */
37
+ allowUndefined?: boolean;
38
+ /**
39
+ * Minimum bitsize for floating-point numbers: 16, 32, or 64
40
+ * @default 16
41
+ */
42
+ minFloatSize?: (typeof FloatSize)[keyof typeof FloatSize];
43
+ }
package/lib/options.js ADDED
@@ -0,0 +1,5 @@
1
+ export const FloatSize = {
2
+ f16: 16,
3
+ f32: 32,
4
+ f64: 64,
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "microcbor",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "lib"
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "homepage": "https://github.com/joeltg/microcbor#readme",
34
34
  "devDependencies": {
35
- "@ava/typescript": "^5.0.0",
35
+ "@ava/typescript": "^6.0.0",
36
36
  "@types/node": "^22.13.9",
37
37
  "ava": "^6.2.0",
38
38
  "cbor": "^10.0.3",