66
77// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
88
9+ const util = require ( "util" ) ;
910const acorn = require ( "acorn-dynamic-import" ) . default ;
1011const Tapable = require ( "tapable" ) ;
1112const json5 = require ( "json5" ) ;
@@ -37,6 +38,92 @@ const POSSIBLE_AST_OPTIONS = [{
3738 }
3839} ] ;
3940
41+ class StackedSetMap {
42+ constructor ( defaultValue , parentStack ) {
43+ this . defaultValue = defaultValue ;
44+ this . stack = parentStack === undefined ? [ ] : parentStack . slice ( ) ;
45+ this . map = new Map ( ) ;
46+ this . stack . push ( this . map ) ;
47+ }
48+
49+ add ( item ) {
50+ this . map . set ( item , true ) ;
51+ }
52+
53+ set ( item , value ) {
54+ this . map . set ( item , value ) ;
55+ }
56+
57+ delete ( item ) {
58+ this . map . set ( item , false ) ;
59+ }
60+
61+ has ( item ) {
62+ return this . get ( item , false ) ;
63+ }
64+
65+ get ( item ) {
66+ const topValue = this . map . get ( item ) ;
67+ if ( typeof topValue !== "undefined" )
68+ return topValue ;
69+ for ( var i = this . stack . length - 2 ; i >= 0 ; i -- ) {
70+ const value = this . stack [ i ] . get ( item ) ;
71+ if ( typeof value !== "undefined" ) {
72+ this . map . set ( item , value ) ;
73+ return value ;
74+ }
75+ }
76+ this . map . set ( item , this . defaultValue ) ;
77+ return this . defaultValue ;
78+ }
79+
80+ createChild ( ) {
81+ return new StackedSetMap ( this . defaultValue , this . stack ) ;
82+ }
83+
84+ get length ( ) {
85+ throw new Error ( "Parser.definitions is no longer an Array" ) ;
86+ }
87+
88+ set length ( value ) {
89+ throw new Error ( "Parser.definitions is no longer an Array" ) ;
90+ }
91+ }
92+
93+ StackedSetMap . prototype . push = util . deprecate ( function ( item ) {
94+ this . add ( item ) ;
95+ } , "Parser.definitions is no longer an Array: Use add instead." ) ;
96+
97+ class TrackingSet {
98+ constructor ( set ) {
99+ this . set = set ;
100+ this . set2 = new Set ( ) ;
101+ this . stack = set . stack ;
102+ }
103+
104+ add ( item ) {
105+ this . set2 . add ( item ) ;
106+ return this . set . add ( item ) ;
107+ }
108+
109+ delete ( item ) {
110+ this . set2 . delete ( item ) ;
111+ return this . set . delete ( item ) ;
112+ }
113+
114+ has ( item ) {
115+ return this . set . has ( item ) ;
116+ }
117+
118+ createChild ( ) {
119+ return this . set . createChild ( ) ;
120+ }
121+
122+ getAddedItems ( ) {
123+ return this . set2 ;
124+ }
125+ }
126+
40127class Parser extends Tapable {
41128 constructor ( options ) {
42129 super ( ) ;
@@ -207,8 +294,8 @@ class Parser extends Tapable {
207294 let res ;
208295 let name ;
209296 if ( expr . argument . type === "Identifier" ) {
210- name = this . scope . renames [ "$" + expr . argument . name ] || expr . argument . name ;
211- if ( this . scope . definitions . indexOf ( name ) === - 1 ) {
297+ name = this . scope . renames . get ( expr . argument . name ) || expr . argument . name ;
298+ if ( ! this . scope . definitions . has ( name ) ) {
212299 res = this . applyPluginsBailResult1 ( "evaluate typeof " + name , expr ) ;
213300 if ( res !== undefined ) return res ;
214301 }
@@ -248,8 +335,8 @@ class Parser extends Tapable {
248335 return new BasicEvaluatedExpression ( ) . setString ( "undefined" ) . setRange ( expr . range ) ;
249336 } ) ;
250337 this . plugin ( "evaluate Identifier" , function ( expr ) {
251- const name = this . scope . renames [ "$" + expr . name ] || expr . name ;
252- if ( this . scope . definitions . indexOf ( expr . name ) === - 1 ) {
338+ const name = this . scope . renames . get ( expr . name ) || expr . name ;
339+ if ( ! this . scope . definitions . has ( expr . name ) ) {
253340 const result = this . applyPluginsBailResult1 ( "evaluate Identifier " + name , expr ) ;
254341 if ( result ) return result ;
255342 return new BasicEvaluatedExpression ( ) . setIdentifier ( name ) . setRange ( expr . range ) ;
@@ -258,7 +345,7 @@ class Parser extends Tapable {
258345 }
259346 } ) ;
260347 this . plugin ( "evaluate ThisExpression" , function ( expr ) {
261- const name = this . scope . renames . $ this;
348+ const name = this . scope . renames . get ( " this" ) ;
262349 if ( name ) {
263350 const result = this . applyPluginsBailResult1 ( "evaluate Identifier " + name , expr ) ;
264351 if ( result ) return result ;
@@ -625,8 +712,8 @@ class Parser extends Tapable {
625712 // Declarations
626713 prewalkFunctionDeclaration ( statement ) {
627714 if ( statement . id ) {
628- this . scope . renames [ "$" + statement . id . name ] = undefined ;
629- this . scope . definitions . push ( statement . id . name ) ;
715+ this . scope . renames . set ( statement . id . name , null ) ;
716+ this . scope . definitions . add ( statement . id . name ) ;
630717 }
631718 }
632719
@@ -649,8 +736,8 @@ class Parser extends Tapable {
649736 this . applyPluginsBailResult ( "import" , statement , source ) ;
650737 statement . specifiers . forEach ( function ( specifier ) {
651738 const name = specifier . local . name ;
652- this . scope . renames [ "$" + name ] = undefined ;
653- this . scope . definitions . push ( name ) ;
739+ this . scope . renames . set ( name , null ) ;
740+ this . scope . definitions . add ( name ) ;
654741 switch ( specifier . type ) {
655742 case "ImportDefaultSpecifier" :
656743 this . applyPluginsBailResult ( "import specifier" , statement , source , "default" , name ) ;
@@ -678,9 +765,12 @@ class Parser extends Tapable {
678765 throw new Error ( "Doesn't occur?" ) ;
679766 } else {
680767 if ( ! this . applyPluginsBailResult ( "export declaration" , statement , statement . declaration ) ) {
681- const pos = this . scope . definitions . length ;
768+ const originalDefinitions = this . scope . definitions ;
769+ const tracker = new TrackingSet ( this . scope . definitions ) ;
770+ this . scope . definitions = tracker ;
682771 this . prewalkStatement ( statement . declaration ) ;
683- const newDefs = this . scope . definitions . slice ( pos ) ;
772+ const newDefs = Array . from ( tracker . getAddedItems ( ) ) ;
773+ this . scope . definitions = originalDefinitions ;
684774 for ( let index = newDefs . length - 1 ; index >= 0 ; index -- ) {
685775 const def = newDefs [ index ] ;
686776 this . applyPluginsBailResult ( "export specifier" , statement , def , def , index ) ;
@@ -714,9 +804,12 @@ class Parser extends Tapable {
714804
715805 prewalkExportDefaultDeclaration ( statement ) {
716806 if ( / D e c l a r a t i o n $ / . test ( statement . declaration . type ) ) {
717- const pos = this . scope . definitions . length ;
807+ const originalDefinitions = this . scope . definitions ;
808+ const tracker = new TrackingSet ( this . scope . definitions ) ;
809+ this . scope . definitions = tracker ;
718810 this . prewalkStatement ( statement . declaration ) ;
719- const newDefs = this . scope . definitions . slice ( pos ) ;
811+ const newDefs = Array . from ( tracker . getAddedItems ( ) ) ;
812+ this . scope . definitions = originalDefinitions ;
720813 for ( let index = 0 , len = newDefs . length ; index < len ; index ++ ) {
721814 const def = newDefs [ index ] ;
722815 this . applyPluginsBailResult ( "export specifier" , statement , def , "default" ) ;
@@ -756,8 +849,8 @@ class Parser extends Tapable {
756849
757850 prewalkClassDeclaration ( statement ) {
758851 if ( statement . id ) {
759- this . scope . renames [ "$" + statement . id . name ] = undefined ;
760- this . scope . definitions . push ( statement . id . name ) ;
852+ this . scope . renames . set ( statement . id . name , null ) ;
853+ this . scope . definitions . add ( statement . id . name ) ;
761854 }
762855 }
763856
@@ -798,9 +891,8 @@ class Parser extends Tapable {
798891 this . enterPattern ( declarator . id , ( name , decl ) => {
799892 if ( ! this . applyPluginsBailResult1 ( "var-" + declarator . kind + " " + name , decl ) ) {
800893 if ( ! this . applyPluginsBailResult1 ( "var " + name , decl ) ) {
801- this . scope . renames [ "$" + name ] = undefined ;
802- if ( this . scope . definitions . indexOf ( name ) < 0 )
803- this . scope . definitions . push ( name ) ;
894+ this . scope . renames . set ( name , null ) ;
895+ this . scope . definitions . add ( name ) ;
804896 }
805897 }
806898 } ) ;
@@ -819,9 +911,8 @@ class Parser extends Tapable {
819911 if ( renameIdentifier && declarator . id . type === "Identifier" && this . applyPluginsBailResult1 ( "can-rename " + renameIdentifier , declarator . init ) ) {
820912 // renaming with "var a = b;"
821913 if ( ! this . applyPluginsBailResult1 ( "rename " + renameIdentifier , declarator . init ) ) {
822- this . scope . renames [ "$" + declarator . id . name ] = this . scope . renames [ "$" + renameIdentifier ] || renameIdentifier ;
823- const idx = this . scope . definitions . indexOf ( declarator . id . name ) ;
824- if ( idx >= 0 ) this . scope . definitions . splice ( idx , 1 ) ;
914+ this . scope . renames . set ( declarator . id . name , this . scope . renames . get ( renameIdentifier ) || renameIdentifier ) ;
915+ this . scope . definitions . delete ( declarator . id . name ) ;
825916 }
826917 } else {
827918 this . walkPattern ( declarator . id ) ;
@@ -979,23 +1070,22 @@ class Parser extends Tapable {
9791070 if ( expression . left . type === "Identifier" && renameIdentifier && this . applyPluginsBailResult1 ( "can-rename " + renameIdentifier , expression . right ) ) {
9801071 // renaming "a = b;"
9811072 if ( ! this . applyPluginsBailResult1 ( "rename " + renameIdentifier , expression . right ) ) {
982- this . scope . renames [ "$" + expression . left . name ] = renameIdentifier ;
983- const idx = this . scope . definitions . indexOf ( expression . left . name ) ;
984- if ( idx >= 0 ) this . scope . definitions . splice ( idx , 1 ) ;
1073+ this . scope . renames . set ( expression . left . name , renameIdentifier ) ;
1074+ this . scope . definitions . delete ( expression . left . name ) ;
9851075 }
9861076 } else if ( expression . left . type === "Identifier" ) {
9871077 if ( ! this . applyPluginsBailResult1 ( "assigned " + expression . left . name , expression ) ) {
9881078 this . walkExpression ( expression . right ) ;
9891079 }
990- this . scope . renames [ "$" + expression . left . name ] = undefined ;
1080+ this . scope . renames . set ( expression . left . name , null ) ;
9911081 if ( ! this . applyPluginsBailResult1 ( "assign " + expression . left . name , expression ) ) {
9921082 this . walkExpression ( expression . left ) ;
9931083 }
9941084 } else {
9951085 this . walkExpression ( expression . right ) ;
9961086 this . walkPattern ( expression . left ) ;
9971087 this . enterPattern ( expression . left , ( name , decl ) => {
998- this . scope . renames [ "$" + name ] = undefined ;
1088+ this . scope . renames . set ( name , null ) ;
9991089 } ) ;
10001090 }
10011091 }
@@ -1061,13 +1151,13 @@ class Parser extends Tapable {
10611151 return ! args [ idx ] ;
10621152 } ) , ( ) => {
10631153 if ( renameThis ) {
1064- this . scope . renames . $ this = renameThis ;
1154+ this . scope . renames . set ( " this" , renameThis ) ;
10651155 }
10661156 for ( let i = 0 ; i < args . length ; i ++ ) {
10671157 const param = args [ i ] ;
10681158 if ( ! param ) continue ;
10691159 if ( ! params [ i ] || params [ i ] . type !== "Identifier" ) continue ;
1070- this . scope . renames [ "$" + params [ i ] . name ] = param ;
1160+ this . scope . renames . set ( params [ i ] . name , param ) ;
10711161 }
10721162 if ( functionExpression . body . type === "BlockStatement" ) {
10731163 this . prewalkStatement ( functionExpression . body ) ;
@@ -1079,7 +1169,7 @@ class Parser extends Tapable {
10791169 if ( expression . callee . type === "MemberExpression" &&
10801170 expression . callee . object . type === "FunctionExpression" &&
10811171 ! expression . callee . computed &&
1082- ( [ "call" , "bind" ] ) . indexOf ( expression . callee . property . name ) >= 0 &&
1172+ ( expression . callee . property . name === "call" || expression . callee . property . name === "bind" ) &&
10831173 expression . arguments &&
10841174 expression . arguments . length > 0
10851175 ) {
@@ -1133,8 +1223,8 @@ class Parser extends Tapable {
11331223 }
11341224
11351225 walkIdentifier ( expression ) {
1136- if ( this . scope . definitions . indexOf ( expression . name ) === - 1 ) {
1137- const result = this . applyPluginsBailResult1 ( "expression " + ( this . scope . renames [ "$" + expression . name ] || expression . name ) , expression ) ;
1226+ if ( ! this . scope . definitions . has ( expression . name ) ) {
1227+ const result = this . applyPluginsBailResult1 ( "expression " + ( this . scope . renames . get ( expression . name ) || expression . name ) , expression ) ;
11381228 if ( result === true )
11391229 return ;
11401230 }
@@ -1145,23 +1235,23 @@ class Parser extends Tapable {
11451235 this . scope = {
11461236 inTry : false ,
11471237 inShorthand : false ,
1148- definitions : oldScope . definitions . slice ( ) ,
1149- renames : Object . create ( oldScope . renames )
1238+ definitions : oldScope . definitions . createChild ( ) ,
1239+ renames : oldScope . renames . createChild ( )
11501240 } ;
11511241
1152- this . scope . renames . $ this = undefined ;
1242+ this . scope . renames . set ( " this" , null ) ;
11531243
11541244 for ( let paramIndex = 0 , len = params . length ; paramIndex < len ; paramIndex ++ ) {
11551245 const param = params [ paramIndex ] ;
11561246
11571247 if ( typeof param !== "string" ) {
11581248 this . enterPattern ( param , param => {
1159- this . scope . renames [ "$" + param ] = undefined ;
1160- this . scope . definitions . push ( param ) ;
1249+ this . scope . renames . set ( param , null ) ;
1250+ this . scope . definitions . add ( param ) ;
11611251 } ) ;
11621252 } else {
1163- this . scope . renames [ "$" + param ] = undefined ;
1164- this . scope . definitions . push ( param ) ;
1253+ this . scope . renames . set ( param , null ) ;
1254+ this . scope . definitions . add ( param ) ;
11651255 }
11661256 }
11671257
@@ -1343,8 +1433,8 @@ class Parser extends Tapable {
13431433 const oldComments = this . comments ;
13441434 this . scope = {
13451435 inTry : false ,
1346- definitions : [ ] ,
1347- renames : { }
1436+ definitions : new StackedSetMap ( false ) ,
1437+ renames : new StackedSetMap ( null )
13481438 } ;
13491439 const state = this . state = initialState || { } ;
13501440 this . comments = comments ;
@@ -1401,11 +1491,11 @@ class Parser extends Tapable {
14011491 }
14021492 let free ;
14031493 if ( expr . type === "Identifier" ) {
1404- free = this . scope . definitions . indexOf ( expr . name ) === - 1 ;
1405- exprName . push ( this . scope . renames [ "$" + expr . name ] || expr . name ) ;
1494+ free = ! this . scope . definitions . has ( expr . name ) ;
1495+ exprName . push ( this . scope . renames . get ( expr . name ) || expr . name ) ;
14061496 } else if ( expr . type === "ThisExpression" && this . scope . renames . $this ) {
14071497 free = true ;
1408- exprName . push ( this . scope . renames . $ this) ;
1498+ exprName . push ( this . scope . renames . get ( " this" ) ) ;
14091499 } else if ( expr . type === "ThisExpression" ) {
14101500 free = false ;
14111501 exprName . push ( "this" ) ;
@@ -1429,3 +1519,4 @@ class Parser extends Tapable {
14291519Parser . ECMA_VERSION = ECMA_VERSION ;
14301520
14311521module . exports = Parser ;
1522+ Parser . StackedSetMap = StackedSetMap ;
0 commit comments