(ast, propertyName = 'scope')
| 59 | } |
| 60 | |
| 61 | const attachScopes: AttachScopes = function attachScopes(ast, propertyName = 'scope') { |
| 62 | let scope = new Scope(); |
| 63 | |
| 64 | walk(ast, { |
| 65 | enter(n, parent) { |
| 66 | const node = n as estree.Node; |
| 67 | // function foo () {...} |
| 68 | // class Foo {...} |
| 69 | if (/(?:Function|Class)Declaration/.test(node.type)) { |
| 70 | scope.addDeclaration(node, false, false); |
| 71 | } |
| 72 | |
| 73 | // var foo = 1 |
| 74 | if (node.type === 'VariableDeclaration') { |
| 75 | const { kind } = node; |
| 76 | const isBlockDeclaration = blockDeclarations[kind]; |
| 77 | node.declarations.forEach((declaration) => { |
| 78 | scope.addDeclaration(declaration, isBlockDeclaration, true); |
| 79 | }); |
| 80 | } |
| 81 | |
| 82 | let newScope: AttachedScope | undefined; |
| 83 | |
| 84 | // create new function scope |
| 85 | if (node.type.includes('Function')) { |
| 86 | const func = node as estree.Function; |
| 87 | newScope = new Scope({ |
| 88 | parent: scope, |
| 89 | block: false, |
| 90 | params: func.params |
| 91 | }); |
| 92 | |
| 93 | // named function expressions - the name is considered |
| 94 | // part of the function's scope |
| 95 | if (func.type === 'FunctionExpression' && func.id) { |
| 96 | newScope.addDeclaration(func, false, false); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | // create new for scope |
| 101 | if (/For(?:In|Of)?Statement/.test(node.type)) { |
| 102 | newScope = new Scope({ |
| 103 | parent: scope, |
| 104 | block: true |
| 105 | }); |
| 106 | } |
| 107 | |
| 108 | // create new block scope |
| 109 | if (node.type === 'BlockStatement' && !parent.type.includes('Function')) { |
| 110 | newScope = new Scope({ |
| 111 | parent: scope, |
| 112 | block: true |
| 113 | }); |
| 114 | } |
| 115 | |
| 116 | // catch clause has its own block scope |
| 117 | if (node.type === 'CatchClause') { |
| 118 | newScope = new Scope({ |
no outgoing calls
no test coverage detected