UNPKG

1.7 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 node.declarations.forEach( declaration => scope.addDeclaration( declaration, isBlockDeclaration, true ) );
24 }
25
26 let newScope;
27
28 // create new function scope
29 if ( /Function/.test( node.type ) ) {
30 newScope = new Scope({
31 parent: scope,
32 block: false,
33 params: node.params
34 });
35
36 // named function expressions - the name is considered
37 // part of the function's scope
38 if ( node.type === 'FunctionExpression' && node.id ) {
39 newScope.addDeclaration( node, false, false );
40 }
41 }
42
43 // create new block scope
44 if ( node.type === 'BlockStatement' && !/Function/.test( parent.type ) ) {
45 newScope = new Scope({
46 parent: scope,
47 block: true
48 });
49 }
50
51 // catch clause has its own block scope
52 if ( node.type === 'CatchClause' ) {
53 newScope = new Scope({
54 parent: scope,
55 params: [ node.param ],
56 block: true
57 });
58 }
59
60 if ( newScope ) {
61 Object.defineProperty( node, '_scope', {
62 value: newScope,
63 configurable: true
64 });
65
66 scope = newScope;
67 }
68 },
69 leave ( node ) {
70 if ( node._scope ) {
71 scope = scope.parent;
72 }
73 }
74 });
75}