poe-code 6.0.0 → 7.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "6.0.0",
3
+ "version": "7.0.0",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- import type { ArrowFunctionExpression, AwaitExpression, FunctionDeclaration, FunctionExpression, ParseResult, SourceSpan } from "../parse.js";
1
+ import type { ArrowFunctionExpression, AwaitExpression, BlockStatement, FunctionDeclaration, FunctionExpression, ParseResult, SourceSpan } from "../parse.js";
2
2
  import { type GeneratorCompletion } from "./generator.js";
3
3
  import { type OtelSpan } from "../observability/otel.js";
4
4
  import type { Budget } from "./budget.js";
@@ -25,6 +25,7 @@ export type AsyncEvaluationContext = {
25
25
  onSuspend?: () => void;
26
26
  captureReplayState?: () => unknown;
27
27
  rootNode?: ParseResult;
28
+ functionBody?: BlockStatement;
28
29
  restoredLoopIterations: Map<number, LoopIterationSnapshot>;
29
30
  resumeTarget?: {
30
31
  nodeId?: number;
@@ -5,6 +5,7 @@ import { getThenable, resolveSandboxValue } from "./promise.js";
5
5
  import { runAsyncPrefix, suspendJob } from "./jobs.js";
6
6
  import { awaitSandboxValue } from "./cancel.js";
7
7
  import { hoistVarDeclarations } from "./var-hoist.js";
8
+ import { boundIdentifiers, containsParameterExpression, hoistedVarDeclarations } from "../parse/bindings.js";
8
9
  import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxPromise, allocateProducedSandboxValue, isSandboxPromise } from "./values.js";
9
10
  export function emitResumeBreakpoint(context, breakpoint) {
10
11
  context.onYield?.({
@@ -112,6 +113,7 @@ function createGeneratorClosure(node, context, evaluateNode) {
112
113
  const channel = createGeneratorChannel(async (generatorYield) => {
113
114
  const result = await evaluateNode(node.body, {
114
115
  ...closureContext,
116
+ functionBody: node.body,
115
117
  generatorYield: (value, yieldNodeId) => {
116
118
  generator.state = "suspended";
117
119
  return generatorYield(value, yieldNodeId);
@@ -166,6 +168,7 @@ async function executeClosure(node, args, thisValue, context, evaluateNode) {
166
168
  const scope = await createClosureScope(node, args, thisValue, context, evaluateNode);
167
169
  const result = await evaluateNode(node.body, {
168
170
  ...context,
171
+ functionBody: node.body.type === "BlockStatement" ? node.body : undefined,
169
172
  scope
170
173
  });
171
174
  if (result.kind === "error") {
@@ -187,16 +190,32 @@ async function createClosureScope(node, args, thisValue, context, evaluateNode)
187
190
  scope.declare("arguments", "let", createSandboxArguments(args));
188
191
  }
189
192
  await bindParameters(node.params, args, scope, context, evaluateNode);
190
- hoistVarDeclarations(node.body, scope);
191
- return scope;
193
+ const bodyScope = node.params.some(containsParameterExpression)
194
+ ? scope.child({}, { functionBoundary: true })
195
+ : scope;
196
+ hoistVarDeclarations(node.body, bodyScope);
197
+ if (bodyScope !== scope) {
198
+ for (const declaration of hoistedVarDeclarations([node.body])) {
199
+ for (const declarator of declaration.declarations) {
200
+ for (const identifier of boundIdentifiers(declarator.id)) {
201
+ if (!scope.hasOwnBinding(identifier.name))
202
+ continue;
203
+ const parameter = scope.lookup(identifier.name);
204
+ if (parameter.found)
205
+ bodyScope.assign(identifier.name, parameter.value);
206
+ }
207
+ }
208
+ }
209
+ }
210
+ return bodyScope;
192
211
  }
193
212
  function isBlockBody(body) {
194
213
  return body.type === "BlockStatement";
195
214
  }
196
215
  async function bindParameters(params, args, scope, context, evaluateNode) {
197
216
  for (const param of params) {
198
- for (const name of getParameterBindingNames(param)) {
199
- scope.predeclare(name, "let");
217
+ for (const identifier of boundIdentifiers(param)) {
218
+ scope.predeclare(identifier.name, "var");
200
219
  }
201
220
  }
202
221
  for (let index = 0; index < params.length; index += 1) {
@@ -204,7 +223,7 @@ async function bindParameters(params, args, scope, context, evaluateNode) {
204
223
  if (param.type === "RestElement") {
205
224
  const rest = args.slice(index);
206
225
  context.budget.allocateArrayLength(rest.length);
207
- const binding = await bindPattern(param, rest, { kind: "let" }, scope, {
226
+ const binding = await bindPattern(param, rest, { kind: "var", initialize: true }, scope, {
208
227
  evaluate: (defaultNode) => evaluateNode(defaultNode, { ...context, scope })
209
228
  });
210
229
  if (!binding.ok) {
@@ -217,7 +236,7 @@ async function bindParameters(params, args, scope, context, evaluateNode) {
217
236
  }
218
237
  return;
219
238
  }
220
- const binding = await bindPattern(param, args[index], { kind: "let" }, scope, {
239
+ const binding = await bindPattern(param, args[index], { kind: "var", initialize: true }, scope, {
221
240
  evaluate: (defaultNode) => evaluateNode(defaultNode, { ...context, scope })
222
241
  });
223
242
  if (!binding.ok) {
@@ -230,24 +249,6 @@ async function bindParameters(params, args, scope, context, evaluateNode) {
230
249
  }
231
250
  }
232
251
  }
233
- function getParameterBindingNames(pattern) {
234
- switch (pattern.type) {
235
- case "Identifier":
236
- return [pattern.name];
237
- case "MemberExpression":
238
- return [];
239
- case "AssignmentPattern":
240
- return getParameterBindingNames(pattern.left);
241
- case "RestElement":
242
- return getParameterBindingNames(pattern.argument);
243
- case "ArrayPattern":
244
- return pattern.elements.flatMap((element) => element === null ? [] : getParameterBindingNames(element));
245
- case "ObjectPattern":
246
- return pattern.properties.flatMap((property) => property.type === "RestElement"
247
- ? getParameterBindingNames(property)
248
- : getParameterBindingNames(property.value));
249
- }
250
- }
251
252
  export function normalizeClosureResult(result, budget) {
252
253
  if (isSandboxPromise(result) &&
253
254
  (result.synchronousPrefix !== undefined || result.hostCall !== undefined)) {
@@ -803,7 +803,9 @@ function isParseResult(value) {
803
803
  Object.hasOwn(value, "span"));
804
804
  }
805
805
  function createBlockContext(node, context) {
806
- const scope = node === context.rootNode || context.generatorResume !== undefined
806
+ const scope = node === context.rootNode ||
807
+ node === context.functionBody ||
808
+ context.generatorResume !== undefined
807
809
  ? context.scope
808
810
  : context.scope.child();
809
811
  const blockContext = {
@@ -816,15 +818,15 @@ function createBlockContext(node, context) {
816
818
  return blockContext;
817
819
  }
818
820
  function predeclareBlockBindings(node, context) {
819
- predeclareStatementListBindings(node.body, context);
821
+ predeclareStatementListBindings(node.body, context, node === context.functionBody || node === context.rootNode);
820
822
  }
821
- function predeclareStatementListBindings(statements, context) {
823
+ function predeclareStatementListBindings(statements, context, functionBody = false) {
822
824
  const { scope } = context;
823
825
  const names = new Set();
824
826
  for (const statement of statements) {
825
827
  if (statement.type === "FunctionDeclaration") {
826
828
  const name = statement.id.name;
827
- if (names.has(name)) {
829
+ if (names.has(name) && !(functionBody && scope.getOwnBindingKind(name) === "var")) {
828
830
  throw new Error(`Cannot redeclare binding '${name}' in the same scope.`);
829
831
  }
830
832
  const closure = createInterpretedClosure(statement, context, evaluateNode);
@@ -838,7 +840,7 @@ function predeclareStatementListBindings(statements, context) {
838
840
  throw new Error(`Cannot redeclare binding '${name}' in the same scope.`);
839
841
  }
840
842
  names.add(name);
841
- scope.declare(name, "const", closure);
843
+ scope.declare(name, functionBody ? "var" : "let", closure);
842
844
  continue;
843
845
  }
844
846
  if (statement.type !== "VariableDeclaration" || statement.kind === "var") {
@@ -5,6 +5,7 @@ import { type SandboxValue } from "./values.js";
5
5
  type Pattern = VariableDeclarator["id"] | AssignmentPattern | MemberExpression | RestElement;
6
6
  export type PatternTarget = {
7
7
  kind: VariableDeclarationKind;
8
+ initialize?: true;
8
9
  } | {
9
10
  assign: true;
10
11
  };
@@ -20,7 +20,7 @@ export async function bindPattern(pattern, value, target, scope, context) {
20
20
  }
21
21
  }
22
22
  function bindIdentifier(pattern, value, target, scope) {
23
- if ("assign" in target || target.kind === "var") {
23
+ if ("assign" in target || (target.kind === "var" && target.initialize !== true)) {
24
24
  if ("assign" in target) {
25
25
  const binding = scope.lookup(pattern.name);
26
26
  if (!binding.found) {
@@ -1,140 +1,10 @@
1
+ import { boundIdentifiers, hoistedVarDeclarations } from "../parse/bindings.js";
1
2
  export function hoistVarDeclarations(node, scope) {
2
- if (node.type === "BlockStatement") {
3
- for (const statement of node.body) {
4
- hoistVarStatement(statement, scope);
5
- }
6
- return;
7
- }
8
- switch (node.type) {
9
- case "VariableDeclaration":
10
- case "IfStatement":
11
- case "ForStatement":
12
- case "ForInStatement":
13
- case "ForOfStatement":
14
- case "WhileStatement":
15
- case "DoWhileStatement":
16
- case "TryStatement":
17
- case "SwitchStatement":
18
- case "ExportNamedDeclaration":
19
- hoistVarStatement(node, scope);
20
- return;
21
- default:
22
- return;
23
- }
24
- }
25
- function hoistVarStatement(statement, scope) {
26
- switch (statement.type) {
27
- case "VariableDeclaration":
28
- declareVarBindings(statement, scope);
29
- return;
30
- case "BlockStatement":
31
- hoistVarDeclarations(statement, scope);
32
- return;
33
- case "IfStatement":
34
- hoistVarStatement(statement.consequent, scope);
35
- if (statement.alternate !== undefined) {
36
- hoistVarStatement(statement.alternate, scope);
37
- }
38
- return;
39
- case "ForStatement":
40
- if (statement.init?.type === "VariableDeclaration") {
41
- declareVarBindings(statement.init, scope);
42
- }
43
- hoistVarStatement(statement.body, scope);
44
- return;
45
- case "ForInStatement":
46
- case "ForOfStatement":
47
- if (statement.left.type === "VariableDeclaration") {
48
- declareVarBindings(statement.left, scope);
49
- }
50
- hoistVarStatement(statement.body, scope);
51
- return;
52
- case "WhileStatement":
53
- case "DoWhileStatement":
54
- hoistVarStatement(statement.body, scope);
55
- return;
56
- case "TryStatement":
57
- hoistVarDeclarations(statement.block, scope);
58
- if (statement.handler !== undefined) {
59
- hoistVarDeclarations(statement.handler.body, scope);
60
- }
61
- if (statement.finalizer !== undefined) {
62
- hoistVarDeclarations(statement.finalizer, scope);
3
+ for (const declaration of hoistedVarDeclarations([node])) {
4
+ for (const declarator of declaration.declarations) {
5
+ for (const identifier of boundIdentifiers(declarator.id)) {
6
+ scope.declareVar(identifier.name);
63
7
  }
64
- return;
65
- case "SwitchStatement":
66
- for (const switchCase of statement.cases) {
67
- for (const consequent of switchCase.consequent) {
68
- hoistVarStatement(consequent, scope);
69
- }
70
- }
71
- return;
72
- case "ExportNamedDeclaration":
73
- hoistVarStatement(statement.declaration, scope);
74
- return;
75
- case "FunctionDeclaration":
76
- case "ExportDefaultDeclaration":
77
- case "ImportDeclaration":
78
- case "BreakStatement":
79
- case "ContinueStatement":
80
- case "EmptyStatement":
81
- case "ExpressionStatement":
82
- case "ReturnStatement":
83
- case "ThrowStatement":
84
- return;
85
- }
86
- }
87
- function declareVarBindings(declaration, scope) {
88
- if (declaration.kind !== "var") {
89
- return;
90
- }
91
- for (const declarator of declaration.declarations) {
92
- for (const name of getPatternBindingNames(declarator.id)) {
93
- scope.declareVar(name);
94
8
  }
95
9
  }
96
10
  }
97
- function getPatternBindingNames(pattern) {
98
- switch (pattern.type) {
99
- case "Identifier":
100
- return [pattern.name];
101
- case "ArrayPattern":
102
- return pattern.elements.flatMap((element) => element === null || element.type === "MemberExpression"
103
- ? []
104
- : getNestedPatternBindingNames(element));
105
- case "ObjectPattern":
106
- return pattern.properties.flatMap((property) => property.type === "RestElement"
107
- ? property.argument.type === "MemberExpression"
108
- ? []
109
- : getNestedPatternBindingNames(property.argument)
110
- : property.value.type === "MemberExpression"
111
- ? []
112
- : getNestedPatternBindingNames(property.value));
113
- }
114
- }
115
- function getNestedPatternBindingNames(pattern) {
116
- switch (pattern.type) {
117
- case "Identifier":
118
- return [pattern.name];
119
- case "AssignmentPattern":
120
- return pattern.left.type === "MemberExpression"
121
- ? []
122
- : getNestedPatternBindingNames(pattern.left);
123
- case "RestElement":
124
- return pattern.argument.type === "MemberExpression"
125
- ? []
126
- : getNestedPatternBindingNames(pattern.argument);
127
- case "ArrayPattern":
128
- return pattern.elements.flatMap((element) => element === null || element.type === "MemberExpression"
129
- ? []
130
- : getNestedPatternBindingNames(element));
131
- case "ObjectPattern":
132
- return pattern.properties.flatMap((property) => property.type === "RestElement"
133
- ? property.argument.type === "MemberExpression"
134
- ? []
135
- : getNestedPatternBindingNames(property.argument)
136
- : property.value.type === "MemberExpression"
137
- ? []
138
- : getNestedPatternBindingNames(property.value));
139
- }
140
- }
@@ -3,14 +3,12 @@ import { AS003 } from "./rules/AS003.js";
3
3
  import { AS004 } from "./rules/AS004.js";
4
4
  import { AS005 } from "./rules/AS005.js";
5
5
  import { AS006_007 } from "./rules/AS006-007.js";
6
- import { AS008 } from "./rules/AS008.js";
7
6
  import { AS009 } from "./rules/AS009.js";
8
7
  import { AS010 } from "./rules/AS010.js";
9
8
  import { AS011 } from "./rules/AS011.js";
10
9
  import { AS013 } from "./rules/AS013.js";
11
10
  import { AS015 } from "./rules/AS015.js";
12
11
  import { AS_ASYNC_NOT_NEEDED } from "./rules/AS-async-not-needed.js";
13
- import { AS_AWAIT_NON_PROMISE } from "./rules/AS-await-non-promise.js";
14
12
  import { AS_DESTRUCTURE_NULL_DEFAULT } from "./rules/AS-destructure-null-default.js";
15
13
  import { AS_EXPORT_IMPORT_META } from "./rules/AS-export-import-meta.js";
16
14
  import { AS_FLOATING_PROMISE } from "./rules/AS-floating-promise.js";
@@ -35,14 +33,12 @@ const RULES = [
35
33
  AS_UNUSED_IMPORT,
36
34
  AS006_007,
37
35
  AS_MISSING_ASYNC,
38
- AS008,
39
36
  AS009,
40
37
  AS010,
41
38
  AS011,
42
39
  AS013,
43
40
  AS015,
44
41
  AS_IMPORT_CYCLE,
45
- AS_AWAIT_NON_PROMISE,
46
42
  AS_FLOATING_PROMISE,
47
43
  AS_ASYNC_NOT_NEEDED,
48
44
  AS_JSDOC_TYPE,
@@ -156,7 +156,10 @@ class AS001Scanner {
156
156
  (previousToken.value === "." || previousToken.value === "?.");
157
157
  const isPropertyKey = nextSignificantChar === ":" && !canStartStatement;
158
158
  const isMemberName = isMemberNameToken(token, previousToken, previousPreviousToken, braceContextStack, nextSignificantChar);
159
- if (canStartStatement && nextSignificantChar === ":" && !this.isLoopLabelStart()) {
159
+ if (canStartStatement &&
160
+ nextSignificantChar === ":" &&
161
+ token.value !== "default" &&
162
+ !this.isLoopLabelStart()) {
160
163
  this.report("label", token.start, this.positionWithinSource(token.start.offset + token.value.length));
161
164
  }
162
165
  else if (!isMemberProperty && !isPropertyKey && !isMemberName) {
@@ -214,9 +217,6 @@ class AS001Scanner {
214
217
  case "class":
215
218
  case "eval":
216
219
  case "Function":
217
- case "switch":
218
- case "this":
219
- case "var":
220
220
  case "with":
221
221
  this.report(token.value, token.start, token.end);
222
222
  return;
@@ -1,5 +1,6 @@
1
1
  import { parseModule } from "../../parse/parser.js";
2
2
  import { KNOWN_RUNTIME_GLOBALS } from "./known-globals.js";
3
+ import { hoistedVarDeclarations } from "../../parse/bindings.js";
3
4
  export function AS003(source, options = {}) {
4
5
  return new AS003Scanner(options.filename ?? "<input>", new Set([...KNOWN_RUNTIME_GLOBALS, ...(options.allowedGlobals ?? [])])).scan(source);
5
6
  }
@@ -52,6 +53,9 @@ class AS003Scanner {
52
53
  case "TryStatement":
53
54
  this.visitTryStatement(node);
54
55
  return;
56
+ case "SwitchStatement":
57
+ this.visitSwitchStatement(node);
58
+ return;
55
59
  case "VariableDeclaration":
56
60
  this.visitVariableDeclaration(node);
57
61
  return;
@@ -75,8 +79,14 @@ class AS003Scanner {
75
79
  return;
76
80
  }
77
81
  }
78
- visitBlock(node) {
79
- this.withScope(this.collectBlockBindings(node.body), () => {
82
+ visitBlock(node, functionBody = false) {
83
+ const bindings = this.collectBlockBindings(node.body);
84
+ if (functionBody) {
85
+ for (const declaration of hoistedVarDeclarations(node.body)) {
86
+ bindings.push(...this.collectDeclarationBindings(declaration));
87
+ }
88
+ }
89
+ this.withScope(bindings, () => {
80
90
  for (const statement of node.body) {
81
91
  this.visitStatement(statement);
82
92
  }
@@ -93,7 +103,9 @@ class AS003Scanner {
93
103
  }
94
104
  }
95
105
  visitForStatement(node) {
96
- const bindings = node.init?.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.init) : [];
106
+ const bindings = node.init?.type === "VariableDeclaration" && node.init.kind !== "var"
107
+ ? this.collectDeclarationBindings(node.init)
108
+ : [];
97
109
  this.withScope(bindings, () => {
98
110
  if (node.init !== undefined) {
99
111
  if (node.init.type === "VariableDeclaration") {
@@ -113,7 +125,9 @@ class AS003Scanner {
113
125
  });
114
126
  }
115
127
  visitForOfStatement(node) {
116
- const bindings = node.left.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.left) : [];
128
+ const bindings = node.left.type === "VariableDeclaration" && node.left.kind !== "var"
129
+ ? this.collectDeclarationBindings(node.left)
130
+ : [];
117
131
  this.withScope(bindings, () => {
118
132
  if (node.left.type === "VariableDeclaration") {
119
133
  this.visitVariableDeclaration(node.left);
@@ -129,6 +143,17 @@ class AS003Scanner {
129
143
  this.visitExpression(node.test);
130
144
  this.visitStatement(node.body);
131
145
  }
146
+ visitSwitchStatement(node) {
147
+ this.visitExpression(node.discriminant);
148
+ this.withScope(this.collectBlockBindings(node.cases.flatMap((switchCase) => switchCase.consequent)), () => {
149
+ for (const switchCase of node.cases) {
150
+ if (switchCase.test !== undefined)
151
+ this.visitExpression(switchCase.test);
152
+ for (const statement of switchCase.consequent)
153
+ this.visitStatement(statement);
154
+ }
155
+ });
156
+ }
132
157
  visitTryStatement(node) {
133
158
  this.visitBlock(node.block);
134
159
  if (node.handler !== undefined) {
@@ -202,8 +227,20 @@ class AS003Scanner {
202
227
  this.visitAssignmentExpression(node);
203
228
  return;
204
229
  case "CallExpression":
230
+ case "NewExpression":
205
231
  this.visitCallExpression(node);
206
232
  return;
233
+ case "SequenceExpression":
234
+ for (const expression of node.expressions)
235
+ this.visitExpression(expression);
236
+ return;
237
+ case "UpdateExpression":
238
+ this.visitExpression(node.argument);
239
+ return;
240
+ case "TaggedTemplateExpression":
241
+ this.visitExpression(node.tag);
242
+ this.visitTemplateLiteral(node.quasi);
243
+ return;
207
244
  case "TemplateLiteral":
208
245
  this.visitTemplateLiteral(node);
209
246
  return;
@@ -221,7 +258,7 @@ class AS003Scanner {
221
258
  this.visitBindingElement(parameter);
222
259
  }
223
260
  if (node.body.type === "BlockStatement") {
224
- this.visitBlock(node.body);
261
+ this.visitBlock(node.body, true);
225
262
  }
226
263
  else {
227
264
  this.visitExpression(node.body);
@@ -442,6 +479,9 @@ class AS003Scanner {
442
479
  }
443
480
  collectModuleBindings(body) {
444
481
  const bindings = [];
482
+ for (const declaration of hoistedVarDeclarations(body)) {
483
+ bindings.push(...this.collectDeclarationBindings(declaration));
484
+ }
445
485
  for (const statement of body) {
446
486
  if (statement.type === "ImportDeclaration") {
447
487
  bindings.push(...this.collectImportBindings(statement));
@@ -451,7 +491,7 @@ class AS003Scanner {
451
491
  bindings.push({ kind: "let", name: statement.id.name });
452
492
  continue;
453
493
  }
454
- if (statement.type === "VariableDeclaration") {
494
+ if (statement.type === "VariableDeclaration" && statement.kind !== "var") {
455
495
  bindings.push(...this.collectDeclarationBindings(statement));
456
496
  continue;
457
497
  }
@@ -467,7 +507,7 @@ class AS003Scanner {
467
507
  if (statement.type === "FunctionDeclaration") {
468
508
  bindings.push({ kind: "let", name: statement.id.name });
469
509
  }
470
- if (statement.type === "VariableDeclaration") {
510
+ if (statement.type === "VariableDeclaration" && statement.kind !== "var") {
471
511
  bindings.push(...this.collectDeclarationBindings(statement));
472
512
  }
473
513
  }
@@ -1,4 +1,5 @@
1
1
  import { parseModule } from "../../parse/parser.js";
2
+ import { hoistedVarDeclarations } from "../../parse/bindings.js";
2
3
  export function AS006_007(source, options = {}) {
3
4
  return new AS006007Scanner(options.filename ?? "<input>").scan(source);
4
5
  }
@@ -58,6 +59,9 @@ class AS006007Scanner {
58
59
  case "TryStatement":
59
60
  this.visitTryStatement(node);
60
61
  return;
62
+ case "SwitchStatement":
63
+ this.visitSwitchStatement(node);
64
+ return;
61
65
  case "VariableDeclaration":
62
66
  this.visitVariableDeclaration(node);
63
67
  return;
@@ -75,8 +79,14 @@ class AS006007Scanner {
75
79
  return;
76
80
  }
77
81
  }
78
- visitBlock(node) {
79
- this.withScope(this.collectBlockBindings(node.body), () => {
82
+ visitBlock(node, functionBody = false) {
83
+ const bindings = this.collectBlockBindings(node.body);
84
+ if (functionBody) {
85
+ for (const declaration of hoistedVarDeclarations(node.body)) {
86
+ bindings.push(...this.collectDeclarationBindings(declaration));
87
+ }
88
+ }
89
+ this.withScope(bindings, () => {
80
90
  for (const statement of node.body) {
81
91
  this.visitStatement(statement);
82
92
  }
@@ -90,7 +100,9 @@ class AS006007Scanner {
90
100
  }
91
101
  }
92
102
  visitForStatement(node) {
93
- const bindings = node.init?.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.init) : [];
103
+ const bindings = node.init?.type === "VariableDeclaration" && node.init.kind !== "var"
104
+ ? this.collectDeclarationBindings(node.init)
105
+ : [];
94
106
  this.withScope(bindings, () => {
95
107
  if (node.init !== undefined) {
96
108
  if (node.init.type === "VariableDeclaration") {
@@ -110,7 +122,9 @@ class AS006007Scanner {
110
122
  });
111
123
  }
112
124
  visitForOfStatement(node) {
113
- const bindings = node.left.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.left) : [];
125
+ const bindings = node.left.type === "VariableDeclaration" && node.left.kind !== "var"
126
+ ? this.collectDeclarationBindings(node.left)
127
+ : [];
114
128
  this.withScope(bindings, () => {
115
129
  if (node.left.type === "VariableDeclaration") {
116
130
  this.visitVariableDeclaration(node.left);
@@ -143,6 +157,18 @@ class AS006007Scanner {
143
157
  this.visitBlock(node.body);
144
158
  });
145
159
  }
160
+ visitSwitchStatement(node) {
161
+ this.visitExpression(node.discriminant);
162
+ const statements = node.cases.flatMap((switchCase) => switchCase.consequent);
163
+ this.withScope(this.collectBlockBindings(statements), () => {
164
+ for (const switchCase of node.cases) {
165
+ if (switchCase.test !== undefined)
166
+ this.visitExpression(switchCase.test);
167
+ for (const statement of switchCase.consequent)
168
+ this.visitStatement(statement);
169
+ }
170
+ });
171
+ }
146
172
  visitThrowStatement(node) {
147
173
  this.visitExpression(node.argument);
148
174
  }
@@ -202,8 +228,20 @@ class AS006007Scanner {
202
228
  this.visitAssignmentExpression(node);
203
229
  return;
204
230
  case "CallExpression":
231
+ case "NewExpression":
205
232
  this.visitCallExpression(node);
206
233
  return;
234
+ case "SequenceExpression":
235
+ for (const expression of node.expressions)
236
+ this.visitExpression(expression);
237
+ return;
238
+ case "UpdateExpression":
239
+ this.visitExpression(node.argument);
240
+ return;
241
+ case "TaggedTemplateExpression":
242
+ this.visitExpression(node.tag);
243
+ this.visitTemplateLiteral(node.quasi);
244
+ return;
207
245
  case "TemplateLiteral":
208
246
  this.visitTemplateLiteral(node);
209
247
  return;
@@ -222,7 +260,7 @@ class AS006007Scanner {
222
260
  this.visitBindingElement(parameter);
223
261
  }
224
262
  if (node.body.type === "BlockStatement") {
225
- this.visitBlock(node.body);
263
+ this.visitBlock(node.body, true);
226
264
  return;
227
265
  }
228
266
  this.visitExpression(node.body);
@@ -436,6 +474,9 @@ class AS006007Scanner {
436
474
  }
437
475
  collectModuleBindings(body) {
438
476
  const bindings = [];
477
+ for (const declaration of hoistedVarDeclarations(body)) {
478
+ bindings.push(...this.collectDeclarationBindings(declaration));
479
+ }
439
480
  for (const statement of body) {
440
481
  if (statement.type === "ImportDeclaration") {
441
482
  bindings.push(...this.collectImportBindings(statement));
@@ -445,7 +486,7 @@ class AS006007Scanner {
445
486
  bindings.push(this.createBinding(statement.id, "let"));
446
487
  continue;
447
488
  }
448
- if (statement.type === "VariableDeclaration") {
489
+ if (statement.type === "VariableDeclaration" && statement.kind !== "var") {
449
490
  bindings.push(...this.collectDeclarationBindings(statement));
450
491
  continue;
451
492
  }
@@ -461,7 +502,7 @@ class AS006007Scanner {
461
502
  if (statement.type === "FunctionDeclaration") {
462
503
  bindings.push(this.createBinding(statement.id, "let"));
463
504
  }
464
- if (statement.type === "VariableDeclaration") {
505
+ if (statement.type === "VariableDeclaration" && statement.kind !== "var") {
465
506
  bindings.push(...this.collectDeclarationBindings(statement));
466
507
  }
467
508
  }
@@ -0,0 +1,6 @@
1
+ import type { ArrayPattern, AssignmentPattern, Identifier, MemberExpression, ObjectPattern, ParseResult, RestElement, VariableDeclaration } from "./parser.js";
2
+ type BindingPattern = Identifier | ArrayPattern | ObjectPattern | AssignmentPattern | RestElement | MemberExpression;
3
+ export declare function boundIdentifiers(pattern: BindingPattern): Iterable<Identifier>;
4
+ export declare function containsParameterExpression(pattern: BindingPattern): boolean;
5
+ export declare function hoistedVarDeclarations(nodes: readonly ParseResult[]): Iterable<VariableDeclaration>;
6
+ export {};