msgpackr 1.8.5 → 1.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/README.md CHANGED
@@ -173,8 +173,10 @@ The following options properties can be provided to the Packr or Unpackr constru
173
173
  * `sequential` - Encode structures in serialized data, and reference previously encoded structures with expectation that decoder will read the encoded structures in the same order as encoded, with `unpackMultiple`.
174
174
  * `largeBigIntToFloat` - If a bigint needs to be encoded that is larger than will fit in 64-bit integers, it will be encoded as a float-64 (otherwise will throw a RangeError).
175
175
  * `encodeUndefinedAsNil` - Encodes a value of `undefined` as a MessagePack `nil`, the same as a `null`.
176
- * `int64AsType` - This will decode uint64 and int64 numbers as the specified type. The type can be `bigint` (default), `number`, or `string`.
176
+ * `int64AsType` - This will decode uint64 and int64 numbers as the specified type. The type can be `bigint` (default), `number`, `string`, or `auto` (where range [-2^53...2^53] is represented by number and everything else by a bigint).
177
177
  * `onInvalidDate` - This can be provided as function that will be called when an invalid date is provided. The function can throw an error, or return a value that will be encoded in place of the invalid date. If not provided, an invalid date will be encoded as an invalid timestamp (which decodes with msgpackr back to an invalid date).
178
+ * `mapAsEmptyObject` - Encodes JS `Map`s as empty objects (for back-compat with older libraries).
179
+ * `setAsEmptyObject` - Encodes JS `Set`s as empty objects (for back-compat with older libraries).
178
180
 
179
181
  ### 32-bit Float Options
180
182
  By default all non-integer numbers are serialized as 64-bit float (double). This is fast, and ensures maximum precision. However, often real-world data doesn't not need 64-bits of precision, and using 32-bit encoding can be much more space efficient. There are several options that provide more efficient encodings. Using the decimal rounding options for encoding and decoding provides lossless storage of common decimal representations like 7.99, in more efficient 32-bit format (rather than 64-bit). The `useFloat32` property has several possible options, available from the module as constants:
@@ -72,6 +72,8 @@
72
72
  return this ? this.unpack(source, options) : Unpackr.prototype.unpack.call(defaultOptions, source, options)
73
73
  })
74
74
  }
75
+ if (!source.buffer && source.constructor === ArrayBuffer)
76
+ source = typeof Buffer !== 'undefined' ? Buffer.from(source) : new Uint8Array(source);
75
77
  if (typeof options === 'object') {
76
78
  srcEnd = options.end || source.length;
77
79
  position$1 = options.start || 0;
@@ -205,7 +207,13 @@
205
207
  // over read
206
208
  throw new Error('Unexpected end of MessagePack data')
207
209
  } else if (!sequentialMode) {
208
- throw new Error('Data read, but end of buffer not reached ' + JSON.stringify(result).slice(0, 100))
210
+ let jsonView;
211
+ try {
212
+ jsonView = JSON.stringify(result, (_, value) => typeof value === "bigint" ? `${value}n` : value).slice(0, 100);
213
+ } catch(error) {
214
+ jsonView = '(JSON view not available ' + error + ')';
215
+ }
216
+ throw new Error('Data read, but end of buffer not reached ' + jsonView)
209
217
  }
210
218
  // else more to read, but we are reading sequentially, so don't clear source yet
211
219
  return result
@@ -361,6 +369,9 @@
361
369
  value += dataView.getUint32(position$1 + 4);
362
370
  } else if (currentUnpackr.int64AsType === 'string') {
363
371
  value = dataView.getBigUint64(position$1).toString();
372
+ } else if (currentUnpackr.int64AsType === 'auto') {
373
+ value = dataView.getBigUint64(position$1);
374
+ if (value<=BigInt(2)<<BigInt(52)) value=Number(value);
364
375
  } else
365
376
  value = dataView.getBigUint64(position$1);
366
377
  position$1 += 8;
@@ -383,6 +394,9 @@
383
394
  value += dataView.getUint32(position$1 + 4);
