poe-code 5.0.4 → 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/dist/index.js +3457 -3542
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safejs/dist/interp/async.d.ts +2 -1
- package/packages/safejs/dist/interp/async.js +56 -33
- package/packages/safejs/dist/interp/cancel.d.ts +7 -2
- package/packages/safejs/dist/interp/cancel.js +128 -92
- package/packages/safejs/dist/interp/exceptions.js +7 -3
- package/packages/safejs/dist/interp/globals/collections.js +2 -0
- package/packages/safejs/dist/interp/globals/console-json.js +4 -0
- package/packages/safejs/dist/interp/globals/error.js +1 -5
- package/packages/safejs/dist/interp/globals/math.js +2 -4
- package/packages/safejs/dist/interp/globals/misc.js +5 -0
- package/packages/safejs/dist/interp/globals/object-array.js +25 -0
- package/packages/safejs/dist/interp/globals/regex.js +1 -1
- package/packages/safejs/dist/interp/host-bridge.js +8 -5
- package/packages/safejs/dist/interp/interpreter.js +33 -37
- package/packages/safejs/dist/interp/iteration.d.ts +3 -3
- package/packages/safejs/dist/interp/iteration.js +20 -9
- package/packages/safejs/dist/interp/methods/array.js +1 -0
- package/packages/safejs/dist/interp/methods/function.d.ts +1 -1
- package/packages/safejs/dist/interp/methods/function.js +17 -1
- package/packages/safejs/dist/interp/methods/generator.js +1 -0
- package/packages/safejs/dist/interp/methods/map.js +1 -0
- package/packages/safejs/dist/interp/methods/number.js +1 -0
- package/packages/safejs/dist/interp/methods/regex.js +1 -0
- package/packages/safejs/dist/interp/methods/set.js +1 -0
- package/packages/safejs/dist/interp/methods/string.js +1 -0
- package/packages/safejs/dist/interp/patterns.d.ts +1 -0
- package/packages/safejs/dist/interp/patterns.js +1 -1
- package/packages/safejs/dist/interp/promise-tracker.d.ts +12 -2
- package/packages/safejs/dist/interp/promise-tracker.js +65 -7
- package/packages/safejs/dist/interp/promise.d.ts +7 -5
- package/packages/safejs/dist/interp/promise.js +531 -148
- package/packages/safejs/dist/interp/values.d.ts +6 -0
- package/packages/safejs/dist/interp/values.js +25 -5
- package/packages/safejs/dist/interp/var-hoist.js +5 -135
- package/packages/safejs/dist/lint/index.js +0 -4
- package/packages/safejs/dist/lint/rules/AS001.js +4 -9
- package/packages/safejs/dist/lint/rules/AS003.js +47 -7
- package/packages/safejs/dist/lint/rules/AS006-007.js +48 -7
- package/packages/safejs/dist/parse/bindings.d.ts +6 -0
- package/packages/safejs/dist/parse/bindings.js +90 -0
- package/packages/safejs/dist/parse/parser.js +70 -37
- package/packages/safejs/dist/snapshot/dump-format.d.ts +1 -1
- package/packages/safejs/dist/snapshot/dump-format.js +1 -1
- package/packages/safejs/dist/snapshot/replay-data.js +3 -0
- package/packages/safejs/dist/lint/rules/AS-await-non-promise.d.ts +0 -13
- package/packages/safejs/dist/lint/rules/AS-await-non-promise.js +0 -301
- package/packages/safejs/dist/lint/rules/AS008.d.ts +0 -13
- package/packages/safejs/dist/lint/rules/AS008.js +0 -386
|
@@ -52,6 +52,9 @@ export type SandboxCallContext = {
|
|
|
52
52
|
};
|
|
53
53
|
export type SandboxClosure = {
|
|
54
54
|
readonly async?: true;
|
|
55
|
+
readonly sandbox?: true;
|
|
56
|
+
readonly boundTarget?: SandboxClosure;
|
|
57
|
+
readonly cancellationSignal?: AbortSignal;
|
|
55
58
|
readonly kind: "fn";
|
|
56
59
|
readonly name?: string;
|
|
57
60
|
readonly properties?: SandboxObject;
|
|
@@ -82,6 +85,9 @@ type CopyFromSandboxOptions = {
|
|
|
82
85
|
};
|
|
83
86
|
export declare function createSandboxClosure(input: {
|
|
84
87
|
async?: boolean;
|
|
88
|
+
sandbox?: boolean;
|
|
89
|
+
boundTarget?: SandboxClosure;
|
|
90
|
+
cancellationSignal?: AbortSignal;
|
|
85
91
|
call: (args: readonly SandboxValue[], context?: SandboxCallContext) => SandboxValue | Promise<SandboxValue>;
|
|
86
92
|
construct?: (args: readonly SandboxValue[], context?: SandboxCallContext) => SandboxValue | Promise<SandboxValue>;
|
|
87
93
|
name?: string;
|
|
@@ -2,6 +2,7 @@ import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
|
2
2
|
import { SandboxError } from "./budget.js";
|
|
3
3
|
import { observeSandboxPromise, trackSandboxPromise } from "./promise-tracker.js";
|
|
4
4
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
5
|
+
import { invokeCancelableClosure, readPromiseCancellation, registerPromiseCancellation } from "./cancel.js";
|
|
5
6
|
import { parseRegex } from "./regex/parse.js";
|
|
6
7
|
import { assertSandboxDataDepth } from "../graph-depth.js";
|
|
7
8
|
import { copySandboxArgumentProperties, createSandboxArguments, getSandboxArgumentEntries, isSandboxArguments } from "./arguments.js";
|
|
@@ -17,15 +18,30 @@ const sandboxRetainedValues = Symbol("SandboxRetainedValues");
|
|
|
17
18
|
export function createSandboxClosure(input) {
|
|
18
19
|
const closure = {
|
|
19
20
|
kind: "fn",
|
|
20
|
-
call: input.call,
|
|
21
|
+
call: (args, context) => invokeCancelableClosure(closure, input.call, args, context),
|
|
21
22
|
name: input.name,
|
|
22
|
-
...(input.construct === undefined
|
|
23
|
+
...(input.construct === undefined
|
|
24
|
+
? {}
|
|
25
|
+
: {
|
|
26
|
+
construct: (args, context) => invokeCancelableClosure(closure, input.construct, args, context, true)
|
|
27
|
+
}),
|
|
23
28
|
...(input.async === true ? { async: true } : {})
|
|
24
29
|
};
|
|
25
30
|
Object.defineProperty(closure, sandboxClosureBrand, {
|
|
26
31
|
enumerable: false,
|
|
27
32
|
value: true
|
|
28
33
|
});
|
|
34
|
+
if (input.sandbox === true) {
|
|
35
|
+
Object.defineProperty(closure, "sandbox", { value: true });
|
|
36
|
+
}
|
|
37
|
+
if (input.boundTarget !== undefined) {
|
|
38
|
+
Object.defineProperty(closure, "boundTarget", { value: input.boundTarget });
|
|
39
|
+
}
|
|
40
|
+
if (input.cancellationSignal !== undefined) {
|
|
41
|
+
Object.defineProperty(closure, "cancellationSignal", {
|
|
42
|
+
value: input.cancellationSignal
|
|
43
|
+
});
|
|
44
|
+
}
|
|
29
45
|
if (input.properties !== undefined) {
|
|
30
46
|
Object.defineProperty(closure, "properties", {
|
|
31
47
|
enumerable: false,
|
|
@@ -40,11 +56,14 @@ export function createSandboxClosure(input) {
|
|
|
40
56
|
return Object.freeze(closure);
|
|
41
57
|
}
|
|
42
58
|
export function createSandboxPromise(promise, metadata = {}) {
|
|
59
|
+
const original = metadata.trackReplay === false
|
|
60
|
+
? promise
|
|
61
|
+
: (promiseReplayContext.getStore()?.track(promise) ?? promise);
|
|
43
62
|
const sandboxPromise = {
|
|
44
63
|
kind: "promise",
|
|
45
|
-
promise
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
get promise() {
|
|
65
|
+
return readPromiseCancellation(sandboxPromise, original);
|
|
66
|
+
}
|
|
48
67
|
};
|
|
49
68
|
Object.defineProperty(sandboxPromise, sandboxPromiseBrand, {
|
|
50
69
|
enumerable: false,
|
|
@@ -70,6 +89,7 @@ export function createSandboxPromise(promise, metadata = {}) {
|
|
|
70
89
|
});
|
|
71
90
|
}
|
|
72
91
|
trackSandboxPromise(sandboxPromise);
|
|
92
|
+
registerPromiseCancellation(sandboxPromise);
|
|
73
93
|
return Object.freeze(sandboxPromise);
|
|
74
94
|
}
|
|
75
95
|
export function createSandboxGenerator(channel, metadata = undefined) {
|
|
@@ -1,140 +1,10 @@
|
|
|
1
|
+
import { boundIdentifiers, hoistedVarDeclarations } from "../parse/bindings.js";
|
|
1
2
|
export function hoistVarDeclarations(node, scope) {
|
|
2
|
-
|
|
3
|
-
for (const
|
|
4
|
-
|
|
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 &&
|
|
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,17 +217,9 @@ 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;
|
|
223
|
-
case "new":
|
|
224
|
-
if (!this.source.slice(this.skipTriviaFrom(token.end.offset)).startsWith("RegExp")) {
|
|
225
|
-
this.report(token.value, token.start, token.end);
|
|
226
|
-
}
|
|
227
|
-
return;
|
|
228
223
|
default:
|
|
229
224
|
return;
|
|
230
225
|
}
|
|
@@ -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.
|
|
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"
|
|
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"
|
|
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.
|
|
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"
|
|
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"
|
|
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 {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export function* boundIdentifiers(pattern) {
|
|
2
|
+
switch (pattern.type) {
|
|
3
|
+
case "Identifier":
|
|
4
|
+
yield pattern;
|
|
5
|
+
return;
|
|
6
|
+
case "AssignmentPattern":
|
|
7
|
+
yield* boundIdentifiers(pattern.left);
|
|
8
|
+
return;
|
|
9
|
+
case "RestElement":
|
|
10
|
+
yield* boundIdentifiers(pattern.argument);
|
|
11
|
+
return;
|
|
12
|
+
case "ArrayPattern":
|
|
13
|
+
for (const element of pattern.elements) {
|
|
14
|
+
if (element !== null)
|
|
15
|
+
yield* boundIdentifiers(element);
|
|
16
|
+
}
|
|
17
|
+
return;
|
|
18
|
+
case "ObjectPattern":
|
|
19
|
+
for (const property of pattern.properties) {
|
|
20
|
+
yield* boundIdentifiers(property.type === "RestElement" ? property : property.value);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
case "MemberExpression":
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function containsParameterExpression(pattern) {
|
|
28
|
+
switch (pattern.type) {
|
|
29
|
+
case "AssignmentPattern":
|
|
30
|
+
case "MemberExpression":
|
|
31
|
+
return true;
|
|
32
|
+
case "RestElement":
|
|
33
|
+
return containsParameterExpression(pattern.argument);
|
|
34
|
+
case "ArrayPattern":
|
|
35
|
+
return pattern.elements.some((element) => element !== null && containsParameterExpression(element));
|
|
36
|
+
case "ObjectPattern":
|
|
37
|
+
return pattern.properties.some((property) => property.type === "RestElement"
|
|
38
|
+
? containsParameterExpression(property.argument)
|
|
39
|
+
: property.computed || containsParameterExpression(property.value));
|
|
40
|
+
case "Identifier":
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function* hoistedVarDeclarations(nodes) {
|
|
45
|
+
for (const node of nodes) {
|
|
46
|
+
switch (node.type) {
|
|
47
|
+
case "VariableDeclaration":
|
|
48
|
+
if (node.kind === "var")
|
|
49
|
+
yield node;
|
|
50
|
+
break;
|
|
51
|
+
case "BlockStatement":
|
|
52
|
+
yield* hoistedVarDeclarations(node.body);
|
|
53
|
+
break;
|
|
54
|
+
case "IfStatement":
|
|
55
|
+
yield* hoistedVarDeclarations([node.consequent]);
|
|
56
|
+
if (node.alternate !== undefined)
|
|
57
|
+
yield* hoistedVarDeclarations([node.alternate]);
|
|
58
|
+
break;
|
|
59
|
+
case "ForStatement":
|
|
60
|
+
if (node.init?.type === "VariableDeclaration")
|
|
61
|
+
yield* hoistedVarDeclarations([node.init]);
|
|
62
|
+
yield* hoistedVarDeclarations([node.body]);
|
|
63
|
+
break;
|
|
64
|
+
case "ForInStatement":
|
|
65
|
+
case "ForOfStatement":
|
|
66
|
+
if (node.left.type === "VariableDeclaration")
|
|
67
|
+
yield* hoistedVarDeclarations([node.left]);
|
|
68
|
+
yield* hoistedVarDeclarations([node.body]);
|
|
69
|
+
break;
|
|
70
|
+
case "WhileStatement":
|
|
71
|
+
case "DoWhileStatement":
|
|
72
|
+
yield* hoistedVarDeclarations([node.body]);
|
|
73
|
+
break;
|
|
74
|
+
case "TryStatement":
|
|
75
|
+
yield* hoistedVarDeclarations([node.block]);
|
|
76
|
+
if (node.handler !== undefined)
|
|
77
|
+
yield* hoistedVarDeclarations([node.handler.body]);
|
|
78
|
+
if (node.finalizer !== undefined)
|
|
79
|
+
yield* hoistedVarDeclarations([node.finalizer]);
|
|
80
|
+
break;
|
|
81
|
+
case "SwitchStatement":
|
|
82
|
+
for (const switchCase of node.cases)
|
|
83
|
+
yield* hoistedVarDeclarations(switchCase.consequent);
|
|
84
|
+
break;
|
|
85
|
+
case "ExportNamedDeclaration":
|
|
86
|
+
yield* hoistedVarDeclarations([node.declaration]);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|