/
ParameterScope.ts
91 lines (86 loc) · 2.85 KB
/
ParameterScope.ts
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import type { AstContext } from '../../Module';
import type { InclusionContext } from '../ExecutionContext';
import type Identifier from '../nodes/Identifier';
import SpreadElement from '../nodes/SpreadElement';
import type { ExpressionEntity } from '../nodes/shared/Expression';
import { UNKNOWN_EXPRESSION } from '../nodes/shared/Expression';
import LocalVariable from '../variables/LocalVariable';
import ChildScope from './ChildScope';
import type Scope from './Scope';
export default class ParameterScope extends ChildScope {
readonly hoistedBodyVarScope: ChildScope;
protected parameters: readonly LocalVariable[][] = [];
private readonly context: AstContext;
private hasRest = false;
constructor(parent: Scope, context: AstContext) {
super(parent);
this.context = context;
this.hoistedBodyVarScope = new ChildScope(this);
}
/**
* Adds a parameter to this scope. Parameters must be added in the correct
* order, e.g. from left to right.
*/
addParameterDeclaration(identifier: Identifier): LocalVariable {
const name = identifier.name;
let variable = this.hoistedBodyVarScope.variables.get(name) as LocalVariable;
if (variable) {
variable.addDeclaration(identifier, null);
} else {
variable = new LocalVariable(name, identifier, UNKNOWN_EXPRESSION, this.context);
}
this.variables.set(name, variable);
return variable;
}
addParameterVariables(parameters: LocalVariable[][], hasRest: boolean): void {
this.parameters = parameters;
for (const parameterList of parameters) {
for (const parameter of parameterList) {
parameter.alwaysRendered = true;
}
}
this.hasRest = hasRest;
}
includeCallArguments(
context: InclusionContext,
parameters: readonly (ExpressionEntity | SpreadElement)[]
): void {
let calledFromTryStatement = false;
let argumentIncluded = false;
const restParameter = this.hasRest && this.parameters[this.parameters.length - 1];
for (const checkedArgument of parameters) {
if (checkedArgument instanceof SpreadElement) {
for (const argument of parameters) {
argument.include(context, false);
}
break;
}
}
for (let index = parameters.length - 1; index >= 0; index--) {
const parameterVariables = this.parameters[index] || restParameter;
const argument = parameters[index];
if (parameterVariables) {
calledFromTryStatement = false;
if (parameterVariables.length === 0) {
// handle empty destructuring
argumentIncluded = true;
} else {
for (const variable of parameterVariables) {
if (variable.included) {
argumentIncluded = true;
}
if (variable.calledFromTryStatement) {
calledFromTryStatement = true;
}
}
}
}
if (!argumentIncluded && argument.shouldBeIncluded(context)) {
argumentIncluded = true;
}
if (argumentIncluded) {
argument.include(context, calledFromTryStatement);
}
}
}
}