cbor-x 0.8.0 → 0.9.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
3
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = global || self, factory(global.msgpackr = {}));
4
+ (global = global || self, factory(global.CBOR = {}));
5
5
  }(this, (function (exports) { 'use strict';
6
6
 
7
7
  let decoder;
@@ -21,10 +21,12 @@
21
21
  let referenceMap;
22
22
  let currentExtensions = [];
23
23
  let dataView;
24
+ let restoreMapsAsObject;
24
25
  let defaultOptions = {
25
26
  useRecords: false,
26
27
  mapsAsObjects: true
27
28
  };
29
+ let sequentialMode = false;
28
30
 
29
31
  class Decoder {
30
32
  constructor(options) {
@@ -36,12 +38,12 @@
36
38
  }
37
39
  Object.assign(this, options);
38
40
  }
39
- decode(source, end, continueReading) {
41
+ decode(source, end) {
40
42
  if (src) {
41
43
  // re-entrant execution, save the state and restore it after we do this decode
42
44
  return saveState(() => {
43
45
  clearSource();
44
- return this ? this.decode(source, end, continueReading) : Decoder.prototype.decode.call(defaultOptions, source, end, continueReading)
46
+ return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
45
47
  })
46
48
  }
47
49
  srcEnd = end > -1 ? end : source.length;
@@ -57,17 +59,7 @@
57
59
  currentDecoder = this;
58
60
  if (this.structures) {
59
61
  currentStructures = this.structures;
60
- try {
61
- return read()
62
- } finally {
63
- if (position >= srcEnd || !continueReading) {
64
- // finished reading this source, cleanup references
65
- currentStructures = null;
66
- src = null;
67
- if (referenceMap)
68
- referenceMap = null;
69
- }
70
- }
62
+ return checkedRead()
71
63
  } else if (!currentStructures || currentStructures.length > 0) {
72
64
  currentStructures = [];
73
65
  }
@@ -76,26 +68,19 @@
76
68
  if (!currentStructures || currentStructures.length > 0)
77
69
  currentStructures = [];
78
70
  }
79
- try {
80
- return read()
81
- } finally {
82
- if (position >= srcEnd || !continueReading) {
83
- src = null;
84
- if (referenceMap)
85
- referenceMap = null;
86
- }
87
- }
71
+ return checkedRead()
88
72
  }
89
73
  decodeMultiple(source, forEach) {
74
+ let values, lastPosition = 0;
90
75
  try {
91
- let decoder = this;
92
76
  let size = source.length;
93
- let value = this ? this.decode(source, size, true) : defaultDecoder.decode(source, size, true);
94
- let values;
77
+ sequentialMode = true;
78
+ let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
95
79
  if (forEach) {
96
80
  forEach(value);
97
81
  while(position < size) {
98
- if (forEach(read()) === false) {
82
+ lastPosition = position;
83
+ if (forEach(checkedRead()) === false) {
99
84
  return
100
85
  }
101
86
  }
@@ -103,15 +88,48 @@
103
88
  else {
104
89
  values = [ value ];
105
90
  while(position < size) {
106
- values.push(read());
91
+ lastPosition = position;
92
+ values.push(checkedRead());
107
93
  }
108
94
  return values
109
95
  }
96
+ } catch(error) {
97
+ error.lastPosition = lastPosition;
98
+ error.values = values;
99
+ throw error
110
100
  } finally {
101
+ sequentialMode = false;
111
102
  clearSource();
112
103
  }
113
104
  }
114
105
  }
106
+ function checkedRead() {
107
+ try {
108
+ let result = read();
109
+ if (position == srcEnd) {
110
+ // finished reading this source, cleanup references
111
+ currentStructures = null;
112
+ src = null;
113
+ if (referenceMap)
114
+ referenceMap = null;
115
+ } else if (position > srcEnd) {
116
+ // over read
117
+ let error = new Error('Unexpected end of CBOR data');
118
+ error.incomplete = true;
119
+ throw error
120
+ } else if (!sequentialMode) {
121
+ throw new Error('Data read, but end of buffer not reached')
122
+ }
123
+ // else more to read, but we are reading sequentially, so don't clear source yet
124
+ return result
125
+ } catch(error) {
126
+ clearSource();
127
+ if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
128
+ error.incomplete = true;
129
+ }
130
+ throw error
131
+ }
132
+ }
115
133
 
116
134
  function read() {
117
135
  let token = src[position++];
@@ -176,6 +194,10 @@
176
194
  object[key] = read();
177
195
  return object
178
196
  } else {
197
+ if (restoreMapsAsObject) {
198
+ currentDecoder.mapsAsObjects = true;
199
+ restoreMapsAsObject = false;
200
+ }
179
201
  let map = new Map();
180
202
  while ((key = read()) != STOP_CODE)
181
203
  map.set(key, read());
@@ -222,6 +244,10 @@
222
244
  }
223
245
  return object
224
246
  } else {
247
+ if (restoreMapsAsObject) {
248
+ currentDecoder.mapsAsObjects = true;
249
+ restoreMapsAsObject = false;
250
+ }
225
251
  let map = new Map();
226
252
  for (let i = 0; i < token; i++) {
227
253
  map.set(read(), read());
@@ -693,6 +719,16 @@
693
719
  };
694
720
 
695
721
  currentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md
722
+ (currentExtensions[259] = (read) => {
723
+ // https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
724
+ // for decoding as a standard Map
725
+ if (currentDecoder.mapsAsObjects) {
726
+ currentDecoder.mapsAsObjects = false;
727
+ restoreMapsAsObject = true;
728
+ }
729
+ return read()
730
+ }).handlesRead = true;
731
+
696
732
 
697
733
  const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
698
734
  const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 81, 82];
@@ -719,6 +755,7 @@
719
755
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
720
756
  let savedStructures = currentStructures;
721
757
  let savedDecoder = currentDecoder;
758
+ let savedSequentialMode = sequentialMode;
722
759
  let value = callback();
723
760
  srcEnd = savedSrcEnd;
724
761
  position = savedPosition;
@@ -727,6 +764,7 @@
727
764
  srcString = savedSrcString;
728
765
  referenceMap = savedReferenceMap;
729
766
  src = savedSrc;
767
+ sequentialMode = savedSequentialMode;
730
768
  currentStructures = savedStructures;
731
769
  currentDecoder = savedDecoder;
732
770
  dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
@@ -742,7 +780,7 @@
742
780
  currentExtensions[extension.tag] = extension.decode;
743
781
  }
744
782
 
745
- let mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
783
+ const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
746
784
  for (let i = 0; i < 256; i++) {
747
785
  mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
748
786
  }
@@ -754,7 +792,14 @@
754
792
  ALWAYS: 1,
755
793
  DECIMAL_ROUND: 3,
756
794
  DECIMAL_FIT: 4
757
- };
795
+ };
796
+ let f32Array = new Float32Array(1);
797
+ let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
798
+ function roundFloat32(float32Number) {
799
+ f32Array[0] = float32Number;
800
+ let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
801
+ return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
802
+ }
758
803
 
