poe-code 4.0.57 → 4.0.59

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.
Files changed (51) hide show
  1. package/dist/cli/program.js +2 -1
  2. package/dist/cli/program.js.map +1 -1
  3. package/dist/index.js +1755 -2241
  4. package/dist/index.js.map +4 -4
  5. package/dist/metafile.json +1 -1
  6. package/package.json +1 -1
  7. package/packages/safejs/dist/graph-depth.js +4 -0
  8. package/packages/safejs/dist/interp/arguments.d.ts +10 -0
  9. package/packages/safejs/dist/interp/arguments.js +44 -0
  10. package/packages/safejs/dist/interp/async.js +3 -1
  11. package/packages/safejs/dist/interp/values.d.ts +1 -1
  12. package/packages/safejs/dist/interp/values.js +27 -2
  13. package/packages/safejs/dist/lint/index.js +0 -4
  14. package/packages/safejs/dist/lint/rules/AS-async-not-needed.d.ts +1 -1
  15. package/packages/safejs/dist/lint/rules/AS-async-not-needed.js +15 -3
  16. package/packages/safejs/dist/lint/rules/AS-await-non-promise.js +10 -0
  17. package/packages/safejs/dist/lint/rules/AS-destructure-null-default.js +9 -0
  18. package/packages/safejs/dist/lint/rules/AS-export-import-meta.js +17 -0
  19. package/packages/safejs/dist/lint/rules/AS-floating-promise.js +23 -2
  20. package/packages/safejs/dist/lint/rules/AS-frontmatter-field-unused.js +9 -0
  21. package/packages/safejs/dist/lint/rules/AS-jsdoc-type.js +10 -0
  22. package/packages/safejs/dist/lint/rules/AS-large-literal.js +9 -0
  23. package/packages/safejs/dist/lint/rules/AS-missing-async.d.ts +1 -1
  24. package/packages/safejs/dist/lint/rules/AS-missing-async.js +9 -1
  25. package/packages/safejs/dist/lint/rules/AS-mutating-frozen.js +9 -0
  26. package/packages/safejs/dist/lint/rules/AS-needless-template.js +9 -0
  27. package/packages/safejs/dist/lint/rules/AS-shadow-global.js +12 -0
  28. package/packages/safejs/dist/lint/rules/AS-unbounded-loop.js +9 -0
  29. package/packages/safejs/dist/lint/rules/AS-unreachable.js +9 -1
  30. package/packages/safejs/dist/lint/rules/AS-unused-import.js +22 -0
  31. package/packages/safejs/dist/lint/rules/AS001.js +0 -6
  32. package/packages/safejs/dist/lint/rules/AS003.js +22 -0
  33. package/packages/safejs/dist/lint/rules/AS006-007.js +19 -0
  34. package/packages/safejs/dist/lint/rules/AS008.js +9 -0
  35. package/packages/safejs/dist/lint/rules/AS009.js +9 -0
  36. package/packages/safejs/dist/lint/rules/AS010.js +9 -0
  37. package/packages/safejs/dist/lint/rules/AS011.js +9 -0
  38. package/packages/safejs/dist/lint/rules/AS015.js +9 -0
  39. package/packages/safejs/dist/parse/parser.d.ts +1 -0
  40. package/packages/safejs/dist/parse/parser.js +4 -7
  41. package/packages/safejs/dist/snapshot/arguments.d.ts +17 -0
  42. package/packages/safejs/dist/snapshot/arguments.js +34 -0
  43. package/packages/safejs/dist/snapshot/dump-format.js +15 -3
  44. package/packages/safejs/dist/snapshot/restore.js +27 -1
  45. package/packages/safejs/dist/snapshot/serialize.d.ts +2 -1
  46. package/packages/safejs/dist/snapshot/serialize.js +20 -10
  47. package/packages/safejs/dist/snapshot/validation.js +50 -1
  48. package/packages/safejs/dist/lint/rules/AS002.d.ts +0 -13
  49. package/packages/safejs/dist/lint/rules/AS002.js +0 -525
  50. package/packages/safejs/dist/lint/rules/AS012.d.ts +0 -13
  51. package/packages/safejs/dist/lint/rules/AS012.js +0 -384
