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/.vscode/launch.json +22 -0
- package/README.md +49 -45
- package/SECURITY.md +11 -0
- package/{unpack.d.ts → decode.d.ts} +12 -11
- package/decode.js +86 -33
- package/dist/index.js +194 -49
- package/dist/index.min.js +65 -51
- package/dist/node.cjs +228 -81
- package/dist/test.js +33 -1
- package/encode.d.ts +6 -0
- package/encode.js +31 -18
- package/index.d.ts +7 -6
- package/index.js +2 -2
- package/iterators.js +85 -0
- package/node-index.js +24 -0
- package/package.json +16 -17
- package/rollup.config.js +5 -5
- package/stream.js +20 -22
- package/tests/benchmark.cjs +13 -7
- package/tests/{test-compatibility.js → test-compatibility.cjs} +7 -12
- package/tests/test-incomplete.js +41 -0
- package/tests/test-node-iterators.js +72 -0
- package/tests/test-node-stream.js +17 -5
- package/tests/test.js +33 -2
- package/index.mjs +0 -35
- package/node.js +0 -25
- package/pack.d.ts +0 -9
- package/tests/test.mjs +0 -31
package/dist/node.cjs
CHANGED
|
@@ -25,10 +25,12 @@ let srcStringEnd = 0;
|
|
|
25
25
|
let referenceMap;
|
|
26
26
|
let currentExtensions = [];
|
|
27
27
|
let dataView;
|
|
28
|
+
let restoreMapsAsObject;
|
|
28
29
|
let defaultOptions = {
|
|
29
30
|
useRecords: false,
|
|
30
31
|
mapsAsObjects: true
|
|
31
32
|
};
|
|
33
|
+
let sequentialMode = false;
|
|
32
34
|
|
|
33
35
|
class Decoder {
|
|
34
36
|
constructor(options) {
|
|
@@ -40,12 +42,12 @@ class Decoder {
|
|
|
40
42
|
}
|
|
41
43
|
Object.assign(this, options);
|
|
42
44
|
}
|
|
43
|
-
decode(source, end
|
|
45
|
+
decode(source, end) {
|
|
44
46
|
if (src) {
|
|
45
47
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
46
48
|
return saveState(() => {
|
|
47
49
|
clearSource();
|
|
48
|
-
return this ? this.decode(source, end
|
|
50
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
49
51
|
})
|
|
50
52
|
}
|
|
51
53
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -63,17 +65,7 @@ class Decoder {
|
|
|
63
65
|
currentDecoder = this;
|
|
64
66
|
if (this.structures) {
|
|
65
67
|
currentStructures = this.structures;
|
|
66
|
-
|
|
67
|
-
return read()
|
|
68
|
-
} finally {
|
|
69
|
-
if (position >= srcEnd || !continueReading) {
|
|
70
|
-
// finished reading this source, cleanup references
|
|
71
|
-
currentStructures = null;
|
|
72
|
-
src = null;
|
|
73
|
-
if (referenceMap)
|
|
74
|
-
referenceMap = null;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
68
|
+
return checkedRead()
|
|
77
69
|
} else if (!currentStructures || currentStructures.length > 0) {
|
|
78
70
|
currentStructures = [];
|
|
79
71
|
}
|
|
@@ -82,26 +74,19 @@ class Decoder {
|
|
|
82
74
|
if (!currentStructures || currentStructures.length > 0)
|
|
83
75
|
currentStructures = [];
|
|
84
76
|
}
|
|
85
|
-
|
|
86
|
-
return read()
|
|
87
|
-
} finally {
|
|
88
|
-
if (position >= srcEnd || !continueReading) {
|
|
89
|
-
src = null;
|
|
90
|
-
if (referenceMap)
|
|
91
|
-
referenceMap = null;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
77
|
+
return checkedRead()
|
|
94
78
|
}
|
|
95
79
|
decodeMultiple(source, forEach) {
|
|
80
|
+
let values, lastPosition = 0;
|
|
96
81
|
try {
|
|
97
|
-
let decoder = this;
|
|
98
82
|
let size = source.length;
|
|
99
|
-
|
|
100
|
-
let
|
|
83
|
+
sequentialMode = true;
|
|
84
|
+
let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
|
|
101
85
|
if (forEach) {
|
|
102
86
|
forEach(value);
|
|
103
87
|
while(position < size) {
|
|
104
|
-
|
|
88
|
+
lastPosition = position;
|
|
89
|
+
if (forEach(checkedRead()) === false) {
|
|
105
90
|
return
|
|
106
91
|
}
|
|
107
92
|
}
|
|
@@ -109,17 +94,47 @@ class Decoder {
|
|
|
109
94
|
else {
|
|
110
95
|
values = [ value ];
|
|
111
96
|
while(position < size) {
|
|
112
|
-
|
|
97
|
+
lastPosition = position;
|
|
98
|
+
values.push(checkedRead());
|
|
113
99
|
}
|
|
114
100
|
return values
|
|
115
101
|
}
|
|
102
|
+
} catch(error) {
|
|
103
|
+
error.lastPosition = lastPosition;
|
|
104
|
+
error.values = values;
|
|
105
|
+
throw error
|
|
116
106
|
} finally {
|
|
107
|
+
sequentialMode = false;
|
|
117
108
|
clearSource();
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
111
|
}
|
|
121
|
-
function
|
|
122
|
-
|
|
112
|
+
function checkedRead() {
|
|
113
|
+
try {
|
|
114
|
+
let result = read();
|
|
115
|
+
if (position == srcEnd) {
|
|
116
|
+
// finished reading this source, cleanup references
|
|
117
|
+
currentStructures = null;
|
|
118
|
+
src = null;
|
|
119
|
+
if (referenceMap)
|
|
120
|
+
referenceMap = null;
|
|
121
|
+
} else if (position > srcEnd) {
|
|
122
|
+
// over read
|
|
123
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
124
|
+
error.incomplete = true;
|
|
125
|
+
throw error
|
|
126
|
+
} else if (!sequentialMode) {
|
|
127
|
+
throw new Error('Data read, but end of buffer not reached')
|
|
128
|
+
}
|
|
129
|
+
// else more to read, but we are reading sequentially, so don't clear source yet
|
|
130
|
+
return result
|
|
131
|
+
} catch(error) {
|
|
132
|
+
clearSource();
|
|
133
|
+
if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
|
|
134
|
+
error.incomplete = true;
|
|
135
|
+
}
|
|
136
|
+
throw error
|
|
137
|
+
}
|
|
123
138
|
}
|
|
124
139
|
|
|
125
140
|
function read() {
|
|
@@ -185,6 +200,10 @@ function read() {
|
|
|
185
200
|
object[key] = read();
|
|
186
201
|
return object
|
|
187
202
|
} else {
|
|
203
|
+
if (restoreMapsAsObject) {
|
|
204
|
+
currentDecoder.mapsAsObjects = true;
|
|
205
|
+
restoreMapsAsObject = false;
|
|
206
|
+
}
|
|
188
207
|
let map = new Map();
|
|
189
208
|
while ((key = read()) != STOP_CODE)
|
|
190
209
|
map.set(key, read());
|
|
@@ -231,6 +250,10 @@ function read() {
|
|
|
231
250
|
}
|
|
232
251
|
return object
|
|
233
252
|
} else {
|
|
253
|
+
if (restoreMapsAsObject) {
|
|
254
|
+
currentDecoder.mapsAsObjects = true;
|
|
255
|
+
restoreMapsAsObject = false;
|
|
256
|
+
}
|
|
234
257
|
let map = new Map();
|
|
235
258
|
for (let i = 0; i < token; i++) {
|
|
236
259
|
map.set(read(), read());
|
|
@@ -338,10 +361,18 @@ function setExtractor(extractStrings) {
|
|
|
338
361
|
return function readString(length) {
|
|
339
362
|
let string = strings[stringPosition++];
|
|
340
363
|
if (string == null) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
364
|
+
let extraction = extractStrings(position, srcEnd, length, src);
|
|
365
|
+
if (typeof extraction == 'string') {
|
|
366
|
+
string = extraction;
|
|
367
|
+
strings = EMPTY_ARRAY;
|
|
368
|
+
} else {
|
|
369
|
+
strings = extraction;
|
|
370
|
+
stringPosition = 1;
|
|
371
|
+
srcStringEnd = 1; // even if a utf-8 string was decoded, must indicate we are in the midst of extracted strings and can't skip strings
|
|
372
|
+
string = strings[0];
|
|
373
|
+
if (string === undefined)
|
|
374
|
+
throw new Error('Unexpected end of buffer')
|
|
375
|
+
}
|
|
345
376
|
}
|
|
346
377
|
let srcStringLength = string.length;
|
|
347
378
|
if (srcStringLength <= length) {
|
|
@@ -727,6 +758,16 @@ currentExtensions[40010] = (id) => {
|
|
|
727
758
|
};
|
|
728
759
|
|
|
729
760
|
currentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md
|
|
761
|
+
(currentExtensions[259] = (read) => {
|
|
762
|
+
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
763
|
+
// for decoding as a standard Map
|
|
764
|
+
if (currentDecoder.mapsAsObjects) {
|
|
765
|
+
currentDecoder.mapsAsObjects = false;
|
|
766
|
+
restoreMapsAsObject = true;
|
|
767
|
+
}
|
|
768
|
+
return read()
|
|
769
|
+
}).handlesRead = true;
|
|
770
|
+
|
|
730
771
|
|
|
731
772
|
const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
|
|
732
773
|
const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 81, 82];
|
|
@@ -755,6 +796,7 @@ function saveState(callback) {
|
|
|
755
796
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
756
797
|
let savedStructures = currentStructures;
|
|
757
798
|
let savedDecoder = currentDecoder;
|
|
799
|
+
let savedSequentialMode = sequentialMode;
|
|
758
800
|
let value = callback();
|
|
759
801
|
srcEnd = savedSrcEnd;
|
|
760
802
|
position = savedPosition;
|
|
@@ -765,6 +807,7 @@ function saveState(callback) {
|
|
|
765
807
|
strings = savedStrings;
|
|
766
808
|
referenceMap = savedReferenceMap;
|
|
767
809
|
src = savedSrc;
|
|
810
|
+
sequentialMode = savedSequentialMode;
|
|
768
811
|
currentStructures = savedStructures;
|
|
769
812
|
currentDecoder = savedDecoder;
|
|
770
813
|
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
@@ -780,7 +823,7 @@ function addExtension(extension) {
|
|
|
780
823
|
currentExtensions[extension.tag] = extension.decode;
|
|
781
824
|
}
|
|
782
825
|
|
|
783
|
-
|
|
826
|
+
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
784
827
|
for (let i = 0; i < 256; i++) {
|
|
785
828
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
|
|
786
829
|
}
|
|
@@ -792,7 +835,14 @@ const FLOAT32_OPTIONS = {
|
|
|
792
835
|
ALWAYS: 1,
|
|
793
836
|
DECIMAL_ROUND: 3,
|
|
794
837
|
DECIMAL_FIT: 4
|
|
795
|
-
};
|
|
838
|
+
};
|
|
839
|
+
let f32Array = new Float32Array(1);
|
|
840
|
+
let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
|
|
841
|
+
function roundFloat32(float32Number) {
|
|
842
|
+
f32Array[0] = float32Number;
|
|
843
|
+
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
|
|
844
|
+
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
|
|
845
|
+
}
|
|
796
846
|
|
|
797
847
|
let textEncoder;
|
|
798
848
|
try {
|
|
@@ -837,11 +887,8 @@ class Encoder extends Decoder {
|
|
|
837
887
|
let recordIdsToRemove = [];
|
|
838
888
|
let transitionsCount = 0;
|
|
839
889
|
let serializationsSinceTransitionRebuild = 0;
|
|
840
|
-
if (this.structures && this.structures.length > maxSharedStructures) {
|
|
841
|
-
throw new Error('Too many shared structures')
|
|
842
|
-
}
|
|
843
890
|
|
|
844
|
-
this.encode = function(value) {
|
|
891
|
+
this.encode = function(value, encodeOptions) {
|
|
845
892
|
if (!target) {
|
|
846
893
|
target = new ByteArrayAllocate(8192);
|
|
847
894
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -854,7 +901,8 @@ class Encoder extends Decoder {
|
|
|
854
901
|
targetView = new DataView(target.buffer, 0, target.length);
|
|
855
902
|
safeEnd = target.length - 10;
|
|
856
903
|
position$1 = 0;
|
|
857
|
-
}
|
|
904
|
+
} else if (encodeOptions === REUSE_BUFFER_MODE)
|
|
905
|
+
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
858
906
|
start = position$1;
|
|
859
907
|
referenceMap = encoder.structuredClone ? new Map() : null;
|
|
860
908
|
sharedStructures = encoder.structures;
|
|
@@ -862,7 +910,7 @@ class Encoder extends Decoder {
|
|
|
862
910
|
if (sharedStructures.uninitialized)
|
|
863
911
|
encoder.structures = sharedStructures = encoder.getStructures();
|
|
864
912
|
let sharedStructuresLength = sharedStructures.length;
|
|
865
|
-
if (sharedStructuresLength >
|
|
913
|
+
if (sharedStructuresLength > maxSharedStructures && !isSequential)
|
|
866
914
|
sharedStructuresLength = maxSharedStructures;
|
|
867
915
|
if (!sharedStructures.transitions) {
|
|
868
916
|
// rebuild our structure transitions
|
|
@@ -872,8 +920,8 @@ class Encoder extends Decoder {
|
|
|
872
920
|
if (!keys)
|
|
873
921
|
continue
|
|
874
922
|
let nextTransition, transition = sharedStructures.transitions;
|
|
875
|
-
for (let
|
|
876
|
-
let key = keys[
|
|
923
|
+
for (let j = 0, l = keys.length; j < l; j++) {
|
|
924
|
+
let key = keys[j];
|
|
877
925
|
nextTransition = transition[key];
|
|
878
926
|
if (!nextTransition) {
|
|
879
927
|
nextTransition = transition[key] = Object.create(null);
|
|
@@ -902,7 +950,12 @@ class Encoder extends Decoder {
|
|
|
902
950
|
referenceMap = null;
|
|
903
951
|
return serialized
|
|
904
952
|
}
|
|
905
|
-
|
|
953
|
+
if (encodeOptions === REUSE_BUFFER_MODE) {
|
|
954
|
+
target.start = start;
|
|
955
|
+
target.end = position$1;
|
|
956
|
+
return target
|
|
957
|
+
}
|
|
958
|
+
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
906
959
|
} finally {
|
|
907
960
|
if (sharedStructures) {
|
|
908
961
|
if (serializationsSinceTransitionRebuild < 10)
|
|
@@ -916,7 +969,7 @@ class Encoder extends Decoder {
|
|
|
916
969
|
recordIdsToRemove = [];
|
|
917
970
|
} else if (recordIdsToRemove.length > 0 && !isSequential) {
|
|
918
971
|
for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
|
|
919
|
-
recordIdsToRemove[i][RECORD_SYMBOL] =
|
|
972
|
+
recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
|
|
920
973
|
}
|
|
921
974
|
recordIdsToRemove = [];
|
|
922
975
|
}
|
|
@@ -924,13 +977,15 @@ class Encoder extends Decoder {
|
|
|
924
977
|
if (encoder.structures.length > maxSharedStructures) {
|
|
925
978
|
encoder.structures = encoder.structures.slice(0, maxSharedStructures);
|
|
926
979
|
}
|
|
927
|
-
|
|
980
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
981
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
928
982
|
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
|
|
929
983
|
// get updated structures and try again if the update failed
|
|
930
984
|
encoder.structures = encoder.getStructures() || [];
|
|
931
985
|
return encoder.encode(value)
|
|
932
986
|
}
|
|
933
987
|
lastSharedStructuresLength = encoder.structures.length;
|
|
988
|
+
return returnBuffer
|
|
934
989
|
}
|
|
935
990
|
}
|
|
936
991
|
}
|
|
@@ -1051,7 +1106,7 @@ class Encoder extends Decoder {
|
|
|
1051
1106
|
targetView.setFloat32(position$1, value);
|
|
1052
1107
|
let xShifted;
|
|
1053
1108
|
if (useFloat32 < 4 ||
|
|
1054
|
-
|
|
1109
|
+
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
1055
1110
|
((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
|
|
1056
1111
|
position$1 += 4;
|
|
1057
1112
|
return
|
|
@@ -1097,6 +1152,12 @@ class Encoder extends Decoder {
|
|
|
1097
1152
|
encode(value[i]);
|
|
1098
1153
|
}
|
|
1099
1154
|
} else if (constructor === Map) {
|
|
1155
|
+
if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
|
|
1156
|
+
// 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
|
|
1157
|
+
target[position$1++] = 0xd9;
|
|
1158
|
+
target[position$1++] = 1;
|
|
1159
|
+
target[position$1++] = 3;
|
|
1160
|
+
}
|
|
1100
1161
|
length = value.size;
|
|
1101
1162
|
if (length < 0x18) {
|
|
1102
1163
|
target[position$1++] = 0xa0 | length;
|
|
@@ -1174,10 +1235,9 @@ class Encoder extends Decoder {
|
|
|
1174
1235
|
}
|
|
1175
1236
|
position$1 += 8;
|
|
1176
1237
|
} else if (type === 'undefined') {
|
|
1177
|
-
//target[position++] = 0xc1 // this is the "never-used" byte
|
|
1178
1238
|
target[position$1++] = 0xf7;
|
|
1179
1239
|
} else {
|
|
1180
|
-
throw new Error('Unknown type ' + type)
|
|
1240
|
+
throw new Error('Unknown type: ' + type)
|
|
1181
1241
|
}
|
|
1182
1242
|
};
|
|
1183
1243
|
|
|
@@ -1266,7 +1326,7 @@ class Encoder extends Decoder {
|
|
|
1266
1326
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1267
1327
|
let newTransitions = 0;
|
|
1268
1328
|
let length = keys.length;
|
|
1269
|
-
for (let i =0; i < length; i++) {
|
|
1329
|
+
for (let i = 0; i < length; i++) {
|
|
1270
1330
|
let key = keys[i];
|
|
1271
1331
|
nextTransition = transition[key];
|
|
1272
1332
|
if (!nextTransition) {
|
|
@@ -1276,7 +1336,7 @@ class Encoder extends Decoder {
|
|
|
1276
1336
|
transition = nextTransition;
|
|
1277
1337
|
}
|
|
1278
1338
|
let recordId = transition[RECORD_SYMBOL];
|
|
1279
|
-
if (recordId) {
|
|
1339
|
+
if (recordId !== undefined) {
|
|
1280
1340
|
target[position$1++] = 0xd9; // tag two byte
|
|
1281
1341
|
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
1282
1342
|
target[position$1++] = recordId;
|
|
@@ -1303,7 +1363,7 @@ class Encoder extends Decoder {
|
|
|
1303
1363
|
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1304
1364
|
// record the removal of the id, we can maintain our shared structure
|
|
1305
1365
|
if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
|
|
1306
|
-
recordIdsToRemove.shift()[RECORD_SYMBOL] =
|
|
1366
|
+
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1307
1367
|
recordIdsToRemove.push(transition);
|
|
1308
1368
|
if (length < 0x16)
|
|
1309
1369
|
target[position$1++] = 0x82 + length; // array header, length of values + 2
|
|
@@ -1443,7 +1503,9 @@ function typedArrayEncoder(tag) {
|
|
|
1443
1503
|
}
|
|
1444
1504
|
function writeBuffer(buffer, makeRoom) {
|
|
1445
1505
|
let length = buffer.byteLength;
|
|
1446
|
-
if (length <
|
|
1506
|
+
if (length < 0x18) {
|
|
1507
|
+
target[position$1++] = 0x40 + length;
|
|
1508
|
+
} else if (length < 0x100) {
|
|
1447
1509
|
target[position$1++] = 0x58;
|
|
1448
1510
|
target[position$1++] = length;
|
|
1449
1511
|
} else if (length < 0x10000) {
|
|
@@ -1498,24 +1560,21 @@ function addExtension$1(extension) {
|
|
|
1498
1560
|
}
|
|
1499
1561
|
let defaultEncoder = new Encoder({ useRecords: false });
|
|
1500
1562
|
const encode = defaultEncoder.encode;
|
|
1501
|
-
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1563
|
+
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1564
|
+
const REUSE_BUFFER_MODE = 1000;
|
|
1502
1565
|
|
|
1503
1566
|
class EncoderStream extends stream.Transform {
|
|
1504
1567
|
constructor(options) {
|
|
1505
1568
|
if (!options)
|
|
1506
1569
|
options = {};
|
|
1570
|
+
options.writableObjectMode = true;
|
|
1507
1571
|
super(options);
|
|
1508
1572
|
options.sequential = true;
|
|
1509
|
-
this.encoder = new Encoder(options);
|
|
1573
|
+
this.encoder = options.encoder || new Encoder(options);
|
|
1510
1574
|
}
|
|
1511
|
-
|
|
1575
|
+
_transform(value, encoding, callback) {
|
|
1512
1576
|
this.push(this.encoder.encode(value));
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
end(value) {
|
|
1516
|
-
if (value != null)
|
|
1517
|
-
this.push(this.encoder.encode(value));
|
|
1518
|
-
this.push(null);
|
|
1577
|
+
callback();
|
|
1519
1578
|
}
|
|
1520
1579
|
}
|
|
1521
1580
|
|
|
@@ -1526,53 +1585,136 @@ class DecoderStream extends stream.Transform {
|
|
|
1526
1585
|
options.objectMode = true;
|
|
1527
1586
|
super(options);
|
|
1528
1587
|
options.structures = [];
|
|
1529
|
-
this.decoder = new Decoder(options);
|
|
1588
|
+
this.decoder = options.decoder || new Decoder(options);
|
|
1530
1589
|
}
|
|
1531
1590
|
_transform(chunk, encoding, callback) {
|
|
1532
1591
|
if (this.incompleteBuffer) {
|
|
1533
1592
|
chunk = Buffer.concat([this.incompleteBuffer, chunk]);
|
|
1534
1593
|
this.incompleteBuffer = null;
|
|
1535
1594
|
}
|
|
1536
|
-
let
|
|
1537
|
-
let size = chunk.length;
|
|
1595
|
+
let values;
|
|
1538
1596
|
try {
|
|
1539
|
-
this.
|
|
1540
|
-
position = getPosition();
|
|
1541
|
-
while (position < size) {
|
|
1542
|
-
let value = read();
|
|
1543
|
-
this.push(value);
|
|
1544
|
-
position = getPosition();
|
|
1545
|
-
}
|
|
1597
|
+
values = this.decoder.decodeMultiple(chunk);
|
|
1546
1598
|
} catch(error) {
|
|
1547
|
-
if (error.incomplete)
|
|
1548
|
-
this.incompleteBuffer = chunk.slice(
|
|
1599
|
+
if (error.incomplete) {
|
|
1600
|
+
this.incompleteBuffer = chunk.slice(error.lastPosition);
|
|
1601
|
+
values = error.values;
|
|
1602
|
+
}
|
|
1549
1603
|
else
|
|
1550
1604
|
throw error
|
|
1551
1605
|
} finally {
|
|
1552
|
-
|
|
1606
|
+
for (let value of values || []) {
|
|
1607
|
+
if (value === null)
|
|
1608
|
+
value = this.getNullValue();
|
|
1609
|
+
this.push(value);
|
|
1610
|
+
}
|
|
1553
1611
|
}
|
|
1554
1612
|
if (callback) callback();
|
|
1555
1613
|
}
|
|
1614
|
+
getNullValue() {
|
|
1615
|
+
return Symbol.for(null)
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
|
|
1621
|
+
* If the argument is only Async Iterable, the return value will be an Async Iterable.
|
|
1622
|
+
* @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
|
|
1623
|
+
* @param {options} [options] - cbor-x Encoder options
|
|
1624
|
+
* @returns {IterableIterator|Promise.<AsyncIterableIterator>}
|
|
1625
|
+
*/
|
|
1626
|
+
function encodeIter (objectIterator, options = {}) {
|
|
1627
|
+
if (!objectIterator || typeof objectIterator !== 'object') {
|
|
1628
|
+
throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
|
|
1629
|
+
} else if (typeof objectIterator[Symbol.iterator] === 'function') {
|
|
1630
|
+
return encodeIterSync(objectIterator, options)
|
|
1631
|
+
} else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
|
|
1632
|
+
return encodeIterAsync(objectIterator, options)
|
|
1633
|
+
} else {
|
|
1634
|
+
throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
function * encodeIterSync (objectIterator, options) {
|
|
1639
|
+
const encoder = new Encoder(options);
|
|
1640
|
+
for (const value of objectIterator) {
|
|
1641
|
+
yield encoder.encode(value);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
async function * encodeIterAsync (objectIterator, options) {
|
|
1646
|
+
const encoder = new Encoder(options);
|
|
1647
|
+
for await (const value of objectIterator) {
|
|
1648
|
+
yield encoder.encode(value);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/**
|
|
1653
|
+
* Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
|
|
1654
|
+
* Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
|
|
1655
|
+
* @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
|
|
1656
|
+
* @param {object} [options] - Decoder options
|
|
1657
|
+
* @returns {IterableIterator|Promise.<AsyncIterableIterator}
|
|
1658
|
+
*/
|
|
1659
|
+
function decodeIter (bufferIterator, options = {}) {
|
|
1660
|
+
if (!bufferIterator || typeof bufferIterator !== 'object') {
|
|
1661
|
+
throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
const decoder = new Decoder(options);
|
|
1665
|
+
let incomplete;
|
|
1666
|
+
const parser = (chunk) => {
|
|
1667
|
+
let yields;
|
|
1668
|
+
// if there's incomplete data from previous chunk, concatinate and try again
|
|
1669
|
+
if (incomplete) {
|
|
1670
|
+
chunk = Buffer.concat([incomplete, chunk]);
|
|
1671
|
+
incomplete = undefined;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
try {
|
|
1675
|
+
yields = decoder.decodeMultiple(chunk);
|
|
1676
|
+
} catch (err) {
|
|
1677
|
+
if (err.incomplete) {
|
|
1678
|
+
incomplete = chunk.slice(err.lastPosition);
|
|
1679
|
+
yields = err.values;
|
|
1680
|
+
} else {
|
|
1681
|
+
throw err
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return yields
|
|
1685
|
+
};
|
|
1686
|
+
|
|
1687
|
+
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
1688
|
+
return (function * iter () {
|
|
1689
|
+
for (const value of bufferIterator) {
|
|
1690
|
+
yield * parser(value);
|
|
1691
|
+
}
|
|
1692
|
+
})()
|
|
1693
|
+
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
1694
|
+
return (async function * iter () {
|
|
1695
|
+
for await (const value of bufferIterator) {
|
|
1696
|
+
yield * parser(value);
|
|
1697
|
+
}
|
|
1698
|
+
})()
|
|
1699
|
+
}
|
|
1556
1700
|
}
|
|
1557
1701
|
|
|
1558
1702
|
const useRecords = false;
|
|
1559
1703
|
const mapsAsObjects = true;
|
|
1560
1704
|
|
|
1561
|
-
const extractor = tryRequire('
|
|
1705
|
+
const extractor = tryRequire('cbor-extract');
|
|
1562
1706
|
if (extractor)
|
|
1563
1707
|
setExtractor(extractor.extractStrings);
|
|
1564
|
-
|
|
1565
|
-
Object.assign(exports, unpackModule.FLOAT32_OPTIONS)
|
|
1566
|
-
*/
|
|
1708
|
+
|
|
1567
1709
|
function tryRequire(moduleId) {
|
|
1568
1710
|
try {
|
|
1569
1711
|
let require$1 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('node.cjs', document.baseURI).href)));
|
|
1570
1712
|
return require$1(moduleId)
|
|
1571
1713
|
} catch (error) {
|
|
1572
1714
|
if (typeof window == 'undefined')
|
|
1573
|
-
console.warn('Native extraction module not loaded,
|
|
1715
|
+
console.warn('Native extraction module not loaded, cbor-x will still run, but with decreased performance. ' + error.message.split('\n')[0]);
|
|
1574
1716
|
else
|
|
1575
|
-
console.warn('For browser usage, directly use
|
|
1717
|
+
console.warn('For browser usage, directly use cbor-x/decode or cbor-x/encode modules. ' + error.message.split('\n')[0]);
|
|
1576
1718
|
}
|
|
1577
1719
|
}
|
|
1578
1720
|
|
|
@@ -1585,10 +1727,15 @@ exports.Encoder = Encoder;
|
|
|
1585
1727
|
exports.EncoderStream = EncoderStream;
|
|
1586
1728
|
exports.FLOAT32_OPTIONS = FLOAT32_OPTIONS;
|
|
1587
1729
|
exports.NEVER = NEVER;
|
|
1730
|
+
exports.REUSE_BUFFER_MODE = REUSE_BUFFER_MODE;
|
|
1588
1731
|
exports.Tag = Tag;
|
|
1589
1732
|
exports.addExtension = addExtension$1;
|
|
1733
|
+
exports.clearSource = clearSource;
|
|
1590
1734
|
exports.decode = decode;
|
|
1735
|
+
exports.decodeIter = decodeIter;
|
|
1591
1736
|
exports.decodeMultiple = decodeMultiple;
|
|
1592
1737
|
exports.encode = encode;
|
|
1738
|
+
exports.encodeIter = encodeIter;
|
|
1593
1739
|
exports.mapsAsObjects = mapsAsObjects;
|
|
1740
|
+
exports.roundFloat32 = roundFloat32;
|
|
1594
1741
|
exports.useRecords = useRecords;
|
package/dist/test.js
CHANGED
|
@@ -581,7 +581,7 @@
|
|
|
581
581
|
outcomesScore: outcomesScore
|
|
582
582
|
};
|
|
583
583
|
|
|
584
|
-
//import inspector from 'inspector'; inspector.open(
|
|
584
|
+
//import inspector from 'inspector'; inspector.open(9229, null, true); debugger
|
|
585
585
|
function tryRequire(module) {
|
|
586
586
|
try {
|
|
587
587
|
return require(module)
|
|
@@ -659,6 +659,13 @@
|
|
|
659
659
|
assert.deepEqual(deserialized, data);
|
|
660
660
|
});
|
|
661
661
|
|
|
662
|
+
test('255 chars', function() {
|
|
663
|
+
const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W';
|
|
664
|
+
var serialized = CBOR.encode(data);
|
|
665
|
+
var deserialized = CBOR.decode(serialized);
|
|
666
|
+
assert.equal(deserialized, data);
|
|
667
|
+
});
|
|
668
|
+
|
|
662
669
|
test('encode/decode sample data', function(){
|
|
663
670
|
var data = sampleData;
|
|
664
671
|
var serialized = CBOR.encode(data);
|
|
@@ -787,10 +794,13 @@
|
|
|
787
794
|
let fa = new Float32Array(b.buffer, 8, 2);
|
|
788
795
|
fa[0] = 2.25;
|
|
789
796
|
fa[1] = 6;
|
|
797
|
+
let map = new Map();
|
|
798
|
+
map.set('key', 'value');
|
|
790
799
|
let object = {
|
|
791
800
|
error: new Error('test'),
|
|
792
801
|
set: new Set(['a', 'b']),
|
|
793
802
|
regexp: /test/gi,
|
|
803
|
+
map,
|
|
794
804
|
float32Array: fa,
|
|
795
805
|
uint16Array: new Uint16Array([3,4])
|
|
796
806
|
};
|
|
@@ -800,6 +810,7 @@
|
|
|
800
810
|
var serialized = encoder.encode(object);
|
|
801
811
|
var deserialized = encoder.decode(serialized);
|
|
802
812
|
assert.deepEqual(Array.from(deserialized.set), Array.from(object.set));
|
|
813
|
+
assert.equal(deserialized.map.get('key'), 'value');
|
|
803
814
|
assert.equal(deserialized.error.message, object.error.message);
|
|
804
815
|
assert.equal(deserialized.regexp.test('TEST'), true);
|
|
805
816
|
assert.equal(deserialized.float32Array.constructor.name, 'Float32Array');
|
|
@@ -810,6 +821,19 @@
|
|
|
810
821
|
assert.equal(deserialized.uint16Array[1], 4);
|
|
811
822
|
});
|
|
812
823
|
|
|
824
|
+
test('explicit maps and sets', function () {
|
|
825
|
+
let map = new Map();
|
|
826
|
+
map.set('key', { inside: 'value'});
|
|
827
|
+
let object = {
|
|
828
|
+
set: new Set(['a', 'b']),
|
|
829
|
+
map,
|
|
830
|
+
};
|
|
831
|
+
var serialized = encode(object); // default encoder
|
|
832
|
+
var deserialized = decode(serialized);
|
|
833
|
+
assert.deepEqual(Array.from(deserialized.set), Array.from(object.set));
|
|
834
|
+
assert.equal(deserialized.map.get('key').inside, 'value');
|
|
835
|
+
});
|
|
836
|
+
|
|
813
837
|
test('object without prototype', function(){
|
|
814
838
|
var data = Object.create(null);
|
|
815
839
|
data.test = 3;
|
|
@@ -825,6 +849,13 @@
|
|
|
825
849
|
var decoded = decode(encoded);
|
|
826
850
|
assert.equal(decoded.length, size);
|
|
827
851
|
});
|
|
852
|
+
test('little buffer', function() {
|
|
853
|
+
var data = typeof Buffer == 'undefined' ? new Uint8Array(0) : Buffer.alloc(0);
|
|
854
|
+
var encoded = encode(data);
|
|
855
|
+
assert.equal(encoded.length, 1); // make sure to use canonical form
|
|
856
|
+
var decoded = decode(encoded);
|
|
857
|
+
assert.equal(decoded.length, 0);
|
|
858
|
+
});
|
|
828
859
|
|
|
829
860
|
test('random strings', function(){
|
|
830
861
|
var data = [];
|
|
@@ -872,6 +903,7 @@
|
|
|
872
903
|
let encoder = new Encoder({
|
|
873
904
|
mapsAsObjects: true,
|
|
874
905
|
useTimestamp32: true,
|
|
906
|
+
useTag259ForMaps: false,
|
|
875
907
|
});
|
|
876
908
|
var serialized = encoder.encode(data);
|
|
877
909
|
var deserialized = encoder.decode(serialized);
|