759
804
  let textEncoder;
760
805
  try {
@@ -799,11 +844,8 @@
799
844
  let recordIdsToRemove = [];
800
845
  let transitionsCount = 0;
801
846
  let serializationsSinceTransitionRebuild = 0;
802
- if (this.structures && this.structures.length > maxSharedStructures) {
803
- throw new Error('Too many shared structures')
804
- }
805
847
 
806
- this.encode = function(value) {
848
+ this.encode = function(value, encodeOptions) {
807
849
  if (!target) {
808
850
  target = new ByteArrayAllocate(8192);
809
851
  targetView = new DataView(target.buffer, 0, 8192);
@@ -816,7 +858,8 @@
816
858
  targetView = new DataView(target.buffer, 0, target.length);
817
859
  safeEnd = target.length - 10;
818
860
  position$1 = 0;
819
- }
861
+ } else if (encodeOptions === REUSE_BUFFER_MODE)
862
+ position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
820
863
  start = position$1;
821
864
  referenceMap = encoder.structuredClone ? new Map() : null;
822
865
  sharedStructures = encoder.structures;
@@ -824,7 +867,7 @@
824
867
  if (sharedStructures.uninitialized)
825
868
  encoder.structures = sharedStructures = encoder.getStructures();
826
869
  let sharedStructuresLength = sharedStructures.length;
827
- if (sharedStructuresLength > maxSharedStructures && !isSequential)
870
+ if (sharedStructuresLength > maxSharedStructures && !isSequential)
828
871
  sharedStructuresLength = maxSharedStructures;
829
872
  if (!sharedStructures.transitions) {
830
873
  // rebuild our structure transitions
@@ -834,8 +877,8 @@
834
877
  if (!keys)
835
878
  continue
836
879
  let nextTransition, transition = sharedStructures.transitions;
837
- for (let i =0, l = keys.length; i < l; i++) {
838
- let key = keys[i];
880
+ for (let j = 0, l = keys.length; j < l; j++) {
881
+ let key = keys[j];
839
882
  nextTransition = transition[key];
840
883
  if (!nextTransition) {
841
884
  nextTransition = transition[key] = Object.create(null);
@@ -864,7 +907,12 @@
864
907
  referenceMap = null;
865
908
  return serialized
866
909
  }
867
- return target.subarray(start, position$1) // position can change if we call encode again in saveStructures, so we get the buffer now
910
+ if (encodeOptions === REUSE_BUFFER_MODE) {
911
+ target.start = start;
912
+ target.end = position$1;
913
+ return target
914
+ }
915
+ return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
868
916
  } finally {
869
917
  if (sharedStructures) {
870
918
  if (serializationsSinceTransitionRebuild < 10)
@@ -878,7 +926,7 @@
878
926
  recordIdsToRemove = [];
879
927
  } else if (recordIdsToRemove.length > 0 && !isSequential) {
880
928
  for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
881
- recordIdsToRemove[i][RECORD_SYMBOL] = 0;
929
+ recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
882
930
  }
883
931
  recordIdsToRemove = [];
884
932
  }
@@ -886,13 +934,15 @@
886
934
  if (encoder.structures.length > maxSharedStructures) {
887
935
  encoder.structures = encoder.structures.slice(0, maxSharedStructures);
888
936
  }
889
-
937
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
938
+ let returnBuffer = target.subarray(start, position$1);
890
939
  if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
891
940
  // get updated structures and try again if the update failed
892
941
  encoder.structures = encoder.getStructures() || [];
893
942
  return encoder.encode(value)
894
943
  }
895
944
  lastSharedStructuresLength = encoder.structures.length;
945
+ return returnBuffer
896
946
  }
897
947
  }
898
948
  }
