module ts { export interface ReferencePathMatchResult { fileReference ? : FileReference ; diagnosticMessage ? : DiagnosticMessage ; isNoDefaultLib ? : boolean ; } export function getDeclarationOfKind ( symbol , kind ) { var declarations = symbol . declarations ; for ( var i = 0 ; i < declarations . length ; i ++ ) { var declaration = declarations [ i ] ; if ( declaration . kind === kind ) { return declaration ; } } return undefined ; } export interface StringSymbolWriter extends SymbolWriter { string ( ) : string ; } var stringWriters = [ ] ; export function getSingleLineStringWriter ( ) { if ( stringWriters . length == 0 ) { var str = "" ; var writeText = text => str += text ; return { string : ( ) => str , writeKeyword : writeText , writeOperator : writeText , writePunctuation : writeText , writeSpace : writeText , writeStringLiteral : writeText , writeParameter : writeText , writeSymbol : writeText , writeLine : ( ) => str += " " , increaseIndent : ( ) => { } , decreaseIndent : ( ) => { } , clear : ( ) => str = "" , trackSymbol : ( ) => { } } ; } return stringWriters . pop ( ) ; } export function releaseStringWriter ( writer ) { writer . clear ( ) ; stringWriters . push ( writer ) ; } export function getFullWidth ( node ) { return node . end - node . pos ; } export function hasFlag ( val , flag ) { return ( val & flag ) !== 0 ; } export function containsParseError ( node ) { if ( ! hasFlag ( node . parserContextFlags , ParserContextFlags . HasPropagatedChildContainsErrorFlag ) ) { var val = hasFlag ( node . parserContextFlags , ParserContextFlags . ContainsError ) || forEachChild ( node , containsParseError ) ; if ( val ) { node . parserContextFlags |= ParserContextFlags . ContainsError ; } node . parserContextFlags |= ParserContextFlags . HasPropagatedChildContainsErrorFlag ; } return hasFlag ( node . parserContextFlags , ParserContextFlags . ContainsError ) ; } export function getSourceFileOfNode ( node ) { while ( node && node . kind !== SyntaxKind . SourceFile ) { node = node . parent ; } return < SourceFile > node ; } export function nodePosToString ( node ) { var file = getSourceFileOfNode ( node ) ; var loc = file . getLineAndCharacterFromPosition ( node . pos ) ; return file . filename + "(" + loc . line + "," + loc . character + ")" ; } export function getStartPosOfNode ( node ) { return node . pos ; } export function isMissingNode ( node ) { return node . pos === node . end && node . kind !== SyntaxKind . EndOfFileToken ; } export function getTokenPosOfNode ( node , sourceFile ? ) { if ( isMissingNode ( node ) ) { return node . pos ; } return skipTrivia ( ( sourceFile || getSourceFileOfNode ( node ) ) . text , node . pos ) ; } export function getSourceTextOfNodeFromSourceFile ( sourceFile , node ) { if ( isMissingNode ( node ) ) { return "" ; } var text = sourceFile . text ; return text . substring ( skipTrivia ( text , node . pos ) , node . end ) ; } export function getTextOfNodeFromSourceText ( sourceText , node ) { if ( isMissingNode ( node ) ) { return "" ; } return sourceText . substring ( skipTrivia ( sourceText , node . pos ) , node . end ) ; } export function getTextOfNode ( node ) { return getSourceTextOfNodeFromSourceFile ( getSourceFileOfNode ( node ) , node ) ; } export function escapeIdentifier ( identifier ) { return identifier . length >= 2 && identifier . charCodeAt ( 0 ) === CharacterCodes . _ && identifier . charCodeAt ( 1 ) === CharacterCodes . _ ? "_" + identifier : identifier ; } export function unescapeIdentifier ( identifier ) { return identifier . length >= 3 && identifier . charCodeAt ( 0 ) === CharacterCodes . _ && identifier . charCodeAt ( 1 ) === CharacterCodes . _ && identifier . charCodeAt ( 2 ) === CharacterCodes . _ ? identifier . substr ( 1 ) : identifier ; } export function declarationNameToString ( name ) { return getFullWidth ( name ) === 0 ? "(Missing)" : getTextOfNode ( name ) ; } export function createDiagnosticForNode ( node , message , arg0 ? , arg1 ? , arg2 ? ) { node = getErrorSpanForNode ( node ) ; var file = getSourceFileOfNode ( node ) ; var start = getTokenPosOfNode ( node , file ) ; var length = node . end - start ; return createFileDiagnostic ( file , start , length , message , arg0 , arg1 , arg2 ) ; } export function createDiagnosticForNodeFromMessageChain ( node , messageChain , newLine ) { node = getErrorSpanForNode ( node ) ; var file = getSourceFileOfNode ( node ) ; var start = skipTrivia ( file . text , node . pos ) ; var length = node . end - start ; return flattenDiagnosticChain ( file , start , length , messageChain , newLine ) ; } export function getErrorSpanForNode ( node ) { var errorSpan ; switch ( node . kind ) { case SyntaxKind . VariableDeclaration : case SyntaxKind . ClassDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . ModuleDeclaration : case SyntaxKind . EnumDeclaration : case SyntaxKind . EnumMember : errorSpan = ( < Declaration > node ) . name ; break ; } return errorSpan && errorSpan . pos < errorSpan . end ? errorSpan : node ; } export function isExternalModule ( file ) { return file . externalModuleIndicator !== undefined ; } export function isDeclarationFile ( file ) { return ( file . flags & NodeFlags . DeclarationFile ) !== 0 ; } export function isConstEnumDeclaration ( node ) { return node . kind === SyntaxKind . EnumDeclaration && isConst ( node ) ; } export function isConst ( node ) { return ! ! ( node . flags & NodeFlags . Const ) ; } export function isLet ( node ) { return ! ! ( node . flags & NodeFlags . Let ) ; } export function isPrologueDirective ( node ) { return node . kind === SyntaxKind . ExpressionStatement && ( < ExpressionStatement > node ) . expression . kind === SyntaxKind . StringLiteral ; } export function getLeadingCommentRangesOfNode ( node , sourceFileOfNode ? ) { sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode ( node ) ; if ( node . kind === SyntaxKind . Parameter || node . kind === SyntaxKind . TypeParameter ) { return concatenate ( getTrailingCommentRanges ( sourceFileOfNode . text , node . pos ) , getLeadingCommentRanges ( sourceFileOfNode . text , node . pos ) ) ; } else { return getLeadingCommentRanges ( sourceFileOfNode . text , node . pos ) ; } } export function getJsDocComments ( node , sourceFileOfNode ) { return filter ( getLeadingCommentRangesOfNode ( node , sourceFileOfNode ) , isJsDocComment ) ; function isJsDocComment ( comment ) { return sourceFileOfNode . text . charCodeAt ( comment . pos + 1 ) === CharacterCodes . asterisk && sourceFileOfNode . text . charCodeAt ( comment . pos + 2 ) === CharacterCodes . asterisk && sourceFileOfNode . text . charCodeAt ( comment . pos + 3 ) !== CharacterCodes . slash ; } } export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/ ; export function forEachReturnStatement < T > ( body , visitor ) { return traverse ( body ) ; function traverse ( node ) { switch ( node . kind ) { case SyntaxKind . ReturnStatement : return visitor ( < ReturnStatement > node ) ; case SyntaxKind . Block : case SyntaxKind . IfStatement : case SyntaxKind . DoStatement : case SyntaxKind . WhileStatement : case SyntaxKind . ForStatement : case SyntaxKind . ForInStatement : case SyntaxKind . WithStatement : case SyntaxKind . SwitchStatement : case SyntaxKind . CaseClause : case SyntaxKind . DefaultClause : case SyntaxKind . LabeledStatement : case SyntaxKind . TryStatement : case SyntaxKind . TryBlock : case SyntaxKind . CatchClause : case SyntaxKind . FinallyBlock : return forEachChild ( node , traverse ) ; } } } export function isAnyFunction ( node ) { if ( node ) { switch ( node . kind ) { case SyntaxKind . FunctionExpression : case SyntaxKind . FunctionDeclaration : case SyntaxKind . ArrowFunction : case SyntaxKind . Method : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . Constructor : return true ; } } return false ; } export function isFunctionBlock ( node ) { return node !== undefined && node . kind === SyntaxKind . Block && isAnyFunction ( node . parent ) ; } export function isObjectLiteralMethod ( node ) { return node !== undefined && node . kind === SyntaxKind . Method && node . parent . kind === SyntaxKind . ObjectLiteralExpression ; } export function getContainingFunction ( node ) { while ( true ) { node = node . parent ; if ( ! node || isAnyFunction ( node ) ) { return < FunctionLikeDeclaration > node ; } } } export function getThisContainer ( node , includeArrowFunctions ) { while ( true ) { node = node . parent ; if ( ! node ) { return undefined ; } switch ( node . kind ) { case SyntaxKind . ArrowFunction : if ( ! includeArrowFunctions ) { continue ; } case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . ModuleDeclaration : case SyntaxKind . Property : case SyntaxKind . Method : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . EnumDeclaration : case SyntaxKind . SourceFile : return node ; } } } export function getSuperContainer ( node ) { while ( true ) { node = node . parent ; if ( ! node ) { return undefined ; } switch ( node . kind ) { case SyntaxKind . Property : case SyntaxKind . Method : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : return node ; } } } export function getInvokedExpression ( node ) { if ( node . kind === SyntaxKind . TaggedTemplateExpression ) { return ( < TaggedTemplateExpression > node ) . tag ; } return ( < CallExpression > node ) . expression ; } export function isExpression ( node ) { switch ( node . kind ) { case SyntaxKind . ThisKeyword : case SyntaxKind . SuperKeyword : case SyntaxKind . NullKeyword : case SyntaxKind . TrueKeyword : case SyntaxKind . FalseKeyword : case SyntaxKind . RegularExpressionLiteral : case SyntaxKind . ArrayLiteralExpression : case SyntaxKind . ObjectLiteralExpression : case SyntaxKind . PropertyAccessExpression : case SyntaxKind . ElementAccessExpression : case SyntaxKind . CallExpression : case SyntaxKind . NewExpression : case SyntaxKind . TaggedTemplateExpression : case SyntaxKind . TypeAssertionExpression : case SyntaxKind . ParenthesizedExpression : case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : case SyntaxKind . VoidExpression : case SyntaxKind . DeleteExpression : case SyntaxKind . TypeOfExpression : case SyntaxKind . PrefixUnaryExpression : case SyntaxKind . PostfixUnaryExpression : case SyntaxKind . BinaryExpression : case SyntaxKind . ConditionalExpression : case SyntaxKind . TemplateExpression : case SyntaxKind . NoSubstitutionTemplateLiteral : case SyntaxKind . OmittedExpression : return true ; case SyntaxKind . QualifiedName : while ( node . parent . kind === SyntaxKind . QualifiedName ) { node = node . parent ; } return node . parent . kind === SyntaxKind . TypeQuery ; case SyntaxKind . Identifier : if ( node . parent . kind === SyntaxKind . TypeQuery ) { return true ; } case SyntaxKind . NumericLiteral : case SyntaxKind . StringLiteral : var parent = node . parent ; switch ( parent . kind ) { case SyntaxKind . VariableDeclaration : case SyntaxKind . Parameter : case SyntaxKind . Property : case SyntaxKind . EnumMember : case SyntaxKind . PropertyAssignment : return ( < VariableDeclaration > parent ) . initializer === node ; case SyntaxKind . ExpressionStatement : case SyntaxKind . IfStatement : case SyntaxKind . DoStatement : case SyntaxKind . WhileStatement : case SyntaxKind . ReturnStatement : case SyntaxKind . WithStatement : case SyntaxKind . SwitchStatement : case SyntaxKind . CaseClause : case SyntaxKind . ThrowStatement : case SyntaxKind . SwitchStatement : return ( < ExpressionStatement > parent ) . expression === node ; case SyntaxKind . ForStatement : return ( < ForStatement > parent ) . initializer === node || ( < ForStatement > parent ) . condition === node || ( < ForStatement > parent ) . iterator === node ; case SyntaxKind . ForInStatement : return ( < ForInStatement > parent ) . variable === node || ( < ForInStatement > parent ) . expression === node ; case SyntaxKind . TypeAssertionExpression : return node === ( < TypeAssertion > parent ) . expression ; case SyntaxKind . TemplateSpan : return node === ( < TemplateSpan > parent ) . expression ; default : if ( isExpression ( parent ) ) { return true ; } } } return false ; } export function isExternalModuleImportDeclaration ( node ) { return node . kind === SyntaxKind . ImportDeclaration && ( < ImportDeclaration > node ) . moduleReference . kind === SyntaxKind . ExternalModuleReference ; } export function getExternalModuleImportDeclarationExpression ( node ) { Debug . assert ( isExternalModuleImportDeclaration ( node ) ) ; return ( < ExternalModuleReference > ( < ImportDeclaration > node ) . moduleReference ) . expression ; } export function isInternalModuleImportDeclaration ( node ) { return node . kind === SyntaxKind . ImportDeclaration && ( < ImportDeclaration > node ) . moduleReference . kind !== SyntaxKind . ExternalModuleReference ; } export function hasDotDotDotToken ( node ) { return node && node . kind === SyntaxKind . Parameter && ( < ParameterDeclaration > node ) . dotDotDotToken !== undefined ; } export function hasQuestionToken ( node ) { if ( node ) { switch ( node . kind ) { case SyntaxKind . Parameter : return ( < ParameterDeclaration > node ) . questionToken !== undefined ; case SyntaxKind . Method : return ( < MethodDeclaration > node ) . questionToken !== undefined ; case SyntaxKind . ShorthandPropertyAssignment : case SyntaxKind . PropertyAssignment : case SyntaxKind . Property : return ( < PropertyDeclaration > node ) . questionToken !== undefined ; } } return false ; } export function hasRestParameters ( s ) { return s . parameters . length > 0 && s . parameters [ s . parameters . length - 1 ] . dotDotDotToken !== undefined ; } export function isLiteralKind ( kind ) { return SyntaxKind . FirstLiteralToken <= kind && kind <= SyntaxKind . LastLiteralToken ; } export function isTextualLiteralKind ( kind ) { return kind === SyntaxKind . StringLiteral || kind === SyntaxKind . NoSubstitutionTemplateLiteral ; } export function isTemplateLiteralKind ( kind ) { return SyntaxKind . FirstTemplateToken <= kind && kind <= SyntaxKind . LastTemplateToken ; } export function isInAmbientContext ( node ) { while ( node ) { if ( node . flags & ( NodeFlags . Ambient | NodeFlags . DeclarationFile ) ) return true ; node = node . parent ; } return false ; } export function isDeclaration ( node ) { switch ( node . kind ) { case SyntaxKind . TypeParameter : case SyntaxKind . Parameter : case SyntaxKind . VariableDeclaration : case SyntaxKind . Property : case SyntaxKind . PropertyAssignment : case SyntaxKind . ShorthandPropertyAssignment : case SyntaxKind . EnumMember : case SyntaxKind . Method : case SyntaxKind . FunctionDeclaration : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . Constructor : case SyntaxKind . ClassDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . EnumDeclaration : case SyntaxKind . ModuleDeclaration : case SyntaxKind . ImportDeclaration : return true ; } return false ; } export function isStatement ( n ) { switch ( n . kind ) { case SyntaxKind . BreakStatement : case SyntaxKind . ContinueStatement : case SyntaxKind . DebuggerStatement : case SyntaxKind . DoStatement : case SyntaxKind . ExpressionStatement : case SyntaxKind . EmptyStatement : case SyntaxKind . ForInStatement : case SyntaxKind . ForStatement : case SyntaxKind . IfStatement : case SyntaxKind . LabeledStatement : case SyntaxKind . ReturnStatement : case SyntaxKind . SwitchStatement : case SyntaxKind . ThrowKeyword : case SyntaxKind . TryStatement : case SyntaxKind . VariableStatement : case SyntaxKind . WhileStatement : case SyntaxKind . WithStatement : case SyntaxKind . ExportAssignment : return true ; default : return false ; } } export function isDeclarationOrFunctionExpressionOrCatchVariableName ( name ) { if ( name . kind !== SyntaxKind . Identifier && name . kind !== SyntaxKind . StringLiteral && name . kind !== SyntaxKind . NumericLiteral ) { return false ; } var parent = name . parent ; if ( isDeclaration ( parent ) || parent . kind === SyntaxKind . FunctionExpression ) { return ( < Declaration > parent ) . name === name ; } if ( parent . kind === SyntaxKind . CatchClause ) { return ( < CatchClause > parent ) . name === name ; } return false ; } export function getClassBaseTypeNode ( node ) { var heritageClause = getHeritageClause ( node . heritageClauses , SyntaxKind . ExtendsKeyword ) ; return heritageClause && heritageClause . types . length > 0 ? heritageClause . types [ 0 ] : undefined ; } export function getClassImplementedTypeNodes ( node ) { var heritageClause = getHeritageClause ( node . heritageClauses , SyntaxKind . ImplementsKeyword ) ; return heritageClause ? heritageClause . types : undefined ; } export function getInterfaceBaseTypeNodes ( node ) { var heritageClause = getHeritageClause ( node . heritageClauses , SyntaxKind . ExtendsKeyword ) ; return heritageClause ? heritageClause . types : undefined ; } export function getHeritageClause ( clauses , kind ) { if ( clauses ) { for ( var i = 0 , n = clauses . length ; i < n ; i ++ ) { if ( clauses [ i ] . token === kind ) { return clauses [ i ] ; } } } return undefined ; } export function tryResolveScriptReference ( program , sourceFile , reference ) { if ( ! program . getCompilerOptions ( ) . noResolve ) { var referenceFileName = isRootedDiskPath ( reference . filename ) ? reference . filename : combinePaths ( getDirectoryPath ( sourceFile . filename ) , reference . filename ) ; referenceFileName = getNormalizedAbsolutePath ( referenceFileName , program . getCompilerHost ( ) . getCurrentDirectory ( ) ) ; return program . getSourceFile ( referenceFileName ) ; } } export function getAncestor ( node , kind ) { switch ( kind ) { case SyntaxKind . ClassDeclaration : while ( node ) { switch ( node . kind ) { case SyntaxKind . ClassDeclaration : return < ClassDeclaration > node ; case SyntaxKind . EnumDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . ModuleDeclaration : case SyntaxKind . ImportDeclaration : return undefined ; default : node = node . parent ; continue ; } } break ; default : while ( node ) { if ( node . kind === kind ) { return node ; } node = node . parent ; } break ; } return undefined ; } export function getFileReferenceFromReferencePath ( comment , commentRange ) { var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim ; var isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim ; if ( simpleReferenceRegEx . exec ( comment ) ) { if ( isNoDefaultLibRegEx . exec ( comment ) ) { return { isNoDefaultLib : true } ; } else { var matchResult = fullTripleSlashReferencePathRegEx . exec ( comment ) ; if ( matchResult ) { var start = commentRange . pos ; var end = commentRange . end ; return { fileReference : { pos : start , end : end , filename : matchResult [ 3 ] } , isNoDefaultLib : false } ; } else { return { diagnosticMessage : Diagnostics . Invalid_reference_directive_syntax , isNoDefaultLib : false } ; } } } return undefined ; } export function isKeyword ( token ) { return SyntaxKind . FirstKeyword <= token && token <= SyntaxKind . LastKeyword ; } export function isTrivia ( token ) { return SyntaxKind . FirstTriviaToken <= token && token <= SyntaxKind . LastTriviaToken ; } export function isModifier ( token ) { switch ( token ) { case SyntaxKind . PublicKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : case SyntaxKind . StaticKeyword : case SyntaxKind . ExportKeyword : case SyntaxKind . DeclareKeyword : case SyntaxKind . ConstKeyword : return true ; } return false ; } }