-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Scope.js
80 lines (64 loc) · 2.15 KB
/
Scope.js
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
import { blank, keys } from '../../utils/object.js';
import LocalVariable from '../variables/LocalVariable';
import ExportDefaultVariable from '../variables/ExportDefaultVariable';
import { UNDEFINED_ASSIGNMENT } from '../values';
export default class Scope {
constructor ( options = {} ) {
this.parent = options.parent;
this.isModuleScope = !!options.isModuleScope;
this.children = [];
if ( this.parent ) this.parent.children.push( this );
this.variables = blank();
}
/**
* @param identifier
* @param {Object} [options] - valid options are
* {(Node|null)} init
* {boolean} isHoisted
* @return {Variable}
*/
addDeclaration ( identifier, options = {} ) {
const name = identifier.name;
if ( this.variables[ name ] ) {
const variable = this.variables[ name ];
variable.addDeclaration( identifier );
options.init && variable.bindAssignmentAtPath( [], options.init );
} else {
this.variables[ name ] = new LocalVariable( identifier.name, identifier, options.init || UNDEFINED_ASSIGNMENT );
}
return this.variables[ name ];
}
addExportDefaultDeclaration ( name, exportDefaultDeclaration ) {
this.variables.default = new ExportDefaultVariable( name, exportDefaultDeclaration );
return this.variables.default;
}
addReturnExpression ( expression ) {
this.parent && this.parent.addReturnExpression( expression );
}
contains ( name ) {
return !!this.variables[ name ] ||
( this.parent ? this.parent.contains( name ) : false );
}
deshadow ( names ) {
keys( this.variables ).forEach( key => {
const declaration = this.variables[ key ];
// we can disregard exports.foo etc
if ( declaration.exportName && declaration.isReassigned ) return;
const name = declaration.getName( true );
let deshadowed = name;
let i = 1;
while ( names.has( deshadowed ) ) {
deshadowed = `${name}$$${i++}`;
}
declaration.name = deshadowed;
} );
this.children.forEach( scope => scope.deshadow( names ) );
}
findLexicalBoundary () {
return this.parent.findLexicalBoundary();
}
findVariable ( name ) {
return this.variables[ name ] ||
( this.parent && this.parent.findVariable( name ) );
}
}