@@ -1013,7 +1063,7 @@
1013
1063
  targetView.setFloat32(position$1, value);
1014
1064
  let xShifted;
1015
1065
  if (useFloat32 < 4 ||
1016
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1066
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
1017
1067
  ((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
1018
1068
  position$1 += 4;
1019
1069
  return
@@ -1059,6 +1109,12 @@
1059
1109
  encode(value[i]);
1060
1110
  }
1061
1111
  } else if (constructor === Map) {
1112
+ if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
1113
+ // use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way
1114
+ target[position$1++] = 0xd9;
1115
+ target[position$1++] = 1;
1116
+ target[position$1++] = 3;
1117
+ }
1062
1118
  length = value.size;
1063
1119
  if (length < 0x18) {
1064
1120
  target[position$1++] = 0xa0 | length;
@@ -1136,10 +1192,9 @@
1136
1192
  }
1137
1193
  position$1 += 8;
1138
1194
  } else if (type === 'undefined') {
1139
- //target[position++] = 0xc1 // this is the "never-used" byte
1140
1195
  target[position$1++] = 0xf7;
1141
1196
  } else {
1142
- throw new Error('Unknown type ' + type)
1197
+ throw new Error('Unknown type: ' + type)
1143
1198
  }
1144
1199
  };
1145
1200
 
@@ -1228,7 +1283,7 @@
1228
1283
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
1229
1284
  let newTransitions = 0;
1230
1285
  let length = keys.length;
