import { Syntax } from "estraverse" ; import * as esrecurse from "esrecurse" ; import * as ESTree from "estree" ; function getLast < T > ( xs ) { return xs [ xs . length - 1 ] || null ; } export type AssignmentType = ESTree . AssignmentPattern | ESTree . AssignmentExpression ; export interface ICallbackOption { topLevel : boolean ; rest : boolean ; assignments : AssignmentType [ ] ; } export type PatternVisitorCallback = ( id : ESTree . Identifier , option : ICallbackOption ) => void ; export class PatternVisitor extends esrecurse . Visitor { public static isPattern ( node ) { const nodeType = node . type ; return ( nodeType === Syntax . Identifier || nodeType === Syntax . ObjectPattern || nodeType === Syntax . ArrayPattern || nodeType === Syntax . SpreadElement || nodeType === Syntax . RestElement || nodeType === Syntax . AssignmentPattern ) ; } public rootPattern : any ; public callback : PatternVisitorCallback ; public assignments : AssignmentType [ ] ; public rightHandNodes : any [ ] ; public restElements : any [ ] ; public constructor ( options , rootPattern , callback ) { super ( undefined , options ) ; this . rootPattern = rootPattern ; this . callback = callback ; this . assignments = [ ] ; this . rightHandNodes = [ ] ; this . restElements = [ ] ; } public Identifier ( pattern ) { const lastRestElement = getLast ( this . restElements ) ; this . callback ( pattern , { topLevel : pattern === this . rootPattern , rest : lastRestElement !== null && lastRestElement !== undefined && lastRestElement . argument === pattern , assignments : this . assignments , } ) ; } public Property ( property ) { if ( property . computed ) { this . rightHandNodes . push ( property . key ) ; } this . visit ( property . value ) ; } public ArrayPattern ( pattern ) { for ( let i = 0 , iz = pattern . elements . length ; i < iz ; ++ i ) { const element = pattern . elements [ i ] ; this . visit ( element ) ; } } public AssignmentPattern ( pattern ) { this . assignments . push ( pattern ) ; this . visit ( pattern . left ) ; this . rightHandNodes . push ( pattern . right ) ; this . assignments . pop ( ) ; } public RestElement ( pattern ) { this . restElements . push ( pattern ) ; this . visit ( pattern . argument ) ; this . restElements . pop ( ) ; } public MemberExpression ( node ) { if ( node . computed ) { this . rightHandNodes . push ( node . property ) ; } this . rightHandNodes . push ( node . object ) ; } public SpreadElement ( node ) { this . visit ( node . argument ) ; } public ArrayExpression ( node ) { node . elements . forEach ( this . visit , this ) ; } public AssignmentExpression ( node ) { this . assignments . push ( node ) ; this . visit ( node . left ) ; this . rightHandNodes . push ( node . right ) ; this . assignments . pop ( ) ; } public CallExpression ( node ) { node . arguments . forEach ( a => { this . rightHandNodes . push ( a ) ; } ) ; this . visit ( node . callee ) ; } }