@ Nullable private static Node getEnclosingTarget ( Node targetNode ) { checkState ( checkNotNull ( targetNode ) . isValidAssignmentTarget ( ) , targetNode ) ; Node parent = checkNotNull ( targetNode . getParent ( ) , targetNode ) ; boolean targetIsFirstChild = parent . getFirstChild ( ) == targetNode ; if ( parent . isDefaultValue ( ) || parent . isRest ( ) ) { // in `([something = targetNode] = x)` targetNode isn't actually acting // as a target. checkState ( targetIsFirstChild , parent ) ; // The DEFAULT_VALUE or REST occupies the place where the assignment target it contains would // otherwise be in the AST, so pretend it is the target for the logic below. targetNode = parent ; parent = checkNotNull ( targetNode . getParent ( ) ) ; targetIsFirstChild = targetNode == parent . getFirstChild ( ) ; } switch ( parent . getToken ( ) ) { case ARRAY_PATTERN : // e.g. ([targetNode] = something) return parent ; case OBJECT_PATTERN : // e.g. ({...rest} = something); return parent ; case COMPUTED_PROP : // e.g. ({[expression]: targetNode} = something) // e.g. ({[expression]: targetNode = default} = something) // make sure the effective target (targetNode or DEFAULT_VALUE containing it) // isn't the expression part checkState ( ! targetIsFirstChild , parent ) ; // otherwise the same as STRING_KEY so fall through case STRING_KEY : // e.g. ({parent: targetNode} = something) Node grandparent = checkNotNull ( parent . getParent ( ) , parent ) ; checkState ( grandparent . isObjectPattern ( ) , grandparent ) ; return grandparent ; case PARAM_LIST : // e.g. `function foo(targetNode) {}` case LET : case CONST : case VAR : // non-destructured declarations // e.g. `let targetNode = 3;` return null ; case FUNCTION : case CLASS : // e.g. `function targetNode() {}` // e.g. `class targetNode {}` checkState ( targetIsFirstChild , targetNode ) ; return null ; case FOR_IN : case FOR_OF : case FOR_AWAIT_OF : // e.g. `for ({length} in obj) {}` // targetNode is `{length}` // e.g. `for ({length} of obj) {}` // targetNode is `{length}` checkState ( targetIsFirstChild , targetNode ) ; return null ; case DESTRUCTURING_LHS : // destructured declarations // e.g. `let [a] = 3`; // targetNode is `[a]` checkState ( targetIsFirstChild , targetNode ) ; return null ; case IMPORT : // e.g. `import targetNode from './foo/bar';` return null ; case IMPORT_SPEC : // e.g. `import {bar as targetNode} from './foo/bar';` // e.g. `import {targetNode} from './foo/bar';` // AST will have {targetNode as targetNode} checkState ( ! targetIsFirstChild , parent ) ; return null ; case CATCH : // e.g. `try {} catch (foo) {}` return null ; default : // e.g. targetNode = something checkState ( isAssignmentOp ( parent ) && targetIsFirstChild , parent ) ; return null ; } }
Returns the immediately enclosing target node for a given target node or null if none found .