msgpackr 1.7.0-beta1 → 1.7.1

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/test.js CHANGED
@@ -179,6 +179,7 @@
179
179
  let result;
180
180
  if (currentUnpackr.randomAccessStructure && src[position] < 0x40 && src[position] >= 0x20 && readStruct) {
181
181
  result = readStruct(src, position, srcEnd, currentUnpackr);
182
+ src = null; // dispose of this so that recursive unpack calls don't save state
182
183
  if (!(options && options.lazy) && result)
183
184
  result = result.toJSON();
184
185
  position = srcEnd;
@@ -189,7 +190,7 @@
189
190
 
190
191
  if (position == srcEnd) {
191
192
  // finished reading this source, cleanup references
192
- if (currentStructures.restoreStructures)
193
+ if (currentStructures && currentStructures.restoreStructures)
193
194
  restoreStructures();
194
195
  currentStructures = null;
195
196
  src = null;
@@ -204,7 +205,7 @@
204
205
  // else more to read, but we are reading sequentially, so don't clear source yet
205
206
  return result
206
207
  } catch(error) {
207
- if (currentStructures?.restoreStructures)
208
+ if (currentStructures && currentStructures.restoreStructures)
208
209
  restoreStructures();
209
210
  clearSource();
210
211
  if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer') || position > srcEnd) {
@@ -244,7 +245,10 @@
244
245
  if (currentUnpackr.mapsAsObjects) {
245
246
  let object = {};
246
247
  for (let i = 0; i < token; i++) {
247
- object[readKey()] = read();
248
+ let key = readKey();
249
+ if (key === '__proto__')
250
+ key = '__proto_';
251
+ object[key] = read();
248
252
  }
249
253
  return object
250
254
  } else {
@@ -473,7 +477,7 @@
473
477
  // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
474
478
  if (readObject.count++ > inlineObjectReadThreshold) {
475
479
  let readObject = structure.read = (new Function('r', 'return function(){return ' + (currentUnpackr.freezeData ? 'Object.freeze' : '') +
476
- '({' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read);
480
+ '({' + structure.map(key => key === '__proto__' ? '__proto_:r()' : validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '})}'))(read);
477
481
  if (structure.highByte === 0)
478
482
  structure.read = createSecondByteReader(firstId, structure.read);
479
483
  return readObject() // second byte is already read, if there is one so immediately read object
@@ -481,6 +485,8 @@
481
485
  let object = {};
482
486
  for (let i = 0, l = structure.length; i < l; i++) {
483
487
  let key = structure[i];
488
+ if (key === '__proto__')
489
+ key = '__proto_';
484
490
  object[key] = read();
485
491
  }
486
492
  if (currentUnpackr.freezeData)
@@ -601,7 +607,10 @@
601
607
  if (currentUnpackr.mapsAsObjects) {
602
608
  let object = {};
603
609
  for (let i = 0; i < length; i++) {
604
- object[readKey()] = read();
610
+ let key = readKey();
611
+ if (key === '__proto__')
612
+ key = '__proto_';
613
+ object[key] = read();
605
614
  }
606
615
  return object
607
616
  } else {
@@ -1171,12 +1180,11 @@
1171
1180
  writeStruct(value);
1172
1181
  else
1173
1182
  pack(value);
1174
- if (bundledStrings$1) {
1175
- writeBundles(start, pack);
1176
- }
1177
- packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1178
1183
  if (referenceMap && referenceMap.idsToInsert) {
1179
- position$1 += referenceMap.idsToInsert.length * 6;
1184
+ let incrementPosition = referenceMap.idsToInsert.length * 6;
1185
+ if (bundledStrings$1)
1186
+ writeBundles(start, pack, incrementPosition);
1187
+ position$1 += incrementPosition;
1180
1188
  if (position$1 > safeEnd)
1181
1189
  makeRoom(position$1);
1182
1190
  packr.offset = position$1;
@@ -1184,6 +1192,9 @@
1184
1192
  referenceMap = null;
1185
1193
  return serialized
1186
1194
  }
1195
+ if (bundledStrings$1)
1196
+ writeBundles(start, pack, 0);
1197
+ packr.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
1187
1198
  if (encodeOptions & REUSE_BUFFER_MODE) {
1188
1199
  target.start = start;
1189
1200
  target.end = position$1;
@@ -1962,9 +1973,9 @@
1962
1973
  return serialized
1963
1974
  }
1964
1975
 
1965
- function writeBundles(start, pack) {
1976
+ function writeBundles(start, pack, incrementPosition) {
1966
1977
  if (bundledStrings$1.length > 0) {
1967
- targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start);
1978
+ targetView.setUint32(bundledStrings$1.position + start, position$1 + incrementPosition - bundledStrings$1.position - start);
1968
1979
  let writeStrings = bundledStrings$1;
1969
1980
  bundledStrings$1 = null;
1970
1981
  pack(writeStrings[0]);
@@ -1997,6 +2008,14 @@
1997
2008
  const TYPE_NAMES = ['num', 'object', 'string', 'ascii'];
1998
2009
  TYPE_NAMES[DATE] = 'date';
1999
2010
  const float32Headers = [false, true, true, false, false, true, true, false];
2011
+ let evalSupported;
2012
+ try {
2013
+ new Function('');
2014
+ evalSupported = true;
2015
+ } catch(error) {
2016
+ // if eval variants are not supported, do not create inline object readers ever
2017
+ }
2018
+
2000
2019
  let updatedPosition;
2001
2020
  const hasNodeBuffer$1 = typeof Buffer !== 'undefined';
2002
2021
  let textEncoder$1, currentSource;
@@ -2433,7 +2452,7 @@
2433
2452
  case 27: recordId = src[position++] + (src[position++] << 8) + (src[position++] << 16) + (src[position++] << 24); break;
2434
2453
  }
2435
2454
  }
2436
- let structure = unpackr.typedStructs?.[recordId];
2455
+ let structure = unpackr.typedStructs && unpackr.typedStructs[recordId];
2437
2456
  if (!structure) {
2438
2457
  // copy src buffer because getStructures will override it
2439
2458
  src = Uint8Array.prototype.slice.call(src, position, srcEnd);
@@ -2453,23 +2472,13 @@
2453
2472
  };
2454
2473
  var prototype = construct.prototype;
2455
2474
  let properties = [];
2456
- Object.defineProperty(prototype, 'toJSON', {
2457
- value() {
2458
- // return an enumerable object with own properties to JSON stringify
2459
- let resolved = {};
2460
- for (let i = 0, l = properties.length; i < l; i++) {
2461
- let key = properties[i].key;
2462
- resolved[key] = this[key];
2463
- }
2464
- return resolved;
2465
- },
2466
- // not enumerable or anything
2467
- });
2468
2475
  let currentOffset = 0;
2469
2476
  let lastRefProperty;
2470
2477
  for (let i = 0, l = structure.length; i < l; i++) {
2471
2478
  let definition = structure[i];
2472
2479
  let [ type, size, key, enumerationOffset ] = definition;
2480
+ if (key === '__proto__')
2481
+ key = '__proto_';
2473
2482
  let property = {
2474
2483
  key,
2475
2484
  offset: currentOffset,
@@ -2513,8 +2522,7 @@
2513
2522
  lastRefProperty.next = property;
2514
2523
  lastRefProperty = property;
2515
2524
  property.multiGetCount = 0;
2516
- get = function() {
2517
- let source = this[sourceSymbol];
2525
+ get = function(source) {
2518
2526
  let src = source.bytes;
2519
2527
  let position = source.position;
2520
2528
  let refStart = currentOffset + position;
@@ -2565,8 +2573,7 @@
2565
2573
  if (lastRefProperty && !lastRefProperty.next)
2566
2574
  lastRefProperty.next = property;
2567
2575
  lastRefProperty = property;
2568
- get = function() {
2569
- let source = this[sourceSymbol];
2576
+ get = function(source) {
2570
2577
  let position = source.position;
2571
2578
  let refStart = currentOffset + position;
2572
2579
  let ref = getRef(source, position);
@@ -2598,8 +2605,7 @@
2598
2605
  case NUMBER:
2599
2606
  switch(size) {
2600
2607
  case 4:
2601
- get = function () {
2602
- let source = this[sourceSymbol];
2608
+ get = function (source) {
2603
2609
  let src = source.bytes;
2604
2610
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2605
2611
  let position = source.position + property.offset;
@@ -2617,8 +2623,7 @@
2617
2623
  };
2618
2624
  break;
2619
2625
  case 8:
2620
- get = function () {
2621
- let source = this[sourceSymbol];
2626
+ get = function (source) {
2622
2627
  let src = source.bytes;
2623
2628
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2624
2629
  let value = dataView.getFloat64(source.position + property.offset, true);
@@ -2631,8 +2636,7 @@
2631
2636
  };
2632
2637
  break;
2633
2638
  case 1:
2634
- get = function () {
2635
- let source = this[sourceSymbol];
2639
+ get = function (source) {
2636
2640
  let src = source.bytes;
2637
2641
  let value = src[source.position + property.offset];
2638
2642
  return value < 0xf6 ? value : toConstant(value);
@@ -2641,8 +2645,7 @@
2641
2645
  }
2642
2646
  break;
2643
2647
  case DATE:
2644
- get = function () {
2645
- let source = this[sourceSymbol];
2648
+ get = function (source) {
2646
2649
  let src = source.bytes;
2647
2650
  let dataView = src.dataView || (src.dataView = new DataView(src.buffer, src.byteOffset, src.byteLength));
2648
2651
  return new Date(dataView.getFloat64(source.position + property.offset, true));
@@ -2652,8 +2655,38 @@
2652
2655
  }
2653
2656
  property.get = get;
2654
2657
  }
2655
- for (let property of properties) // assign in enumeration order
2656
- Object.defineProperty(prototype, property.key, { get: property.get, enumerable: true });
2658
+ // TODO: load the srcString for faster string decoding on toJSON
2659
+ if (evalSupported) {
2660
+ let objectLiteralProperties = [];
2661
+ let args = [];
2662
+ let i = 0;
2663
+ for (let property of properties) { // assign in enumeration order
2664
+ Object.defineProperty(prototype, property.key, { get: withSource(property.get), enumerable: true });
2665
+ let valueFunction = 'v' + i++;
2666
+ args.push(valueFunction);
2667
+ objectLiteralProperties.push('[' + JSON.stringify(property.key) + ']:' + valueFunction + '(s)');
2668
+ }
2669
+ let toObject = (new Function(...args, 'return function(s){return{' + objectLiteralProperties.join(',') + '}}')).apply(null, properties.map(prop => prop.get));
2670
+ Object.defineProperty(prototype, 'toJSON', {
2671
+ value() {
2672
+ return toObject(this[sourceSymbol]);
2673
+ }
2674
+ });
2675
+ } else {
2676
+ Object.defineProperty(prototype, 'toJSON', {
2677
+ value() {
2678
+ // return an enumerable object with own properties to JSON stringify
2679
+ let resolved = {};
2680
+ for (let i = 0, l = properties.length; i < l; i++) {
2681
+ let key = properties[i].key;
2682
+
2683
+ resolved[key] = this[key];
2684
+ }
2685
+ return resolved;
2686
+ },
2687
+ // not enumerable or anything
2688
+ });
2689
+ }
2657
2690
  }
2658
2691
  var instance = new construct();
2659
2692
  instance[sourceSymbol] = {
@@ -2673,6 +2706,11 @@
2673
2706
  }
2674
2707
  throw new Error('Unknown constant');
2675
2708
  }
2709
+ function withSource(get) {
2710
+ return function() {
2711
+ return get(this[sourceSymbol]);
2712
+ }
2713
+ }
2676
2714
 
2677
2715
  function saveState$1() {
2678
2716
  if (currentSource) {
@@ -2706,7 +2744,7 @@
2706
2744
  packr._mergeStructures(existing);
2707
2745
  return compatible;
2708
2746
  };
2709
- packr.lastTypedStructuresLength = packr.typedStructs?.length;
2747
+ packr.lastTypedStructuresLength = packr.typedStructs && packr.typedStructs.length;
2710
2748
  return structures;
2711
2749
  }
2712
2750
 
@@ -3045,6 +3083,17 @@
3045
3083
  assert.deepEqual(data, deserialized);
3046
3084
  assert.equal(deserialized.extendedInstance.getDouble(), 8);
3047
3085
  });
3086
+ test('proto handling', function() {
3087
+ var objectWithProto = JSON.parse('{"__proto__":{"foo":3}}');
3088
+ var decoded = unpack(pack(objectWithProto));
3089
+ assert(!decoded.foo);
3090
+ var objectsWithProto = [objectWithProto, objectWithProto, objectWithProto, objectWithProto, objectWithProto, objectWithProto];
3091
+ let packr = new Packr$1();
3092
+ var decoded = packr.unpack(packr.pack(objectsWithProto));
3093
+ for (let object of decoded) {
3094
+ assert(!decoded.foo);
3095
+ }
3096
+ });
3048
3097
 
3049
3098
  test.skip('text decoder', function() {
3050
3099
  let td = new TextDecoder('ISO-8859-15');
@@ -3113,6 +3162,23 @@
3113
3162
  assert.equal(deserialized.uint16Array[1], 4);
3114
3163
  });
3115
3164
 
3165
+ test('structured clone with bundled strings', function() {
3166
+ const packer = new Packr$1({
3167
+ structuredClone: true, // both options must be enabled
3168
+ bundleStrings: true,
3169
+ });
3170
+
3171
+ const v = {};
3172
+
3173
+ const shared = {
3174
+ name1: v,
3175
+ name2: v, // one key has to be named `data`
3176
+ };
3177
+
3178
+ let deserialized = packer.unpack(packer.pack(shared));
3179
+ assert.equal(deserialized.name1, deserialized.name2);
3180
+ });
3181
+
3116
3182
  test('object without prototype', function(){
3117
3183
  var data = Object.create(null);
3118
3184
  data.test = 3;