@@ -31,6 +31,9 @@ class ASUnreachableScanner {
31
31
  }
32
32
  visitStatement(node) {
33
33
  switch (node.type) {
34
+ case "FunctionDeclaration":
35
+ this.visitArrowFunction(node);
36
+ return false;
34
37
  case "BlockStatement":
35
38
  return this.visitBlock(node);
36
39
  case "ExpressionStatement":
@@ -75,7 +78,6 @@ class ASUnreachableScanner {
75
78
  this.visitExpression(node.declaration);
76
79
  return false;
77
80
  case "ImportDeclaration":
78
- case "FunctionDeclaration":
79
81
  case "EmptyStatement":
80
82
  return false;
81
83
  }
@@ -156,6 +158,12 @@ class ASUnreachableScanner {
156
158
  }
157
159
  visitExpression(node) {
158
160
  switch (node.type) {
161
+ case "YieldExpression":
162
+ if (node.argument !== undefined) {
163
+ this.visitExpression(node.argument);
164
+ }
165
+ return;
166
+ case "FunctionExpression":
159
167
  case "ArrowFunctionExpression":
160
168
  this.visitArrowFunction(node);
161
169
  return;
@@ -55,6 +55,9 @@ class ASUnusedImportScanner {
55
55
  }
56
56
  visitStatement(node) {
57
57
  switch (node.type) {
58
+ case "FunctionDeclaration":
59
+ this.visitArrowFunction(node);
60
+ return;
58
61
  case "ExportNamedDeclaration":
59
62
  this.visitVariableDeclaration(node.declaration);
60
63
  return;
@@ -182,9 +185,15 @@ class ASUnusedImportScanner {
182
185
  }
183
186
  visitExpression(node) {
184
187
  switch (node.type) {
188
+ case "YieldExpression":
189
+ if (node.argument !== undefined) {
190
+ this.visitExpression(node.argument);
191
+ }
192
+ return;
185
193
  case "Identifier":
186
194
  this.markRead(node);
187
195
  return;
196
+ case "FunctionExpression":
188
197
  case "ArrowFunctionExpression":
189
198
  this.visitArrowFunction(node);
190
199
  return;
@@ -417,6 +426,10 @@ class ASUnusedImportScanner {
417
426
  bindings.push(...this.collectImportBindings(statement));
418
427
  continue;
419
428
  }
429
+ if (statement.type === "FunctionDeclaration") {
430
+ bindings.push({ kind: "let", name: statement.id.name });
431
+ continue;
432
+ }
420
433
  if (statement.type === "VariableDeclaration") {
421
434
  bindings.push(...this.collectDeclarationBindings(statement));
422
435
  continue;
@@ -430,6 +443,9 @@ class ASUnusedImportScanner {
430
443
  collectBlockBindings(body) {
431
444
  const bindings = [];
432
445
  for (const statement of body) {
446
+ if (statement.type === "FunctionDeclaration") {
447
+ bindings.push({ kind: "let", name: statement.id.name });
448
+ }
433
449
  if (statement.type === "VariableDeclaration") {
434
450
  bindings.push(...this.collectDeclarationBindings(statement));
435
451
  }
@@ -438,6 +454,12 @@ class ASUnusedImportScanner {
438
454
  }
439
455
  collectParameterBindings(node) {
440
456
  const bindings = [];
457
+ if (node.type !== "ArrowFunctionExpression") {
458
+ bindings.push({ kind: "param", name: "arguments" });
459
+ if (node.type === "FunctionExpression" && node.id !== undefined) {
460
+ bindings.push({ kind: "param", name: node.id.name });
461
+ }
462
+ }
441
463
  for (const parameter of node.params) {
442
464
  this.collectBindingNamesFromElement(parameter, "param", bindings);
443
465
  }
@@ -165,11 +165,6 @@ class AS001Scanner {
165
165
  pendingClassBody = true;
166
166
  }
167
167
  }
168
- if (token.value === "function" && nextSignificantChar === "*") {
169
- const generatorStart = this.positionWithinSource(this.skipTriviaFrom(this.index));
170
- const generatorEnd = this.positionWithinSource(this.skipTriviaFrom(this.index) + 1);
171
- this.report("generator", generatorStart, generatorEnd);
172
- }
173
168
  }
174
169
  const isStatementBrace = token.type === "punctuator" && token.value === "{" && canStartStatement;
175
170
  if (token.type === "punctuator" && token.value === "{") {
@@ -218,7 +213,6 @@ class AS001Scanner {
218
213
  switch (token.value) {
219
214
  case "class":
220
215
  case "eval":
221
- case "function":
222
216
  case "Function":
223
217
  case "switch":
224
218
  case "this":
@@ -26,6 +26,9 @@ class AS003Scanner {
26
26
  }
27
27
  visitStatement(node) {
28
28
  switch (node.type) {
29
+ case "FunctionDeclaration":
30
+ this.visitArrowFunction(node);
31
+ return;
29
32
  case "BlockStatement":
30
33
  this.visitBlock(node);
31
34
  return;
@@ -159,9 +162,15 @@ class AS003Scanner {
159
162
  }
160
163
  visitExpression(node) {
161
164
  switch (node.type) {
165
+ case "YieldExpression":
166
+ if (node.argument !== undefined) {
167
+ this.visitExpression(node.argument);
168
+ }
169
+ return;
162
170
  case "Identifier":
163
171
  this.visitIdentifier(node);
164
172
  return;
173
+ case "FunctionExpression":
165
174
  case "ArrowFunctionExpression":
166
175
  this.visitArrowFunction(node);
167
176
  return;
@@ -438,6 +447,10 @@ class AS003Scanner {
438
447
  bindings.push(...this.collectImportBindings(statement));
439
448
  continue;
440
449
  }
450
+ if (statement.type === "FunctionDeclaration") {
451
+ bindings.push({ kind: "let", name: statement.id.name });
452
+ continue;
453
+ }
441
454
  if (statement.type === "VariableDeclaration") {
442
455
  bindings.push(...this.collectDeclarationBindings(statement));
443
456
  continue;
@@ -451,6 +464,9 @@ class AS003Scanner {
451
464
  collectBlockBindings(body) {
452
465
  const bindings = [];
453
466
  for (const statement of body) {
467
+ if (statement.type === "FunctionDeclaration") {
468
+ bindings.push({ kind: "let", name: statement.id.name });
469
+ }
454
470
  if (statement.type === "VariableDeclaration") {
455
471
  bindings.push(...this.collectDeclarationBindings(statement));
456
472
  }
@@ -459,6 +475,12 @@ class AS003Scanner {
459
475
  }
460
476
  collectParameterBindings(node) {
461
477
  const bindings = [];
478
+ if (node.type !== "ArrowFunctionExpression") {
479
+ bindings.push({ kind: "let", name: "arguments" });
480
+ if (node.type === "FunctionExpression" && node.id !== undefined) {
481
+ bindings.push({ kind: "const", name: node.id.name });
482
+ }
483
+ }
462
484
  for (const parameter of node.params) {
463
485
  this.collectBindingNamesFromElement(parameter, "param", bindings);
464
486
  }
@@ -26,6 +26,9 @@ class AS006007Scanner {
26
26
  }
27
27
  visitStatement(node) {
28
28
  switch (node.type) {
29
+ case "FunctionDeclaration":
30
+ this.visitArrowFunction(node);
31
+ return;
29
32
  case "ExportNamedDeclaration":
30
33
  this.visitVariableDeclaration(node.declaration);
31
34
  return;
@@ -159,9 +162,15 @@ class AS006007Scanner {
159
162
  }
160
163
  visitExpression(node) {
161
164
  switch (node.type) {
165
+ case "YieldExpression":
166
+ if (node.argument !== undefined) {
167
+ this.visitExpression(node.argument);
168
+ }
169
+ return;
162
170
  case "Identifier":
163
171
  this.markRead(node);
164
172
  return;
173
+ case "FunctionExpression":
165
174
  case "ArrowFunctionExpression":
166
175
  this.visitArrowFunction(node);
167
176
  return;
@@ -432,6 +441,10 @@ class AS006007Scanner {
432
441
  bindings.push(...this.collectImportBindings(statement));
433
442
  continue;
434
443
  }
444
+ if (statement.type === "FunctionDeclaration") {
445
+ bindings.push(this.createBinding(statement.id, "let"));
446
+ continue;
447
+ }
435
448
  if (statement.type === "VariableDeclaration") {
436
449
  bindings.push(...this.collectDeclarationBindings(statement));
437
450
  continue;
@@ -445,6 +458,9 @@ class AS006007Scanner {
445
458
  collectBlockBindings(body) {
446
459
  const bindings = [];
447
460
  for (const statement of body) {
461
+ if (statement.type === "FunctionDeclaration") {
462
+ bindings.push(this.createBinding(statement.id, "let"));
463
+ }
448
464
  if (statement.type === "VariableDeclaration") {
449
465
  bindings.push(...this.collectDeclarationBindings(statement));
450
466
  }
@@ -453,6 +469,9 @@ class AS006007Scanner {
453
469
  }
454
470
  collectParameterBindings(node) {
455
471
  const bindings = [];
472
+ if (node.type === "FunctionExpression" && node.id !== undefined) {
473
+ bindings.push(this.createBinding(node.id, "param"));
474
+ }
456
475
  for (const parameter of node.params) {
457
476
  this.collectBindingNamesFromElement(parameter, "param", bindings);
458
477
  }
@@ -23,6 +23,9 @@ class AS008Scanner {
23
23
  }
24
24
  visitStatement(node) {
25
25
  switch (node.type) {
26
+ case "FunctionDeclaration":
27
+ this.visitArrowFunction(node);
28
+ return;
26
29
  case "BlockStatement":
27
30
  this.withNestedScope(() => {
28
31
  this.visitBlock(node);
@@ -141,6 +144,12 @@ class AS008Scanner {
141
144
  }
142
145
  visitExpression(node) {
143
146
  switch (node.type) {
147
+ case "YieldExpression":
148
+ if (node.argument !== undefined) {
149
+ this.visitExpression(node.argument);
150
+ }
151
+ return;
152
+ case "FunctionExpression":
144
153
  case "ArrowFunctionExpression":
145
154
  this.visitArrowFunction(node);
146
155
  return;
@@ -28,6 +28,9 @@ class AS009Scanner {
28
28
  }
29
29
  visitStatement(node) {
30
30
  switch (node.type) {
31
+ case "FunctionDeclaration":
32
+ this.visitArrowFunction(node);
33
+ return;
31
34
  case "BlockStatement":
32
35
  this.visitBlockStatement(node.body);
33
36
  return;
@@ -157,6 +160,12 @@ class AS009Scanner {
157
160
  }
158
161
  visitExpression(node) {
159
162
  switch (node.type) {
163
+ case "YieldExpression":
164
+ if (node.argument !== undefined) {
165
+ this.visitExpression(node.argument);
166
+ }
167
+ return;
168
+ case "FunctionExpression":
160
169
  case "ArrowFunctionExpression":
161
170
  this.visitArrowFunction(node);
162
171
  return;
@@ -38,6 +38,9 @@ class AS010Scanner {
38
38
  }
39
39
  visitStatement(node) {
40
40
  switch (node.type) {
41
+ case "FunctionDeclaration":
42
+ this.visitArrowFunction(node);
43
+ return;
41
44
  case "BlockStatement":
42
45
  this.visitBlock(node);
43
46
  return;
@@ -176,9 +179,15 @@ class AS010Scanner {
176
179
  }
177
180
  visitExpression(node) {
178
181
  switch (node.type) {
182
+ case "YieldExpression":
183
+ if (node.argument !== undefined) {
184
+ this.visitExpression(node.argument);
185
+ }
186
+ return;
179
187
  case "Identifier":
180
188
  this.markRead(node);
181
189
  return;
190
+ case "FunctionExpression":
182
191
  case "ArrowFunctionExpression":
183
192
  this.visitArrowFunction(node);
184
193
  return;
@@ -21,6 +21,9 @@ class AS011Scanner {
21
21
  }
22
22
  visitStatement(node) {
23
23
  switch (node.type) {
24
+ case "FunctionDeclaration":
25
+ this.visitArrowFunction(node);
26
+ return;
24
27
  case "BlockStatement":
25
28
  for (const statement of node.body) {
26
29
  this.visitStatement(statement);
@@ -138,6 +141,12 @@ class AS011Scanner {
138
141
  }
139
142
  visitExpression(node) {
140
143
  switch (node.type) {
144
+ case "YieldExpression":
145
+ if (node.argument !== undefined) {
146
+ this.visitExpression(node.argument);
147
+ }
148
+ return;
149
+ case "FunctionExpression":
141
150
  case "ArrowFunctionExpression":
142
151
  this.visitArrowFunction(node);
143
152
  return;
@@ -19,6 +19,9 @@ class AS015Scanner {
19
19
  }
20
20
  visitStatement(node) {
21
21
  switch (node.type) {
22
+ case "FunctionDeclaration":
23
+ this.visitArrowFunction(node);
24
+ return;
22
25
  case "BlockStatement":
23
26
  for (const statement of node.body) {
24
27
  this.visitStatement(statement);
@@ -136,6 +139,12 @@ class AS015Scanner {
136
139
  }
137
140
  visitExpression(node) {
138
141
  switch (node.type) {
142
+ case "YieldExpression":
143
+ if (node.argument !== undefined) {
144
+ this.visitExpression(node.argument);
145
+ }
146
+ return;
147
+ case "FunctionExpression":
139
148
  case "ArrowFunctionExpression":
140
149
  this.visitArrowFunction(node);
141
150
  return;
@@ -346,6 +346,7 @@ export type ArrowFunctionExpression = BaseNode & {
346
346
  expression: boolean;
347
347
  params: Array<AssignmentPattern | ArrayPattern | Identifier | ObjectPattern | RestElement>;
348
348
  };
349
+ export type FunctionNode = ArrowFunctionExpression | FunctionDeclaration | FunctionExpression;
349
350
  export type Expression = ArrowFunctionExpression | AssignmentExpression | ArrayExpression | AwaitExpression | BinaryExpression | BooleanLiteral | CallExpression | ConditionalExpression | FunctionExpression | Identifier | LogicalExpression | MemberExpression | MetaProperty | NewExpression | NullLiteral | NumericLiteral | ObjectExpression | RegexLiteral | SequenceExpression | StringLiteral | TaggedTemplateExpression | TemplateLiteral | ThisExpression | UnaryExpression | UpdateExpression | UndefinedLiteral | YieldExpression;
350
351
  export type ParseResult = Expression | Statement;
351
352
  export declare function parse(source: string, filename?: string): ParseResult;
@@ -170,13 +170,13 @@ class Parser {
170
170
  };
171
171
  }
172
172
  parseExpression(options = {}) {
173
- const first = this.parseNonSequenceExpression();
173
+ const first = this.parseAssignmentExpression();
174
174
  if (options.allowSequence !== true || this.consumePunctuator(",") === undefined) {
175
175
  return first;
176
176
  }
177
177
  const expressions = [first.node];
178
178
  do {
179
- expressions.push(this.parseNonSequenceExpression().node);
179
+ expressions.push(this.parseAssignmentExpression().node);
180
180
  } while (this.consumePunctuator(",") !== undefined);
181
181
  return {
182
182
  node: {
@@ -187,7 +187,7 @@ class Parser {
187
187
  parenthesized: false
188
188
  };
189
189
  }
190
- parseNonSequenceExpression() {
190
+ parseAssignmentExpression() {
191
191
  const arrowFunction = this.tryParseArrowFunctionExpression();
192
192
  if (arrowFunction !== undefined) {
193
193
  return {
@@ -195,9 +195,6 @@ class Parser {
195
195
  parenthesized: false
196
196
  };
197
197
  }
198
- return this.parseAssignmentExpression();
199
- }
200
- parseAssignmentExpression() {
201
198
  const patternAssignment = this.tryParsePatternAssignmentExpression();
202
199
  if (patternAssignment !== undefined) {
203
200
  return {
@@ -271,7 +268,7 @@ class Parser {
271
268
  }
272
269
  const consequent = this.parseExpression();
273
270
  this.expectPunctuator(":");
274
- const alternate = this.parseConditionalExpression();
271
+ const alternate = this.parseAssignmentExpression();
275
272
  return {
276
273
  node: {
277
274
  type: "ConditionalExpression",
@@ -0,0 +1,17 @@
1
+ import type { SandboxObject, SandboxValue } from "../interp/values.js";
2
+ type PropertyFlags = {
3
+ configurable: boolean;
4
+ enumerable: boolean;
5
+ writable: boolean;
6
+ };
7
+ export type SerializedArguments<TValue> = {
8
+ kind: "arguments";
9
+ extensible: boolean;
10
+ lengthBeforeCallee: boolean;
11
+ iterator: PropertyFlags | null;
12
+ properties: Record<string, PropertyFlags & {
13
+ value: TValue;
14
+ }>;
15
+ };
16
+ export declare function serializeArguments<TValue>(value: SandboxObject, serializeValue: (entry: SandboxValue, key: string) => TValue): SerializedArguments<TValue>;
17
+ export {};
@@ -0,0 +1,34 @@
1
+ export function serializeArguments(value, serializeValue) {
2
+ const properties = Object.create(null);
3
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
4
+ if (!("value" in descriptor)) {
5
+ if (key !== "callee")
6
+ throw new TypeError(`Cannot snapshot arguments accessor '${key}'.`);
7
+ continue;
8
+ }
9
+ properties[key] = {
10
+ value: serializeValue(descriptor.value, key),
11
+ configurable: descriptor.configurable === true,
12
+ enumerable: descriptor.enumerable === true,
13
+ writable: descriptor.writable === true
14
+ };
15
+ }
16
+ const iterator = Object.getOwnPropertyDescriptor(value, Symbol.iterator);
17
+ if (iterator !== undefined && iterator.value !== Array.prototype.values) {
18
+ throw new TypeError("Cannot snapshot a replaced arguments iterator.");
19
+ }
20
+ const names = Object.getOwnPropertyNames(value);
21
+ return {
22
+ kind: "arguments",
23
+ extensible: Object.isExtensible(value),
24
+ lengthBeforeCallee: names.includes("length") && names.indexOf("length") < names.indexOf("callee"),
25
+ iterator: iterator === undefined
26
+ ? null
27
+ : {
28
+ configurable: iterator.configurable === true,
29
+ enumerable: iterator.enumerable === true,
30
+ writable: iterator.writable === true
31
+ },
32
+ properties
33
+ };
34
+ }
@@ -1,5 +1,7 @@
1
1
  export const DUMP_FORMAT_VERSION = 1;
2
2
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
3
+ import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
4
+ import { serializeArguments } from "./arguments.js";
3
5
  const SKIP_VALUE = Symbol("SafeJS.skip-dump-value");
4
6
  export function serializeSafeJSSnapshot(snapshot) {
5
7
  for (const [key, value] of getEnumerableDataEntries(snapshot)) {
@@ -76,7 +78,13 @@ function serializeHeapReference(value, path, state) {
76
78
  }
77
79
  if (!state.serializedHeapIds.has(id)) {
78
80
  state.serializedHeapIds.add(id);
79
- if (Array.isArray(value)) {
81
+ if (isSandboxArguments(value)) {
82
+ state.heap[String(id)] = serializeArguments(value, (entry, key) => {
83
+ const serialized = serializeDumpValue(entry, `${path}.${key}`, state);
84
+ return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
85
+ });
86
+ }
87
+ else if (Array.isArray(value)) {
80
88
  state.heap[String(id)] = {
81
89
  kind: "array",
82
90
  items: serializeArrayItems(value, path, state)
@@ -116,7 +124,7 @@ function indexHeapContainers(snapshot) {
116
124
  const heapIds = new WeakMap();
117
125
  let nextId = 1;
118
126
  for (const [value, stat] of stats.entries()) {
119
- if (stat.count > 1 || stat.cyclic) {
127
+ if (stat.count > 1 || stat.cyclic || isSandboxArguments(value)) {
120
128
  heapIds.set(value, nextId);
121
129
  nextId += 1;
122
130
  }
@@ -149,7 +157,11 @@ function collectContainerStats(value, stats, ancestors) {
149
157
  }
150
158
  stat.expanded = true;
151
159
  ancestors.add(value);
152
- const entries = Array.isArray(value) ? getArrayDataItems(value) : getEnumerableDataValues(value);
160
+ const entries = isSandboxArguments(value)
161
+ ? getSandboxArgumentEntries(value).map(([, entry]) => entry)
162
+ : Array.isArray(value)
163
+ ? getArrayDataItems(value)
164
+ : getEnumerableDataValues(value);
153
165
  for (const entry of entries) {
154
166
  collectContainerStats(entry, stats, ancestors);
155
167
  }
@@ -2,7 +2,7 @@ import { Budget } from "../interp/budget.js";
2
2
  import { SnapshotMismatchError } from "../restore.js";
3
3
  import { Scope } from "../interp/interpreter.js";
4
4
  import { wrapCallerInjectedBindings } from "../interp/host-bridge.js";
5
- import { createSandboxClosure, createSandboxGenerator, createSandboxMap, createSandboxPromise, createSandboxRegex, createSandboxSet, measureSandboxData } from "../interp/values.js";
5
+ import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxMap, createSandboxPromise, createSandboxRegex, createSandboxSet, measureSandboxData } from "../interp/values.js";
6
6
  import { createGeneratorChannel, restoreGeneratorChannel } from "../interp/generator.js";
7
7
  import { hashSource } from "../parse/hash.js";
8
8
  import { parseModule } from "../parse/parser.js";
@@ -327,6 +327,30 @@ function restoreHeapValue(id, state) {
327
327
  }
328
328
  return array;
329
329
  }
330
+ if (serialized.kind === "arguments") {
331
+ const args = createSandboxArguments([]);
332
+ if (!serialized.lengthBeforeCallee)
333
+ delete args.length;
334
+ state.heapValueById.set(id, args);
335
+ for (const [key, descriptor] of Object.entries(serialized.properties)) {
336
+ Object.defineProperty(args, key, {
337
+ ...descriptor,
338
+ value: deserializeValue(descriptor.value, state)
339
+ });
340
+ }
341
+ if (serialized.iterator === null) {
342
+ Reflect.deleteProperty(args, Symbol.iterator);
343
+ }
344
+ else {
345
+ Object.defineProperty(args, Symbol.iterator, {
346
+ ...serialized.iterator,
347
+ value: Array.prototype.values
348
+ });
349
+ }
350
+ if (!serialized.extensible)
351
+ Object.preventExtensions(args);
352
+ return args;
353
+ }
330
354
  if (serialized.kind === "map") {
331
355
  const map = createSandboxMap();
332
356
  state.heapValueById.set(id, map);
@@ -399,6 +423,8 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
399
423
  }
400
424
  if (node.type !== "ArrowFunctionExpression") {
401
425
  scope.declare("this", "const", thisValue);
426
+ state.budget.allocateArrayLength(args.length);
427
+ scope.declare("arguments", "let", createSandboxArguments(args));
402
428
  }
403
429
  for (let index = 0; index < node.params.length; index += 1) {
404
430
  const param = node.params[index];
@@ -1,3 +1,4 @@
1
+ import { type SerializedArguments } from "./arguments.js";
1
2
  import { type SandboxMap, type SandboxGenerator, type SandboxRegex, type SandboxSet } from "../interp/values.js";
2
3
  type SnapshotId = number | string;
3
4
  type SerializedUndefinedValue = {
@@ -36,7 +37,7 @@ export type SerializedReferenceValue = {
36
37
  kind: "ref";
37
38
  id: number;
38
39
  };
39
- export type SerializedHeapValue = {
40
+ export type SerializedHeapValue = SerializedArguments<SerializedSnapshotValue> | {
40
41
  kind: "array";
41
42
  items: SerializedSnapshotValue[];
42
43
  } | {
@@ -1,6 +1,7 @@
1
1
  import { hashSource } from "../parse/hash.js";
2
2
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
3
- import { isSandboxGenerator, isSandboxMap, isSandboxRegex, isSandboxSet } from "../interp/values.js";
3
+ import { serializeArguments } from "./arguments.js";
4
+ import { isSandboxArguments, isSandboxGenerator, isSandboxMap, isSandboxRegex, isSandboxSet } from "../interp/values.js";
4
5
  export class UnsnapshotableValueError extends Error {
5
6
  path;
6
7
  constructor(path) {
@@ -180,7 +181,10 @@ function serializeHeapReference(value, path, state) {
180
181
  }
181
182
  if (!state.serializedHeapIds.has(id)) {
182
183
  state.serializedHeapIds.add(id);
183
- if (isSandboxMap(value)) {
184
+ if (isSandboxArguments(value)) {
185
+ state.heap[String(id)] = serializeArguments(value, (entry, key) => serializeValue(entry, `${path}.${key}`, state));
186
+ }
187
+ else if (isSandboxMap(value)) {
184
188
  state.heap[String(id)] = {
185
189
  kind: "map",
186
190
  entries: [...value.entries].map(([key, entry], index) => [
@@ -273,7 +277,11 @@ function indexHeapContainers(input) {
273
277
  const heapIds = new WeakMap();
274
278
  let nextId = 1;
275
279
  for (const [value, stat] of stats.entries()) {
276
- if (stat.count > 1 || stat.cyclic || isSandboxMap(value) || isSandboxSet(value)) {
280
+ if (stat.count > 1 ||
281
+ stat.cyclic ||
282
+ isSandboxArguments(value) ||
283
+ isSandboxMap(value) ||
284
+ isSandboxSet(value)) {
277
285
  heapIds.set(value, nextId);
278
286
  nextId += 1;
279
287
  }
@@ -313,13 +321,15 @@ function collectContainerStats(value, stats, ancestors) {
313
321
  }
314
322
  stat.expanded = true;
315
323
  ancestors.add(value);
316
- const entries = isSandboxMap(value)
317
- ? [...value.entries].flatMap(([key, entry]) => [key, entry])
318
- : isSandboxSet(value)
319
- ? [...value.values]
320
- : Array.isArray(value)
321
- ? value
322
- : Object.values(value);
324
+ const entries = isSandboxArguments(value)
325
+ ? Object.values(Object.getOwnPropertyDescriptors(value)).flatMap((descriptor) => "value" in descriptor ? [descriptor.value] : [])
326
+ : isSandboxMap(value)
327
+ ? [...value.entries].flatMap(([key, entry]) => [key, entry])
328
+ : isSandboxSet(value)
329
+ ? [...value.values]
330
+ : Array.isArray(value)
331
+ ? value
332
+ : Object.values(value);
323
333
  for (const entry of entries) {
324
334
  collectContainerStats(entry, stats, ancestors);
325
335
  }