seroval 1.6.11 → 1.6.12

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.
@@ -1003,11 +1003,18 @@ function parseAsyncIteratorFactory(ctx) {
1003
1003
  function createObjectNode(id, current, empty, record) {
1004
1004
  return createSerovalNode(empty ? 11 : 10, id, void 0, void 0, void 0, record, void 0, void 0, void 0, void 0, getObjectFlag(current), void 0);
1005
1005
  }
1006
- function createMapNode(ctx, id, k, v) {
1006
+ /**
1007
+ * Gets the sentinel node for a Map. Call it before parsing the entries, so
1008
+ * that an outer Map declares the sentinel before any Map inside it uses it.
1009
+ */
1010
+ function parseMapSentinel(ctx) {
1011
+ return parseSpecialReference(ctx, 0);
1012
+ }
1013
+ function createMapNode(id, sentinel, k, v) {
1007
1014
  return createSerovalNode(8, id, void 0, void 0, void 0, void 0, {
1008
1015
  k,
1009
1016
  v
1010
- }, void 0, parseSpecialReference(ctx, 0), void 0, void 0, void 0);
1017
+ }, void 0, sentinel, void 0, void 0, void 0);
1011
1018
  }
1012
1019
  function createPromiseConstructorNode(ctx, id, resolver) {
1013
1020
  return createSerovalNode(22, id, resolver, void 0, void 0, void 0, void 0, void 0, parseSpecialReference(ctx, 1), void 0, void 0, void 0);
@@ -1110,13 +1117,14 @@ async function parseAggregateError$1(ctx, depth, id, current) {
1110
1117
  return createAggregateErrorNode(id, current, options ? await parseProperties$1(ctx, depth, options) : void 0);
1111
1118
  }
1112
1119
  async function parseMap$1(ctx, depth, id, current) {
1120
+ const sentinel = parseMapSentinel(ctx.base);
1113
1121
  const keyNodes = [];
1114
1122
  const valueNodes = [];
1115
1123
  for (const [key, value] of current.entries()) {
1116
1124
  keyNodes.push(await parseAsync(ctx, depth, key));
1117
1125
  valueNodes.push(await parseAsync(ctx, depth, value));
1118
1126
  }
1119
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
1127
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
1120
1128
  }
1121
1129
  async function parseSet$1(ctx, depth, id, current) {
1122
1130
  const items = [];
@@ -1770,30 +1778,36 @@ function getAssignmentExpression(assignment) {
1770
1778
  case 4: return "Object.defineProperty(" + assignment.s + ",\"__proto__\",{value:" + assignment.k + ",configurable:!0,enumerable:!0,writable:!0})";
1771
1779
  }
1772
1780
  }
1781
+ const MAX_ASSIGNMENT_CHAIN_LENGTH = 100;
1773
1782
  function mergeAssignments(assignments) {
1774
1783
  const newAssignments = [];
1775
1784
  let current = assignments[0];
1785
+ let chainLength = 1;
1776
1786
  for (let i = 1, len = assignments.length, item, prev = current; i < len; i++) {
1777
1787
  item = assignments[i];
1778
- if (item.t === 0 && item.v === prev.v) current = {
1788
+ if (chainLength === MAX_ASSIGNMENT_CHAIN_LENGTH) {
1789
+ newAssignments.push(current);
1790
+ current = item;
1791
+ chainLength = 0;
1792
+ } else if (item.t === 0 && prev.t === 0 && item.v === prev.v) current = {
1779
1793
  t: 0,
1780
1794
  s: item.s,
1781
1795
  k: void 0,
1782
1796
  v: getAssignmentExpression(current)
1783
1797
  };
1784
- else if (item.t === 2 && item.s === prev.s) current = {
1798
+ else if (item.t === 2 && prev.t === 2 && item.s === prev.s) current = {
1785
1799
  t: 2,
1786
1800
  s: getAssignmentExpression(current),
1787
1801
  k: item.k,
1788
1802
  v: item.v
1789
1803
  };
1790
- else if (item.t === 1 && item.s === prev.s) current = {
1804
+ else if (item.t === 1 && prev.t === 1 && item.s === prev.s) current = {
1791
1805
  t: 1,
1792
1806
  s: getAssignmentExpression(current),
1793
1807
  k: void 0,
1794
1808
  v: item.v
1795
1809
  };
1796
- else if (item.t === 3 && item.s === prev.s) current = {
1810
+ else if (item.t === 3 && prev.t === 2 && item.s === prev.s) current = {
1797
1811
  t: 3,
1798
1812
  s: getAssignmentExpression(current),
1799
1813
  k: item.k,
@@ -1802,7 +1816,9 @@ function mergeAssignments(assignments) {
1802
1816
  else {
1803
1817
  newAssignments.push(current);
1804
1818
  current = item;
1819
+ chainLength = 0;
1805
1820
  }
1821
+ chainLength++;
1806
1822
  prev = item;
1807
1823
  }
1808
1824
  newAssignments.push(current);
@@ -1997,6 +2013,22 @@ function isIndexedValueInStack(ctx, node) {
1997
2013
  return node.t === 4 && ctx.stack.includes(node.i);
1998
2014
  }
1999
2015
  /**
2016
+ * Checks if the node, or any node inside it, is read from more than one
2017
+ * place. Such a node must not be created inside a deferred assignment,
2018
+ * because the places that read it may run before the assignment does.
2019
+ */
2020
+ function hasMarkedNode(ctx, node) {
2021
+ if (Array.isArray(node)) {
2022
+ for (let i = 0, len = node.length; i < len; i++) if (hasMarkedNode(ctx, node[i])) return true;
2023
+ return false;
2024
+ }
2025
+ if (node == null || typeof node !== "object") return false;
2026
+ const current = node;
2027
+ if (current.t !== 4 && typeof current.i === "number" && isSerializerRefMarked(ctx, current.i)) return true;
2028
+ for (const key in current) if (hasMarkedNode(ctx, current[key])) return true;
2029
+ return false;
2030
+ }
2031
+ /**
2000
2032
  * Produces an assignment expression. `id` generates a reference
2001
2033
  * parameter (through `getRefParam`) and has the option to
2002
2034
  * return the reference parameter directly or assign a value to
@@ -2206,7 +2238,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2206
2238
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2207
2239
  return "";
2208
2240
  }
2209
- if (val.t !== 4 && val.i != null && isSerializerRefMarked(base, val.i)) {
2241
+ if (val.t !== 4 && val.i != null && hasMarkedNode(base, val)) {
2242
+ markSerializerRef(base, val.i);
2210
2243
  const serialized = "(" + serialize$1(ctx, val) + ",[" + sentinel + "," + sentinel + "])";
2211
2244
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2212
2245
  createDeleteAssignment(ctx, id, sentinel);
@@ -2221,7 +2254,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2221
2254
  if (isIndexedValueInStack(base, val)) {
2222
2255
  const valueRef = getRefParam(ctx, val.i);
2223
2256
  markSerializerRef(base, id);
2224
- if (key.t !== 4 && key.i != null && isSerializerRefMarked(base, key.i)) {
2257
+ if (key.t !== 4 && key.i != null && hasMarkedNode(base, key)) {
2258
+ markSerializerRef(base, key.i);
2225
2259
  const serialized = "(" + serialize$1(ctx, key) + ",[" + sentinel + "," + sentinel + "])";
2226
2260
  createSetAssignment(ctx, id, getRefParam(ctx, key.i), valueRef);
2227
2261
  createDeleteAssignment(ctx, id, sentinel);
@@ -2617,13 +2651,14 @@ function parseAggregateError(ctx, depth, id, current) {
2617
2651
  return createAggregateErrorNode(id, current, options ? parseProperties(ctx, depth, options) : void 0);
2618
2652
  }
2619
2653
  function parseMap(ctx, depth, id, current) {
2654
+ const sentinel = parseMapSentinel(ctx.base);
2620
2655
  const keyNodes = [];
2621
2656
  const valueNodes = [];
2622
2657
  for (const [key, value] of current.entries()) {
2623
2658
  keyNodes.push(parseSOS(ctx, depth, key));
2624
2659
  valueNodes.push(parseSOS(ctx, depth, value));
2625
2660
  }
2626
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
2661
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
2627
2662
  }
2628
2663
  function parseSet(ctx, depth, id, current) {
2629
2664
  const items = [];
package/dist/dev/index.js CHANGED
@@ -1002,11 +1002,18 @@ function parseAsyncIteratorFactory(ctx) {
1002
1002
  function createObjectNode(id, current, empty, record) {
1003
1003
  return createSerovalNode(empty ? 11 : 10, id, void 0, void 0, void 0, record, void 0, void 0, void 0, void 0, getObjectFlag(current), void 0);
1004
1004
  }
1005
- function createMapNode(ctx, id, k, v) {
1005
+ /**
1006
+ * Gets the sentinel node for a Map. Call it before parsing the entries, so
1007
+ * that an outer Map declares the sentinel before any Map inside it uses it.
1008
+ */
1009
+ function parseMapSentinel(ctx) {
1010
+ return parseSpecialReference(ctx, 0);
1011
+ }
1012
+ function createMapNode(id, sentinel, k, v) {
1006
1013
  return createSerovalNode(8, id, void 0, void 0, void 0, void 0, {
1007
1014
  k,
1008
1015
  v
1009
- }, void 0, parseSpecialReference(ctx, 0), void 0, void 0, void 0);
1016
+ }, void 0, sentinel, void 0, void 0, void 0);
1010
1017
  }
1011
1018
  function createPromiseConstructorNode(ctx, id, resolver) {
1012
1019
  return createSerovalNode(22, id, resolver, void 0, void 0, void 0, void 0, void 0, parseSpecialReference(ctx, 1), void 0, void 0, void 0);
@@ -1109,13 +1116,14 @@ async function parseAggregateError$1(ctx, depth, id, current) {
1109
1116
  return createAggregateErrorNode(id, current, options ? await parseProperties$1(ctx, depth, options) : void 0);
1110
1117
  }
1111
1118
  async function parseMap$1(ctx, depth, id, current) {
1119
+ const sentinel = parseMapSentinel(ctx.base);
1112
1120
  const keyNodes = [];
1113
1121
  const valueNodes = [];
1114
1122
  for (const [key, value] of current.entries()) {
1115
1123
  keyNodes.push(await parseAsync(ctx, depth, key));
1116
1124
  valueNodes.push(await parseAsync(ctx, depth, value));
1117
1125
  }
1118
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
1126
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
1119
1127
  }
1120
1128
  async function parseSet$1(ctx, depth, id, current) {
1121
1129
  const items = [];
@@ -1769,30 +1777,36 @@ function getAssignmentExpression(assignment) {
1769
1777
  case 4: return "Object.defineProperty(" + assignment.s + ",\"__proto__\",{value:" + assignment.k + ",configurable:!0,enumerable:!0,writable:!0})";
1770
1778
  }
1771
1779
  }
1780
+ const MAX_ASSIGNMENT_CHAIN_LENGTH = 100;
1772
1781
  function mergeAssignments(assignments) {
1773
1782
  const newAssignments = [];
1774
1783
  let current = assignments[0];
1784
+ let chainLength = 1;
1775
1785
  for (let i = 1, len = assignments.length, item, prev = current; i < len; i++) {
1776
1786
  item = assignments[i];
1777
- if (item.t === 0 && item.v === prev.v) current = {
1787
+ if (chainLength === MAX_ASSIGNMENT_CHAIN_LENGTH) {
1788
+ newAssignments.push(current);
1789
+ current = item;
1790
+ chainLength = 0;
1791
+ } else if (item.t === 0 && prev.t === 0 && item.v === prev.v) current = {
1778
1792
  t: 0,
1779
1793
  s: item.s,
1780
1794
  k: void 0,
1781
1795
  v: getAssignmentExpression(current)
1782
1796
  };
1783
- else if (item.t === 2 && item.s === prev.s) current = {
1797
+ else if (item.t === 2 && prev.t === 2 && item.s === prev.s) current = {
1784
1798
  t: 2,
1785
1799
  s: getAssignmentExpression(current),
1786
1800
  k: item.k,
1787
1801
  v: item.v
1788
1802
  };
1789
- else if (item.t === 1 && item.s === prev.s) current = {
1803
+ else if (item.t === 1 && prev.t === 1 && item.s === prev.s) current = {
1790
1804
  t: 1,
1791
1805
  s: getAssignmentExpression(current),
1792
1806
  k: void 0,
1793
1807
  v: item.v
1794
1808
  };
1795
- else if (item.t === 3 && item.s === prev.s) current = {
1809
+ else if (item.t === 3 && prev.t === 2 && item.s === prev.s) current = {
1796
1810
  t: 3,
1797
1811
  s: getAssignmentExpression(current),
1798
1812
  k: item.k,
@@ -1801,7 +1815,9 @@ function mergeAssignments(assignments) {
1801
1815
  else {
1802
1816
  newAssignments.push(current);
1803
1817
  current = item;
1818
+ chainLength = 0;
1804
1819
  }
1820
+ chainLength++;
1805
1821
  prev = item;
1806
1822
  }
1807
1823
  newAssignments.push(current);
@@ -1996,6 +2012,22 @@ function isIndexedValueInStack(ctx, node) {
1996
2012
  return node.t === 4 && ctx.stack.includes(node.i);
1997
2013
  }
1998
2014
  /**
2015
+ * Checks if the node, or any node inside it, is read from more than one
2016
+ * place. Such a node must not be created inside a deferred assignment,
2017
+ * because the places that read it may run before the assignment does.
2018
+ */
2019
+ function hasMarkedNode(ctx, node) {
2020
+ if (Array.isArray(node)) {
2021
+ for (let i = 0, len = node.length; i < len; i++) if (hasMarkedNode(ctx, node[i])) return true;
2022
+ return false;
2023
+ }
2024
+ if (node == null || typeof node !== "object") return false;
2025
+ const current = node;
2026
+ if (current.t !== 4 && typeof current.i === "number" && isSerializerRefMarked(ctx, current.i)) return true;
2027
+ for (const key in current) if (hasMarkedNode(ctx, current[key])) return true;
2028
+ return false;
2029
+ }
2030
+ /**
1999
2031
  * Produces an assignment expression. `id` generates a reference
2000
2032
  * parameter (through `getRefParam`) and has the option to
2001
2033
  * return the reference parameter directly or assign a value to
@@ -2205,7 +2237,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2205
2237
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2206
2238
  return "";
2207
2239
  }
2208
- if (val.t !== 4 && val.i != null && isSerializerRefMarked(base, val.i)) {
2240
+ if (val.t !== 4 && val.i != null && hasMarkedNode(base, val)) {
2241
+ markSerializerRef(base, val.i);
2209
2242
  const serialized = "(" + serialize$1(ctx, val) + ",[" + sentinel + "," + sentinel + "])";
2210
2243
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2211
2244
  createDeleteAssignment(ctx, id, sentinel);
@@ -2220,7 +2253,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2220
2253
  if (isIndexedValueInStack(base, val)) {
2221
2254
  const valueRef = getRefParam(ctx, val.i);
2222
2255
  markSerializerRef(base, id);
2223
- if (key.t !== 4 && key.i != null && isSerializerRefMarked(base, key.i)) {
2256
+ if (key.t !== 4 && key.i != null && hasMarkedNode(base, key)) {
2257
+ markSerializerRef(base, key.i);
2224
2258
  const serialized = "(" + serialize$1(ctx, key) + ",[" + sentinel + "," + sentinel + "])";
2225
2259
  createSetAssignment(ctx, id, getRefParam(ctx, key.i), valueRef);
2226
2260
  createDeleteAssignment(ctx, id, sentinel);
@@ -2616,13 +2650,14 @@ function parseAggregateError(ctx, depth, id, current) {
2616
2650
  return createAggregateErrorNode(id, current, options ? parseProperties(ctx, depth, options) : void 0);
2617
2651
  }
2618
2652
  function parseMap(ctx, depth, id, current) {
2653
+ const sentinel = parseMapSentinel(ctx.base);
2619
2654
  const keyNodes = [];
2620
2655
  const valueNodes = [];
2621
2656
  for (const [key, value] of current.entries()) {
2622
2657
  keyNodes.push(parseSOS(ctx, depth, key));
2623
2658
  valueNodes.push(parseSOS(ctx, depth, value));
2624
2659
  }
2625
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
2660
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
2626
2661
  }
2627
2662
  function parseSet(ctx, depth, id, current) {
2628
2663
  const items = [];
package/dist/index.cjs CHANGED
@@ -996,11 +996,18 @@ function parseAsyncIteratorFactory(ctx) {
996
996
  function createObjectNode(id, current, empty, record) {
997
997
  return createSerovalNode(empty ? 11 : 10, id, void 0, void 0, void 0, record, void 0, void 0, void 0, void 0, getObjectFlag(current), void 0);
998
998
  }
999
- function createMapNode(ctx, id, k, v) {
999
+ /**
1000
+ * Gets the sentinel node for a Map. Call it before parsing the entries, so
1001
+ * that an outer Map declares the sentinel before any Map inside it uses it.
1002
+ */
1003
+ function parseMapSentinel(ctx) {
1004
+ return parseSpecialReference(ctx, 0);
1005
+ }
1006
+ function createMapNode(id, sentinel, k, v) {
1000
1007
  return createSerovalNode(8, id, void 0, void 0, void 0, void 0, {
1001
1008
  k,
1002
1009
  v
1003
- }, void 0, parseSpecialReference(ctx, 0), void 0, void 0, void 0);
1010
+ }, void 0, sentinel, void 0, void 0, void 0);
1004
1011
  }
1005
1012
  function createPromiseConstructorNode(ctx, id, resolver) {
1006
1013
  return createSerovalNode(22, id, resolver, void 0, void 0, void 0, void 0, void 0, parseSpecialReference(ctx, 1), void 0, void 0, void 0);
@@ -1103,13 +1110,14 @@ async function parseAggregateError$1(ctx, depth, id, current) {
1103
1110
  return createAggregateErrorNode(id, current, options ? await parseProperties$1(ctx, depth, options) : void 0);
1104
1111
  }
1105
1112
  async function parseMap$1(ctx, depth, id, current) {
1113
+ const sentinel = parseMapSentinel(ctx.base);
1106
1114
  const keyNodes = [];
1107
1115
  const valueNodes = [];
1108
1116
  for (const [key, value] of current.entries()) {
1109
1117
  keyNodes.push(await parseAsync(ctx, depth, key));
1110
1118
  valueNodes.push(await parseAsync(ctx, depth, value));
1111
1119
  }
1112
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
1120
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
1113
1121
  }
1114
1122
  async function parseSet$1(ctx, depth, id, current) {
1115
1123
  const items = [];
@@ -1763,30 +1771,36 @@ function getAssignmentExpression(assignment) {
1763
1771
  case 4: return "Object.defineProperty(" + assignment.s + ",\"__proto__\",{value:" + assignment.k + ",configurable:!0,enumerable:!0,writable:!0})";
1764
1772
  }
1765
1773
  }
1774
+ const MAX_ASSIGNMENT_CHAIN_LENGTH = 100;
1766
1775
  function mergeAssignments(assignments) {
1767
1776
  const newAssignments = [];
1768
1777
  let current = assignments[0];
1778
+ let chainLength = 1;
1769
1779
  for (let i = 1, len = assignments.length, item, prev = current; i < len; i++) {
1770
1780
  item = assignments[i];
1771
- if (item.t === 0 && item.v === prev.v) current = {
1781
+ if (chainLength === MAX_ASSIGNMENT_CHAIN_LENGTH) {
1782
+ newAssignments.push(current);
1783
+ current = item;
1784
+ chainLength = 0;
1785
+ } else if (item.t === 0 && prev.t === 0 && item.v === prev.v) current = {
1772
1786
  t: 0,
1773
1787
  s: item.s,
1774
1788
  k: void 0,
1775
1789
  v: getAssignmentExpression(current)
1776
1790
  };
1777
- else if (item.t === 2 && item.s === prev.s) current = {
1791
+ else if (item.t === 2 && prev.t === 2 && item.s === prev.s) current = {
1778
1792
  t: 2,
1779
1793
  s: getAssignmentExpression(current),
1780
1794
  k: item.k,
1781
1795
  v: item.v
1782
1796
  };
1783
- else if (item.t === 1 && item.s === prev.s) current = {
1797
+ else if (item.t === 1 && prev.t === 1 && item.s === prev.s) current = {
1784
1798
  t: 1,
1785
1799
  s: getAssignmentExpression(current),
1786
1800
  k: void 0,
1787
1801
  v: item.v
1788
1802
  };
1789
- else if (item.t === 3 && item.s === prev.s) current = {
1803
+ else if (item.t === 3 && prev.t === 2 && item.s === prev.s) current = {
1790
1804
  t: 3,
1791
1805
  s: getAssignmentExpression(current),
1792
1806
  k: item.k,
@@ -1795,7 +1809,9 @@ function mergeAssignments(assignments) {
1795
1809
  else {
1796
1810
  newAssignments.push(current);
1797
1811
  current = item;
1812
+ chainLength = 0;
1798
1813
  }
1814
+ chainLength++;
1799
1815
  prev = item;
1800
1816
  }
1801
1817
  newAssignments.push(current);
@@ -1990,6 +2006,22 @@ function isIndexedValueInStack(ctx, node) {
1990
2006
  return node.t === 4 && ctx.stack.includes(node.i);
1991
2007
  }
1992
2008
  /**
2009
+ * Checks if the node, or any node inside it, is read from more than one
2010
+ * place. Such a node must not be created inside a deferred assignment,
2011
+ * because the places that read it may run before the assignment does.
2012
+ */
2013
+ function hasMarkedNode(ctx, node) {
2014
+ if (Array.isArray(node)) {
2015
+ for (let i = 0, len = node.length; i < len; i++) if (hasMarkedNode(ctx, node[i])) return true;
2016
+ return false;
2017
+ }
2018
+ if (node == null || typeof node !== "object") return false;
2019
+ const current = node;
2020
+ if (current.t !== 4 && typeof current.i === "number" && isSerializerRefMarked(ctx, current.i)) return true;
2021
+ for (const key in current) if (hasMarkedNode(ctx, current[key])) return true;
2022
+ return false;
2023
+ }
2024
+ /**
1993
2025
  * Produces an assignment expression. `id` generates a reference
1994
2026
  * parameter (through `getRefParam`) and has the option to
1995
2027
  * return the reference parameter directly or assign a value to
@@ -2199,7 +2231,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2199
2231
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2200
2232
  return "";
2201
2233
  }
2202
- if (val.t !== 4 && val.i != null && isSerializerRefMarked(base, val.i)) {
2234
+ if (val.t !== 4 && val.i != null && hasMarkedNode(base, val)) {
2235
+ markSerializerRef(base, val.i);
2203
2236
  const serialized = "(" + serialize$1(ctx, val) + ",[" + sentinel + "," + sentinel + "])";
2204
2237
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2205
2238
  createDeleteAssignment(ctx, id, sentinel);
@@ -2214,7 +2247,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2214
2247
  if (isIndexedValueInStack(base, val)) {
2215
2248
  const valueRef = getRefParam(ctx, val.i);
2216
2249
  markSerializerRef(base, id);
2217
- if (key.t !== 4 && key.i != null && isSerializerRefMarked(base, key.i)) {
2250
+ if (key.t !== 4 && key.i != null && hasMarkedNode(base, key)) {
2251
+ markSerializerRef(base, key.i);
2218
2252
  const serialized = "(" + serialize$1(ctx, key) + ",[" + sentinel + "," + sentinel + "])";
2219
2253
  createSetAssignment(ctx, id, getRefParam(ctx, key.i), valueRef);
2220
2254
  createDeleteAssignment(ctx, id, sentinel);
@@ -2610,13 +2644,14 @@ function parseAggregateError(ctx, depth, id, current) {
2610
2644
  return createAggregateErrorNode(id, current, options ? parseProperties(ctx, depth, options) : void 0);
2611
2645
  }
2612
2646
  function parseMap(ctx, depth, id, current) {
2647
+ const sentinel = parseMapSentinel(ctx.base);
2613
2648
  const keyNodes = [];
2614
2649
  const valueNodes = [];
2615
2650
  for (const [key, value] of current.entries()) {
2616
2651
  keyNodes.push(parseSOS(ctx, depth, key));
2617
2652
  valueNodes.push(parseSOS(ctx, depth, value));
2618
2653
  }
2619
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
2654
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
2620
2655
  }
2621
2656
  function parseSet(ctx, depth, id, current) {
2622
2657
  const items = [];
package/dist/index.js CHANGED
@@ -995,11 +995,18 @@ function parseAsyncIteratorFactory(ctx) {
995
995
  function createObjectNode(id, current, empty, record) {
996
996
  return createSerovalNode(empty ? 11 : 10, id, void 0, void 0, void 0, record, void 0, void 0, void 0, void 0, getObjectFlag(current), void 0);
997
997
  }
998
- function createMapNode(ctx, id, k, v) {
998
+ /**
999
+ * Gets the sentinel node for a Map. Call it before parsing the entries, so
1000
+ * that an outer Map declares the sentinel before any Map inside it uses it.
1001
+ */
1002
+ function parseMapSentinel(ctx) {
1003
+ return parseSpecialReference(ctx, 0);
1004
+ }
1005
+ function createMapNode(id, sentinel, k, v) {
999
1006
  return createSerovalNode(8, id, void 0, void 0, void 0, void 0, {
1000
1007
  k,
1001
1008
  v
1002
- }, void 0, parseSpecialReference(ctx, 0), void 0, void 0, void 0);
1009
+ }, void 0, sentinel, void 0, void 0, void 0);
1003
1010
  }
1004
1011
  function createPromiseConstructorNode(ctx, id, resolver) {
1005
1012
  return createSerovalNode(22, id, resolver, void 0, void 0, void 0, void 0, void 0, parseSpecialReference(ctx, 1), void 0, void 0, void 0);
@@ -1102,13 +1109,14 @@ async function parseAggregateError$1(ctx, depth, id, current) {
1102
1109
  return createAggregateErrorNode(id, current, options ? await parseProperties$1(ctx, depth, options) : void 0);
1103
1110
  }
1104
1111
  async function parseMap$1(ctx, depth, id, current) {
1112
+ const sentinel = parseMapSentinel(ctx.base);
1105
1113
  const keyNodes = [];
1106
1114
  const valueNodes = [];
1107
1115
  for (const [key, value] of current.entries()) {
1108
1116
  keyNodes.push(await parseAsync(ctx, depth, key));
1109
1117
  valueNodes.push(await parseAsync(ctx, depth, value));
1110
1118
  }
1111
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
1119
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
1112
1120
  }
1113
1121
  async function parseSet$1(ctx, depth, id, current) {
1114
1122
  const items = [];
@@ -1762,30 +1770,36 @@ function getAssignmentExpression(assignment) {
1762
1770
  case 4: return "Object.defineProperty(" + assignment.s + ",\"__proto__\",{value:" + assignment.k + ",configurable:!0,enumerable:!0,writable:!0})";
1763
1771
  }
1764
1772
  }
1773
+ const MAX_ASSIGNMENT_CHAIN_LENGTH = 100;
1765
1774
  function mergeAssignments(assignments) {
1766
1775
  const newAssignments = [];
1767
1776
  let current = assignments[0];
1777
+ let chainLength = 1;
1768
1778
  for (let i = 1, len = assignments.length, item, prev = current; i < len; i++) {
1769
1779
  item = assignments[i];
1770
- if (item.t === 0 && item.v === prev.v) current = {
1780
+ if (chainLength === MAX_ASSIGNMENT_CHAIN_LENGTH) {
1781
+ newAssignments.push(current);
1782
+ current = item;
1783
+ chainLength = 0;
1784
+ } else if (item.t === 0 && prev.t === 0 && item.v === prev.v) current = {
1771
1785
  t: 0,
1772
1786
  s: item.s,
1773
1787
  k: void 0,
1774
1788
  v: getAssignmentExpression(current)
1775
1789
  };
1776
- else if (item.t === 2 && item.s === prev.s) current = {
1790
+ else if (item.t === 2 && prev.t === 2 && item.s === prev.s) current = {
1777
1791
  t: 2,
1778
1792
  s: getAssignmentExpression(current),
1779
1793
  k: item.k,
1780
1794
  v: item.v
1781
1795
  };
1782
- else if (item.t === 1 && item.s === prev.s) current = {
1796
+ else if (item.t === 1 && prev.t === 1 && item.s === prev.s) current = {
1783
1797
  t: 1,
1784
1798
  s: getAssignmentExpression(current),
1785
1799
  k: void 0,
1786
1800
  v: item.v
1787
1801
  };
1788
- else if (item.t === 3 && item.s === prev.s) current = {
1802
+ else if (item.t === 3 && prev.t === 2 && item.s === prev.s) current = {
1789
1803
  t: 3,
1790
1804
  s: getAssignmentExpression(current),
1791
1805
  k: item.k,
@@ -1794,7 +1808,9 @@ function mergeAssignments(assignments) {
1794
1808
  else {
1795
1809
  newAssignments.push(current);
1796
1810
  current = item;
1811
+ chainLength = 0;
1797
1812
  }
1813
+ chainLength++;
1798
1814
  prev = item;
1799
1815
  }
1800
1816
  newAssignments.push(current);
@@ -1989,6 +2005,22 @@ function isIndexedValueInStack(ctx, node) {
1989
2005
  return node.t === 4 && ctx.stack.includes(node.i);
1990
2006
  }
1991
2007
  /**
2008
+ * Checks if the node, or any node inside it, is read from more than one
2009
+ * place. Such a node must not be created inside a deferred assignment,
2010
+ * because the places that read it may run before the assignment does.
2011
+ */
2012
+ function hasMarkedNode(ctx, node) {
2013
+ if (Array.isArray(node)) {
2014
+ for (let i = 0, len = node.length; i < len; i++) if (hasMarkedNode(ctx, node[i])) return true;
2015
+ return false;
2016
+ }
2017
+ if (node == null || typeof node !== "object") return false;
2018
+ const current = node;
2019
+ if (current.t !== 4 && typeof current.i === "number" && isSerializerRefMarked(ctx, current.i)) return true;
2020
+ for (const key in current) if (hasMarkedNode(ctx, current[key])) return true;
2021
+ return false;
2022
+ }
2023
+ /**
1992
2024
  * Produces an assignment expression. `id` generates a reference
1993
2025
  * parameter (through `getRefParam`) and has the option to
1994
2026
  * return the reference parameter directly or assign a value to
@@ -2198,7 +2230,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2198
2230
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2199
2231
  return "";
2200
2232
  }
2201
- if (val.t !== 4 && val.i != null && isSerializerRefMarked(base, val.i)) {
2233
+ if (val.t !== 4 && val.i != null && hasMarkedNode(base, val)) {
2234
+ markSerializerRef(base, val.i);
2202
2235
  const serialized = "(" + serialize$1(ctx, val) + ",[" + sentinel + "," + sentinel + "])";
2203
2236
  createSetAssignment(ctx, id, keyRef, getRefParam(ctx, val.i));
2204
2237
  createDeleteAssignment(ctx, id, sentinel);
@@ -2213,7 +2246,8 @@ function serializeMapEntry(ctx, id, key, val, sentinel) {
2213
2246
  if (isIndexedValueInStack(base, val)) {
2214
2247
  const valueRef = getRefParam(ctx, val.i);
2215
2248
  markSerializerRef(base, id);
2216
- if (key.t !== 4 && key.i != null && isSerializerRefMarked(base, key.i)) {
2249
+ if (key.t !== 4 && key.i != null && hasMarkedNode(base, key)) {
2250
+ markSerializerRef(base, key.i);
2217
2251
  const serialized = "(" + serialize$1(ctx, key) + ",[" + sentinel + "," + sentinel + "])";
2218
2252
  createSetAssignment(ctx, id, getRefParam(ctx, key.i), valueRef);
2219
2253
  createDeleteAssignment(ctx, id, sentinel);
@@ -2609,13 +2643,14 @@ function parseAggregateError(ctx, depth, id, current) {
2609
2643
  return createAggregateErrorNode(id, current, options ? parseProperties(ctx, depth, options) : void 0);
2610
2644
  }
2611
2645
  function parseMap(ctx, depth, id, current) {
2646
+ const sentinel = parseMapSentinel(ctx.base);
2612
2647
  const keyNodes = [];
2613
2648
  const valueNodes = [];
2614
2649
  for (const [key, value] of current.entries()) {
2615
2650
  keyNodes.push(parseSOS(ctx, depth, key));
2616
2651
  valueNodes.push(parseSOS(ctx, depth, value));
2617
2652
  }
2618
- return createMapNode(ctx.base, id, keyNodes, valueNodes);
2653
+ return createMapNode(id, sentinel, keyNodes, valueNodes);
2619
2654
  }
2620
2655
  function parseSet(ctx, depth, id, current) {
2621
2656
  const items = [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "seroval",
3
3
  "type": "module",
4
- "version": "1.6.11",
4
+ "version": "1.6.12",
5
5
  "files": [
6
6
  "dist"
7
7
  ],