import { Node , SyntaxKind } from 'typescript' ; import { syntaxKindName } from './syntax-kind' ; import { TSQueryOptions , TSQueryProperties , TSQueryTraverseOptions } from './tsquery-types' ; const FILTERED_KEYS = [ 'parent' ] ; const LITERAL_KINDS = [ SyntaxKind . FalseKeyword , SyntaxKind . NoSubstitutionTemplateLiteral , SyntaxKind . NullKeyword , SyntaxKind . NumericLiteral , SyntaxKind . RegularExpressionLiteral , SyntaxKind . StringLiteral , SyntaxKind . TrueKeyword ] ; const PARSERS = { [ SyntaxKind . FalseKeyword ] : ( ) => false , [ SyntaxKind . NoSubstitutionTemplateLiteral ] : ( properties ) => properties . text , [ SyntaxKind . NullKeyword ] : ( ) => null , [ SyntaxKind . NumericLiteral ] : ( properties ) => + properties . text , [ SyntaxKind . RegularExpressionLiteral ] : ( properties ) => new RegExp ( properties . text ) , [ SyntaxKind . StringLiteral ] : ( properties ) => properties . text , [ SyntaxKind . TrueKeyword ] : ( ) => true } ; export function traverseChildren ( node , iterator , options ) { const ancestors = [ ] ; traverse ( node , { enter ( childNode , parentNode ) { if ( parentNode != null ) { ancestors . unshift ( parentNode ) ; } iterator ( childNode , ancestors ) ; } , leave ( ) { ancestors . shift ( ) ; } , visitAllChildren : ! ! options . visitAllChildren } ) ; } function traverse ( node , traverseOptions ) { traverseOptions . enter ( node , node . parent || null ) ; if ( traverseOptions . visitAllChildren ) { node . getChildren ( ) . forEach ( child => traverse ( child , traverseOptions ) ) ; } else { node . forEachChild ( child => traverse ( child , traverseOptions ) ) ; } traverseOptions . leave ( node , node . parent || null ) ; } export function getVisitorKeys ( node ) { return ! ! node ? Object . keys ( node ) . filter ( key => ! FILTERED_KEYS . includes ( key ) ) . filter ( key => { const value = ( node as any ) [ key ] ; return Array . isArray ( value ) || typeof value === 'object' ; } ) : [ ] ; } const propertiesMap = new WeakMap < Node , TSQueryProperties > ( ) ; export function getProperties ( node ) { let properties = propertiesMap . get ( node ) ; if ( ! properties ) { properties = { kindName : syntaxKindName ( node . kind ) , text : hasKey ( node , 'text' ) ? node . text : getTextIfNotSynthesized ( node ) } ; if ( node . kind === SyntaxKind . Identifier ) { properties . name = hasKey ( node , 'name' ) ? node . name : properties . text ; } if ( LITERAL_KINDS . includes ( node . kind ) ) { properties . value = PARSERS [ node . kind ] ( properties ) ; } propertiesMap . set ( node , properties ) ; } return properties ; } function hasKey < K extends { [ key ] : any ; } > ( node , property ) { return node [ property ] != null ; } function getTextIfNotSynthesized ( node ) { return ! ( node . pos >= 0 ) ? '' : node . getText ( ) ; }