cborg 4.5.2 → 4.5.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [4.5.4](https://github.com/rvagg/cborg/compare/v4.5.3...v4.5.4) (2026-01-20)
2
+
3
+ ## [4.5.3](https://github.com/rvagg/cborg/compare/v4.5.2...v4.5.3) (2026-01-20)
4
+
1
5
  ## [4.5.2](https://github.com/rvagg/cborg/compare/v4.5.1...v4.5.2) (2026-01-20)
2
6
 
3
7
  ## [4.5.1](https://github.com/rvagg/cborg/compare/v4.5.0...v4.5.1) (2026-01-20)
package/lib/7float.js CHANGED
@@ -11,10 +11,10 @@ import { encodeUint } from './0uint.js'
11
11
  * @typedef {import('../interface').EncodeOptions} EncodeOptions
12
12
  */
13
13
 
14
- const MINOR_FALSE = 20
15
- const MINOR_TRUE = 21
16
- const MINOR_NULL = 22
17
- const MINOR_UNDEFINED = 23
14
+ export const MINOR_FALSE = 20
15
+ export const MINOR_TRUE = 21
16
+ export const MINOR_NULL = 22
17
+ export const MINOR_UNDEFINED = 23
18
18
 
19
19
  /**
20
20
  * @param {Uint8Array} _data
package/lib/byte-utils.js CHANGED
@@ -34,6 +34,10 @@ export function asU8A (buf) {
34
34
  return isBuffer(buf) ? new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength) : buf
35
35
  }
36
36
 
37
+ // Threshold for switching between manual utf8Slice and native TextDecoder/Buffer
38
+ // Manual decoding has overhead from array building; native is fast for strings > 32 bytes
39
+ const UTF8_THRESHOLD = 32
40
+
37
41
  export const toString = useBuffer
38
42
  ? // eslint-disable-line operator-linebreak
39
43
  /**
@@ -42,7 +46,7 @@ export const toString = useBuffer
42
46
  * @param {number} end
43
47
  */
44
48
  (bytes, start, end) => {
45
- return end - start > 64
49
+ return end - start > UTF8_THRESHOLD
46
50
  ? // eslint-disable-line operator-linebreak
47
51
  // @ts-ignore
48
52
  globalThis.Buffer.from(bytes.subarray(start, end)).toString('utf8')
@@ -56,7 +60,7 @@ export const toString = useBuffer
56
60
  * @param {number} end
57
61
  */
58
62
  (bytes, start, end) => {
59
- return end - start > 64
63
+ return end - start > UTF8_THRESHOLD
60
64
  ? textDecoder.decode(bytes.subarray(start, end))
61
65
  : utf8Slice(bytes, start, end)
62
66
  }
package/lib/encode.js CHANGED
@@ -3,16 +3,16 @@ import { Token, Type } from './token.js'
3
3
  import { Bl, U8Bl } from './bl.js'
4
4
  import { encodeErrPrefix } from './common.js'
5
5
  import { quickEncodeToken } from './jump.js'
6
- import { asU8A, compare } from './byte-utils.js'
6
+ import { asU8A, compare, fromString } from './byte-utils.js'
7
7
 
8
- import { encodeUint } from './0uint.js'
8
+ import { encodeUint, encodeUintValue } from './0uint.js'
9
9
  import { encodeNegint } from './1negint.js'
10
10
  import { encodeBytes } from './2bytes.js'
11
11
  import { encodeString } from './3string.js'
12
12
  import { encodeArray } from './4array.js'
13
13
  import { encodeMap } from './5map.js'
14
14
  import { encodeTag } from './6tag.js'
15
- import { encodeFloat } from './7float.js'
15
+ import { encodeFloat, MINOR_FALSE, MINOR_TRUE, MINOR_NULL, MINOR_UNDEFINED } from './7float.js'
16
16
 
17
17
  /**
18
18
  * @typedef {import('../interface').EncodeOptions} EncodeOptions
@@ -468,6 +468,139 @@ function tokensToEncoded (writer, tokens, encoders, options) {
468
468
  }
469
469
  }
470
470
 
471
+ // CBOR major type prefixes, cached from Type for hot path performance
472
+ const MAJOR_UINT = Type.uint.majorEncoded
473
+ const MAJOR_NEGINT = Type.negint.majorEncoded
474
+ const MAJOR_BYTES = Type.bytes.majorEncoded
475
+ const MAJOR_STRING = Type.string.majorEncoded
476
+ const MAJOR_ARRAY = Type.array.majorEncoded
477
+
478
+ // Simple value bytes (CBOR major type 7 + minor value)
479
+ const SIMPLE_FALSE = Type.float.majorEncoded | MINOR_FALSE
480
+ const SIMPLE_TRUE = Type.float.majorEncoded | MINOR_TRUE
481
+ const SIMPLE_NULL = Type.float.majorEncoded | MINOR_NULL
482
+ const SIMPLE_UNDEFINED = Type.float.majorEncoded | MINOR_UNDEFINED
483
+
484
+ const neg1b = BigInt(-1)
485
+ const pos1b = BigInt(1)
486
+
487
+ /**
488
+ * Check if direct encoding can be used for the given options.
489
+ * Direct encoding bypasses token creation for most values.
490
+ * @param {EncodeOptions} options
491
+ * @returns {boolean}
492
+ */
493
+ function canDirectEncode (options) {
494
+ // Cannot use direct encode with addBreakTokens (needs special break token handling).
495
+ // Direct encode checks typeEncoders per-value, falling back to tokens as needed.
496
+ // Maps fall back to token-based encoding for efficient key sorting.
497
+ return options.addBreakTokens !== true
498
+ }
499
+
500
+ /**
501
+ * Direct encode a value to the writer, bypassing token creation for most types.
502
+ * Falls back to token-based encoding for custom type encoders.
503
+ * @param {ByteWriter} writer
504
+ * @param {any} data
505
+ * @param {EncodeOptions} options
506
+ * @param {Reference|undefined} refStack
507
+ */
508
+ function directEncode (writer, data, options, refStack) {
509
+ const typ = is(data)
510
+
511
+ // Check for custom encoder for THIS specific type
512
+ const customEncoder = options.typeEncoders && options.typeEncoders[typ]
513
+ if (customEncoder) {
514
+ const tokens = customEncoder(data, typ, options, refStack)
515
+ if (tokens != null) {
516
+ // Custom encoder returned tokens, serialize immediately
517
+ tokensToEncoded(writer, tokens, cborEncoders, options)
518
+ return
519
+ }
520
+ // Custom encoder returned null, fall through to default handling
521
+ }
522
+
523
+ // Direct encode based on type
524
+ switch (typ) {
525
+ case 'null':
526
+ writer.push([SIMPLE_NULL])
527
+ return
528
+
529
+ case 'undefined':
530
+ writer.push([SIMPLE_UNDEFINED])
531
+ return
532
+
533
+ case 'boolean':
534
+ writer.push([data ? SIMPLE_TRUE : SIMPLE_FALSE])
535
+ return
536
+
537
+ case 'number':
538
+ if (!Number.isInteger(data) || !Number.isSafeInteger(data)) {
539
+ // Float, use token encoder for complex float encoding
540
+ encodeFloat(writer, new Token(Type.float, data), options)
541
+ } else if (data >= 0) {
542
+ encodeUintValue(writer, MAJOR_UINT, data)
543
+ } else {
544
+ // Negative integer
545
+ encodeUintValue(writer, MAJOR_NEGINT, data * -1 - 1)
546
+ }
547
+ return
548
+
549
+ case 'bigint':
550
+ if (data >= BigInt(0)) {
551
+ encodeUintValue(writer, MAJOR_UINT, data)
552
+ } else {
553
+ encodeUintValue(writer, MAJOR_NEGINT, data * neg1b - pos1b)
554
+ }
555
+ return
556
+
557
+ case 'string': {
558
+ const bytes = fromString(data)
559
+ encodeUintValue(writer, MAJOR_STRING, bytes.length)
560
+ writer.push(bytes)
561
+ return
562
+ }
563
+
564
+ case 'Uint8Array':
565
+ encodeUintValue(writer, MAJOR_BYTES, data.length)
566
+ writer.push(data)
567
+ return
568
+
569
+ case 'Array':
570
+ if (!data.length) {
571
+ writer.push([MAJOR_ARRAY]) // Empty array: 0x80
572
+ return
573
+ }
574
+ refStack = Ref.createCheck(refStack, data)
575
+ encodeUintValue(writer, MAJOR_ARRAY, data.length)
576
+ for (const elem of data) {
577
+ directEncode(writer, elem, options, refStack)
578
+ }
579
+ return
580
+
581
+ case 'Object':
582
+ case 'Map':
583
+ // Maps require key sorting, use token-based encoding for efficiency
584
+ // (pre-encoding all keys for sorting is expensive)
585
+ {
586
+ const tokens = typeEncoders.Object(data, typ, options, refStack)
587
+ tokensToEncoded(writer, tokens, cborEncoders, options)
588
+ }
589
+ return
590
+
591
+ default:
592
+ // Fall back to token-based encoding for other types (DataView, TypedArrays, etc.)
593
+ {
594
+ const typeEncoder = typeEncoders[typ]
595
+ if (!typeEncoder) {
596
+ throw new Error(`${encodeErrPrefix} unsupported type: ${typ}`)
597
+ }
598
+ const tokens = typeEncoder(data, typ, options, refStack)
599
+ tokensToEncoded(writer, tokens, cborEncoders, options)
600
+ }
601
+ }
602
+ }
603
+
471
604
  /**
472
605
  * @param {any} data
473
606
  * @param {TokenTypeEncoder[]} encoders
@@ -518,6 +651,14 @@ function encodeCustom (data, encoders, options, destination) {
518
651
  */
519
652
  function encode (data, options) {
520
653
  options = Object.assign({}, defaultEncodeOptions, options)
654
+
655
+ // Use direct encode path when possible
656
+ if (canDirectEncode(options)) {
657
+ defaultWriter.reset()
658
+ directEncode(defaultWriter, data, options, undefined)
659
+ return defaultWriter.toBytes(true)
660
+ }
661
+
521
662
  return encodeCustom(data, cborEncoders, options)
522
663
  }
523
664
 
@@ -529,6 +670,14 @@ function encode (data, options) {
529
670
  */
530
671
  function encodeInto (data, destination, options) {
531
672
  options = Object.assign({}, defaultEncodeOptions, options)
673
+
674
+ // Use direct encode path when possible
675
+ if (canDirectEncode(options)) {
676
+ const writer = new U8Bl(destination)
677
+ directEncode(writer, data, options, undefined)
678
+ return { written: writer.toBytes().length }
679
+ }
680
+
532
681
  const result = encodeCustom(data, cborEncoders, options, destination)
533
682
  return { written: result.length }
534
683
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cborg",
3
- "version": "4.5.2",
3
+ "version": "4.5.4",
4
4
  "description": "Fast CBOR with a focus on strictness",
5
5
  "main": "cborg.js",
6
6
  "type": "module",
@@ -53,6 +53,15 @@ export namespace encodeFloat {
53
53
  function encodedSize(token: Token, options: EncodeOptions): number;
54
54
  let compareTokens: (tok1: Token, tok2: Token) => number;
55
55
  }
56
+ /**
57
+ * @typedef {import('../interface').ByteWriter} ByteWriter
58
+ * @typedef {import('../interface').DecodeOptions} DecodeOptions
59
+ * @typedef {import('../interface').EncodeOptions} EncodeOptions
60
+ */
61
+ export const MINOR_FALSE: 20;
62
+ export const MINOR_TRUE: 21;
63
+ export const MINOR_NULL: 22;
64
+ export const MINOR_UNDEFINED: 23;
56
65
  export type ByteWriter = import("../interface").ByteWriter;
57
66
  export type DecodeOptions = import("../interface").DecodeOptions;
58
67
  export type EncodeOptions = import("../interface").EncodeOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"7float.d.ts","sourceRoot":"","sources":["../../lib/7float.js"],"names":[],"mappings":"AAkBA;;;;;;GAMG;AACH,uCANW,UAAU,QACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CASjB;AAED;;;;;;GAMG;AACH,mCANW,UAAU,QACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAOjB;AAoBD;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;GAIG;AACH,oCAJW,UAAU,SACV,KAAK,WACL,aAAa,QAwCvB;;IAED;;;;OAIG;IACH,4BAJW,KAAK,WACL,aAAa,GACX,MAAM,CAsBlB;;;yBAjKY,OAAO,cAAc,EAAE,UAAU;4BACjC,OAAO,cAAc,EAAE,aAAa;4BACpC,OAAO,cAAc,EAAE,aAAa;sBAPrB,YAAY"}
1
+ {"version":3,"file":"7float.d.ts","sourceRoot":"","sources":["../../lib/7float.js"],"names":[],"mappings":"AAkBA;;;;;;GAMG;AACH,uCANW,UAAU,QACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CASjB;AAED;;;;;;GAMG;AACH,mCANW,UAAU,QACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAOjB;AAoBD;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;;;GAMG;AACH,oCANW,UAAU,OACV,MAAM,UACN,MAAM,WACN,aAAa,GACX,KAAK,CAIjB;AAED;;;;GAIG;AACH,oCAJW,UAAU,SACV,KAAK,WACL,aAAa,QAwCvB;;IAED;;;;OAIG;IACH,4BAJW,KAAK,WACL,aAAa,GACX,MAAM,CAsBlB;;;AAlKD;;;;GAIG;AAEH,0BAA2B,EAAE,CAAA;AAC7B,yBAA0B,EAAE,CAAA;AAC5B,yBAA0B,EAAE,CAAA;AAC5B,8BAA+B,EAAE,CAAA;yBARpB,OAAO,cAAc,EAAE,UAAU;4BACjC,OAAO,cAAc,EAAE,aAAa;4BACpC,OAAO,cAAc,EAAE,aAAa;sBAPrB,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"byte-utils.d.ts","sourceRoot":"","sources":["../../lib/byte-utils.js"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,2BAHW,UAAU,GAAC,MAAM,EAAE,GACjB,UAAU,CAQtB;AA8ND;;;;GAIG;AACH,4BAJW,UAAU,MACV,UAAU,GACR,MAAM,CAgBlB;AA4HD;;;GAGG;AACH,kDAHW,MAAM,EAAE,GACN,MAAM,CAkBlB;AA/ZD,gCAMkD;AA4B9C;;;;GAIG;AACH,gCAJW,UAAU,SACV,MAAM,OACN,MAAM,UAQhB;AAcL,mCAGe,MAAM,iDAYN,MAAM,yCAIhB;AAOE,+BAHI,MAAM,EAAE,GACN,UAAU,CAItB;AAIG;;;;GAIG;AACH,6BAJW,UAAU,SACV,MAAM,OACN,MAAM,2BAOhB;AAcD;;;;GAIG;AACH,+BAJW,UAAU,EAAE,UACZ,MAAM,GACJ,UAAU,CActB;AAwBD;;;GAGG;AACH,4BAHW,MAAM,GACJ,UAAU,CAMtB;AAaD;;;GAGG;AACH,yBAHW,UAAU,GACR,MAAM,CAQlB;AAiBH;;;GAGG;AACD,6BAHS,MAAM,GAAC,UAAU,GACf,UAAU,CAQpB"}
1
+ {"version":3,"file":"byte-utils.d.ts","sourceRoot":"","sources":["../../lib/byte-utils.js"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,2BAHW,UAAU,GAAC,MAAM,EAAE,GACjB,UAAU,CAQtB;AAkOD;;;;GAIG;AACH,4BAJW,UAAU,MACV,UAAU,GACR,MAAM,CAgBlB;AA4HD;;;GAGG;AACH,kDAHW,MAAM,EAAE,GACN,MAAM,CAkBlB;AAnaD,gCAMkD;AAgC9C;;;;GAIG;AACH,gCAJW,UAAU,SACV,MAAM,OACN,MAAM,UAQhB;AAcL,mCAGe,MAAM,iDAYN,MAAM,yCAIhB;AAOE,+BAHI,MAAM,EAAE,GACN,UAAU,CAItB;AAIG;;;;GAIG;AACH,6BAJW,UAAU,SACV,MAAM,OACN,MAAM,2BAOhB;AAcD;;;;GAIG;AACH,+BAJW,UAAU,EAAE,UACZ,MAAM,GACJ,UAAU,CActB;AAwBD;;;GAGG;AACH,4BAHW,MAAM,GACJ,UAAU,CAMtB;AAaD;;;GAGG;AACH,yBAHW,UAAU,GACR,MAAM,CAQlB;AAiBH;;;GAGG;AACD,6BAHS,MAAM,GAAC,UAAU,GACf,UAAU,CAQpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../lib/encode.js"],"names":[],"mappings":"AAwCA,oCAAoC;AACpC,oCADc,gBAAgB,EAAE,CAY/B;AAnBD,4BAA4B;AAC5B,mCADW,aAAa,CAKtB;sBA+XW,KAAK,GAAG;IAAE,SAAS,CAAC,EAAE,UAAU,CAAA;CAAE;4BApZlC,OAAO,cAAc,EAAE,aAAa;kCACpC,OAAO,cAAc,EAAE,mBAAmB;wBAC1C,OAAO,cAAc,EAAE,SAAS;gCAChC,OAAO,cAAc,EAAE,iBAAiB;+BACxC,OAAO,cAAc,EAAE,gBAAgB;kCACvC,OAAO,cAAc,EAAE,mBAAmB;yBAC1C,OAAO,cAAc,EAAE,UAAU;AA0R9C;;;;;GAKG;AACH,oCALW,GAAG,YACH,aAAa,aACb,SAAS,GACP,mBAAmB,CAgB/B;AA4LD;;;;GAIG;AACH,6BAJW,GAAG,YACH,aAAa,GACX,UAAU,CAKtB;AAnDD;;;;;;GAMG;AACH,mCANW,GAAG,YACH,gBAAgB,EAAE,WAClB,aAAa,gBACb,UAAU,GACR,UAAU,CAoCtB;AAYD;;;;;GAKG;AACH,iCALW,GAAG,eACH,UAAU,YACV,aAAa,GACX;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAM/B;AA3dD,8BAA8B;AAC9B,4BADiB,SAAS;IA0BxB;;;;OAIG;IACH,0BAJW,SAAS,GAAC,SAAS,OACnB,MAAM,GAAC,GAAG,EAAE,GACV,SAAS,CAOrB;IAlCD;;;OAGG;IACH,iBAHW,MAAM,GAAC,GAAG,EAAE,UACZ,SAAS,GAAC,SAAS,EAK7B;IAFC,oBAAc;IACd,qDAAoB;IAGtB;;;OAGG;IACH,cAHW,MAAM,GAAC,GAAG,EAAE,GACV,OAAO,CAWnB;CAaF;sBA9F2B,YAAY"}
1
+ {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../lib/encode.js"],"names":[],"mappings":"AAwCA,oCAAoC;AACpC,oCADc,gBAAgB,EAAE,CAY/B;AAnBD,4BAA4B;AAC5B,mCADW,aAAa,CAKtB;sBA+XW,KAAK,GAAG;IAAE,SAAS,CAAC,EAAE,UAAU,CAAA;CAAE;4BApZlC,OAAO,cAAc,EAAE,aAAa;kCACpC,OAAO,cAAc,EAAE,mBAAmB;wBAC1C,OAAO,cAAc,EAAE,SAAS;gCAChC,OAAO,cAAc,EAAE,iBAAiB;+BACxC,OAAO,cAAc,EAAE,gBAAgB;kCACvC,OAAO,cAAc,EAAE,mBAAmB;yBAC1C,OAAO,cAAc,EAAE,UAAU;AA0R9C;;;;;GAKG;AACH,oCALW,GAAG,YACH,aAAa,aACb,SAAS,GACP,mBAAmB,CAgB/B;AAiUD;;;;GAIG;AACH,6BAJW,GAAG,YACH,aAAa,GACX,UAAU,CAatB;AA3DD;;;;;;GAMG;AACH,mCANW,GAAG,YACH,gBAAgB,EAAE,WAClB,aAAa,gBACb,UAAU,GACR,UAAU,CAoCtB;AAoBD;;;;;GAKG;AACH,iCALW,GAAG,eACH,UAAU,YACV,aAAa,GACX;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAc/B;AAhnBD,8BAA8B;AAC9B,4BADiB,SAAS;IA0BxB;;;;OAIG;IACH,0BAJW,SAAS,GAAC,SAAS,OACnB,MAAM,GAAC,GAAG,EAAE,GACV,SAAS,CAOrB;IAlCD;;;OAGG;IACH,iBAHW,MAAM,GAAC,GAAG,EAAE,UACZ,SAAS,GAAC,SAAS,EAK7B;IAFC,oBAAc;IACd,qDAAoB;IAGtB;;;OAGG;IACH,cAHW,MAAM,GAAC,GAAG,EAAE,GACV,OAAO,CAWnB;CAaF;sBA9F2B,YAAY"}