384
395
  } else if (currentUnpackr.int64AsType === 'string') {
385
396
  value = dataView.getBigInt64(position$1).toString();
397
+ } else if (currentUnpackr.int64AsType === 'auto') {
398
+ value = dataView.getBigInt64(position$1);
399
+ if (value>=BigInt(-2)<<BigInt(52)&&value<=BigInt(2)<<BigInt(52)) value=Number(value);
386
400
  } else
387
401
  value = dataView.getBigInt64(position$1);
388
402
  position$1 += 8;
@@ -912,9 +926,10 @@
912
926
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
913
927
  currentExtensions[0].noBuffer = true;
914
928
 
929
+ let global = typeof globalThis === 'object' ? globalThis : window;
915
930
  currentExtensions[0x65] = () => {
916
931
  let data = read();
917
- return (globalThis[data[0]] || Error)(data[1])
932
+ return (global[data[0]] || Error)(data[1])
918
933
  };
919
934
 
920
935
  currentExtensions[0x69] = (data) => {
@@ -958,7 +973,7 @@
958
973
  if (!typedArrayName)
959
974
  throw new Error('Could not find typed array for code ' + typeCode)
960
975
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
961
- return new globalThis[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
976
+ return new global[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
962
977
  };
963
978
  currentExtensions[0x78] = () => {
964
979
  let data = read();
@@ -1184,7 +1199,7 @@
1184
1199
  if (hasSharedUpdate)
1185
1200
  hasSharedUpdate = false;
1186
1201
  try {
1187
- if (packr.randomAccessStructure && value.constructor && value.constructor === Object)
1202
+ if (packr.randomAccessStructure && value && value.constructor && value.constructor === Object)
1188
1203
  writeStruct(value);
1189
1204
  else
1190
1205
  pack(value);
@@ -1471,21 +1486,24 @@
1471
1486
  } else if (constructor === Array) {
1472
1487
  packArray(value);
1473
1488
  } else if (constructor === Map) {
1474
- length = value.size;
1475
- if (length < 0x10) {
1476
- target[position++] = 0x80 | length;
1477
- } else if (length < 0x10000) {
1478
- target[position++] = 0xde;
1479
- target[position++] = length >> 8;
1480
- target[position++] = length & 0xff;
1481
- } else {
1482
- target[position++] = 0xdf;
1483
- targetView.setUint32(position, length);
1484
- position += 4;
1485
- }
1486
- for (let [ key, entryValue ] of value) {
1487
- pack(key);
1488
- pack(entryValue);
1489
+ if (this.mapAsEmptyObject) target[position++] = 0x80;
1490
+ else {
1491
+ length = value.size;
1492
+ if (length < 0x10) {
1493
+ target[position++] = 0x80 | length;
1494
+ } else if (length < 0x10000) {
1495
+ target[position++] = 0xde;
1496
+ target[position++] = length >> 8;
1497
+ target[position++] = length & 0xff;
1498
+ } else {
1499
+ target[position++] = 0xdf;
1500
+ targetView.setUint32(position, length);
1501
+ position += 4;
1502
+ }
1503
+ for (let [key, entryValue] of value) {
1504
+ pack(key);
1505
+ pack(entryValue);
1506
+ }
1489
1507
  }
1490
1508
  } else {
1491
1509
  for (let i = 0, l = extensions.length; i < l; i++) {
@@ -1548,6 +1566,8 @@
1548
1566
  if (Array.isArray(value)) {
1549
1567
  packArray(value);
1550
1568
  } else {
1569
+ if (value.toJSON) // use this as an alternate mechanism for expressing how to serialize
1570
+ return pack(value.toJSON());
1551
1571
  // no extension found, write as object
1552
1572
  writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
1553
1573
  }
@@ -1868,6 +1888,7 @@
1868
1888
  }
1869
1889
  }, {
1870
1890
  pack(set, allocateForWrite, pack) {
1891
+ if (this.setAsEmptyObject) return pack({})
1871
1892
  let array = Array.from(set);
1872
1893
  let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
1873
1894
  if (this.moreTypes) {