@ -183,11 +183,11 @@ export function extract_identifiers_from_destructuring(node, nodes = []) {
* @ typedef { Object } DestructuredAssignment
* @ property { import ( 'estree' ) . Identifier | import ( 'estree' ) . MemberExpression } node The node the destructuring path end in . Can be a member expression only for assignment expressions
* @ property { boolean } is _rest ` true ` if this is a ` ...rest ` destructuring
* @ property { ( expression : import ( 'estree' ) . Expression ) => import ( 'estree' ) . Identifier | import ( 'estree' ) . MemberExpression | import ( 'estree' ) . CallExpression } expression Returns an expression which walks the path starting at the given expression .
* This will be a call expression if a rest element or default is involved —
* e. g . ` const { foo: { bar: baz = 42 }, ...rest } = quux ` —
* since we can ' t represent ` baz ` or ` rest ` purely as a path
* @ property { ( expression : import ( 'estree' ) . Expression ) => import ( 'estree' ) . Identifier | import ( 'estree' ) . MemberExpression | import ( 'estree' ) . CallExpression } update _expression Like ` expression ` but without default values .
* @ property { boolean } has _default _value ` true ` if this has a fallback value like ` const { foo = 'bar } = .. `
* @ property { ( expression : import ( 'estree' ) . Expression ) => import ( 'estree' ) . Identifier | import ( 'estree' ) . MemberExpression | import ( 'estree' ) . CallExpression | import ( 'estree' ) . AwaitExpression } expression Returns an expression which walks the path starting at the given expression .
* This will be a call expression if a rest element or default is involved — e. g . ` const { foo: { bar: baz = 42 }, ...rest } = quux ` — since we can ' t represent ` baz ` or ` rest ` purely as a path
* Will be an await expression in case of an async default value ( ` const { foo = await bar } = ... ` )
* @ property { ( expression : import ( 'estree' ) . Expression ) => import ( 'estree' ) . Identifier | import ( 'estree' ) . MemberExpression | import ( 'estree' ) . CallExpression | import ( 'estree' ) . AwaitExpression } update _expression Like ` expression ` but without default values .
* /
/ * *
@ -200,7 +200,8 @@ export function extract_paths(param) {
[ ] ,
param ,
( node ) => /** @type {import('estree').Identifier | import('estree').MemberExpression} */ ( node ) ,
( node ) => /** @type {import('estree').Identifier | import('estree').MemberExpression} */ ( node )
( node ) => /** @type {import('estree').Identifier | import('estree').MemberExpression} */ ( node ) ,
false
) ;
}
@ -209,15 +210,17 @@ export function extract_paths(param) {
* @ param { import ( 'estree' ) . Node } param
* @ param { DestructuredAssignment [ 'expression' ] } expression
* @ param { DestructuredAssignment [ 'update_expression' ] } update _expression
* @ param { boolean } has _default _value
* @ returns { DestructuredAssignment [ ] }
* /
function _extract _paths ( assignments = [ ] , param , expression , update _expression ) {
function _extract _paths ( assignments = [ ] , param , expression , update _expression , has _default _value ) {
switch ( param . type ) {
case 'Identifier' :
case 'MemberExpression' :
assignments . push ( {
node : param ,
is _rest : false ,
has _default _value ,
expression ,
update _expression
} ) ;
@ -246,17 +249,30 @@ function _extract_paths(assignments = [], param, expression, update_expression)
assignments . push ( {
node : prop . argument ,
is _rest : true ,
has _default _value ,
expression : rest _expression ,
update _expression : rest _expression
} ) ;
} else {
_extract _paths ( assignments , prop . argument , rest _expression , rest _expression ) ;
_extract _paths (
assignments ,
prop . argument ,
rest _expression ,
rest _expression ,
has _default _value
) ;
}
} else {
/** @type {DestructuredAssignment['expression']} */
const object _expression = ( object ) =>
b . member ( expression ( object ) , prop . key , prop . computed || prop . key . type !== 'Identifier' ) ;
_extract _paths ( assignments , prop . value , object _expression , object _expression ) ;
_extract _paths (
assignments ,
prop . value ,
object _expression ,
object _expression ,
has _default _value
) ;
}
}
@ -274,16 +290,29 @@ function _extract_paths(assignments = [], param, expression, update_expression)
assignments . push ( {
node : element . argument ,
is _rest : true ,
has _default _value ,
expression : rest _expression ,
update _expression : rest _expression
} ) ;
} else {
_extract _paths ( assignments , element . argument , rest _expression , rest _expression ) ;
_extract _paths (
assignments ,
element . argument ,
rest _expression ,
rest _expression ,
has _default _value
) ;
}
} else {
/** @type {DestructuredAssignment['expression']} */
const array _expression = ( object ) => b . member ( expression ( object ) , b . literal ( i ) , true ) ;
_extract _paths ( assignments , element , array _expression , array _expression ) ;
_extract _paths (
assignments ,
element ,
array _expression ,
array _expression ,
has _default _value
) ;
}
}
}
@ -293,16 +322,22 @@ function _extract_paths(assignments = [], param, expression, update_expression)
case 'AssignmentPattern' : {
/** @type {DestructuredAssignment['expression']} */
const fallback _expression = ( object ) =>
b . call ( '$.value_or_fallback' , expression ( object ) , param . right ) ;
is _expression _async ( param . right )
? b . await (
b . call ( '$.value_or_fallback_async' , expression ( object ) , b . thunk ( param . right , true ) )
)
: b . call ( '$.value_or_fallback' , expression ( object ) , b . thunk ( param . right ) ) ;
if ( param . left . type === 'Identifier' ) {
assignments . push ( {
node : param . left ,
is _rest : false ,
has _default _value : true ,
expression : fallback _expression ,
update _expression
} ) ;
} else {
_extract _paths ( assignments , param . left , fallback _expression , update _expression );
_extract _paths ( assignments , param . left , fallback _expression , update _expression , true );
}
break ;
@ -370,3 +405,100 @@ export function is_simple_expression(node) {
export function unwrap _optional ( node ) {
return node . type === 'ChainExpression' ? node . expression : node ;
}
/ * *
* @ param { import ( 'estree' ) . Expression | import ( 'estree' ) . Pattern } expression
* @ returns { boolean }
* /
export function is _expression _async ( expression ) {
switch ( expression . type ) {
case 'AwaitExpression' : {
return true ;
}
case 'ArrayPattern' : {
return expression . elements . some ( ( element ) => element && is _expression _async ( element ) ) ;
}
case 'ArrayExpression' : {
return expression . elements . some ( ( element ) => {
if ( ! element ) {
return false ;
} else if ( element . type === 'SpreadElement' ) {
return is _expression _async ( element . argument ) ;
} else {
return is _expression _async ( element ) ;
}
} ) ;
}
case 'AssignmentPattern' :
case 'AssignmentExpression' :
case 'BinaryExpression' :
case 'LogicalExpression' : {
return is _expression _async ( expression . left ) || is _expression _async ( expression . right ) ;
}
case 'CallExpression' :
case 'NewExpression' : {
return (
( expression . callee . type !== 'Super' && is _expression _async ( expression . callee ) ) ||
expression . arguments . some ( ( element ) => {
if ( element . type === 'SpreadElement' ) {
return is _expression _async ( element . argument ) ;
} else {
return is _expression _async ( element ) ;
}
} )
) ;
}
case 'ChainExpression' : {
return is _expression _async ( expression . expression ) ;
}
case 'ConditionalExpression' : {
return (
is _expression _async ( expression . test ) ||
is _expression _async ( expression . alternate ) ||
is _expression _async ( expression . consequent )
) ;
}
case 'ImportExpression' : {
return is _expression _async ( expression . source ) ;
}
case 'MemberExpression' : {
return (
( expression . object . type !== 'Super' && is _expression _async ( expression . object ) ) ||
( expression . property . type !== 'PrivateIdentifier' &&
is _expression _async ( expression . property ) )
) ;
}
case 'ObjectPattern' :
case 'ObjectExpression' : {
return expression . properties . some ( ( property ) => {
if ( property . type === 'SpreadElement' ) {
return is _expression _async ( property . argument ) ;
} else if ( property . type === 'Property' ) {
return (
( property . key . type !== 'PrivateIdentifier' && is _expression _async ( property . key ) ) ||
is _expression _async ( property . value )
) ;
}
} ) ;
}
case 'RestElement' : {
return is _expression _async ( expression . argument ) ;
}
case 'SequenceExpression' :
case 'TemplateLiteral' : {
return expression . expressions . some ( ( subexpression ) => is _expression _async ( subexpression ) ) ;
}
case 'TaggedTemplateExpression' : {
return is _expression _async ( expression . tag ) || is _expression _async ( expression . quasi ) ;
}
case 'UnaryExpression' :
case 'UpdateExpression' : {
return is _expression _async ( expression . argument ) ;
}
case 'YieldExpression' : {
return expression . argument ? is _expression _async ( expression . argument ) : false ;
}
default :
return false ;
}
}