-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathassignments.ts
More file actions
62 lines (56 loc) · 1.81 KB
/
Copy pathassignments.ts
File metadata and controls
62 lines (56 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import type {Expression, Identifier, Node, Pattern, VariableDeclaration} from "acorn";
import {syntaxError} from "./syntaxError.js";
import {ancestor} from "./walk.js";
type Assignable = Expression | Pattern | VariableDeclaration;
export function checkAssignments(
node: Node,
{
input,
locals,
references,
globals
}: {
input: string;
locals: Map<Node, Set<string>>;
references: Identifier[];
globals: Set<string>;
}
): void {
function isLocal({name}: Identifier, parents: Node[]): boolean {
for (const p of parents) if (locals.get(p)?.has(name)) return true;
return false;
}
function checkConst(node: Assignable, parents: Node[]) {
switch (node.type) {
case "Identifier":
if (isLocal(node, parents)) break;
if (references.includes(node))
throw syntaxError(`Assignment to external variable '${node.name}'`, node, input);
if (globals.has(node.name))
throw syntaxError(`Assignment to global '${node.name}'`, node, input);
break;
case "ArrayPattern":
for (const e of node.elements) if (e) checkConst(e, parents);
break;
case "ObjectPattern":
for (const p of node.properties) checkConst(p.type === "Property" ? p.value : p, parents);
break;
case "RestElement":
checkConst(node.argument, parents);
break;
}
}
function checkConstArgument({argument}: {argument: Assignable}, parents: Node[]) {
checkConst(argument, parents);
}
function checkConstLeft({left}: {left: Assignable}, parents: Node[]) {
checkConst(left, parents);
}
ancestor(node, {
AssignmentExpression: checkConstLeft,
AssignmentPattern: checkConstLeft,
UpdateExpression: checkConstArgument,
ForOfStatement: checkConstLeft,
ForInStatement: checkConstLeft
});
}