UNPKG

1.73 kBJavaScriptView Raw
1import { walk } from 'estree-walker';
2import Scope from './Scope.js';
3
4const blockDeclarations = {
5 'const': true,
6 'let': true
7};
8
9export default function attachScopes ( statement ) {
10 let { node, scope } = statement;
11
12 walk( node, {
13 enter ( node, parent ) {
14 // function foo () {...}
15 // class Foo {...}
16 if ( /(Function|Class)Declaration/.test( node.type ) ) {
17 scope.addDeclaration( node, false, false );
18 }
19
20 // var foo = 1, bar = 2
21 if ( node.type === 'VariableDeclaration' ) {
22 const isBlockDeclaration = blockDeclarations[ node.kind ];
23
24 node.declarations.forEach( declarator => {
25 scope.addDeclaration( declarator, isBlockDeclaration, true );
26 });
27 }
28
29 let newScope;
30
31 // create new function scope
32 if ( /Function/.test( node.type ) ) {
33 newScope = new Scope({
34 parent: scope,
35 block: false,
36 params: node.params
37 });
38
39 // named function expressions - the name is considered
40 // part of the function's scope
41 if ( node.type === 'FunctionExpression' && node.id ) {
42 newScope.addDeclaration( node, false, false );
43 }
44 }
45
46 // create new block scope
47 if ( node.type === 'BlockStatement' && ( !parent || !/Function/.test( parent.type ) ) ) {
48 newScope = new Scope({
49 parent: scope,
50 block: true
51 });
52 }
53
54 // catch clause has its own block scope
55 if ( node.type === 'CatchClause' ) {
56 newScope = new Scope({
57 parent: scope,
58 params: [ node.param ],
59 block: true
60 });
61 }
62
63 if ( newScope ) {
64 Object.defineProperty( node, '_scope', {
65 value: newScope,
66 configurable: true
67 });
68
69 scope = newScope;
70 }
71 },
72 leave ( node ) {
73 if ( node._scope ) {
74 scope = scope.parent;
75 }
76 }
77 });
78}