msgpackr 1.11.1 → 1.11.3

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
@@ -915,7 +915,10 @@
915
915
  if (typeof property === 'string') return property;
916
916
  if (typeof property === 'number' || typeof property === 'boolean' || typeof property === 'bigint') return property.toString();
917
917
  if (property == null) return property + '';
918
- throw new Error('Invalid property type for record', typeof property);
918
+ if (currentUnpackr.allowArraysInMapKeys && Array.isArray(property) && property.flat().every(item => ['string', 'number', 'boolean', 'bigint'].includes(typeof item))) {
919
+ return property.flat().toString();
920
+ }
921
+ throw new Error(`Invalid property type for record: ${typeof property}`);
919
922
  }
920
923
  // the registration of the record definition extension (as "r")
921
924
  const recordDefinition = (id, highByte) => {
@@ -940,21 +943,47 @@
940
943
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
941
944
  currentExtensions[0].noBuffer = true;
942
945
 
943
- currentExtensions[0x42] = (data) => {
944
- // decode bigint
945
- let length = data.length;
946
- let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
947
- for (let i = 1; i < length; i++) {
948
- value <<= BigInt(8);
949
- value += BigInt(data[i]);
946
+ currentExtensions[0x42] = data => {
947
+ let headLength = (data.byteLength % 8) || 8;
948
+ let head = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
949
+ for (let i = 1; i < headLength; i++) {
950
+ head <<= BigInt(8);
951
+ head += BigInt(data[i]);
950
952
  }
951
- return value;
953
+ if (data.byteLength !== headLength) {
954
+ let view = new DataView(data.buffer, data.byteOffset, data.byteLength);
955
+ let decode = (start, end) => {
956
+ let length = end - start;
957
+ if (length <= 40) {
958
+ let out = view.getBigUint64(start);
959
+ for (let i = start + 8; i < end; i += 8) {
960
+ out <<= BigInt(64n);
961
+ out |= view.getBigUint64(i);
962
+ }
963
+ return out
964
+ }
965
+ // if (length === 8) return view.getBigUint64(start)
966
+ let middle = start + (length >> 4 << 3);
967
+ let left = decode(start, middle);
968
+ let right = decode(middle, end);
969
+ return (left << BigInt((end - middle) * 8)) | right
970
+ };
971
+ head = (head << BigInt((view.byteLength - headLength) * 8)) | decode(headLength, view.byteLength);
972
+ }
973
+ return head
952
974
  };
953
975
 
954
- let errors = { Error, TypeError, ReferenceError };
976
+ let errors = {
977
+ Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError: typeof AggregateError === 'function' ? AggregateError : null,
978
+ };
955
979
  currentExtensions[0x65] = () => {
956
980
  let data = read();
957
- return (errors[data[0]] || Error)(data[1], { cause: data[2] })
981
+ if (!errors[data[0]]) {
982
+ let error = Error(data[1], { cause: data[2] });
983
+ error.name = data[0];
984
+ return error
985
+ }
986
+ return errors[data[0]](data[1], { cause: data[2] })
958
987
  };
959
988
 
960
989
  currentExtensions[0x69] = (data) => {
@@ -965,20 +994,33 @@
965
994
  referenceMap = new Map();
966
995
  let token = src[position$1];
967
996
  let target;
968
- // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
969
- // ahead past references to record structure definitions
997
+ // TODO: handle any other types that can cycle and make the code more robust if there are other extensions
970
998
  if (token >= 0x90 && token < 0xa0 || token == 0xdc || token == 0xdd)
971
999
  target = [];
1000
+ else if (token >= 0x80 && token < 0x90 || token == 0xde || token == 0xdf)
1001
+ target = new Map();
1002
+ else if ((token >= 0xc7 && token <= 0xc9 || token >= 0xd4 && token <= 0xd8) && src[position$1 + 1] === 0x73)
1003
+ target = new Set();
972
1004
  else
973
1005
  target = {};
974
1006
 
975
1007
  let refEntry = { target }; // a placeholder object
976
1008
  referenceMap.set(id, refEntry);
977
1009
  let targetProperties = read(); // read the next value as the target object to id
978
- if (refEntry.used) // there is a cycle, so we have to assign properties to original target
979
- return Object.assign(target, targetProperties)
980
- refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
981
- return targetProperties // no cycle, can just use the returned read object
1010
+ if (!refEntry.used) {
1011
+ // no cycle, can just use the returned read object
1012
+ return refEntry.target = targetProperties // replace the placeholder with the real one
1013
+ } else {
1014
+ // there is a cycle, so we have to assign properties to original target
1015
+ Object.assign(target, targetProperties);
1016
+ }
1017
+
1018
+ // copy over map/set entries if we're able to
1019
+ if (target instanceof Map)
1020
+ for (let [k, v] of targetProperties.entries()) target.set(k, v);
1021
+ if (target instanceof Set)
1022
+ for (let i of Array.from(targetProperties)) target.add(i);
1023
+ return target
982
1024
  };
983
1025
 
984
1026
  currentExtensions[0x70] = (data) => {
@@ -997,18 +1039,16 @@
997
1039
  let glbl = typeof globalThis === 'object' ? globalThis : window;
998
1040
  currentExtensions[0x74] = (data) => {
999
1041
  let typeCode = data[0];
1042
+ // we always have to slice to get a new ArrayBuffer that is aligned
1043
+ let buffer = Uint8Array.prototype.slice.call(data, 1).buffer;
1044
+
1000
1045
  let typedArrayName = typedArrays[typeCode];
1001
1046
  if (!typedArrayName) {
1002
- if (typeCode === 16) {
1003
- let ab = new ArrayBuffer(data.length - 1);
1004
- let u8 = new Uint8Array(ab);
1005
- u8.set(data.subarray(1));
1006
- return ab;
1007
- }
1047
+ if (typeCode === 16) return buffer
1048
+ if (typeCode === 17) return new DataView(buffer)
1008
1049
  throw new Error('Could not find typed array for code ' + typeCode)
1009
1050
  }
1010
- // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
1011
- return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
1051
+ return new glbl[typedArrayName](buffer)
1012
1052
  };
1013
1053
  currentExtensions[0x78] = () => {
1014
1054
  let data = read();
@@ -1036,13 +1076,13 @@
1036
1076
  return new Date(
1037
1077
  ((data[0] << 22) + (data[1] << 14) + (data[2] << 6) + (data[3] >> 2)) / 1000000 +
1038
1078
  ((data[3] & 0x3) * 0x100000000 + data[4] * 0x1000000 + (data[5] << 16) + (data[6] << 8) + data[7]) * 1000)
1039
- else if (data.length == 12)// TODO: Implement support for negative
1079
+ else if (data.length == 12)
1040
1080
  return new Date(
1041
1081
  ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
1042
1082
  (((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
1043
1083
  else
1044
1084
  return new Date('invalid')
1045
- }; // notepack defines extension 0 to mean undefined, so use that as the default here
1085
+ };
1046
1086
  // registration of bulk record definition?
1047
1087
  // currentExtensions[0x52] = () =>
1048
1088
 
@@ -1636,11 +1676,11 @@
1636
1676
  } else if (type === 'boolean') {
1637
1677
  target[position++] = value ? 0xc3 : 0xc2;
1638
1678
  } else if (type === 'bigint') {
1639
- if (value < (BigInt(1)<<BigInt(63)) && value >= -(BigInt(1)<<BigInt(63))) {
1679
+ if (value < 0x8000000000000000 && value >= -0x8000000000000000) {
1640
1680
  // use a signed int as long as it fits
1641
1681
  target[position++] = 0xd3;
1642
1682
  targetView.setBigInt64(position, value);
1643
- } else if (value < (BigInt(1)<<BigInt(64)) && value > 0) {
1683
+ } else if (value < 0x10000000000000000 && value > 0) {
1644
1684
  // if we can fit an unsigned int, use that
1645
1685
  target[position++] = 0xcf;
1646
1686
  targetView.setBigUint64(position, value);
@@ -1651,22 +1691,46 @@
1651
1691
  targetView.setFloat64(position, Number(value));
1652
1692
  } else if (this.largeBigIntToString) {
1653
1693
  return pack(value.toString());
1654
- } else if (this.useBigIntExtension && value < BigInt(2)**BigInt(1023) && value > -(BigInt(2)**BigInt(1023))) {
1655
- target[position++] = 0xc7;
1656
- position++;
1657
- target[position++] = 0x42; // "B" for BigInt
1658
- let bytes = [];
1659
- let alignedSign;
1660
- do {
1661
- let byte = value & BigInt(0xff);
1662
- alignedSign = (byte & BigInt(0x80)) === (value < BigInt(0) ? BigInt(0x80) : BigInt(0));
1663
- bytes.push(byte);
1664
- value >>= BigInt(8);
1665
- } while (!((value === BigInt(0) || value === BigInt(-1)) && alignedSign));
1666
- target[position-2] = bytes.length;
1667
- for (let i = bytes.length; i > 0;) {
1668
- target[position++] = Number(bytes[--i]);
1694
+ } else if (this.useBigIntExtension || this.moreTypes) {
1695
+ let empty = value < 0 ? BigInt(-1) : BigInt(0);
1696
+
1697
+ let array;
1698
+ if (value >> BigInt(0x10000) === empty) {
1699
+ let mask = BigInt(0x10000000000000000) - BigInt(1); // literal would overflow
1700
+ let chunks = [];
1701
+ do {
1702
+ chunks.push(value & mask);
1703
+ value >>= BigInt(64);
1704
+ } while (value !== empty)
1705
+
1706
+ array = new Uint8Array(new BigUint64Array(chunks).buffer);
1707
+ array.reverse();
1708
+ } else {
1709
+ let invert = value < 0;
1710
+ let string = (invert ? ~value : value).toString(16);
1711
+ if (string.length % 2) {
1712
+ string = '0' + string;
1713
+ } else if (parseInt(string.charAt(0), 16) >= 8) {
1714
+ string = '00' + string;
1715
+ }
1716
+
1717
+ if (hasNodeBuffer) {
1718
+ array = Buffer.from(string, 'hex');
1719
+ } else {
1720
+ array = new Uint8Array(string.length / 2);
1721
+ for (let i = 0; i < array.length; i++) {
1722
+ array[i] = parseInt(string.slice(i * 2, i * 2 + 2), 16);
1723
+ }
1724
+ }
1725
+
1726
+ if (invert) {
1727
+ for (let i = 0; i < array.length; i++) array[i] = ~array[i];
1728
+ }
1669
1729
  }
1730
+
1731
+ if (array.length + position > safeEnd)
1732
+ makeRoom(array.length + position);
1733
+ position = writeExtensionData(array, target, position, 0x42);
1670
1734
  return
1671
1735
  } else {
1672
1736
  throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, use' +
@@ -1970,7 +2034,7 @@
1970
2034
  }
1971
2035
  }
1972
2036
 
1973
- extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
2037
+ extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, DataView, C1Type ];
1974
2038
  extensions = [{
1975
2039
  pack(date, allocateForWrite, pack) {
1976
2040
  let seconds = date.getTime() / 1000;
@@ -2057,6 +2121,13 @@
2057
2121
  else
2058
2122
  writeBuffer(typedArray, allocateForWrite);
2059
2123
  }
2124
+ }, {
2125
+ pack(arrayBuffer, allocateForWrite) {
2126
+ if (this.moreTypes)
2127
+ writeExtBuffer(arrayBuffer, 0x11, allocateForWrite);
2128
+ else
2129
+ writeBuffer(hasNodeBuffer ? Buffer.from(arrayBuffer) : new Uint8Array(arrayBuffer), allocateForWrite);
2130
+ }
2060
2131
  }, {
2061
2132
  pack(c1, allocateForWrite) { // specific 0xC1 object
2062
2133
  let { target, position} = allocateForWrite(1);
@@ -2099,7 +2170,7 @@
2099
2170
  target[position++] = length >> 8;
2100
2171
  target[position++] = length & 0xff;
2101
2172
  } else {
2102
- let { target, position, targetView } = allocateForWrite(length + 5);
2173
+ var { target, position, targetView } = allocateForWrite(length + 5);
2103
2174
  target[position++] = 0xc6;
2104
2175
  targetView.setUint32(position, length);
2105
2176
  position += 4;