11import { declare } from "@babel/helper-plugin-utils" ;
22import syntaxObjectRestSpread from "@babel/plugin-syntax-object-rest-spread" ;
33import { types as t } from "@babel/core" ;
4+ import type { PluginPass } from "@babel/core" ;
5+ import type { NodePath , Visitor , Scope } from "@babel/traverse" ;
46import { convertFunctionParams } from "@babel/plugin-transform-parameters" ;
57import { isRequired } from "@babel/helper-compilation-targets" ;
68import compatData from "@babel/compat-data/corejs2-built-ins" ;
79import shouldStoreRHSInTemporaryVariable from "./shouldStoreRHSInTemporaryVariable" ;
810
9- // TODO: Remove in Babel 8
11+ const { isAssignmentPattern , isObjectProperty } = t ;
1012// @babel /types <=7.3.3 counts FOO as referenced in var { x: FOO }.
1113// We need to detect this bug to know if "unused" means 0 or 1 references.
12- const ZERO_REFS = ( ( ) => {
14+ if ( ! process . env . BABEL_8_BREAKING ) {
1315 const node = t . identifier ( "a" ) ;
1416 const property = t . objectProperty ( t . identifier ( "key" ) , node ) ;
1517 const pattern = t . objectPattern ( [ property ] ) ;
1618
17- return t . isReferenced ( node , property , pattern ) ? 1 : 0 ;
18- } ) ( ) ;
19+ // eslint-disable-next-line no-var
20+ var ZERO_REFS = t . isReferenced ( node , property , pattern ) ? 1 : 0 ;
21+ }
1922
2023export default declare ( ( api , opts ) => {
2124 api . assertVersion ( 7 ) ;
@@ -36,7 +39,9 @@ export default declare((api, opts) => {
3639 const pureGetters = api . assumption ( "pureGetters" ) ?? loose ;
3740 const setSpreadProperties = api . assumption ( "setSpreadProperties" ) ?? loose ;
3841
39- function getExtendsHelper ( file ) {
42+ function getExtendsHelper (
43+ file : PluginPass ,
44+ ) : t . MemberExpression | t . Identifier {
4045 return useBuiltIns
4146 ? t . memberExpression ( t . identifier ( "Object" ) , t . identifier ( "assign" ) )
4247 : file . addHelper ( "extends" ) ;
@@ -51,7 +56,7 @@ export default declare((api, opts) => {
5156 return foundRestElement ;
5257 }
5358
54- function hasObjectPatternRestElement ( path ) {
59+ function hasObjectPatternRestElement ( path : NodePath ) : boolean {
5560 let foundRestElement = false ;
5661 visitRestElements ( path , restElement => {
5762 if ( restElement . parentPath . isObjectPattern ( ) ) {
@@ -62,15 +67,16 @@ export default declare((api, opts) => {
6267 return foundRestElement ;
6368 }
6469
65- function visitRestElements ( path , visitor ) {
70+ function visitRestElements (
71+ path : NodePath ,
72+ visitor : ( path : NodePath < t . RestElement > ) => any ,
73+ ) {
6674 path . traverse ( {
6775 Expression ( path ) {
68- const parentType = path . parent . type ;
76+ const { parent , key } = path ;
6977 if (
70- ( parentType === "AssignmentPattern" && path . key === "right" ) ||
71- ( parentType === "ObjectProperty" &&
72- path . parent . computed &&
73- path . key === "key" )
78+ ( isAssignmentPattern ( parent ) && key === "right" ) ||
79+ ( isObjectProperty ( parent ) && parent . computed && key === "key" )
7480 ) {
7581 path . skip ( ) ;
7682 }
@@ -79,7 +85,7 @@ export default declare((api, opts) => {
7985 } ) ;
8086 }
8187
82- function hasSpread ( node ) {
88+ function hasSpread ( node : t . ObjectExpression ) : boolean {
8389 for ( const prop of node . properties ) {
8490 if ( t . isSpreadElement ( prop ) ) {
8591 return true ;
@@ -92,9 +98,10 @@ export default declare((api, opts) => {
9298 // were converted to stringLiterals or not
9399 // e.g. extracts {keys: ["a", "b", "3", ++x], allLiteral: false }
94100 // from ast of {a: "foo", b, 3: "bar", [++x]: "baz"}
95- function extractNormalizedKeys ( path ) {
96- const props = path . node . properties ;
97- const keys = [ ] ;
101+ function extractNormalizedKeys ( node : t . ObjectPattern ) {
102+ // RestElement has been removed in createObjectRest
103+ const props = node . properties as t . ObjectProperty [ ] ;
104+ const keys : t . Expression [ ] = [ ] ;
98105 let allLiteral = true ;
99106 let hasTemplateLiteral = false ;
100107
@@ -106,7 +113,14 @@ export default declare((api, opts) => {
106113 keys . push ( t . cloneNode ( prop . key ) ) ;
107114 hasTemplateLiteral = true ;
108115 } else if ( t . isLiteral ( prop . key ) ) {
109- keys . push ( t . stringLiteral ( String ( prop . key . value ) ) ) ;
116+ keys . push (
117+ t . stringLiteral (
118+ String (
119+ //@ts -ignore prop.key can not be a NullLiteral
120+ prop . key . value ,
121+ ) ,
122+ ) ,
123+ ) ;
110124 } else {
111125 keys . push ( t . cloneNode ( prop . key ) ) ;
112126 allLiteral = false ;
@@ -118,8 +132,11 @@ export default declare((api, opts) => {
118132
119133 // replaces impure computed keys with new identifiers
120134 // and returns variable declarators of these new identifiers
121- function replaceImpureComputedKeys ( properties , scope ) {
122- const impureComputedPropertyDeclarators = [ ] ;
135+ function replaceImpureComputedKeys (
136+ properties : NodePath < t . ObjectProperty > [ ] ,
137+ scope : Scope ,
138+ ) {
139+ const impureComputedPropertyDeclarators : t . VariableDeclarator [ ] = [ ] ;
123140 for ( const propPath of properties ) {
124141 const key = propPath . get ( "key" ) ;
125142 if ( propPath . node . computed && ! key . isPure ( ) ) {
@@ -132,13 +149,14 @@ export default declare((api, opts) => {
132149 return impureComputedPropertyDeclarators ;
133150 }
134151
135- function removeUnusedExcludedKeys ( path ) {
152+ function removeUnusedExcludedKeys ( path : NodePath < t . ObjectPattern > ) : void {
136153 const bindings = path . getOuterBindingIdentifierPaths ( ) ;
137154
138155 Object . keys ( bindings ) . forEach ( bindingName => {
139156 const bindingParentPath = bindings [ bindingName ] . parentPath ;
140157 if (
141- path . scope . getBinding ( bindingName ) . references > ZERO_REFS ||
158+ path . scope . getBinding ( bindingName ) . references >
159+ ( process . env . BABEL_8_BREAKING ? 0 : ZERO_REFS ) ||
142160 ! bindingParentPath . isObjectProperty ( )
143161 ) {
144162 return ;
@@ -148,19 +166,24 @@ export default declare((api, opts) => {
148166 }
149167
150168 //expects path to an object pattern
151- function createObjectRest ( path , file , objRef ) {
169+ function createObjectRest (
170+ path : NodePath < t . ObjectPattern > ,
171+ file : PluginPass ,
172+ objRef : t . Identifier | t . MemberExpression ,
173+ ) : [ t . VariableDeclarator [ ] , t . LVal , t . CallExpression ] {
152174 const props = path . get ( "properties" ) ;
153175 const last = props [ props . length - 1 ] ;
154176 t . assertRestElement ( last . node ) ;
155177 const restElement = t . cloneNode ( last . node ) ;
156178 last . remove ( ) ;
157179
158180 const impureComputedPropertyDeclarators = replaceImpureComputedKeys (
159- path . get ( "properties" ) ,
181+ path . get ( "properties" ) as NodePath < t . ObjectProperty > [ ] ,
160182 path . scope ,
161183 ) ;
162- const { keys, allLiteral, hasTemplateLiteral } =
163- extractNormalizedKeys ( path ) ;
184+ const { keys, allLiteral, hasTemplateLiteral } = extractNormalizedKeys (
185+ path . node ,
186+ ) ;
164187
165188 if ( keys . length === 0 ) {
166189 return [
@@ -210,7 +233,11 @@ export default declare((api, opts) => {
210233 ] ;
211234 }
212235
213- function replaceRestElement ( parentPath , paramPath , container ) {
236+ function replaceRestElement (
237+ parentPath : NodePath < t . Function | t . CatchClause > ,
238+ paramPath : NodePath ,
239+ container ?: t . VariableDeclaration [ ] ,
240+ ) : void {
214241 if ( paramPath . isAssignmentPattern ( ) ) {
215242 replaceRestElement ( parentPath , paramPath . get ( "left" ) , container ) ;
216243 return ;
@@ -299,7 +326,7 @@ export default declare((api, opts) => {
299326 for ( let i = 0 ; i < params . length ; ++ i ) {
300327 const param = params [ i ] ;
301328 if ( paramsWithRestElement . has ( i ) ) {
302- replaceRestElement ( param . parentPath , param ) ;
329+ replaceRestElement ( path , param ) ;
303330 }
304331 }
305332 } else {
@@ -360,14 +387,15 @@ export default declare((api, opts) => {
360387 }
361388
362389 let ref = originalPath . node . init ;
363- const refPropertyPath = [ ] ;
390+ const refPropertyPath : NodePath < t . ObjectProperty > [ ] = [ ] ;
364391 let kind ;
365392
366- path . findParent ( path => {
393+ path . findParent ( ( path : NodePath ) : boolean => {
367394 if ( path . isObjectProperty ( ) ) {
368395 refPropertyPath . unshift ( path ) ;
369396 } else if ( path . isVariableDeclarator ( ) ) {
370- kind = path . parentPath . node . kind ;
397+ kind = ( path . parentPath as NodePath < t . VariableDeclaration > ) . node
398+ . kind ;
371399 return true ;
372400 }
373401 } ) ;
@@ -385,12 +413,17 @@ export default declare((api, opts) => {
385413 ) ;
386414 } ) ;
387415
388- const objectPatternPath = path . findParent ( path =>
389- path . isObjectPattern ( ) ,
416+ //@ts -expect-error: findParent can not apply assertions on result shape
417+ const objectPatternPath : NodePath < t . ObjectPattern > = path . findParent (
418+ path => path . isObjectPattern ( ) ,
390419 ) ;
391420
392421 const [ impureComputedPropertyDeclarators , argument , callExpression ] =
393- createObjectRest ( objectPatternPath , file , ref ) ;
422+ createObjectRest (
423+ objectPatternPath ,
424+ file ,
425+ ref as t . MemberExpression ,
426+ ) ;
394427
395428 if ( pureGetters ) {
396429 removeUnusedExcludedKeys ( objectPatternPath ) ;
@@ -402,11 +435,9 @@ export default declare((api, opts) => {
402435
403436 insertionPath . insertBefore ( impureObjRefComputedDeclarators ) ;
404437
405- insertionPath . insertAfter (
438+ insertionPath = insertionPath . insertAfter (
406439 t . variableDeclarator ( argument , callExpression ) ,
407- ) ;
408-
409- insertionPath = insertionPath . getSibling ( insertionPath . key + 1 ) ;
440+ ) [ 0 ] as NodePath < t . VariableDeclarator > ;
410441
411442 path . scope . registerBinding ( kind , insertionPath ) ;
412443
@@ -433,7 +464,7 @@ export default declare((api, opts) => {
433464
434465 const specifiers = [ ] ;
435466
436- for ( const name of Object . keys ( path . getOuterBindingIdentifiers ( path ) ) ) {
467+ for ( const name of Object . keys ( path . getOuterBindingIdentifiers ( true ) ) ) {
437468 specifiers . push (
438469 t . exportSpecifier ( t . identifier ( name ) , t . identifier ( name ) ) ,
439470 ) ;
@@ -449,7 +480,7 @@ export default declare((api, opts) => {
449480 // try {} catch ({a, ...b}) {}
450481 CatchClause ( path ) {
451482 const paramPath = path . get ( "param" ) ;
452- replaceRestElement ( paramPath . parentPath , paramPath ) ;
483+ replaceRestElement ( path , paramPath ) ;
453484 } ,
454485
455486 // ({a, ...b} = c);
@@ -511,14 +542,15 @@ export default declare((api, opts) => {
511542 ] ) ;
512543
513544 path . ensureBlock ( ) ;
545+ const body = node . body as t . BlockStatement ;
514546
515- if ( node . body . body . length === 0 && path . isCompletionRecord ( ) ) {
516- node . body . body . unshift (
547+ if ( body . body . length === 0 && path . isCompletionRecord ( ) ) {
548+ body . body . unshift (
517549 t . expressionStatement ( scope . buildUndefinedNode ( ) ) ,
518550 ) ;
519551 }
520552
521- node . body . body . unshift (
553+ body . body . unshift (
522554 t . expressionStatement (
523555 t . assignmentExpression ( "=" , left , t . cloneNode ( temp ) ) ,
524556 ) ,
@@ -533,8 +565,9 @@ export default declare((api, opts) => {
533565 ] ) ;
534566
535567 path . ensureBlock ( ) ;
568+ const body = node . body as t . BlockStatement ;
536569
537- node . body . body . unshift (
570+ body . body . unshift (
538571 t . variableDeclaration ( node . left . kind , [
539572 t . variableDeclarator ( pattern , t . cloneNode ( key ) ) ,
540573 ] ) ,
@@ -565,11 +598,13 @@ export default declare((api, opts) => {
565598
566599 if ( objectPatterns . length > 0 ) {
567600 const statementPath = path . getStatementParent ( ) ;
601+ const statementNode = statementPath . node ;
602+ const kind =
603+ statementNode . type === "VariableDeclaration"
604+ ? statementNode . kind
605+ : "var" ;
568606 statementPath . insertAfter (
569- t . variableDeclaration (
570- statementPath . node . kind || "var" ,
571- objectPatterns ,
572- ) ,
607+ t . variableDeclaration ( kind , objectPatterns ) ,
573608 ) ;
574609 }
575610 } ,
@@ -627,7 +662,7 @@ export default declare((api, opts) => {
627662 ] ) ;
628663 }
629664
630- for ( const prop of ( path . node . properties : Array ) ) {
665+ for ( const prop of path . node . properties ) {
631666 if ( t . isSpreadElement ( prop ) ) {
632667 make ( ) ;
633668 exp . arguments . push ( prop . argument ) ;
@@ -640,6 +675,6 @@ export default declare((api, opts) => {
640675
641676 path . replaceWith ( exp ) ;
642677 } ,
643- } ,
678+ } as Visitor < PluginPass > ,
644679 } ;
645680} ) ;
0 commit comments