1231
- for (let i =0; i < length; i++) {
1286
+ for (let i = 0; i < length; i++) {
1232
1287
  let key = keys[i];
1233
1288
  nextTransition = transition[key];
1234
1289
  if (!nextTransition) {
@@ -1238,7 +1293,7 @@
1238
1293
  transition = nextTransition;
1239
1294
  }
1240
1295
  let recordId = transition[RECORD_SYMBOL];
1241
- if (recordId) {
1296
+ if (recordId !== undefined) {
1242
1297
  target[position$1++] = 0xd9; // tag two byte
1243
1298
  target[position$1++] = RECORD_STARTING_ID_PREFIX;
1244
1299
  target[position$1++] = recordId;
@@ -1265,7 +1320,7 @@
1265
1320
  transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
1266
1321
  // record the removal of the id, we can maintain our shared structure
1267
1322
  if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
1268
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0; // we are cycling back through, and have to remove old ones
1323
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
1269
1324
  recordIdsToRemove.push(transition);
1270
1325
  if (length < 0x16)
1271
1326
  target[position$1++] = 0x82 + length; // array header, length of values + 2
@@ -1405,7 +1460,9 @@
1405
1460
  }
1406
1461
  function writeBuffer(buffer, makeRoom) {
1407
1462
  let length = buffer.byteLength;
1408
- if (length < 0x100) {
1463
+ if (length < 0x18) {
1464
+ target[position$1++] = 0x40 + length;
1465
+ } else if (length < 0x100) {
1409
1466
  target[position$1++] = 0x58;
1410
1467
  target[position$1++] = length;
1411
1468
  } else if (length < 0x10000) {
@@ -1460,7 +1517,91 @@
1460
1517
  }
1461
1518
  let defaultEncoder = new Encoder({ useRecords: false });
1462
1519
  const encode = defaultEncoder.encode;
1463
- const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1520
+ const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
1521
+ const REUSE_BUFFER_MODE = 1000;
1522
+
1523
+ /**
1524
+ * Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
1525
+ * If the argument is only Async Iterable, the return value will be an Async Iterable.
1526
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
1527
+ * @param {options} [options] - cbor-x Encoder options
1528
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
1529
+ */
1530
+ function encodeIter (objectIterator, options = {}) {
1531
+ if (!objectIterator || typeof objectIterator !== 'object') {
1532
+ throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
1533
+ } else if (typeof objectIterator[Symbol.iterator] === 'function') {
1534
+ return encodeIterSync(objectIterator, options)
1535
+ } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
1536
+ return encodeIterAsync(objectIterator, options)
1537
+ } else {
1538
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
1539
+ }
1540
+ }
1541
+
1542
+ function * encodeIterSync (objectIterator, options) {
1543
+ const encoder = new Encoder(options);
1544
+ for (const value of objectIterator) {
1545
+ yield encoder.encode(value);
1546
+ }
1547
+ }
1548
+
1549
+ async function * encodeIterAsync (objectIterator, options) {
1550
+ const encoder = new Encoder(options);
1551
+ for await (const value of objectIterator) {
1552
+ yield encoder.encode(value);
1553
+ }
1554
+ }
1555
+
1556
+ /**
1557
+ * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
1558
+ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
1559
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
1560
+ * @param {object} [options] - Decoder options
1561
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator}
1562
+ */
1563
+ function decodeIter (bufferIterator, options = {}) {
1564
+ if (!bufferIterator || typeof bufferIterator !== 'object') {
1565
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
1566
+ }
1567
+
1568
+ const decoder = new Decoder(options);
1569
+ let incomplete;
1570
+ const parser = (chunk) => {
1571
+ let yields;
1572
+ // if there's incomplete data from previous chunk, concatinate and try again
1573
+ if (incomplete) {
1574
+ chunk = Buffer.concat([incomplete, chunk]);
1575
+ incomplete = undefined;
1576
+ }
1577
+
1578
+ try {
1579
+ yields = decoder.decodeMultiple(chunk);
1580
+ } catch (err) {
1581
+ if (err.incomplete) {
1582
+ incomplete = chunk.slice(err.lastPosition);
1583
+ yields = err.values;
1584
+ } else {
1585
+ throw err
1586
+ }
1587
+ }
1588
+ return yields
1589
+ };
1590
+
1591
+ if (typeof bufferIterator[Symbol.iterator] === 'function') {
1592
+ return (function * iter () {
1593
+ for (const value of bufferIterator) {
1594
+ yield * parser(value);
1595
+ }
1596
+ })()
1597
+ } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
1598
+ return (async function * iter () {
1599
+ for await (const value of bufferIterator) {
1600
+ yield * parser(value);
1601
+ }
1602
+ })()
1603
+ }
1604
+ }
1464
1605
 
1465
1606
  const useRecords = false;
1466
1607
  const mapsAsObjects = true;
@@ -1474,10 +1615,14 @@
1474
1615
  exports.NEVER = NEVER;
1475
1616
  exports.Tag = Tag;
1476
1617
  exports.addExtension = addExtension$1;
1618
+ exports.clearSource = clearSource;
1477
1619
  exports.decode = decode;
1620
+ exports.decodeIter = decodeIter;
1478
1621
  exports.decodeMultiple = decodeMultiple;
1479
1622
  exports.encode = encode;
1623
+ exports.encodeIter = encodeIter;
1480
1624
  exports.mapsAsObjects = mapsAsObjects;
1625
+ exports.roundFloat32 = roundFloat32;
1481
1626
  exports.useRecords = useRecords;
1482
1627
 
1483
1628
  Object.defineProperty(exports, '__esModule', { value: true });