UNPKG

2.13 kBJavaScriptView Raw
1import { blank, keys } from '../utils/object.js';
2import Declaration from '../Declaration.js';
3
4const extractors = {
5 Identifier ( names, param ) {
6 names.push( param.name );
7 },
8
9 ObjectPattern ( names, param ) {
10 param.properties.forEach( prop => {
11 extractors[ prop.key.type ]( names, prop.key );
12 });
13 },
14
15 ArrayPattern ( names, param ) {
16 param.elements.forEach( element => {
17 if ( element ) extractors[ element.type ]( names, element );
18 });
19 },
20
21 RestElement ( names, param ) {
22 extractors[ param.argument.type ]( names, param.argument );
23 },
24
25 AssignmentPattern ( names, param ) {
26 return extractors[ param.left.type ]( names, param.left );
27 }
28};
29
30function extractNames ( param ) {
31 let names = [];
32
33 extractors[ param.type ]( names, param );
34 return names;
35}
36
37export default class Scope {
38 constructor ( options ) {
39 options = options || {};
40
41 this.parent = options.parent;
42 this.statement = options.statement || this.parent.statement;
43 this.isBlockScope = !!options.block;
44 this.isTopLevel = !this.parent || ( this.parent.isTopLevel && this.isBlockScope );
45
46 this.declarations = blank();
47
48 if ( options.params ) {
49 options.params.forEach( param => {
50 extractNames( param ).forEach( name => {
51 this.declarations[ name ] = new Declaration( param, true, this.statement );
52 });
53 });
54 }
55 }
56
57 addDeclaration ( node, isBlockDeclaration, isVar ) {
58 if ( !isBlockDeclaration && this.isBlockScope ) {
59 // it's a `var` or function node, and this
60 // is a block scope, so we need to go up
61 this.parent.addDeclaration( node, isBlockDeclaration, isVar );
62 } else {
63 extractNames( node.id ).forEach( name => {
64 this.declarations[ name ] = new Declaration( node, false, this.statement );
65 });
66 }
67 }
68
69 contains ( name ) {
70 return this.declarations[ name ] ||
71 ( this.parent ? this.parent.contains( name ) : false );
72 }
73
74 eachDeclaration ( fn ) {
75 keys( this.declarations ).forEach( key => {
76 fn( key, this.declarations[ key ] );
77 });
78 }
79
80 findDeclaration ( name ) {
81 return this.declarations[ name ] ||
82 ( this.parent && this.parent.findDeclaration( name ) );
83 }
84}