import * as ts from 'typescript' ; /**
 * General utility class.
 */ export namespace AstUtils { export function getLanguageVariant ( node ) { if ( /.*\.tsx/i . test ( node . fileName ) ) { return ts . LanguageVariant . JSX ; } else { return ts . LanguageVariant . Standard ; } } export function getFunctionName ( node ) { const expression = node . expression ; let functionName = ( < any > expression ) . text ; if ( functionName === undefined && ( < any > expression ) . name ) { functionName = ( < any > expression ) . name . text ; } return functionName ; } export function getFunctionTarget ( expression ) { if ( expression . expression . kind === ts . SyntaxKind . PropertyAccessExpression ) { const propExp = < ts . PropertyAccessExpression > expression . expression ; return propExp . expression . getText ( ) ; } return null ; } export function isJQuery ( functionTarget ) { return functionTarget === '$' || /^(jquery)$/i . test ( functionTarget ) ; } export function hasModifier ( modifiers , modifierKind ) { if ( modifiers == null ) { return false ; } let result = false ; modifiers . forEach ( ( modifier ) : void => { if ( modifier . kind === modifierKind ) { result = true ; } } ) ; return result ; } export function dumpTypeInfo ( expression , languageServices , typeChecker ) { console . log ( expression . getFullText ( ) ) ; console . log ( '\tkind: ' + expression . kind ) ; if ( expression . kind === ts . SyntaxKind . Identifier || expression . kind === ts . SyntaxKind . PropertyAccessExpression ) { const definitionInfo = languageServices . getDefinitionAtPosition ( 'file.ts' , expression . getStart ( ) ) ; if ( definitionInfo ) { definitionInfo . forEach ( ( info , index ) : void => { console . log ( '\tdefinitionInfo-' + index ) ; console . log ( '\t\tkind: ' + info . kind ) ; console . log ( '\t\tname: ' + info . name ) ; } ) ; } const typeInfo = languageServices . getTypeDefinitionAtPosition ( 'file.ts' , expression . getStart ( ) ) ; if ( typeInfo ) { typeInfo . forEach ( ( info , index ) : void => { console . log ( '\ttypeDefinitionInfo-' + index ) ; console . log ( '\t\tkind: ' + info . kind ) ; console . log ( '\t\tname: ' + info . name ) ; } ) ; } const quickInfo = languageServices . getQuickInfoAtPosition ( 'file.ts' , expression . getStart ( ) ) ; console . log ( '\tquickInfo.kind         = ' + quickInfo . kind ) ; console . log ( '\tquickInfo.kindModifiers= ' + quickInfo . kindModifiers ) ; console . log ( '\tquickInfo.textSpan     = ' + quickInfo . textSpan . start ) ; console . log ( '\tquickInfo.displayParts = ' + quickInfo . displayParts [ 0 ] . text ) ; console . log ( '\tquickInfo.displayParts = ' + quickInfo . displayParts [ 0 ] . kind ) ; const expressionType = typeChecker . getTypeAtLocation ( expression ) ; console . log ( '\ttypeChecker.typeToString : ' + typeChecker . typeToString ( expressionType ) ) ; console . log ( '\ttype.flags: ' + expressionType . flags ) ; console . log ( '\ttype.symbol: ' + expressionType . symbol ) ; const expressionSymbol = typeChecker . getSymbolAtLocation ( expression ) ; if ( expressionSymbol == null ) { console . log ( '\tsymbol: ' + expressionSymbol ) ; } else { console . log ( '\tsymbol.flags: ' + expressionSymbol . flags ) ; console . log ( '\tsymbol.name: ' + expressionSymbol . name ) ; console . log ( '\tsymbol.declarations: ' + expressionSymbol . declarations ) ; } const contextualType = typeChecker . getContextualType ( expression ) ; if ( contextualType == null ) { console . log ( '\tcontextualType: ' + contextualType ) ; } else { console . log ( '\tcontextualType.flags: ' + contextualType . flags ) ; console . log ( '\tcontextualType.symbol: ' + contextualType . symbol ) ; } } } export function isPrivate ( node ) { if ( ( < any > ts ) . NodeFlags . Private != null ) { return ! ! ( node . flags & ( < any > ts ) . NodeFlags . Private ) ; } else { return ! ! ( ( < any > ts ) . getCombinedModifierFlags ( node ) & ( < any > ts ) . ModifierFlags . Private ) ; } } export function isProtected ( node ) { if ( ( < any > ts ) . NodeFlags . Protected != null ) { return ! ! ( node . flags & ( < any > ts ) . NodeFlags . Protected ) ; } else { return ! ! ( ( < any > ts ) . getCombinedModifierFlags ( node ) & ( < any > ts ) . ModifierFlags . Protected ) ; } } export function isPublic ( node ) { if ( ( < any > ts ) . NodeFlags . Public != null ) { return ! ! ( node . flags & ( < any > ts ) . NodeFlags . Public ) ; } else { return ! ! ( ( < any > ts ) . getCombinedModifierFlags ( node ) & ( < any > ts ) . ModifierFlags . Public ) ; } } export function isStatic ( node ) { if ( ( < any > ts ) . NodeFlags . Static != null ) { return ! ! ( node . flags & ( < any > ts ) . NodeFlags . Static ) ; } else { return ! ! ( ( < any > ts ) . getCombinedModifierFlags ( node ) & ( < any > ts ) . ModifierFlags . Static ) ; } } function isBindingPattern ( node ) { return node != null && ( node . kind === ts . SyntaxKind . ArrayBindingPattern || node . kind === ts . SyntaxKind . ObjectBindingPattern ) ; } function walkUpBindingElementsAndPatterns ( node ) { while ( node && ( node . kind === ts . SyntaxKind . BindingElement || isBindingPattern ( node ) ) ) { node = node . parent ; } return node ; } function getCombinedNodeFlags ( node ) { node = walkUpBindingElementsAndPatterns ( node ) ; let flags = node . flags ; if ( node . kind === ts . SyntaxKind . VariableDeclaration ) { node = node . parent ; } if ( node && node . kind === ts . SyntaxKind . VariableDeclarationList ) { flags |= node . flags ; node = node . parent ; } if ( node && node . kind === ts . SyntaxKind . VariableStatement ) { flags |= node . flags ; } return flags ; } export function isLet ( node ) { return ! ! ( getCombinedNodeFlags ( node ) & ts . NodeFlags . Let ) ; } export function isExported ( node ) { if ( ( < any > ts ) . NodeFlags . Export != null ) { return ! ! ( getCombinedNodeFlags ( node ) & ( < any > ts ) . NodeFlags . Export ) ; } else { if ( node . kind === ts . SyntaxKind . VariableDeclaration && node . parent . kind === ts . SyntaxKind . VariableDeclarationList && node . parent . parent . kind === ts . SyntaxKind . VariableStatement ) { if ( AstUtils . hasModifier ( node . parent . parent . modifiers , ts . SyntaxKind . ExportKeyword ) ) { return true ; } } return ! ! ( getCombinedNodeFlags ( node ) & ts . NodeFlags . ExportContext ) ; } } export function isAssignmentOperator ( token ) { return token >= ts . SyntaxKind . FirstAssignment && token <= ts . SyntaxKind . LastAssignment ; } export function isBindingLiteralExpression ( node ) { return ! ! node && ( node . kind === ts . SyntaxKind . ObjectLiteralExpression || node . kind === ts . SyntaxKind . ArrayLiteralExpression ) ; } export function findParentBlock ( child ) { let parent = child . parent ; while ( parent != null ) { if ( parent . kind === ts . SyntaxKind . Block ) { return parent ; } parent = parent . parent ; } throw new Error ( 'Could not determine parent block of node: ' + child ) ; } export function isSameIdentifer ( source , target ) { if ( source == null || target == null ) { return false ; } if ( source . kind === ts . SyntaxKind . Identifier && target . kind === ts . SyntaxKind . Identifier ) { return source . getText ( ) === target . getText ( ) ; } return false ; } export function getDeclaredMethodNames ( node ) { const result = [ ] ; node . members . forEach ( ( classElement ) : void => { if ( classElement . kind === ts . SyntaxKind . MethodDeclaration ) { const methodDeclaration = < ts . MethodDeclaration > classElement ; if ( methodDeclaration . name . kind === ts . SyntaxKind . Identifier ) { result . push ( ( < ts . Identifier > methodDeclaration . name ) . text ) ; } } } ) ; return result ; } export function isDeclarationFunctionType ( node ) { if ( node . type != null ) { if ( node . type . getText ( ) === 'Function' ) { return true ; } return node . type . kind === ts . SyntaxKind . FunctionType ; } else if ( node . initializer != null ) { return node . initializer . kind === ts . SyntaxKind . ArrowFunction || node . initializer . kind === ts . SyntaxKind . FunctionExpression ; } return false ; } export function isUndefined ( node ) { if ( node != null ) { if ( node . kind === ts . SyntaxKind . Identifier ) { return node . getText ( ) === 'undefined' ; } } return false ; } export function isConstant ( node ) { if ( node == null ) { return false ; } return ( node . kind === ts . SyntaxKind . NullKeyword || node . kind === ts . SyntaxKind . StringLiteral || node . kind === ts . SyntaxKind . FalseKeyword || node . kind === ts . SyntaxKind . TrueKeyword || node . kind === ts . SyntaxKind . NumericLiteral ) ; } export function isConstantExpression ( node ) { if ( node . kind === ts . SyntaxKind . BinaryExpression ) { const expression = < ts . BinaryExpression > node ; const kind = expression . operatorToken . kind ; if ( kind >= ts . SyntaxKind . FirstBinaryOperator && kind <= ts . SyntaxKind . LastBinaryOperator ) { return isConstantExpression ( expression . left ) && isConstantExpression ( expression . right ) ; } } if ( node . kind === ts . SyntaxKind . PrefixUnaryExpression || node . kind === ts . SyntaxKind . PostfixUnaryExpression ) { const expression = < ts . PostfixUnaryExpression | ts . PrefixUnaryExpression > ( node ) ; return isConstantExpression ( expression . operand ) ; } return isConstant ( node ) ; } }