interface PromiseConstructor { new < T > ( executor ) : Promise < T > ; reject ( reason ) : Promise < never > ; all < T > ( values ) : Promise < T [ ] > ; } declare var Promise ; namespace ts { export const scanner = createScanner ( ScriptTarget . Latest , true ) ; export const enum SemanticMeaning { None = 0x0 , Value = 0x1 , Type = 0x2 , Namespace = 0x4 , All = Value | Type | Namespace } export function getMeaningFromDeclaration ( node ) { switch ( node . kind ) { case SyntaxKind . VariableDeclaration : return isInJSFile ( node ) && getJSDocEnumTag ( node ) ? SemanticMeaning . All : SemanticMeaning . Value ; case SyntaxKind . Parameter : case SyntaxKind . BindingElement : case SyntaxKind . PropertyDeclaration : case SyntaxKind . PropertySignature : case SyntaxKind . PropertyAssignment : case SyntaxKind . ShorthandPropertyAssignment : case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : case SyntaxKind . CatchClause : case SyntaxKind . JsxAttribute : return SemanticMeaning . Value ; case SyntaxKind . TypeParameter : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . TypeLiteral : return SemanticMeaning . Type ; case SyntaxKind . JSDocTypedefTag : return ( node as JSDocTypedefTag ) . name === undefined ? SemanticMeaning . Value | SemanticMeaning . Type : SemanticMeaning . Type ; case SyntaxKind . EnumMember : case SyntaxKind . ClassDeclaration : return SemanticMeaning . Value | SemanticMeaning . Type ; case SyntaxKind . ModuleDeclaration : if ( isAmbientModule ( node as ModuleDeclaration ) ) { return SemanticMeaning . Namespace | SemanticMeaning . Value ; } else if ( getModuleInstanceState ( node as ModuleDeclaration ) === ModuleInstanceState . Instantiated ) { return SemanticMeaning . Namespace | SemanticMeaning . Value ; } else { return SemanticMeaning . Namespace ; } case SyntaxKind . EnumDeclaration : case SyntaxKind . NamedImports : case SyntaxKind . ImportSpecifier : case SyntaxKind . ImportEqualsDeclaration : case SyntaxKind . ImportDeclaration : case SyntaxKind . ExportAssignment : case SyntaxKind . ExportDeclaration : return SemanticMeaning . All ; case SyntaxKind . SourceFile : return SemanticMeaning . Namespace | SemanticMeaning . Value ; } return SemanticMeaning . All ; } export function getMeaningFromLocation ( node ) { node = getAdjustedReferenceLocation ( node ) ; const parent = node . parent ; if ( node . kind === SyntaxKind . SourceFile ) { return SemanticMeaning . Value ; } else if ( isExportAssignment ( parent ) || isExportSpecifier ( parent ) || isExternalModuleReference ( parent ) || isImportSpecifier ( parent ) || isImportClause ( parent ) || isImportEqualsDeclaration ( parent ) && node === parent . name ) { return SemanticMeaning . All ; } else if ( isInRightSideOfInternalImportEqualsDeclaration ( node ) ) { return getMeaningFromRightHandSideOfImportEquals ( node as Identifier ) ; } else if ( isDeclarationName ( node ) ) { return getMeaningFromDeclaration ( parent ) ; } else if ( isEntityName ( node ) && findAncestor ( node , or ( isJSDocNameReference , isJSDocLinkLike , isJSDocMemberName ) ) ) { return SemanticMeaning . All ; } else if ( isTypeReference ( node ) ) { return SemanticMeaning . Type ; } else if ( isNamespaceReference ( node ) ) { return SemanticMeaning . Namespace ; } else if ( isTypeParameterDeclaration ( parent ) ) { Debug . assert ( isJSDocTemplateTag ( parent . parent ) ) ; return SemanticMeaning . Type ; } else if ( isLiteralTypeNode ( parent ) ) { return SemanticMeaning . Type | SemanticMeaning . Value ; } else { return SemanticMeaning . Value ; } } function getMeaningFromRightHandSideOfImportEquals ( node ) { const name = node . kind === SyntaxKind . QualifiedName ? node : isQualifiedName ( node . parent ) && node . parent . right === node ? node . parent : undefined ; return name && name . parent . kind === SyntaxKind . ImportEqualsDeclaration ? SemanticMeaning . All : SemanticMeaning . Namespace ; } export function isInRightSideOfInternalImportEqualsDeclaration ( node ) { while ( node . parent . kind === SyntaxKind . QualifiedName ) { node = node . parent ; } return isInternalModuleImportEqualsDeclaration ( node . parent ) && node . parent . moduleReference === node ; } function isNamespaceReference ( node ) { return isQualifiedNameNamespaceReference ( node ) || isPropertyAccessNamespaceReference ( node ) ; } function isQualifiedNameNamespaceReference ( node ) { let root = node ; let isLastClause = true ; if ( root . parent . kind === SyntaxKind . QualifiedName ) { while ( root . parent && root . parent . kind === SyntaxKind . QualifiedName ) { root = root . parent ; } isLastClause = ( root as QualifiedName ) . right === node ; } return root . parent . kind === SyntaxKind . TypeReference && ! isLastClause ; } function isPropertyAccessNamespaceReference ( node ) { let root = node ; let isLastClause = true ; if ( root . parent . kind === SyntaxKind . PropertyAccessExpression ) { while ( root . parent && root . parent . kind === SyntaxKind . PropertyAccessExpression ) { root = root . parent ; } isLastClause = ( root as PropertyAccessExpression ) . name === node ; } if ( ! isLastClause && root . parent . kind === SyntaxKind . ExpressionWithTypeArguments && root . parent . parent . kind === SyntaxKind . HeritageClause ) { const decl = root . parent . parent . parent ; return ( decl . kind === SyntaxKind . ClassDeclaration && ( root . parent . parent as HeritageClause ) . token === SyntaxKind . ImplementsKeyword ) || ( decl . kind === SyntaxKind . InterfaceDeclaration && ( root . parent . parent as HeritageClause ) . token === SyntaxKind . ExtendsKeyword ) ; } return false ; } function isTypeReference ( node ) { if ( isRightSideOfQualifiedNameOrPropertyAccess ( node ) ) { node = node . parent ; } switch ( node . kind ) { case SyntaxKind . ThisKeyword : return ! isExpressionNode ( node ) ; case SyntaxKind . ThisType : return true ; } switch ( node . parent . kind ) { case SyntaxKind . TypeReference : return true ; case SyntaxKind . ImportType : return ! ( node . parent as ImportTypeNode ) . isTypeOf ; case SyntaxKind . ExpressionWithTypeArguments : return ! isExpressionWithTypeArgumentsInClassExtendsClause ( node . parent as ExpressionWithTypeArguments ) ; } return false ; } export function isCallExpressionTarget ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isCallExpression , selectExpressionOfCallOrNewExpressionOrDecorator , includeElementAccess , skipPastOuterExpressions ) ; } export function isNewExpressionTarget ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isNewExpression , selectExpressionOfCallOrNewExpressionOrDecorator , includeElementAccess , skipPastOuterExpressions ) ; } export function isCallOrNewExpressionTarget ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isCallOrNewExpression , selectExpressionOfCallOrNewExpressionOrDecorator , includeElementAccess , skipPastOuterExpressions ) ; } export function isTaggedTemplateTag ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isTaggedTemplateExpression , selectTagOfTaggedTemplateExpression , includeElementAccess , skipPastOuterExpressions ) ; } export function isDecoratorTarget ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isDecorator , selectExpressionOfCallOrNewExpressionOrDecorator , includeElementAccess , skipPastOuterExpressions ) ; } export function isJsxOpeningLikeElementTagName ( node , includeElementAccess = false , skipPastOuterExpressions = false ) { return isCalleeWorker ( node , isJsxOpeningLikeElement , selectTagNameOfJsxOpeningLikeElement , includeElementAccess , skipPastOuterExpressions ) ; } function selectExpressionOfCallOrNewExpressionOrDecorator ( node ) { return node . expression ; } function selectTagOfTaggedTemplateExpression ( node ) { return node . tag ; } function selectTagNameOfJsxOpeningLikeElement ( node ) { return node . tagName ; } function isCalleeWorker < T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement > ( node , pred , calleeSelector , includeElementAccess , skipPastOuterExpressions ) { let target = includeElementAccess ? climbPastPropertyOrElementAccess ( node ) : climbPastPropertyAccess ( node ) ; if ( skipPastOuterExpressions ) { target = skipOuterExpressions ( target ) ; } return ! ! target && ! ! target . parent && pred ( target . parent ) && calleeSelector ( target . parent ) === target ; } export function climbPastPropertyAccess ( node ) { return isRightSideOfPropertyAccess ( node ) ? node . parent : node ; } export function climbPastPropertyOrElementAccess ( node ) { return isRightSideOfPropertyAccess ( node ) || isArgumentExpressionOfElementAccess ( node ) ? node . parent : node ; } export function getTargetLabel ( referenceNode , labelName ) { while ( referenceNode ) { if ( referenceNode . kind === SyntaxKind . LabeledStatement && ( referenceNode as LabeledStatement ) . label . escapedText === labelName ) { return ( referenceNode as LabeledStatement ) . label ; } referenceNode = referenceNode . parent ; } return undefined ; } export function hasPropertyAccessExpressionWithName ( node , funcName ) { if ( ! isPropertyAccessExpression ( node . expression ) ) { return false ; } return node . expression . name . text === funcName ; } export function isJumpStatementTarget ( node ) { return isIdentifier ( node ) && tryCast ( node . parent , isBreakOrContinueStatement ) ?. label === node ; } export function isLabelOfLabeledStatement ( node ) { return isIdentifier ( node ) && tryCast ( node . parent , isLabeledStatement ) ?. label === node ; } export function isLabelName ( node ) { return isLabelOfLabeledStatement ( node ) || isJumpStatementTarget ( node ) ; } export function isTagName ( node ) { return tryCast ( node . parent , isJSDocTag ) ?. tagName === node ; } export function isRightSideOfQualifiedName ( node ) { return tryCast ( node . parent , isQualifiedName ) ?. right === node ; } export function isRightSideOfPropertyAccess ( node ) { return tryCast ( node . parent , isPropertyAccessExpression ) ?. name === node ; } export function isArgumentExpressionOfElementAccess ( node ) { return tryCast ( node . parent , isElementAccessExpression ) ?. argumentExpression === node ; } export function isNameOfModuleDeclaration ( node ) { return tryCast ( node . parent , isModuleDeclaration ) ?. name === node ; } export function isNameOfFunctionDeclaration ( node ) { return isIdentifier ( node ) && tryCast ( node . parent , isFunctionLike ) ?. name === node ; } export function isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) { switch ( node . parent . kind ) { case SyntaxKind . PropertyDeclaration : case SyntaxKind . PropertySignature : case SyntaxKind . PropertyAssignment : case SyntaxKind . EnumMember : case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . ModuleDeclaration : return getNameOfDeclaration ( node . parent as Declaration ) === node ; case SyntaxKind . ElementAccessExpression : return ( node . parent as ElementAccessExpression ) . argumentExpression === node ; case SyntaxKind . ComputedPropertyName : return true ; case SyntaxKind . LiteralType : return node . parent . parent . kind === SyntaxKind . IndexedAccessType ; default : return false ; } } export function isExpressionOfExternalModuleImportEqualsDeclaration ( node ) { return isExternalModuleImportEqualsDeclaration ( node . parent . parent ) && getExternalModuleImportEqualsDeclarationExpression ( node . parent . parent ) === node ; } export function getContainerNode ( node ) { if ( isJSDocTypeAlias ( node ) ) { node = node . parent . parent ; } while ( true ) { node = node . parent ; if ( ! node ) { return undefined ; } switch ( node . kind ) { case SyntaxKind . SourceFile : case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . ClassDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . EnumDeclaration : case SyntaxKind . ModuleDeclaration : return node as Declaration ; } } } export function getNodeKind ( node ) { switch ( node . kind ) { case SyntaxKind . SourceFile : return isExternalModule ( node as SourceFile ) ? ScriptElementKind . moduleElement : ScriptElementKind . scriptElement ; case SyntaxKind . ModuleDeclaration : return ScriptElementKind . moduleElement ; case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : return ScriptElementKind . classElement ; case SyntaxKind . InterfaceDeclaration : return ScriptElementKind . interfaceElement ; case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . JSDocCallbackTag : case SyntaxKind . JSDocTypedefTag : return ScriptElementKind . typeElement ; case SyntaxKind . EnumDeclaration : return ScriptElementKind . enumElement ; case SyntaxKind . VariableDeclaration : return getKindOfVariableDeclaration ( node as VariableDeclaration ) ; case SyntaxKind . BindingElement : return getKindOfVariableDeclaration ( getRootDeclaration ( node ) as VariableDeclaration ) ; case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : return ScriptElementKind . functionElement ; case SyntaxKind . GetAccessor : return ScriptElementKind . memberGetAccessorElement ; case SyntaxKind . SetAccessor : return ScriptElementKind . memberSetAccessorElement ; case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : return ScriptElementKind . memberFunctionElement ; case SyntaxKind . PropertyAssignment : const { initializer } = node as PropertyAssignment ; return isFunctionLike ( initializer ) ? ScriptElementKind . memberFunctionElement : ScriptElementKind . memberVariableElement ; case SyntaxKind . PropertyDeclaration : case SyntaxKind . PropertySignature : case SyntaxKind . ShorthandPropertyAssignment : case SyntaxKind . SpreadAssignment : return ScriptElementKind . memberVariableElement ; case SyntaxKind . IndexSignature : return ScriptElementKind . indexSignatureElement ; case SyntaxKind . ConstructSignature : return ScriptElementKind . constructSignatureElement ; case SyntaxKind . CallSignature : return ScriptElementKind . callSignatureElement ; case SyntaxKind . Constructor : case SyntaxKind . ClassStaticBlockDeclaration : return ScriptElementKind . constructorImplementationElement ; case SyntaxKind . TypeParameter : return ScriptElementKind . typeParameterElement ; case SyntaxKind . EnumMember : return ScriptElementKind . enumMemberElement ; case SyntaxKind . Parameter : return hasSyntacticModifier ( node , ModifierFlags . ParameterPropertyModifier ) ? ScriptElementKind . memberVariableElement : ScriptElementKind . parameterElement ; case SyntaxKind . ImportEqualsDeclaration : case SyntaxKind . ImportSpecifier : case SyntaxKind . ExportSpecifier : case SyntaxKind . NamespaceImport : case SyntaxKind . NamespaceExport : return ScriptElementKind . alias ; case SyntaxKind . BinaryExpression : const kind = getAssignmentDeclarationKind ( node as BinaryExpression ) ; const { right } = node as BinaryExpression ; switch ( kind ) { case AssignmentDeclarationKind . ObjectDefinePropertyValue : case AssignmentDeclarationKind . ObjectDefinePropertyExports : case AssignmentDeclarationKind . ObjectDefinePrototypeProperty : case AssignmentDeclarationKind . None : return ScriptElementKind . unknown ; case AssignmentDeclarationKind . ExportsProperty : case AssignmentDeclarationKind . ModuleExports : const rightKind = getNodeKind ( right ) ; return rightKind === ScriptElementKind . unknown ? ScriptElementKind . constElement : rightKind ; case AssignmentDeclarationKind . PrototypeProperty : return isFunctionExpression ( right ) ? ScriptElementKind . memberFunctionElement : ScriptElementKind . memberVariableElement ; case AssignmentDeclarationKind . ThisProperty : return ScriptElementKind . memberVariableElement ; case AssignmentDeclarationKind . Property : return isFunctionExpression ( right ) ? ScriptElementKind . memberFunctionElement : ScriptElementKind . memberVariableElement ; case AssignmentDeclarationKind . Prototype : return ScriptElementKind . localClassElement ; default : { assertType < never > ( kind ) ; return ScriptElementKind . unknown ; } } case SyntaxKind . Identifier : return isImportClause ( node . parent ) ? ScriptElementKind . alias : ScriptElementKind . unknown ; case SyntaxKind . ExportAssignment : const scriptKind = getNodeKind ( ( node as ExportAssignment ) . expression ) ; return scriptKind === ScriptElementKind . unknown ? ScriptElementKind . constElement : scriptKind ; default : return ScriptElementKind . unknown ; } function getKindOfVariableDeclaration ( v ) { return isVarConst ( v ) ? ScriptElementKind . constElement : isLet ( v ) ? ScriptElementKind . letElement : ScriptElementKind . variableElement ; } } export function isThis ( node ) { switch ( node . kind ) { case SyntaxKind . ThisKeyword : return true ; case SyntaxKind . Identifier : return identifierIsThisKeyword ( node as Identifier ) && node . parent . kind === SyntaxKind . Parameter ; default : return false ; } } const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</ ; export interface ListItemInfo { listItemIndex : number ; list : Node ; } export function getLineStartPositionForPosition ( position , sourceFile ) { const lineStarts = getLineStarts ( sourceFile ) ; const line = sourceFile . getLineAndCharacterOfPosition ( position ) . line ; return lineStarts [ line ] ; } export function rangeContainsRange ( r1 , r2 ) { return startEndContainsRange ( r1 . pos , r1 . end , r2 ) ; } export function rangeContainsRangeExclusive ( r1 , r2 ) { return rangeContainsPositionExclusive ( r1 , r2 . pos ) && rangeContainsPositionExclusive ( r1 , r2 . end ) ; } export function rangeContainsPosition ( r , pos ) { return r . pos <= pos && pos <= r . end ; } export function rangeContainsPositionExclusive ( r , pos ) { return r . pos < pos && pos < r . end ; } export function startEndContainsRange ( start , end , range ) { return start <= range . pos && end >= range . end ; } export function rangeContainsStartEnd ( range , start , end ) { return range . pos <= start && range . end >= end ; } export function rangeOverlapsWithStartEnd ( r1 , start , end ) { return startEndOverlapsWithStartEnd ( r1 . pos , r1 . end , start , end ) ; } export function nodeOverlapsWithStartEnd ( node , sourceFile , start , end ) { return startEndOverlapsWithStartEnd ( node . getStart ( sourceFile ) , node . end , start , end ) ; } export function startEndOverlapsWithStartEnd ( start1 , end1 , start2 , end2 ) { const start = Math . max ( start1 , start2 ) ; const end = Math . min ( end1 , end2 ) ; return start < end ; } /**
     * Assumes `candidate.start <= position` holds.
     */ export function positionBelongsToNode ( candidate , position , sourceFile ) { Debug . assert ( candidate . pos <= position ) ; return position < candidate . end || ! isCompletedNode ( candidate , sourceFile ) ; } function isCompletedNode ( n , sourceFile ) { if ( n === undefined || nodeIsMissing ( n ) ) { return false ; } switch ( n . kind ) { case SyntaxKind . ClassDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . EnumDeclaration : case SyntaxKind . ObjectLiteralExpression : case SyntaxKind . ObjectBindingPattern : case SyntaxKind . TypeLiteral : case SyntaxKind . Block : case SyntaxKind . ModuleBlock : case SyntaxKind . CaseBlock : case SyntaxKind . NamedImports : case SyntaxKind . NamedExports : return nodeEndsWith ( n , SyntaxKind . CloseBraceToken , sourceFile ) ; case SyntaxKind . CatchClause : return isCompletedNode ( ( n as CatchClause ) . block , sourceFile ) ; case SyntaxKind . NewExpression : if ( ! ( n as NewExpression ) . arguments ) { return true ; } case SyntaxKind . CallExpression : case SyntaxKind . ParenthesizedExpression : case SyntaxKind . ParenthesizedType : return nodeEndsWith ( n , SyntaxKind . CloseParenToken , sourceFile ) ; case SyntaxKind . FunctionType : case SyntaxKind . ConstructorType : return isCompletedNode ( ( n as SignatureDeclaration ) . type , sourceFile ) ; case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : case SyntaxKind . ConstructSignature : case SyntaxKind . CallSignature : case SyntaxKind . ArrowFunction : if ( ( n as FunctionLikeDeclaration ) . body ) { return isCompletedNode ( ( n as FunctionLikeDeclaration ) . body , sourceFile ) ; } if ( ( n as FunctionLikeDeclaration ) . type ) { return isCompletedNode ( ( n as FunctionLikeDeclaration ) . type , sourceFile ) ; } return hasChildOfKind ( n , SyntaxKind . CloseParenToken , sourceFile ) ; case SyntaxKind . ModuleDeclaration : return ! ! ( n as ModuleDeclaration ) . body && isCompletedNode ( ( n as ModuleDeclaration ) . body , sourceFile ) ; case SyntaxKind . IfStatement : if ( ( n as IfStatement ) . elseStatement ) { return isCompletedNode ( ( n as IfStatement ) . elseStatement , sourceFile ) ; } return isCompletedNode ( ( n as IfStatement ) . thenStatement , sourceFile ) ; case SyntaxKind . ExpressionStatement : return isCompletedNode ( ( n as ExpressionStatement ) . expression , sourceFile ) || hasChildOfKind ( n , SyntaxKind . SemicolonToken , sourceFile ) ; case SyntaxKind . ArrayLiteralExpression : case SyntaxKind . ArrayBindingPattern : case SyntaxKind . ElementAccessExpression : case SyntaxKind . ComputedPropertyName : case SyntaxKind . TupleType : return nodeEndsWith ( n , SyntaxKind . CloseBracketToken , sourceFile ) ; case SyntaxKind . IndexSignature : if ( ( n as IndexSignatureDeclaration ) . type ) { return isCompletedNode ( ( n as IndexSignatureDeclaration ) . type , sourceFile ) ; } return hasChildOfKind ( n , SyntaxKind . CloseBracketToken , sourceFile ) ; case SyntaxKind . CaseClause : case SyntaxKind . DefaultClause : return false ; case SyntaxKind . ForStatement : case SyntaxKind . ForInStatement : case SyntaxKind . ForOfStatement : case SyntaxKind . WhileStatement : return isCompletedNode ( ( n as IterationStatement ) . statement , sourceFile ) ; case SyntaxKind . DoStatement : return hasChildOfKind ( n , SyntaxKind . WhileKeyword , sourceFile ) ? nodeEndsWith ( n , SyntaxKind . CloseParenToken , sourceFile ) : isCompletedNode ( ( n as DoStatement ) . statement , sourceFile ) ; case SyntaxKind . TypeQuery : return isCompletedNode ( ( n as TypeQueryNode ) . exprName , sourceFile ) ; case SyntaxKind . TypeOfExpression : case SyntaxKind . DeleteExpression : case SyntaxKind . VoidExpression : case SyntaxKind . YieldExpression : case SyntaxKind . SpreadElement : const unaryWordExpression = n as ( TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement ) ; return isCompletedNode ( unaryWordExpression . expression , sourceFile ) ; case SyntaxKind . TaggedTemplateExpression : return isCompletedNode ( ( n as TaggedTemplateExpression ) . template , sourceFile ) ; case SyntaxKind . TemplateExpression : const lastSpan = lastOrUndefined ( ( n as TemplateExpression ) . templateSpans ) ; return isCompletedNode ( lastSpan , sourceFile ) ; case SyntaxKind . TemplateSpan : return nodeIsPresent ( ( n as TemplateSpan ) . literal ) ; case SyntaxKind . ExportDeclaration : case SyntaxKind . ImportDeclaration : return nodeIsPresent ( ( n as ExportDeclaration | ImportDeclaration ) . moduleSpecifier ) ; case SyntaxKind . PrefixUnaryExpression : return isCompletedNode ( ( n as PrefixUnaryExpression ) . operand , sourceFile ) ; case SyntaxKind . BinaryExpression : return isCompletedNode ( ( n as BinaryExpression ) . right , sourceFile ) ; case SyntaxKind . ConditionalExpression : return isCompletedNode ( ( n as ConditionalExpression ) . whenFalse , sourceFile ) ; default : return true ; } } function nodeEndsWith ( n , expectedLastToken , sourceFile ) { const children = n . getChildren ( sourceFile ) ; if ( children . length ) { const lastChild = last ( children ) ; if ( lastChild . kind === expectedLastToken ) { return true ; } else if ( lastChild . kind === SyntaxKind . SemicolonToken && children . length !== 1 ) { return children [ children . length - 2 ] . kind === expectedLastToken ; } } return false ; } export function findListItemInfo ( node ) { const list = findContainingList ( node ) ; if ( ! list ) { return undefined ; } const children = list . getChildren ( ) ; const listItemIndex = indexOfNode ( children , node ) ; return { listItemIndex , list } ; } export function hasChildOfKind ( n , kind , sourceFile ) { return ! ! findChildOfKind ( n , kind , sourceFile ) ; } export function findChildOfKind < T extends Node > ( n , kind , sourceFile ) { return find ( n . getChildren ( sourceFile ) , ( c ) : c is T => c . kind === kind ) ; } export function findContainingList ( node ) { const syntaxList = find ( node . parent . getChildren ( ) , ( c ) : c is SyntaxList => isSyntaxList ( c ) && rangeContainsRange ( c , node ) ) ; Debug . assert ( ! syntaxList || contains ( syntaxList . getChildren ( ) , node ) ) ; return syntaxList ; } function isDefaultModifier ( node ) { return node . kind === SyntaxKind . DefaultKeyword ; } function isClassKeyword ( node ) { return node . kind === SyntaxKind . ClassKeyword ; } function isFunctionKeyword ( node ) { return node . kind === SyntaxKind . FunctionKeyword ; } function getAdjustedLocationForClass ( node ) { if ( isNamedDeclaration ( node ) ) { return node . name ; } if ( isClassDeclaration ( node ) ) { const defaultModifier = node . modifiers && find ( node . modifiers , isDefaultModifier ) ; if ( defaultModifier ) return defaultModifier ; } if ( isClassExpression ( node ) ) { const classKeyword = find ( node . getChildren ( ) , isClassKeyword ) ; if ( classKeyword ) return classKeyword ; } } function getAdjustedLocationForFunction ( node ) { if ( isNamedDeclaration ( node ) ) { return node . name ; } if ( isFunctionDeclaration ( node ) ) { const defaultModifier = find ( node . modifiers ! , isDefaultModifier ) ; if ( defaultModifier ) return defaultModifier ; } if ( isFunctionExpression ( node ) ) { const functionKeyword = find ( node . getChildren ( ) , isFunctionKeyword ) ; if ( functionKeyword ) return functionKeyword ; } } function getAncestorTypeNode ( node ) { let lastTypeNode ; findAncestor ( node , a => { if ( isTypeNode ( a ) ) { lastTypeNode = a ; } return ! isQualifiedName ( a . parent ) && ! isTypeNode ( a . parent ) && ! isTypeElement ( a . parent ) ; } ) ; return lastTypeNode ; } export function getContextualTypeFromParentOrAncestorTypeNode ( node , checker ) { const contextualType = getContextualTypeFromParent ( node , checker ) ; if ( contextualType ) return contextualType ; const ancestorTypeNode = getAncestorTypeNode ( node ) ; return ancestorTypeNode && checker . getTypeAtLocation ( ancestorTypeNode ) ; } function getAdjustedLocationForDeclaration ( node , forRename ) { if ( ! forRename ) { switch ( node . kind ) { case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : return getAdjustedLocationForClass ( node as ClassDeclaration | ClassExpression ) ; case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : return getAdjustedLocationForFunction ( node as FunctionDeclaration | FunctionExpression ) ; } } if ( isNamedDeclaration ( node ) ) { return node . name ; } } function getAdjustedLocationForImportDeclaration ( node , forRename ) { if ( node . importClause ) { if ( node . importClause . name && node . importClause . namedBindings ) { return ; } if ( node . importClause . name ) { return node . importClause . name ; } if ( node . importClause . namedBindings ) { if ( isNamedImports ( node . importClause . namedBindings ) ) { const onlyBinding = singleOrUndefined ( node . importClause . namedBindings . elements ) ; if ( ! onlyBinding ) { return ; } return onlyBinding . name ; } else if ( isNamespaceImport ( node . importClause . namedBindings ) ) { return node . importClause . namedBindings . name ; } } } if ( ! forRename ) { return node . moduleSpecifier ; } } function getAdjustedLocationForExportDeclaration ( node , forRename ) { if ( node . exportClause ) { if ( isNamedExports ( node . exportClause ) ) { const onlyBinding = singleOrUndefined ( node . exportClause . elements ) ; if ( ! onlyBinding ) { return ; } return node . exportClause . elements [ 0 ] . name ; } else if ( isNamespaceExport ( node . exportClause ) ) { return node . exportClause . name ; } } if ( ! forRename ) { return node . moduleSpecifier ; } } function getAdjustedLocationForHeritageClause ( node ) { if ( node . types . length === 1 ) { return node . types [ 0 ] . expression ; } } function getAdjustedLocation ( node , forRename ) { const { parent } = node ; if ( isModifier ( node ) && ( forRename || node . kind !== SyntaxKind . DefaultKeyword ) ? contains ( parent . modifiers , node ) : node . kind === SyntaxKind . ClassKeyword ? isClassDeclaration ( parent ) || isClassExpression ( node ) : node . kind === SyntaxKind . FunctionKeyword ? isFunctionDeclaration ( parent ) || isFunctionExpression ( node ) : node . kind === SyntaxKind . InterfaceKeyword ? isInterfaceDeclaration ( parent ) : node . kind === SyntaxKind . EnumKeyword ? isEnumDeclaration ( parent ) : node . kind === SyntaxKind . TypeKeyword ? isTypeAliasDeclaration ( parent ) : node . kind === SyntaxKind . NamespaceKeyword || node . kind === SyntaxKind . ModuleKeyword ? isModuleDeclaration ( parent ) : node . kind === SyntaxKind . ImportKeyword ? isImportEqualsDeclaration ( parent ) : node . kind === SyntaxKind . GetKeyword ? isGetAccessorDeclaration ( parent ) : node . kind === SyntaxKind . SetKeyword && isSetAccessorDeclaration ( parent ) ) { const location = getAdjustedLocationForDeclaration ( parent , forRename ) ; if ( location ) { return location ; } } if ( ( node . kind === SyntaxKind . VarKeyword || node . kind === SyntaxKind . ConstKeyword || node . kind === SyntaxKind . LetKeyword ) && isVariableDeclarationList ( parent ) && parent . declarations . length === 1 ) { const decl = parent . declarations [ 0 ] ; if ( isIdentifier ( decl . name ) ) { return decl . name ; } } if ( node . kind === SyntaxKind . TypeKeyword ) { if ( isImportClause ( parent ) && parent . isTypeOnly ) { const location = getAdjustedLocationForImportDeclaration ( parent . parent , forRename ) ; if ( location ) { return location ; } } if ( isExportDeclaration ( parent ) && parent . isTypeOnly ) { const location = getAdjustedLocationForExportDeclaration ( parent , forRename ) ; if ( location ) { return location ; } } } if ( node . kind === SyntaxKind . AsKeyword ) { if ( isImportSpecifier ( parent ) && parent . propertyName || isExportSpecifier ( parent ) && parent . propertyName || isNamespaceImport ( parent ) || isNamespaceExport ( parent ) ) { return parent . name ; } if ( isExportDeclaration ( parent ) && parent . exportClause && isNamespaceExport ( parent . exportClause ) ) { return parent . exportClause . name ; } } if ( node . kind === SyntaxKind . ImportKeyword && isImportDeclaration ( parent ) ) { const location = getAdjustedLocationForImportDeclaration ( parent , forRename ) ; if ( location ) { return location ; } } if ( node . kind === SyntaxKind . ExportKeyword ) { if ( isExportDeclaration ( parent ) ) { const location = getAdjustedLocationForExportDeclaration ( parent , forRename ) ; if ( location ) { return location ; } } if ( isExportAssignment ( parent ) ) { return skipOuterExpressions ( parent . expression ) ; } } if ( node . kind === SyntaxKind . RequireKeyword && isExternalModuleReference ( parent ) ) { return parent . expression ; } if ( node . kind === SyntaxKind . FromKeyword && ( isImportDeclaration ( parent ) || isExportDeclaration ( parent ) ) && parent . moduleSpecifier ) { return parent . moduleSpecifier ; } if ( ( node . kind === SyntaxKind . ExtendsKeyword || node . kind === SyntaxKind . ImplementsKeyword ) && isHeritageClause ( parent ) && parent . token === node . kind ) { const location = getAdjustedLocationForHeritageClause ( parent ) ; if ( location ) { return location ; } } if ( node . kind === SyntaxKind . ExtendsKeyword ) { if ( isTypeParameterDeclaration ( parent ) && parent . constraint && isTypeReferenceNode ( parent . constraint ) ) { return parent . constraint . typeName ; } if ( isConditionalTypeNode ( parent ) && isTypeReferenceNode ( parent . extendsType ) ) { return parent . extendsType . typeName ; } } if ( node . kind === SyntaxKind . InferKeyword && isInferTypeNode ( parent ) ) { return parent . typeParameter . name ; } if ( node . kind === SyntaxKind . InKeyword && isTypeParameterDeclaration ( parent ) && isMappedTypeNode ( parent . parent ) ) { return parent . name ; } if ( node . kind === SyntaxKind . KeyOfKeyword && isTypeOperatorNode ( parent ) && parent . operator === SyntaxKind . KeyOfKeyword && isTypeReferenceNode ( parent . type ) ) { return parent . type . typeName ; } if ( node . kind === SyntaxKind . ReadonlyKeyword && isTypeOperatorNode ( parent ) && parent . operator === SyntaxKind . ReadonlyKeyword && isArrayTypeNode ( parent . type ) && isTypeReferenceNode ( parent . type . elementType ) ) { return parent . type . elementType . typeName ; } if ( ! forRename ) { if ( node . kind === SyntaxKind . NewKeyword && isNewExpression ( parent ) || node . kind === SyntaxKind . VoidKeyword && isVoidExpression ( parent ) || node . kind === SyntaxKind . TypeOfKeyword && isTypeOfExpression ( parent ) || node . kind === SyntaxKind . AwaitKeyword && isAwaitExpression ( parent ) || node . kind === SyntaxKind . YieldKeyword && isYieldExpression ( parent ) || node . kind === SyntaxKind . DeleteKeyword && isDeleteExpression ( parent ) ) { if ( parent . expression ) { return skipOuterExpressions ( parent . expression ) ; } } if ( ( node . kind === SyntaxKind . InKeyword || node . kind === SyntaxKind . InstanceOfKeyword ) && isBinaryExpression ( parent ) && parent . operatorToken === node ) { return skipOuterExpressions ( parent . right ) ; } if ( node . kind === SyntaxKind . AsKeyword && isAsExpression ( parent ) && isTypeReferenceNode ( parent . type ) ) { return parent . type . typeName ; } if ( node . kind === SyntaxKind . InKeyword && isForInStatement ( parent ) || node . kind === SyntaxKind . OfKeyword && isForOfStatement ( parent ) ) { return skipOuterExpressions ( parent . expression ) ; } } return node ; } /**
     * Adjusts the location used for "find references" and "go to definition" when the cursor was not
     * on a property name.
     */ export function getAdjustedReferenceLocation ( node ) { return getAdjustedLocation ( node , false ) ; } /**
     * Adjusts the location used for "rename" when the cursor was not on a property name.
     */ export function getAdjustedRenameLocation ( node ) { return getAdjustedLocation ( node , true ) ; } /**
     * Gets the token whose text has range [start, end) and
     * position >= start and (position < end or (position === end && token is literal or keyword or identifier))
     */ export function getTouchingPropertyName ( sourceFile , position ) { return getTouchingToken ( sourceFile , position , n => isPropertyNameLiteral ( n ) || isKeyword ( n . kind ) || isPrivateIdentifier ( n ) ) ; } /**
     * Returns the token if position is in [start, end).
     * If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true
     */ export function getTouchingToken ( sourceFile , position , includePrecedingTokenAtEndPosition ? ) { return getTokenAtPositionWorker ( sourceFile , position , false , includePrecedingTokenAtEndPosition , false ) ; } /** Returns a token if position is in [start-of-leading-trivia, end) */ export function getTokenAtPosition ( sourceFile , position ) { return getTokenAtPositionWorker ( sourceFile , position , true , undefined , false ) ; } /** Get the token whose text contains the position */ function getTokenAtPositionWorker ( sourceFile , position , allowPositionInLeadingTrivia , includePrecedingTokenAtEndPosition , includeEndPosition ) { let current = sourceFile ; let foundToken ; outer : while ( true ) { const children = current . getChildren ( sourceFile ) ; const i = binarySearchKey ( children , position , ( _ , i ) => i , ( middle , _ ) => { const start = allowPositionInLeadingTrivia ? children [ middle ] . getFullStart ( ) : children [ middle ] . getStart ( sourceFile , true ) ; if ( start > position ) { return Comparison . GreaterThan ; } if ( nodeContainsPosition ( children [ middle ] ) ) { if ( children [ middle - 1 ] ) { if ( nodeContainsPosition ( children [ middle - 1 ] ) ) { return Comparison . GreaterThan ; } } return Comparison . EqualTo ; } if ( includePrecedingTokenAtEndPosition && start === position && children [ middle - 1 ] && children [ middle - 1 ] . getEnd ( ) === position && nodeContainsPosition ( children [ middle - 1 ] ) ) { return Comparison . GreaterThan ; } return Comparison . LessThan ; } ) ; if ( foundToken ) { return foundToken ; } if ( i >= 0 && children [ i ] ) { current = children [ i ] ; continue outer ; } return current ; } function nodeContainsPosition ( node ) { const start = allowPositionInLeadingTrivia ? node . getFullStart ( ) : node . getStart ( sourceFile , true ) ; if ( start > position ) { return false ; } const end = node . getEnd ( ) ; if ( position < end || ( position === end && ( node . kind === SyntaxKind . EndOfFileToken || includeEndPosition ) ) ) { return true ; } else if ( includePrecedingTokenAtEndPosition && end === position ) { const previousToken = findPrecedingToken ( position , sourceFile , node ) ; if ( previousToken && includePrecedingTokenAtEndPosition ( previousToken ) ) { foundToken = previousToken ; return true ; } } return false ; } } /**
     * Returns the first token where position is in [start, end),
     * excluding `JsxText` tokens containing only whitespace.
     */ export function findFirstNonJsxWhitespaceToken ( sourceFile , position ) { let tokenAtPosition = getTokenAtPosition ( sourceFile , position ) ; while ( isWhiteSpaceOnlyJsxText ( tokenAtPosition ) ) { const nextToken = findNextToken ( tokenAtPosition , tokenAtPosition . parent , sourceFile ) ; if ( ! nextToken ) return ; tokenAtPosition = nextToken ; } return tokenAtPosition ; } /**
     * The token on the left of the position is the token that strictly includes the position
     * or sits to the left of the cursor if it is on a boundary. For example
     *
     *   fo|o               -> will return foo
     *   foo <comment> |bar -> will return foo
     *
     */ export function findTokenOnLeftOfPosition ( file , position ) { const tokenAtPosition = getTokenAtPosition ( file , position ) ; if ( isToken ( tokenAtPosition ) && position > tokenAtPosition . getStart ( file ) && position < tokenAtPosition . getEnd ( ) ) { return tokenAtPosition ; } return findPrecedingToken ( position , file ) ; } export function findNextToken ( previousToken , parent , sourceFile ) { return find ( parent ) ; function find ( n ) { if ( isToken ( n ) && n . pos === previousToken . end ) { return n ; } return firstDefined ( n . getChildren ( sourceFile ) , child => { const shouldDiveInChildNode = ( child . pos <= previousToken . pos && child . end > previousToken . end ) || ( child . pos === previousToken . end ) ; return shouldDiveInChildNode && nodeHasTokens ( child , sourceFile ) ? find ( child ) : undefined ; } ) ; } } /**
     * Finds the rightmost token satisfying `token.end <= position`,
     * excluding `JsxText` tokens containing only whitespace.
     */ export function findPrecedingToken ( position , sourceFile , startNode ? , excludeJsdoc ? ) { const result = find ( startNode || sourceFile ) ; Debug . assert ( ! ( result && isWhiteSpaceOnlyJsxText ( result ) ) ) ; return result ; function find ( n ) { if ( isNonWhitespaceToken ( n ) && n . kind !== SyntaxKind . EndOfFileToken ) { return n ; } const children = n . getChildren ( sourceFile ) ; const i = binarySearchKey ( children , position , ( _ , i ) => i , ( middle , _ ) => { if ( position < children [ middle ] . end ) { if ( ! children [ middle - 1 ] || position >= children [ middle - 1 ] . end ) { return Comparison . EqualTo ; } return Comparison . GreaterThan ; } return Comparison . LessThan ; } ) ; if ( i >= 0 && children [ i ] ) { const child = children [ i ] ; if ( position < child . end ) { const start = child . getStart ( sourceFile , ! excludeJsdoc ) ; const lookInPreviousChild = ( start >= position ) || ! nodeHasTokens ( child , sourceFile ) || isWhiteSpaceOnlyJsxText ( child ) ; if ( lookInPreviousChild ) { const candidate = findRightmostChildNodeWithTokens ( children , i , sourceFile ) ; return candidate && findRightmostToken ( candidate , sourceFile ) ; } else { return find ( child ) ; } } } Debug . assert ( startNode !== undefined || n . kind === SyntaxKind . SourceFile || n . kind === SyntaxKind . EndOfFileToken || isJSDocCommentContainingNode ( n ) ) ; const candidate = findRightmostChildNodeWithTokens ( children , children . length , sourceFile ) ; return candidate && findRightmostToken ( candidate , sourceFile ) ; } } function isNonWhitespaceToken ( n ) { return isToken ( n ) && ! isWhiteSpaceOnlyJsxText ( n ) ; } function findRightmostToken ( n , sourceFile ) { if ( isNonWhitespaceToken ( n ) ) { return n ; } const children = n . getChildren ( sourceFile ) ; if ( children . length === 0 ) { return n ; } const candidate = findRightmostChildNodeWithTokens ( children , children . length , sourceFile ) ; return candidate && findRightmostToken ( candidate , sourceFile ) ; } /**
     * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
     */ function findRightmostChildNodeWithTokens ( children , exclusiveStartPosition , sourceFile ) { for ( let i = exclusiveStartPosition - 1 ; i >= 0 ; i -- ) { const child = children [ i ] ; if ( isWhiteSpaceOnlyJsxText ( child ) ) { Debug . assert ( i > 0 , "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`" ) ; } else if ( nodeHasTokens ( children [ i ] , sourceFile ) ) { return children [ i ] ; } } } export function isInString ( sourceFile , position , previousToken = findPrecedingToken ( position , sourceFile ) ) { if ( previousToken && isStringTextContainingNode ( previousToken ) ) { const start = previousToken . getStart ( sourceFile ) ; const end = previousToken . getEnd ( ) ; if ( start < position && position < end ) { return true ; } if ( position === end ) { return ! ! ( previousToken as LiteralExpression ) . isUnterminated ; } } return false ; } /**
     * returns true if the position is in between the open and close elements of an JSX expression.
     */ export function isInsideJsxElementOrAttribute ( sourceFile , position ) { const token = getTokenAtPosition ( sourceFile , position ) ; if ( ! token ) { return false ; } if ( token . kind === SyntaxKind . JsxText ) { return true ; } if ( token . kind === SyntaxKind . LessThanToken && token . parent . kind === SyntaxKind . JsxText ) { return true ; } if ( token . kind === SyntaxKind . LessThanToken && token . parent . kind === SyntaxKind . JsxExpression ) { return true ; } if ( token && token . kind === SyntaxKind . CloseBraceToken && token . parent . kind === SyntaxKind . JsxExpression ) { return true ; } if ( token . kind === SyntaxKind . LessThanToken && token . parent . kind === SyntaxKind . JsxClosingElement ) { return true ; } return false ; } function isWhiteSpaceOnlyJsxText ( node ) { return isJsxText ( node ) && node . containsOnlyTriviaWhiteSpaces ; } export function isInTemplateString ( sourceFile , position ) { const token = getTokenAtPosition ( sourceFile , position ) ; return isTemplateLiteralKind ( token . kind ) && position > token . getStart ( sourceFile ) ; } export function isInJSXText ( sourceFile , position ) { const token = getTokenAtPosition ( sourceFile , position ) ; if ( isJsxText ( token ) ) { return true ; } if ( token . kind === SyntaxKind . OpenBraceToken && isJsxExpression ( token . parent ) && isJsxElement ( token . parent . parent ) ) { return true ; } if ( token . kind === SyntaxKind . LessThanToken && isJsxOpeningLikeElement ( token . parent ) && isJsxElement ( token . parent . parent ) ) { return true ; } return false ; } export function isInsideJsxElement ( sourceFile , position ) { function isInsideJsxElementTraversal ( node ) { while ( node ) { if ( node . kind >= SyntaxKind . JsxSelfClosingElement && node . kind <= SyntaxKind . JsxExpression || node . kind === SyntaxKind . JsxText || node . kind === SyntaxKind . LessThanToken || node . kind === SyntaxKind . GreaterThanToken || node . kind === SyntaxKind . Identifier || node . kind === SyntaxKind . CloseBraceToken || node . kind === SyntaxKind . OpenBraceToken || node . kind === SyntaxKind . SlashToken ) { node = node . parent ; } else if ( node . kind === SyntaxKind . JsxElement ) { if ( position > node . getStart ( sourceFile ) ) return true ; node = node . parent ; } else { return false ; } } return false ; } return isInsideJsxElementTraversal ( getTokenAtPosition ( sourceFile , position ) ) ; } export function findPrecedingMatchingToken ( token , matchingTokenKind , sourceFile ) { const closeTokenText = tokenToString ( token . kind ) ! ; const matchingTokenText = tokenToString ( matchingTokenKind ) ! ; const tokenFullStart = token . getFullStart ( ) ; const bestGuessIndex = sourceFile . text . lastIndexOf ( matchingTokenText , tokenFullStart ) ; if ( bestGuessIndex === - 1 ) { return undefined ; } if ( sourceFile . text . lastIndexOf ( closeTokenText , tokenFullStart - 1 ) < bestGuessIndex ) { const nodeAtGuess = findPrecedingToken ( bestGuessIndex + 1 , sourceFile ) ; if ( nodeAtGuess && nodeAtGuess . kind === matchingTokenKind ) { return nodeAtGuess ; } } const tokenKind = token . kind ; let remainingMatchingTokens = 0 ; while ( true ) { const preceding = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ; if ( ! preceding ) { return undefined ; } token = preceding ; if ( token . kind === matchingTokenKind ) { if ( remainingMatchingTokens === 0 ) { return token ; } remainingMatchingTokens -- ; } else if ( token . kind === tokenKind ) { remainingMatchingTokens ++ ; } } } export function removeOptionality ( type , isOptionalExpression , isOptionalChain ) { return isOptionalExpression ? type . getNonNullableType ( ) : isOptionalChain ? type . getNonOptionalType ( ) : type ; } export function isPossiblyTypeArgumentPosition ( token , sourceFile , checker ) { const info = getPossibleTypeArgumentsInfo ( token , sourceFile ) ; return info !== undefined && ( isPartOfTypeNode ( info . called ) || getPossibleGenericSignatures ( info . called , info . nTypeArguments , checker ) . length !== 0 || isPossiblyTypeArgumentPosition ( info . called , sourceFile , checker ) ) ; } export function getPossibleGenericSignatures ( called , typeArgumentCount , checker ) { let type = checker . getTypeAtLocation ( called ) ; if ( isOptionalChain ( called . parent ) ) { type = removeOptionality ( type , isOptionalChainRoot ( called . parent ) , true ) ; } const signatures = isNewExpression ( called . parent ) ? type . getConstructSignatures ( ) : type . getCallSignatures ( ) ; return signatures . filter ( candidate => ! ! candidate . typeParameters && candidate . typeParameters . length >= typeArgumentCount ) ; } export interface PossibleTypeArgumentInfo { readonly called : Identifier ; readonly nTypeArguments : number ; } export interface PossibleProgramFileInfo { ProgramFiles ? : string [ ] ; } export function getPossibleTypeArgumentsInfo ( tokenIn , sourceFile ) { if ( sourceFile . text . lastIndexOf ( "<" , tokenIn ? tokenIn . pos : sourceFile . text . length ) === - 1 ) { return undefined ; } let token = tokenIn ; let remainingLessThanTokens = 0 ; let nTypeArguments = 0 ; while ( token ) { switch ( token . kind ) { case SyntaxKind . LessThanToken : token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ; if ( token && token . kind === SyntaxKind . QuestionDotToken ) { token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ; } if ( ! token || ! isIdentifier ( token ) ) return undefined ; if ( ! remainingLessThanTokens ) { return isDeclarationName ( token ) ? undefined : { called : token , nTypeArguments } ; } remainingLessThanTokens -- ; break ; case SyntaxKind . GreaterThanGreaterThanGreaterThanToken : remainingLessThanTokens = + 3 ; break ; case SyntaxKind . GreaterThanGreaterThanToken : remainingLessThanTokens = + 2 ; break ; case SyntaxKind . GreaterThanToken : remainingLessThanTokens ++ ; break ; case SyntaxKind . CloseBraceToken : token = findPrecedingMatchingToken ( token , SyntaxKind . OpenBraceToken , sourceFile ) ; if ( ! token ) return undefined ; break ; case SyntaxKind . CloseParenToken : token = findPrecedingMatchingToken ( token , SyntaxKind . OpenParenToken , sourceFile ) ; if ( ! token ) return undefined ; break ; case SyntaxKind . CloseBracketToken : token = findPrecedingMatchingToken ( token , SyntaxKind . OpenBracketToken , sourceFile ) ; if ( ! token ) return undefined ; break ; case SyntaxKind . CommaToken : nTypeArguments ++ ; break ; case SyntaxKind . EqualsGreaterThanToken : case SyntaxKind . Identifier : case SyntaxKind . StringLiteral : case SyntaxKind . NumericLiteral : case SyntaxKind . BigIntLiteral : case SyntaxKind . TrueKeyword : case SyntaxKind . FalseKeyword : case SyntaxKind . TypeOfKeyword : case SyntaxKind . ExtendsKeyword : case SyntaxKind . KeyOfKeyword : case SyntaxKind . DotToken : case SyntaxKind . BarToken : case SyntaxKind . QuestionToken : case SyntaxKind . ColonToken : break ; default : if ( isTypeNode ( token ) ) { break ; } return undefined ; } token = findPrecedingToken ( token . getFullStart ( ) , sourceFile ) ; } return undefined ; } param tokenAtPosition param predicate export function isInComment ( sourceFile , position , tokenAtPosition ? ) { return formatting . getRangeOfEnclosingComment ( sourceFile , position , undefined , tokenAtPosition ) ; } export function hasDocComment ( sourceFile , position ) { const token = getTokenAtPosition ( sourceFile , position ) ; return ! ! findAncestor ( token , isJSDoc ) ; } function nodeHasTokens ( n , sourceFile ) { return n . kind === SyntaxKind . EndOfFileToken ? ! ! ( n as EndOfFileToken ) . jsDoc : n . getWidth ( sourceFile ) !== 0 ; } export function getNodeModifiers ( node , excludeFlags = ModifierFlags . None ) { const result = [ ] ; const flags = isDeclaration ( node ) ? getCombinedNodeFlagsAlwaysIncludeJSDoc ( node ) & ~ excludeFlags : ModifierFlags . None ; if ( flags & ModifierFlags . Private ) result . push ( ScriptElementKindModifier . privateMemberModifier ) ; if ( flags & ModifierFlags . Protected ) result . push ( ScriptElementKindModifier . protectedMemberModifier ) ; if ( flags & ModifierFlags . Public ) result . push ( ScriptElementKindModifier . publicMemberModifier ) ; if ( flags & ModifierFlags . Static || isClassStaticBlockDeclaration ( node ) ) result . push ( ScriptElementKindModifier . staticModifier ) ; if ( flags & ModifierFlags . Abstract ) result . push ( ScriptElementKindModifier . abstractModifier ) ; if ( flags & ModifierFlags . Export ) result . push ( ScriptElementKindModifier . exportedModifier ) ; if ( flags & ModifierFlags . Deprecated ) result . push ( ScriptElementKindModifier . deprecatedModifier ) ; if ( node . flags & NodeFlags . Ambient ) result . push ( ScriptElementKindModifier . ambientModifier ) ; if ( node . kind === SyntaxKind . ExportAssignment ) result . push ( ScriptElementKindModifier . exportedModifier ) ; return result . length > 0 ? result . join ( "," ) : ScriptElementKindModifier . none ; } export function getTypeArgumentOrTypeParameterList ( node ) { if ( node . kind === SyntaxKind . TypeReference || node . kind === SyntaxKind . CallExpression ) { return ( node as CallExpression ) . typeArguments ; } if ( isFunctionLike ( node ) || node . kind === SyntaxKind . ClassDeclaration || node . kind === SyntaxKind . InterfaceDeclaration ) { return ( node as FunctionLikeDeclaration ) . typeParameters ; } return undefined ; } export function isComment ( kind ) { return kind === SyntaxKind . SingleLineCommentTrivia || kind === SyntaxKind . MultiLineCommentTrivia ; } export function isStringOrRegularExpressionOrTemplateLiteral ( kind ) { if ( kind === SyntaxKind . StringLiteral || kind === SyntaxKind . RegularExpressionLiteral || isTemplateLiteralKind ( kind ) ) { return true ; } return false ; } export function isPunctuation ( kind ) { return SyntaxKind . FirstPunctuation <= kind && kind <= SyntaxKind . LastPunctuation ; } export function isInsideTemplateLiteral ( node , position , sourceFile ) { return isTemplateLiteralKind ( node . kind ) && ( node . getStart ( sourceFile ) < position && position < node . end ) || ( ! ! node . isUnterminated && position === node . end ) ; } export function isAccessibilityModifier ( kind ) { switch ( kind ) { case SyntaxKind . PublicKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : return true ; } return false ; } export function cloneCompilerOptions ( options ) { const result = clone ( options ) ; setConfigFileInOptions ( result , options && options . configFile ) ; return result ; } export function isArrayLiteralOrObjectLiteralDestructuringPattern ( node ) { if ( node . kind === SyntaxKind . ArrayLiteralExpression || node . kind === SyntaxKind . ObjectLiteralExpression ) { if ( node . parent . kind === SyntaxKind . BinaryExpression && ( node . parent as BinaryExpression ) . left === node && ( node . parent as BinaryExpression ) . operatorToken . kind === SyntaxKind . EqualsToken ) { return true ; } if ( node . parent . kind === SyntaxKind . ForOfStatement && ( node . parent as ForOfStatement ) . initializer === node ) { return true ; } if ( isArrayLiteralOrObjectLiteralDestructuringPattern ( node . parent . kind === SyntaxKind . PropertyAssignment ? node . parent . parent : node . parent ) ) { return true ; } } return false ; } export function isInReferenceComment ( sourceFile , position ) { return isInReferenceCommentWorker ( sourceFile , position , true ) ; } export function isInNonReferenceComment ( sourceFile , position ) { return isInReferenceCommentWorker ( sourceFile , position , false ) ; } function isInReferenceCommentWorker ( sourceFile , position , shouldBeReference ) { const range = isInComment ( sourceFile , position , undefined ) ; return ! ! range && shouldBeReference === tripleSlashDirectivePrefixRegex . test ( sourceFile . text . substring ( range . pos , range . end ) ) ; } export function getReplacementSpanForContextToken ( contextToken ) { if ( ! contextToken ) return undefined ; switch ( contextToken . kind ) { case SyntaxKind . StringLiteral : case SyntaxKind . NoSubstitutionTemplateLiteral : return createTextSpanFromStringLiteralLikeContent ( contextToken as StringLiteralLike ) ; default : return createTextSpanFromNode ( contextToken ) ; } } export function createTextSpanFromNode ( node , sourceFile ? , endNode ? ) { return createTextSpanFromBounds ( node . getStart ( sourceFile ) , ( endNode || node ) . getEnd ( ) ) ; } export function createTextSpanFromStringLiteralLikeContent ( node ) { if ( node . isUnterminated ) return undefined ; return createTextSpanFromBounds ( node . getStart ( ) + 1 , node . getEnd ( ) - 1 ) ; } export function createTextRangeFromNode ( node , sourceFile ) { return createRange ( node . getStart ( sourceFile ) , node . end ) ; } export function createTextSpanFromRange ( range ) { return createTextSpanFromBounds ( range . pos , range . end ) ; } export function createTextRangeFromSpan ( span ) { return createRange ( span . start , span . start + span . length ) ; } export function createTextChangeFromStartLength ( start , length , newText ) { return createTextChange ( createTextSpan ( start , length ) , newText ) ; } export function createTextChange ( span , newText ) { return { span , newText } ; } export const typeKeywords = [ SyntaxKind . AnyKeyword , SyntaxKind . AssertsKeyword , SyntaxKind . BigIntKeyword , SyntaxKind . BooleanKeyword , SyntaxKind . FalseKeyword , SyntaxKind . InferKeyword , SyntaxKind . KeyOfKeyword , SyntaxKind . NeverKeyword , SyntaxKind . NullKeyword , SyntaxKind . NumberKeyword , SyntaxKind . ObjectKeyword , SyntaxKind . ReadonlyKeyword , SyntaxKind . StringKeyword , SyntaxKind . SymbolKeyword , SyntaxKind . TrueKeyword , SyntaxKind . VoidKeyword , SyntaxKind . UndefinedKeyword , SyntaxKind . UniqueKeyword , SyntaxKind . UnknownKeyword , ] ; export function isTypeKeyword ( kind ) { return contains ( typeKeywords , kind ) ; } export function isTypeKeywordToken ( node ) { return node . kind === SyntaxKind . TypeKeyword ; } export function isTypeKeywordTokenOrIdentifier ( node ) { return isTypeKeywordToken ( node ) || isIdentifier ( node ) && node . text === "type" ; } /** True if the symbol is for an external module, as opposed to a namespace. */ export function isExternalModuleSymbol ( moduleSymbol ) { return ! ! ( moduleSymbol . flags & SymbolFlags . Module ) && moduleSymbol . name . charCodeAt ( 0 ) === CharacterCodes . doubleQuote ; } /** Returns `true` the first time it encounters a node and `false` afterwards. */ export type NodeSeenTracker < T = Node > = ( node : T ) => boolean ; export function nodeSeenTracker < T extends Node > ( ) { const seen = [ ] ; return node => { const id = getNodeId ( node ) ; return ! seen [ id ] && ( seen [ id ] = true ) ; } ; } export function getSnapshotText ( snap ) { return snap . getText ( 0 , snap . getLength ( ) ) ; } export function repeatString ( str , count ) { let result = "" ; for ( let i = 0 ; i < count ; i ++ ) { result += str ; } return result ; } export function skipConstraint ( type ) { return type . isTypeParameter ( ) ? type . getConstraint ( ) || type : type ; } export function getNameFromPropertyName ( name ) { return name . kind === SyntaxKind . ComputedPropertyName ? isStringOrNumericLiteralLike ( name . expression ) ? name . expression . text : undefined : isPrivateIdentifier ( name ) ? idText ( name ) : getTextOfIdentifierOrLiteral ( name ) ; } export function programContainsModules ( program ) { return program . getSourceFiles ( ) . some ( s => ! s . isDeclarationFile && ! program . isSourceFileFromExternalLibrary ( s ) && ! ! ( s . externalModuleIndicator || s . commonJsModuleIndicator ) ) ; } export function programContainsEsModules ( program ) { return program . getSourceFiles ( ) . some ( s => ! s . isDeclarationFile && ! program . isSourceFileFromExternalLibrary ( s ) && ! ! s . externalModuleIndicator ) ; } export function compilerOptionsIndicateEsModules ( compilerOptions ) { return ! ! compilerOptions . module || getEmitScriptTarget ( compilerOptions ) >= ScriptTarget . ES2015 || ! ! compilerOptions . noEmit ; } export function createModuleSpecifierResolutionHost ( program , host ) { return { fileExists : fileName => program . fileExists ( fileName ) , getCurrentDirectory : ( ) => host . getCurrentDirectory ( ) , readFile : maybeBind ( host , host . readFile ) , useCaseSensitiveFileNames : maybeBind ( host , host . useCaseSensitiveFileNames ) , getSymlinkCache : maybeBind ( host , host . getSymlinkCache ) || program . getSymlinkCache , getModuleSpecifierCache : maybeBind ( host , host . getModuleSpecifierCache ) , getGlobalTypingsCacheLocation : maybeBind ( host , host . getGlobalTypingsCacheLocation ) , redirectTargetsMap : program . redirectTargetsMap , getProjectReferenceRedirect : fileName => program . getProjectReferenceRedirect ( fileName ) , isSourceOfProjectReferenceRedirect : fileName => program . isSourceOfProjectReferenceRedirect ( fileName ) , getNearestAncestorDirectoryWithPackageJson : maybeBind ( host , host . getNearestAncestorDirectoryWithPackageJson ) , getFileIncludeReasons : ( ) => program . getFileIncludeReasons ( ) , } ; } export function getModuleSpecifierResolverHost ( program , host ) { return { ... createModuleSpecifierResolutionHost ( program , host ) , getCommonSourceDirectory : ( ) => program . getCommonSourceDirectory ( ) , } ; } export function makeImportIfNecessary ( defaultImport , namedImports , moduleSpecifier , quotePreference ) { return defaultImport || namedImports && namedImports . length ? makeImport ( defaultImport , namedImports , moduleSpecifier , quotePreference ) : undefined ; } export function makeImport ( defaultImport , namedImports , moduleSpecifier , quotePreference , isTypeOnly ? ) { return factory . createImportDeclaration ( undefined , undefined , defaultImport || namedImports ? factory . createImportClause ( ! ! isTypeOnly , defaultImport , namedImports && namedImports . length ? factory . createNamedImports ( namedImports ) : undefined ) : undefined , typeof moduleSpecifier === "string" ? makeStringLiteral ( moduleSpecifier , quotePreference ) : moduleSpecifier , undefined ) ; } export function makeStringLiteral ( text , quotePreference ) { return factory . createStringLiteral ( text , quotePreference === QuotePreference . Single ) ; } export const enum QuotePreference { Single , Double } export function quotePreferenceFromString ( str , sourceFile ) { return isStringDoubleQuoted ( str , sourceFile ) ? QuotePreference . Double : QuotePreference . Single ; } export function getQuotePreference ( sourceFile , preferences ) { if ( preferences . quotePreference && preferences . quotePreference !== "auto" ) { return preferences . quotePreference === "single" ? QuotePreference . Single : QuotePreference . Double ; } else { const firstModuleSpecifier = sourceFile . imports && find ( sourceFile . imports , n => isStringLiteral ( n ) && ! nodeIsSynthesized ( n . parent ) ) as StringLiteral ; return firstModuleSpecifier ? quotePreferenceFromString ( firstModuleSpecifier , sourceFile ) : QuotePreference . Double ; } } export function getQuoteFromPreference ( qp ) { switch ( qp ) { case QuotePreference . Single : return "'" ; case QuotePreference . Double : return '"' ; default : return Debug . assertNever ( qp ) ; } } export function symbolNameNoDefault ( symbol ) { const escaped = symbolEscapedNameNoDefault ( symbol ) ; return escaped === undefined ? undefined : unescapeLeadingUnderscores ( escaped ) ; } export function symbolEscapedNameNoDefault ( symbol ) { if ( symbol . escapedName !== InternalSymbolName . Default ) { return symbol . escapedName ; } return firstDefined ( symbol . declarations , decl => { const name = getNameOfDeclaration ( decl ) ; return name && name . kind === SyntaxKind . Identifier ? name . escapedText : undefined ; } ) ; } export function isModuleSpecifierLike ( node ) { return isStringLiteralLike ( node ) && ( isExternalModuleReference ( node . parent ) || isImportDeclaration ( node . parent ) || isRequireCall ( node . parent , false ) && node . parent . arguments [ 0 ] === node || isImportCall ( node . parent ) && node . parent . arguments [ 0 ] === node ) ; } export type ObjectBindingElementWithoutPropertyName = BindingElement & { name : Identifier ; } ; export function isObjectBindingElementWithoutPropertyName ( bindingElement ) { return isBindingElement ( bindingElement ) && isObjectBindingPattern ( bindingElement . parent ) && isIdentifier ( bindingElement . name ) && ! bindingElement . propertyName ; } export function getPropertySymbolFromBindingElement ( checker , bindingElement ) { const typeOfPattern = checker . getTypeAtLocation ( bindingElement . parent ) ; return typeOfPattern && checker . getPropertyOfType ( typeOfPattern , bindingElement . name . text ) ; } export function getParentNodeInSpan ( node , file , span ) { if ( ! node ) return undefined ; while ( node . parent ) { if ( isSourceFile ( node . parent ) || ! spanContainsNode ( span , node . parent , file ) ) { return node ; } node = node . parent ; } } function spanContainsNode ( span , node , file ) { return textSpanContainsPosition ( span , node . getStart ( file ) ) && node . getEnd ( ) <= textSpanEnd ( span ) ; } export function findModifier ( node , kind ) { return node . modifiers && find ( node . modifiers , m => m . kind === kind ) ; } export function insertImports ( changes , sourceFile , imports , blankLineBetween ) { const decl = isArray ( imports ) ? imports [ 0 ] : imports ; const importKindPredicate = decl . kind === SyntaxKind . VariableStatement ? isRequireVariableStatement : isAnyImportSyntax ; const existingImportStatements = filter ( sourceFile . statements , importKindPredicate ) ; const sortedNewImports = isArray ( imports ) ? stableSort ( imports , OrganizeImports . compareImportsOrRequireStatements ) : [ imports ] ; if ( ! existingImportStatements . length ) { changes . insertNodesAtTopOfFile ( sourceFile , sortedNewImports , blankLineBetween ) ; } else if ( existingImportStatements && OrganizeImports . importsAreSorted ( existingImportStatements ) ) { for ( const newImport of sortedNewImports ) { const insertionIndex = OrganizeImports . getImportDeclarationInsertionIndex ( existingImportStatements , newImport ) ; if ( insertionIndex === 0 ) { const options = existingImportStatements [ 0 ] === sourceFile . statements [ 0 ] ? { leadingTriviaOption : textChanges . LeadingTriviaOption . Exclude } : { } ; changes . insertNodeBefore ( sourceFile , existingImportStatements [ 0 ] , newImport , false , options ) ; } else { const prevImport = existingImportStatements [ insertionIndex - 1 ] ; changes . insertNodeAfter ( sourceFile , prevImport , newImport ) ; } } } else { const lastExistingImport = lastOrUndefined ( existingImportStatements ) ; if ( lastExistingImport ) { changes . insertNodesAfter ( sourceFile , lastExistingImport , sortedNewImports ) ; } else { changes . insertNodesAtTopOfFile ( sourceFile , sortedNewImports , blankLineBetween ) ; } } } export function getTypeKeywordOfTypeOnlyImport ( importClause , sourceFile ) { Debug . assert ( importClause . isTypeOnly ) ; return cast ( importClause . getChildAt ( 0 , sourceFile ) , isTypeKeywordToken ) ; } export function textSpansEqual ( a , b ) { return ! ! a && ! ! b && a . start === b . start && a . length === b . length ; } export function documentSpansEqual ( a , b ) { return a . fileName === b . fileName && textSpansEqual ( a . textSpan , b . textSpan ) ; } /**
     * Iterates through 'array' by index and performs the callback on each element of array until the callback
     * returns a truthy value, then returns that value.
     * If no such value is found, the callback is applied to each element of array and undefined is returned.
     */ export function forEachUnique < T , U > ( array , callback ) { if ( array ) { for ( let i = 0 ; i < array . length ; i ++ ) { if ( array . indexOf ( array [ i ] ) === i ) { const result = callback ( array [ i ] , i ) ; if ( result ) { return result ; } } } } return undefined ; } export function isTextWhiteSpaceLike ( text , startPos , endPos ) { for ( let i = startPos ; i < endPos ; i ++ ) { if ( ! isWhiteSpaceLike ( text . charCodeAt ( i ) ) ) { return false ; } } return true ; } export function isFirstDeclarationOfSymbolParameter ( symbol ) { const declaration = symbol . declarations ? firstOrUndefined ( symbol . declarations ) : undefined ; return ! ! findAncestor ( declaration , n => isParameter ( n ) ? true : isBindingElement ( n ) || isObjectBindingPattern ( n ) || isArrayBindingPattern ( n ) ? false : "quit" ) ; } const displayPartWriter = getDisplayPartWriter ( ) ; function getDisplayPartWriter ( ) { const absoluteMaximumLength = defaultMaximumTruncationLength * 10 ; let displayParts ; let lineStart ; let indent ; let length ; resetWriter ( ) ; const unknownWrite = ( text ) => writeKind ( text , SymbolDisplayPartKind . text ) ; return { displayParts : ( ) => { const finalText = displayParts . length && displayParts [ displayParts . length - 1 ] . text ; if ( length > absoluteMaximumLength && finalText && finalText !== "..." ) { if ( ! isWhiteSpaceLike ( finalText . charCodeAt ( finalText . length - 1 ) ) ) { displayParts . push ( displayPart ( " " , SymbolDisplayPartKind . space ) ) ; } displayParts . push ( displayPart ( "..." , SymbolDisplayPartKind . punctuation ) ) ; } return displayParts ; } , writeKeyword : text => writeKind ( text , SymbolDisplayPartKind . keyword ) , writeOperator : text => writeKind ( text , SymbolDisplayPartKind . operator ) , writePunctuation : text => writeKind ( text , SymbolDisplayPartKind . punctuation ) , writeTrailingSemicolon : text => writeKind ( text , SymbolDisplayPartKind . punctuation ) , writeSpace : text => writeKind ( text , SymbolDisplayPartKind . space ) , writeStringLiteral : text => writeKind ( text , SymbolDisplayPartKind . stringLiteral ) , writeParameter : text => writeKind ( text , SymbolDisplayPartKind . parameterName ) , writeProperty : text => writeKind ( text , SymbolDisplayPartKind . propertyName ) , writeLiteral : text => writeKind ( text , SymbolDisplayPartKind . stringLiteral ) , writeSymbol , writeLine , write : unknownWrite , writeComment : unknownWrite , getText : ( ) => "" , getTextPos : ( ) => 0 , getColumn : ( ) => 0 , getLine : ( ) => 0 , isAtStartOfLine : ( ) => false , hasTrailingWhitespace : ( ) => false , hasTrailingComment : ( ) => false , rawWrite : notImplemented , getIndent : ( ) => indent , increaseIndent : ( ) => { indent ++ ; } , decreaseIndent : ( ) => { indent -- ; } , clear : resetWriter , trackSymbol : ( ) => false , reportInaccessibleThisError : noop , reportInaccessibleUniqueSymbolError : noop , reportPrivateInBaseOfClassExpression : noop , } ; function writeIndent ( ) { if ( length > absoluteMaximumLength ) return ; if ( lineStart ) { const indentString = getIndentString ( indent ) ; if ( indentString ) { length += indentString . length ; displayParts . push ( displayPart ( indentString , SymbolDisplayPartKind . space ) ) ; } lineStart = false ; } } function writeKind ( text , kind ) { if ( length > absoluteMaximumLength ) return ; writeIndent ( ) ; length += text . length ; displayParts . push ( displayPart ( text , kind ) ) ; } function writeSymbol ( text , symbol ) { if ( length > absoluteMaximumLength ) return ; writeIndent ( ) ; length += text . length ; displayParts . push ( symbolPart ( text , symbol ) ) ; } function writeLine ( ) { if ( length > absoluteMaximumLength ) return ; length += 1 ; displayParts . push ( lineBreakPart ( ) ) ; lineStart = true ; } function resetWriter ( ) { displayParts = [ ] ; lineStart = true ; indent = 0 ; length = 0 ; } } export function symbolPart ( text , symbol ) { return displayPart ( text , displayPartKind ( symbol ) ) ; function displayPartKind ( symbol ) { const flags = symbol . flags ; if ( flags & SymbolFlags . Variable ) { return isFirstDeclarationOfSymbolParameter ( symbol ) ? SymbolDisplayPartKind . parameterName : SymbolDisplayPartKind . localName ; } if ( flags & SymbolFlags . Property ) return SymbolDisplayPartKind . propertyName ; if ( flags & SymbolFlags . GetAccessor ) return SymbolDisplayPartKind . propertyName ; if ( flags & SymbolFlags . SetAccessor ) return SymbolDisplayPartKind . propertyName ; if ( flags & SymbolFlags . EnumMember ) return SymbolDisplayPartKind . enumMemberName ; if ( flags & SymbolFlags . Function ) return SymbolDisplayPartKind . functionName ; if ( flags & SymbolFlags . Class ) return SymbolDisplayPartKind . className ; if ( flags & SymbolFlags . Interface ) return SymbolDisplayPartKind . interfaceName ; if ( flags & SymbolFlags . Enum ) return SymbolDisplayPartKind . enumName ; if ( flags & SymbolFlags . Module ) return SymbolDisplayPartKind . moduleName ; if ( flags & SymbolFlags . Method ) return SymbolDisplayPartKind . methodName ; if ( flags & SymbolFlags . TypeParameter ) return SymbolDisplayPartKind . typeParameterName ; if ( flags & SymbolFlags . TypeAlias ) return SymbolDisplayPartKind . aliasName ; if ( flags & SymbolFlags . Alias ) return SymbolDisplayPartKind . aliasName ; return SymbolDisplayPartKind . text ; } } export function displayPart ( text , kind ) { return { text , kind : SymbolDisplayPartKind [ kind ] } ; } export function spacePart ( ) { return displayPart ( " " , SymbolDisplayPartKind . space ) ; } export function keywordPart ( kind ) { return displayPart ( tokenToString ( kind ) ! , SymbolDisplayPartKind . keyword ) ; } export function punctuationPart ( kind ) { return displayPart ( tokenToString ( kind ) ! , SymbolDisplayPartKind . punctuation ) ; } export function operatorPart ( kind ) { return displayPart ( tokenToString ( kind ) ! , SymbolDisplayPartKind . operator ) ; } export function parameterNamePart ( text ) { return displayPart ( text , SymbolDisplayPartKind . parameterName ) ; } export function propertyNamePart ( text ) { return displayPart ( text , SymbolDisplayPartKind . propertyName ) ; } export function textOrKeywordPart ( text ) { const kind = stringToToken ( text ) ; return kind === undefined ? textPart ( text ) : keywordPart ( kind ) ; } export function textPart ( text ) { return displayPart ( text , SymbolDisplayPartKind . text ) ; } export function typeAliasNamePart ( text ) { return displayPart ( text , SymbolDisplayPartKind . aliasName ) ; } export function typeParameterNamePart ( text ) { return displayPart ( text , SymbolDisplayPartKind . typeParameterName ) ; } export function linkTextPart ( text ) { return displayPart ( text , SymbolDisplayPartKind . linkText ) ; } export function linkNamePart ( text , target ) { return { text , kind : SymbolDisplayPartKind [ SymbolDisplayPartKind . linkName ] , target : { fileName : getSourceFileOfNode ( target ) . fileName , textSpan : createTextSpanFromNode ( target ) , } , } ; } export function linkPart ( text ) { return displayPart ( text , SymbolDisplayPartKind . link ) ; } export function buildLinkParts ( link , checker ? ) { const prefix = isJSDocLink ( link ) ? "link" : isJSDocLinkCode ( link ) ? "linkcode" : "linkplain" ; const parts = [ linkPart ( `{@${ prefix } ` ) ] ; if ( ! link . name ) { if ( link . text ) parts . push ( linkTextPart ( link . text ) ) ; } else { const symbol = checker ?. getSymbolAtLocation ( link . name ) ; const suffix = findLinkNameEnd ( link . text ) ; const name = getTextOfNode ( link . name ) + link . text . slice ( 0 , suffix ) ; const text = link . text . slice ( suffix ) ; const decl = symbol ?. valueDeclaration || symbol ?. declarations ?. [ 0 ] ; if ( decl ) { parts . push ( linkNamePart ( name , decl ) ) ; if ( text ) parts . push ( linkTextPart ( text ) ) ; } else { parts . push ( linkTextPart ( name + ( suffix ? "" : " " ) + text ) ) ; } } parts . push ( linkPart ( "}" ) ) ; return parts ; } function findLinkNameEnd ( text ) { if ( text . indexOf ( "()" ) === 0 ) return 2 ; if ( text [ 0 ] !== "<" ) return 0 ; let brackets = 0 ; let i = 0 ; while ( i < text . length ) { if ( text [ i ] === "<" ) brackets ++ ; if ( text [ i ] === ">" ) brackets -- ; i ++ ; if ( ! brackets ) return i ; } return 0 ; } const carriageReturnLineFeed = "\r\n" ; /**
     * The default is CRLF.
     */ export function getNewLineOrDefaultFromHost ( host , formatSettings ? ) { return formatSettings ?. newLineCharacter || host . getNewLine ?. ( ) || carriageReturnLineFeed ; } export function lineBreakPart ( ) { return displayPart ( "\n" , SymbolDisplayPartKind . lineBreak ) ; } export function mapToDisplayParts ( writeDisplayParts ) { try { writeDisplayParts ( displayPartWriter ) ; return displayPartWriter . displayParts ( ) ; } finally { displayPartWriter . clear ( ) ; } } export function typeToDisplayParts ( typechecker , type , enclosingDeclaration ? , flags = TypeFormatFlags . None ) { return mapToDisplayParts ( writer => { typechecker . writeType ( type , enclosingDeclaration , flags | TypeFormatFlags . MultilineObjectLiterals | TypeFormatFlags . UseAliasDefinedOutsideCurrentScope , writer ) ; } ) ; } export function symbolToDisplayParts ( typeChecker , symbol , enclosingDeclaration ? , meaning ? , flags = SymbolFormatFlags . None ) { return mapToDisplayParts ( writer => { typeChecker . writeSymbol ( symbol , enclosingDeclaration , meaning , flags | SymbolFormatFlags . UseAliasDefinedOutsideCurrentScope , writer ) ; } ) ; } export function signatureToDisplayParts ( typechecker , signature , enclosingDeclaration ? , flags = TypeFormatFlags . None ) { flags |= TypeFormatFlags . UseAliasDefinedOutsideCurrentScope | TypeFormatFlags . MultilineObjectLiterals | TypeFormatFlags . WriteTypeArgumentsOfSignature | TypeFormatFlags . OmitParameterModifiers ; return mapToDisplayParts ( writer => { typechecker . writeSignature ( signature , enclosingDeclaration , flags , undefined , writer ) ; } ) ; } export function isImportOrExportSpecifierName ( location ) { return ! ! location . parent && isImportOrExportSpecifier ( location . parent ) && location . parent . propertyName === location ; } export function getScriptKind ( fileName , host ) { return ensureScriptKind ( fileName , host . getScriptKind && host . getScriptKind ( fileName ) ) ; } export function getSymbolTarget ( symbol , checker ) { let next = symbol ; while ( isAliasSymbol ( next ) || ( isTransientSymbol ( next ) && next . target ) ) { if ( isTransientSymbol ( next ) && next . target ) { next = next . target ; } else { next = skipAlias ( next , checker ) ; } } return next ; } function isTransientSymbol ( symbol ) { return ( symbol . flags & SymbolFlags . Transient ) !== 0 ; } function isAliasSymbol ( symbol ) { return ( symbol . flags & SymbolFlags . Alias ) !== 0 ; } export function getUniqueSymbolId ( symbol , checker ) { return getSymbolId ( skipAlias ( symbol , checker ) ) ; } export function getFirstNonSpaceCharacterPosition ( text , position ) { while ( isWhiteSpaceLike ( text . charCodeAt ( position ) ) ) { position += 1 ; } return position ; } export function getPrecedingNonSpaceCharacterPosition ( text , position ) { while ( position > - 1 && isWhiteSpaceSingleLine ( text . charCodeAt ( position ) ) ) { position -= 1 ; } return position + 1 ; } /**
     * Creates a deep, memberwise clone of a node with no source map location.
     *
     * WARNING: This is an expensive operation and is only intended to be used in refactorings
     * and code fixes (because those are triggered by explicit user actions).
     */ export function getSynthesizedDeepClone < T extends Node | undefined > ( node , includeTrivia = true ) { const clone = node && getSynthesizedDeepCloneWorker ( node as NonNullable < T > ) ; if ( clone && ! includeTrivia ) suppressLeadingAndTrailingTrivia ( clone ) ; return clone ; } export function getSynthesizedDeepCloneWithReplacements < T extends Node > ( node , includeTrivia , replaceNode ) { let clone = replaceNode ( node ) ; if ( clone ) { setOriginalNode ( clone , node ) ; } else { clone = getSynthesizedDeepCloneWorker ( node as NonNullable < T > , replaceNode ) ; } if ( clone && ! includeTrivia ) suppressLeadingAndTrailingTrivia ( clone ) ; return clone as T ; } function getSynthesizedDeepCloneWorker < T extends Node > ( node , replaceNode ? ) { const nodeClone = replaceNode ? n => getSynthesizedDeepCloneWithReplacements ( n , true , replaceNode ) : getSynthesizedDeepClone ; const nodesClone = replaceNode ? ns => ns && getSynthesizedDeepClonesWithReplacements ( ns , true , replaceNode ) : ns => ns && getSynthesizedDeepClones ( ns ) ; const visited = visitEachChild ( node , nodeClone , nullTransformationContext , nodesClone , nodeClone ) ; if ( visited === node ) { const clone = isStringLiteral ( node ) ? setOriginalNode ( factory . createStringLiteralFromNode ( node ) , node ) as Node as T : isNumericLiteral ( node ) ? setOriginalNode ( factory . createNumericLiteral ( node . text , node . numericLiteralFlags ) , node ) as Node as T : factory . cloneNode ( node ) ; return setTextRange ( clone , node ) ; } ( visited as Mutable < T > ) . parent = undefined ! ; return visited ; } export function getSynthesizedDeepClones < T extends Node > ( nodes , includeTrivia ? ) ; export function getSynthesizedDeepClones < T extends Node > ( nodes , includeTrivia ? ) ; export function getSynthesizedDeepClones < T extends Node > ( nodes , includeTrivia = true ) { return nodes && factory . createNodeArray ( nodes . map ( n => getSynthesizedDeepClone ( n , includeTrivia ) ) , nodes . hasTrailingComma ) ; } export function getSynthesizedDeepClonesWithReplacements < T extends Node > ( nodes , includeTrivia , replaceNode ) { return factory . createNodeArray ( nodes . map ( n => getSynthesizedDeepCloneWithReplacements ( n , includeTrivia , replaceNode ) ) , nodes . hasTrailingComma ) ; } /**
     * Sets EmitFlags to suppress leading and trailing trivia on the node.
     */ export function suppressLeadingAndTrailingTrivia ( node ) { suppressLeadingTrivia ( node ) ; suppressTrailingTrivia ( node ) ; } /**
     * Sets EmitFlags to suppress leading trivia on the node.
     */ export function suppressLeadingTrivia ( node ) { addEmitFlagsRecursively ( node , EmitFlags . NoLeadingComments , getFirstChild ) ; } /**
     * Sets EmitFlags to suppress trailing trivia on the node.
     */ export function suppressTrailingTrivia ( node ) { addEmitFlagsRecursively ( node , EmitFlags . NoTrailingComments , getLastChild ) ; } export function copyComments ( sourceNode , targetNode ) { const sourceFile = sourceNode . getSourceFile ( ) ; const text = sourceFile . text ; if ( hasLeadingLineBreak ( sourceNode , text ) ) { copyLeadingComments ( sourceNode , targetNode , sourceFile ) ; } else { copyTrailingAsLeadingComments ( sourceNode , targetNode , sourceFile ) ; } copyTrailingComments ( sourceNode , targetNode , sourceFile ) ; } function hasLeadingLineBreak ( node , text ) { const start = node . getFullStart ( ) ; const end = node . getStart ( ) ; for ( let i = start ; i < end ; i ++ ) { if ( text . charCodeAt ( i ) === CharacterCodes . lineFeed ) return true ; } return false ; } function addEmitFlagsRecursively ( node , flag , getChild ) { addEmitFlags ( node , flag ) ; const child = getChild ( node ) ; if ( child ) addEmitFlagsRecursively ( child , flag , getChild ) ; } function getFirstChild ( node ) { return node . forEachChild ( child => child ) ; } export function getUniqueName ( baseName , sourceFile ) { let nameText = baseName ; for ( let i = 1 ; ! isFileLevelUniqueName ( sourceFile , nameText ) ; i ++ ) { nameText = `${ baseName }_${ i }` ; } return nameText ; } return export function getRenameLocation ( edits , renameFilename , name , preferLastLocation ) { let delta = 0 ; let lastPos = - 1 ; for ( const { fileName , textChanges } of edits ) { Debug . assert ( fileName === renameFilename ) ; for ( const change of textChanges ) { const { span , newText } = change ; const index = indexInTextChange ( newText , name ) ; if ( index !== - 1 ) { lastPos = span . start + delta + index ; if ( ! preferLastLocation ) { return lastPos ; } } delta += newText . length - span . length ; } } Debug . assert ( preferLastLocation ) ; Debug . assert ( lastPos >= 0 ) ; return lastPos ; } export function copyLeadingComments ( sourceNode , targetNode , sourceFile , commentKind ? , hasTrailingNewLine ? ) { forEachLeadingCommentRange ( sourceFile . text , sourceNode . pos , getAddCommentsFunction ( targetNode , sourceFile , commentKind , hasTrailingNewLine , addSyntheticLeadingComment ) ) ; } export function copyTrailingComments ( sourceNode , targetNode , sourceFile , commentKind ? , hasTrailingNewLine ? ) { forEachTrailingCommentRange ( sourceFile . text , sourceNode . end , getAddCommentsFunction ( targetNode , sourceFile , commentKind , hasTrailingNewLine , addSyntheticTrailingComment ) ) ; } /**
     * This function copies the trailing comments for the token that comes before `sourceNode`, as leading comments of `targetNode`.
     * This is useful because sometimes a comment that refers to `sourceNode` will be a leading comment for `sourceNode`, according to the
     * notion of trivia ownership, and instead will be a trailing comment for the token before `sourceNode`, e.g.:
     * `function foo(\* not leading comment for a *\ a: string) {}`
     * The comment refers to `a` but belongs to the `(` token, but we might want to copy it.
     */ export function copyTrailingAsLeadingComments ( sourceNode , targetNode , sourceFile , commentKind ? , hasTrailingNewLine ? ) { forEachTrailingCommentRange ( sourceFile . text , sourceNode . pos , getAddCommentsFunction ( targetNode , sourceFile , commentKind , hasTrailingNewLine , addSyntheticLeadingComment ) ) ; } function getAddCommentsFunction ( targetNode , sourceFile , commentKind , hasTrailingNewLine , cb ) { return ( pos , end , kind , htnl ) => { if ( kind === SyntaxKind . MultiLineCommentTrivia ) { pos += 2 ; end -= 2 ; } else { pos += 2 ; } cb ( targetNode , commentKind || kind , sourceFile . text . slice ( pos , end ) , hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl ) ; } ; } function indexInTextChange ( change , name ) { if ( startsWith ( change , name ) ) return 0 ; let idx = change . indexOf ( " " + name ) ; if ( idx === - 1 ) idx = change . indexOf ( "." + name ) ; if ( idx === - 1 ) idx = change . indexOf ( '"' + name ) ; return idx === - 1 ? - 1 : idx + 1 ; } export function needsParentheses ( expression ) { return isBinaryExpression ( expression ) && expression . operatorToken . kind === SyntaxKind . CommaToken || isObjectLiteralExpression ( expression ) || isAsExpression ( expression ) && isObjectLiteralExpression ( expression . expression ) ; } export function getContextualTypeFromParent ( node , checker ) { const { parent } = node ; switch ( parent . kind ) { case SyntaxKind . NewExpression : return checker . getContextualType ( parent as NewExpression ) ; case SyntaxKind . BinaryExpression : { const { left , operatorToken , right } = parent as BinaryExpression ; return isEqualityOperatorKind ( operatorToken . kind ) ? checker . getTypeAtLocation ( node === right ? left : right ) : checker . getContextualType ( node ) ; } case SyntaxKind . CaseClause : return ( parent as CaseClause ) . expression === node ? getSwitchedType ( parent as CaseClause , checker ) : undefined ; default : return checker . getContextualType ( node ) ; } } export function quote ( sourceFile , preferences , text ) { const quotePreference = getQuotePreference ( sourceFile , preferences ) ; const quoted = JSON . stringify ( text ) ; return quotePreference === QuotePreference . Single ? `'${ stripQuotes ( quoted ) . replace ( /'/g , "\\'" ) . replace ( /\\"/g , '"' ) }'` : quoted ; } export function isEqualityOperatorKind ( kind ) { switch ( kind ) { case SyntaxKind . EqualsEqualsEqualsToken : case SyntaxKind . EqualsEqualsToken : case SyntaxKind . ExclamationEqualsEqualsToken : case SyntaxKind . ExclamationEqualsToken : return true ; default : return false ; } } export function isStringLiteralOrTemplate ( node ) { switch ( node . kind ) { case SyntaxKind . StringLiteral : case SyntaxKind . NoSubstitutionTemplateLiteral : case SyntaxKind . TemplateExpression : case SyntaxKind . TaggedTemplateExpression : return true ; default : return false ; } } export function hasIndexSignature ( type ) { return ! ! type . getStringIndexType ( ) || ! ! type . getNumberIndexType ( ) ; } export function getSwitchedType ( caseClause , checker ) { return checker . getTypeAtLocation ( caseClause . parent . parent . expression ) ; } export const ANONYMOUS = "anonymous function" ; export function getTypeNodeIfAccessible ( type , enclosingScope , program , host ) { const checker = program . getTypeChecker ( ) ; let typeIsAccessible = true ; const notAccessible = ( ) => typeIsAccessible = false ; const res = checker . typeToTypeNode ( type , enclosingScope , NodeBuilderFlags . NoTruncation , { trackSymbol : ( symbol , declaration , meaning ) => { typeIsAccessible = typeIsAccessible && checker . isSymbolAccessible ( symbol , declaration , meaning , false ) . accessibility === SymbolAccessibility . Accessible ; return ! typeIsAccessible ; } , reportInaccessibleThisError : notAccessible , reportPrivateInBaseOfClassExpression : notAccessible , reportInaccessibleUniqueSymbolError : notAccessible , moduleResolverHost : getModuleSpecifierResolverHost ( program , host ) } ) ; return typeIsAccessible ? res : undefined ; } function syntaxRequiresTrailingCommaOrSemicolonOrASI ( kind ) { return kind === SyntaxKind . CallSignature || kind === SyntaxKind . ConstructSignature || kind === SyntaxKind . IndexSignature || kind === SyntaxKind . PropertySignature || kind === SyntaxKind . MethodSignature ; } function syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI ( kind ) { return kind === SyntaxKind . FunctionDeclaration || kind === SyntaxKind . Constructor || kind === SyntaxKind . MethodDeclaration || kind === SyntaxKind . GetAccessor || kind === SyntaxKind . SetAccessor ; } function syntaxRequiresTrailingModuleBlockOrSemicolonOrASI ( kind ) { return kind === SyntaxKind . ModuleDeclaration ; } export function syntaxRequiresTrailingSemicolonOrASI ( kind ) { return kind === SyntaxKind . VariableStatement || kind === SyntaxKind . ExpressionStatement || kind === SyntaxKind . DoStatement || kind === SyntaxKind . ContinueStatement || kind === SyntaxKind . BreakStatement || kind === SyntaxKind . ReturnStatement || kind === SyntaxKind . ThrowStatement || kind === SyntaxKind . DebuggerStatement || kind === SyntaxKind . PropertyDeclaration || kind === SyntaxKind . TypeAliasDeclaration || kind === SyntaxKind . ImportDeclaration || kind === SyntaxKind . ImportEqualsDeclaration || kind === SyntaxKind . ExportDeclaration || kind === SyntaxKind . NamespaceExportDeclaration || kind === SyntaxKind . ExportAssignment ; } export const syntaxMayBeASICandidate = or ( syntaxRequiresTrailingCommaOrSemicolonOrASI , syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI , syntaxRequiresTrailingModuleBlockOrSemicolonOrASI , syntaxRequiresTrailingSemicolonOrASI ) ; function nodeIsASICandidate ( node , sourceFile ) { const lastToken = node . getLastToken ( sourceFile ) ; if ( lastToken && lastToken . kind === SyntaxKind . SemicolonToken ) { return false ; } if ( syntaxRequiresTrailingCommaOrSemicolonOrASI ( node . kind ) ) { if ( lastToken && lastToken . kind === SyntaxKind . CommaToken ) { return false ; } } else if ( syntaxRequiresTrailingModuleBlockOrSemicolonOrASI ( node . kind ) ) { const lastChild = last ( node . getChildren ( sourceFile ) ) ; if ( lastChild && isModuleBlock ( lastChild ) ) { return false ; } } else if ( syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI ( node . kind ) ) { const lastChild = last ( node . getChildren ( sourceFile ) ) ; if ( lastChild && isFunctionBlock ( lastChild ) ) { return false ; } } else if ( ! syntaxRequiresTrailingSemicolonOrASI ( node . kind ) ) { return false ; } if ( node . kind === SyntaxKind . DoStatement ) { return true ; } const topNode = findAncestor ( node , ancestor => ! ancestor . parent ) ! ; const nextToken = findNextToken ( node , topNode , sourceFile ) ; if ( ! nextToken || nextToken . kind === SyntaxKind . CloseBraceToken ) { return true ; } const startLine = sourceFile . getLineAndCharacterOfPosition ( node . getEnd ( ) ) . line ; const endLine = sourceFile . getLineAndCharacterOfPosition ( nextToken . getStart ( sourceFile ) ) . line ; return startLine !== endLine ; } export function positionIsASICandidate ( pos , context , sourceFile ) { const contextAncestor = findAncestor ( context , ancestor => { if ( ancestor . end !== pos ) { return "quit" ; } return syntaxMayBeASICandidate ( ancestor . kind ) ; } ) ; return ! ! contextAncestor && nodeIsASICandidate ( contextAncestor , sourceFile ) ; } export function probablyUsesSemicolons ( sourceFile ) { let withSemicolon = 0 ; let withoutSemicolon = 0 ; const nStatementsToObserve = 5 ; forEachChild ( sourceFile , function visit ( node ) : boolean | undefined { if ( syntaxRequiresTrailingSemicolonOrASI ( node . kind ) ) { const lastToken = node . getLastToken ( sourceFile ) ; if ( lastToken ?. kind === SyntaxKind . SemicolonToken ) { withSemicolon ++ ; } else { withoutSemicolon ++ ; } } else if ( syntaxRequiresTrailingCommaOrSemicolonOrASI ( node . kind ) ) { const lastToken = node . getLastToken ( sourceFile ) ; if ( lastToken ?. kind === SyntaxKind . SemicolonToken ) { withSemicolon ++ ; } else if ( lastToken && lastToken . kind !== SyntaxKind . CommaToken ) { const lastTokenLine = getLineAndCharacterOfPosition ( sourceFile , lastToken . getStart ( sourceFile ) ) . line ; const nextTokenLine = getLineAndCharacterOfPosition ( sourceFile , getSpanOfTokenAtPosition ( sourceFile , lastToken . end ) . start ) . line ; if ( lastTokenLine !== nextTokenLine ) { withoutSemicolon ++ ; } } } if ( withSemicolon + withoutSemicolon >= nStatementsToObserve ) { return true ; } return forEachChild ( node , visit ) ; } ) ; if ( withSemicolon === 0 && withoutSemicolon <= 1 ) { return true ; } return withSemicolon / withoutSemicolon > 1 / nStatementsToObserve ; } export function tryGetDirectories ( host , directoryName ) { return tryIOAndConsumeErrors ( host , host . getDirectories , directoryName ) || [ ] ; } export function tryReadDirectory ( host , path , extensions ? , exclude ? , include ? ) { return tryIOAndConsumeErrors ( host , host . readDirectory , path , extensions , exclude , include ) || emptyArray ; } export function tryFileExists ( host , path ) { return tryIOAndConsumeErrors ( host , host . fileExists , path ) ; } export function tryDirectoryExists ( host , path ) { return tryAndIgnoreErrors ( ( ) => directoryProbablyExists ( path , host ) ) || false ; } export function tryAndIgnoreErrors < T > ( cb ) { try { return cb ( ) ; } catch { return undefined ; } } export function tryIOAndConsumeErrors < T > ( host , toApply , ... args ) { return tryAndIgnoreErrors ( ( ) => toApply && toApply . apply ( host , args ) ) ; } export function findPackageJsons ( startDirectory , host , stopDirectory ? ) { const paths = [ ] ; forEachAncestorDirectory ( startDirectory , ancestor => { if ( ancestor === stopDirectory ) { return true ; } const currentConfigPath = combinePaths ( ancestor , "package.json" ) ; if ( tryFileExists ( host , currentConfigPath ) ) { paths . push ( currentConfigPath ) ; } } ) ; return paths ; } export function findPackageJson ( directory , host ) { let packageJson ; forEachAncestorDirectory ( directory , ancestor => { if ( ancestor === "node_modules" ) return true ; packageJson = findConfigFile ( ancestor , ( f ) => tryFileExists ( host , f ) , "package.json" ) ; if ( packageJson ) { return true ; } } ) ; return packageJson ; } export function getPackageJsonsVisibleToFile ( fileName , host ) { if ( ! host . fileExists ) { return [ ] ; } const packageJsons = [ ] ; forEachAncestorDirectory ( getDirectoryPath ( fileName ) , ancestor => { const packageJsonFileName = combinePaths ( ancestor , "package.json" ) ; if ( host . fileExists ! ( packageJsonFileName ) ) { const info = createPackageJsonInfo ( packageJsonFileName , host ) ; if ( info ) { packageJsons . push ( info ) ; } } } ) ; return packageJsons ; } export function createPackageJsonInfo ( fileName , host ) { if ( ! host . readFile ) { return undefined ; } type PackageJsonRaw = Record < typeof dependencyKeys [ number ] , Record < string , string > | undefined > ; const dependencyKeys = [ "dependencies" , "devDependencies" , "optionalDependencies" , "peerDependencies" ] as const ; const stringContent = host . readFile ( fileName ) || "" ; const content = tryParseJson ( stringContent ) as PackageJsonRaw | undefined ; const info = { } ; if ( content ) { for ( const key of dependencyKeys ) { const dependencies = content [ key ] ; if ( ! dependencies ) { continue ; } const dependencyMap = new Map < string , string > ( ) ; for ( const packageName in dependencies ) { dependencyMap . set ( packageName , dependencies [ packageName ] ) ; } info [ key ] = dependencyMap ; } } const dependencyGroups = [ [ PackageJsonDependencyGroup . Dependencies , info . dependencies ] , [ PackageJsonDependencyGroup . DevDependencies , info . devDependencies ] , [ PackageJsonDependencyGroup . OptionalDependencies , info . optionalDependencies ] , [ PackageJsonDependencyGroup . PeerDependencies , info . peerDependencies ] , ] as const ; return { ... info , parseable : ! ! content , fileName , get , has ( dependencyName , inGroups ) { return ! ! get ( dependencyName , inGroups ) ; } , } ; function get ( dependencyName , inGroups = PackageJsonDependencyGroup . All ) { for ( const [ group , deps ] of dependencyGroups ) { if ( deps && ( inGroups & group ) ) { const dep = deps . get ( dependencyName ) ; if ( dep !== undefined ) { return dep ; } } } } } export interface PackageJsonImportFilter { allowsImportingAmbientModule : ( moduleSymbol : Symbol , moduleSpecifierResolutionHost : ModuleSpecifierResolutionHost ) => boolean ; allowsImportingSourceFile : ( sourceFile : SourceFile , moduleSpecifierResolutionHost : ModuleSpecifierResolutionHost ) => boolean ; /**
         * Use for a specific module specifier that has already been resolved.
         * Use `allowsImportingAmbientModule` or `allowsImportingSourceFile` to resolve
         * the best module specifier for a given module _and_ determine if it’s importable.
         */ allowsImportingSpecifier : ( moduleSpecifier : string ) => boolean ; } export function createPackageJsonImportFilter ( fromFile , preferences , host ) { const packageJsons = ( ( host . getPackageJsonsVisibleToFile && host . getPackageJsonsVisibleToFile ( fromFile . fileName ) ) || getPackageJsonsVisibleToFile ( fromFile . fileName , host ) ) . filter ( p => p . parseable ) ; let usesNodeCoreModules ; return { allowsImportingAmbientModule , allowsImportingSourceFile , allowsImportingSpecifier } ; function moduleSpecifierIsCoveredByPackageJson ( specifier ) { const packageName = getNodeModuleRootSpecifier ( specifier ) ; for ( const packageJson of packageJsons ) { if ( packageJson . has ( packageName ) || packageJson . has ( getTypesPackageName ( packageName ) ) ) { return true ; } } return false ; } function allowsImportingAmbientModule ( moduleSymbol , moduleSpecifierResolutionHost ) { if ( ! packageJsons . length || ! moduleSymbol . valueDeclaration ) { return true ; } const declaringSourceFile = moduleSymbol . valueDeclaration . getSourceFile ( ) ; const declaringNodeModuleName = getNodeModulesPackageNameFromFileName ( declaringSourceFile . fileName , moduleSpecifierResolutionHost ) ; if ( typeof declaringNodeModuleName === "undefined" ) { return true ; } const declaredModuleSpecifier = stripQuotes ( moduleSymbol . getName ( ) ) ; if ( isAllowedCoreNodeModulesImport ( declaredModuleSpecifier ) ) { return true ; } return moduleSpecifierIsCoveredByPackageJson ( declaringNodeModuleName ) || moduleSpecifierIsCoveredByPackageJson ( declaredModuleSpecifier ) ; } function allowsImportingSourceFile ( sourceFile , moduleSpecifierResolutionHost ) { if ( ! packageJsons . length ) { return true ; } const moduleSpecifier = getNodeModulesPackageNameFromFileName ( sourceFile . fileName , moduleSpecifierResolutionHost ) ; if ( ! moduleSpecifier ) { return true ; } return moduleSpecifierIsCoveredByPackageJson ( moduleSpecifier ) ; } function allowsImportingSpecifier ( moduleSpecifier ) { if ( ! packageJsons . length || isAllowedCoreNodeModulesImport ( moduleSpecifier ) ) { return true ; } if ( pathIsRelative ( moduleSpecifier ) || isRootedDiskPath ( moduleSpecifier ) ) { return true ; } return moduleSpecifierIsCoveredByPackageJson ( moduleSpecifier ) ; } function isAllowedCoreNodeModulesImport ( moduleSpecifier ) { if ( isSourceFileJS ( fromFile ) && JsTyping . nodeCoreModules . has ( moduleSpecifier ) ) { if ( usesNodeCoreModules === undefined ) { usesNodeCoreModules = consumesNodeCoreModules ( fromFile ) ; } if ( usesNodeCoreModules ) { return true ; } } return false ; } function getNodeModulesPackageNameFromFileName ( importedFileName , moduleSpecifierResolutionHost ) { if ( ! stringContains ( importedFileName , "node_modules" ) ) { return undefined ; } const specifier = moduleSpecifiers . getNodeModulesPackageName ( host . getCompilationSettings ( ) , fromFile , importedFileName , moduleSpecifierResolutionHost , preferences ) ; if ( ! specifier ) { return undefined ; } if ( ! pathIsRelative ( specifier ) && ! isRootedDiskPath ( specifier ) ) { return getNodeModuleRootSpecifier ( specifier ) ; } } function getNodeModuleRootSpecifier ( fullSpecifier ) { const components = getPathComponents ( getPackageNameFromTypesPackageName ( fullSpecifier ) ) . slice ( 1 ) ; if ( startsWith ( components [ 0 ] , "@" ) ) { return `${ components [ 0 ] }/${ components [ 1 ] }` ; } return components [ 0 ] ; } } function tryParseJson ( text ) { try { return JSON . parse ( text ) ; } catch { return undefined ; } } export function consumesNodeCoreModules ( sourceFile ) { return some ( sourceFile . imports , ( { text } ) => JsTyping . nodeCoreModules . has ( text ) ) ; } export function isInsideNodeModules ( fileOrDirectory ) { return contains ( getPathComponents ( fileOrDirectory ) , "node_modules" ) ; } export function isDiagnosticWithLocation ( diagnostic ) { return diagnostic . file !== undefined && diagnostic . start !== undefined && diagnostic . length !== undefined ; } export function findDiagnosticForNode ( node , sortedFileDiagnostics ) { const span = createTextSpanFromNode ( node ) ; const index = binarySearchKey ( sortedFileDiagnostics , span , identity , compareTextSpans ) ; if ( index >= 0 ) { const diagnostic = sortedFileDiagnostics [ index ] ; Debug . assertEqual ( diagnostic . file , node . getSourceFile ( ) , "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile" ) ; return cast ( diagnostic , isDiagnosticWithLocation ) ; } } export function getDiagnosticsWithinSpan ( span , sortedFileDiagnostics ) { let index = binarySearchKey ( sortedFileDiagnostics , span . start , diag => diag . start , compareValues ) ; if ( index < 0 ) { index = ~ index ; } while ( sortedFileDiagnostics [ index - 1 ] ?. start === span . start ) { index -- ; } const result = [ ] ; const end = textSpanEnd ( span ) ; while ( true ) { const diagnostic = tryCast ( sortedFileDiagnostics [ index ] , isDiagnosticWithLocation ) ; if ( ! diagnostic || diagnostic . start > end ) { break ; } if ( textSpanContainsTextSpan ( span , diagnostic ) ) { result . push ( diagnostic ) ; } index ++ ; } return result ; } export function getRefactorContextSpan ( { startPosition , endPosition } ) { return createTextSpanFromBounds ( startPosition , endPosition === undefined ? startPosition : endPosition ) ; } export function getFixableErrorSpanExpression ( sourceFile , span ) { const token = getTokenAtPosition ( sourceFile , span . start ) ; const expression = findAncestor ( token , node => { if ( node . getStart ( sourceFile ) < span . start || node . getEnd ( ) > textSpanEnd ( span ) ) { return "quit" ; } return isExpression ( node ) && textSpansEqual ( span , createTextSpanFromNode ( node , sourceFile ) ) ; } ) as Expression | undefined ; return expression ; } /**
     * If the provided value is an array, the mapping function is applied to each element; otherwise, the mapping function is applied
     * to the provided value itself.
     */ export function mapOneOrMany < T , U > ( valueOrArray , f ) ; export function mapOneOrMany < T , U > ( valueOrArray , f ) ; export function mapOneOrMany < T , U > ( valueOrArray , f , resultSelector ) ; export function mapOneOrMany < T , U > ( valueOrArray , f , resultSelector ) ; export function mapOneOrMany < T , U > ( valueOrArray , f , resultSelector = identity ) { return valueOrArray ? isArray ( valueOrArray ) ? resultSelector ( map ( valueOrArray , f ) ) : f ( valueOrArray , 0 ) : undefined ; } /**
     * If the provided value is an array, the first element of the array is returned; otherwise, the provided value is returned instead.
     */ export function firstOrOnly < T > ( valueOrArray ) { return isArray ( valueOrArray ) ? first ( valueOrArray ) : valueOrArray ; } export function getNameForExportedSymbol ( symbol , scriptTarget ) { if ( ! ( symbol . flags & SymbolFlags . Transient ) && ( symbol . escapedName === InternalSymbolName . ExportEquals || symbol . escapedName === InternalSymbolName . Default ) ) { return firstDefined ( symbol . declarations , d => isExportAssignment ( d ) ? tryCast ( skipOuterExpressions ( d . expression ) , isIdentifier ) ?. text : undefined ) || codefix . moduleSymbolToValidIdentifier ( getSymbolParentOrFail ( symbol ) , scriptTarget ) ; } return symbol . name ; } function getSymbolParentOrFail ( symbol ) { return Debug . checkDefined ( symbol . parent , `Symbol parent was undefined. Flags: ${ Debug . formatSymbolFlags ( symbol . flags ) }. ` + `Declarations: ${ symbol . declarations ?. map ( d => { const kind = Debug . formatSyntaxKind ( d . kind ) ; const inJS = isInJSFile ( d ) ; const { expression } = d as any ; return ( inJS ? "[JS]" : "" ) + kind + ( expression ? ` (expression: ${ Debug . formatSyntaxKind ( expression . kind ) })` : "" ) ; } ) . join ( ", " ) }.` ) ; } param haystack param needle param startIndex export function stringContainsAt ( haystack , needle , startIndex ) { const needleLength = needle . length ; if ( needleLength + startIndex > haystack . length ) { return false ; } for ( let i = 0 ; i < needleLength ; i ++ ) { if ( needle . charCodeAt ( i ) !== haystack . charCodeAt ( i + startIndex ) ) return false ; } return true ; } export function startsWithUnderscore ( name ) { return name . charCodeAt ( 0 ) === CharacterCodes . _ ; } export function isGlobalDeclaration ( declaration ) { return ! isNonGlobalDeclaration ( declaration ) ; } export function isNonGlobalDeclaration ( declaration ) { const sourceFile = declaration . getSourceFile ( ) ; if ( ! sourceFile . externalModuleIndicator && ! sourceFile . commonJsModuleIndicator ) { return false ; } return isInJSFile ( declaration ) || ! findAncestor ( declaration , isGlobalScopeAugmentation ) ; } export function isDeprecatedDeclaration ( decl ) { return ! ! ( getCombinedNodeFlagsAlwaysIncludeJSDoc ( decl ) & ModifierFlags . Deprecated ) ; } export function shouldUseUriStyleNodeCoreModules ( file , program ) { const decisionFromFile = firstDefined ( file . imports , node => { if ( JsTyping . nodeCoreModules . has ( node . text ) ) { return startsWith ( node . text , "node:" ) ; } } ) ; return decisionFromFile ?? program . usesUriStyleNodeCoreModules ; } export function getNewLineKind ( newLineCharacter ) { return newLineCharacter === "\n" ? NewLineKind . LineFeed : NewLineKind . CarriageReturnLineFeed ; } export type DiagnosticAndArguments = DiagnosticMessage | [ DiagnosticMessage , string ] | [ DiagnosticMessage , string , string ] ; export function diagnosticToString ( diag ) { return isArray ( diag ) ? formatStringFromArgs ( getLocaleSpecificMessage ( diag [ 0 ] ) , diag . slice ( 1 ) as readonly string [ ] ) : getLocaleSpecificMessage ( diag ) ; } /**
     * Get format code settings for a code writing context (e.g. when formatting text changes or completions code).
     */ export function getFormatCodeSettingsForWriting ( { options } , sourceFile ) { const shouldAutoDetectSemicolonPreference = ! options . semicolons || options . semicolons === SemicolonPreference . Ignore ; const shouldRemoveSemicolons = options . semicolons === SemicolonPreference . Remove || shouldAutoDetectSemicolonPreference && ! probablyUsesSemicolons ( sourceFile ) ; return { ... options , semicolons : shouldRemoveSemicolons ? SemicolonPreference . Remove : SemicolonPreference . Ignore , } ; } }