namespace ts . Completions { export const moduleSpecifierResolutionLimit = 100 ; export const moduleSpecifierResolutionCacheAttemptLimit = 1000 ; export type Log = ( message : string ) => void ; export enum SortText { LocalDeclarationPriority = "10" , LocationPriority = "11" , OptionalMember = "12" , MemberDeclaredBySpreadAssignment = "13" , SuggestedClassMembers = "14" , GlobalsOrKeywords = "15" , AutoImportSuggestions = "16" , JavascriptIdentifiers = "17" , DeprecatedLocalDeclarationPriority = "18" , DeprecatedLocationPriority = "19" , DeprecatedOptionalMember = "20" , DeprecatedMemberDeclaredBySpreadAssignment = "21" , DeprecatedSuggestedClassMembers = "22" , DeprecatedGlobalsOrKeywords = "23" , DeprecatedAutoImportSuggestions = "24" } const enum SortTextId { LocalDeclarationPriority = 10 , LocationPriority = 11 , OptionalMember = 12 , MemberDeclaredBySpreadAssignment = 13 , SuggestedClassMembers = 14 , GlobalsOrKeywords = 15 , AutoImportSuggestions = 16 , _JavaScriptIdentifiers = 17 , _DeprecatedStart = 18 , _First = LocalDeclarationPriority , DeprecatedOffset = _DeprecatedStart - _First } /**
     * Special values for `CompletionInfo['source']` used to disambiguate
     * completion items with the same `name`. (Each completion item must
     * have a unique name/source combination, because those two fields
     * comprise `CompletionEntryIdentifier` in `getCompletionEntryDetails`.
     *
     * When the completion item is an auto-import suggestion, the source
     * is the module specifier of the suggestion. To avoid collisions,
     * the values here should not be a module specifier we would ever
     * generate for an auto-import.
     */ export enum CompletionSource { /** Completions that require `this.` insertion text */ ThisProperty = "ThisProperty/" , /** Auto-import that comes attached to a class member snippet */ ClassMemberSnippet = "ClassMemberSnippet/" } const enum SymbolOriginInfoKind { ThisType = 1 << 0 , SymbolMember = 1 << 1 , Export = 1 << 2 , Promise = 1 << 3 , Nullable = 1 << 4 , ResolvedExport = 1 << 5 , SymbolMemberNoExport = SymbolMember , SymbolMemberExport = SymbolMember | Export } interface SymbolOriginInfo { kind : SymbolOriginInfoKind ; isDefaultExport ? : boolean ; isFromPackageJson ? : boolean ; fileName ? : string ; } interface SymbolOriginInfoExport extends SymbolOriginInfo { symbolName : string ; moduleSymbol : Symbol ; isDefaultExport : boolean ; exportName : string ; exportMapKey : string ; } interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo { symbolName : string ; moduleSymbol : Symbol ; exportName : string ; moduleSpecifier : string ; } function originIsThisType ( origin ) { return ! ! ( origin . kind & SymbolOriginInfoKind . ThisType ) ; } function originIsSymbolMember ( origin ) { return ! ! ( origin . kind & SymbolOriginInfoKind . SymbolMember ) ; } function originIsExport ( origin ) { return ! ! ( origin && origin . kind & SymbolOriginInfoKind . Export ) ; } function originIsResolvedExport ( origin ) { return ! ! ( origin && origin . kind === SymbolOriginInfoKind . ResolvedExport ) ; } function originIncludesSymbolName ( origin ) { return originIsExport ( origin ) || originIsResolvedExport ( origin ) ; } function originIsPackageJsonImport ( origin ) { return ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) && ! ! origin . isFromPackageJson ; } function originIsPromise ( origin ) { return ! ! ( origin . kind & SymbolOriginInfoKind . Promise ) ; } function originIsNullableMember ( origin ) { return ! ! ( origin . kind & SymbolOriginInfoKind . Nullable ) ; } interface UniqueNameSet { add ( name ) : void ; has ( name ) : boolean ; } /**
     * Map from symbol index in `symbols` -> SymbolOriginInfo.
     * Only populated for symbols that come from other modules.
     */ type SymbolOriginInfoMap = Record < number , SymbolOriginInfo > ; /** Map from symbol id -> SortTextId. */ type SymbolSortTextIdMap = ( SortTextId | undefined ) [ ] ; const enum KeywordCompletionFilters { None , All , ClassElementKeywords , InterfaceElementKeywords , ConstructorParameterKeywords , FunctionLikeBodyKeywords , TypeAssertionKeywords , TypeKeywords , TypeKeyword , Last = TypeKeywords } const enum GlobalsSearch { Continue , Success , Fail } interface ModuleSpecifierResolutioContext { tryResolve : ( exportInfo : readonly SymbolExportInfo [ ] , isFromAmbientModule : boolean ) => ModuleSpecifierResolutionResult | undefined ; resolutionLimitExceeded : ( ) => boolean ; } interface ModuleSpecifierResolutionResult { exportInfo ? : SymbolExportInfo ; moduleSpecifier : string ; } function resolvingModuleSpecifiers < TReturn > ( logPrefix , host , program , sourceFile , preferences , isForImportStatementCompletion , cb ) { const start = timestamp ( ) ; let resolutionLimitExceeded = false ; let ambientCount = 0 ; let resolvedCount = 0 ; let resolvedFromCacheCount = 0 ; let cacheAttemptCount = 0 ; const result = cb ( { tryResolve , resolutionLimitExceeded : ( ) => resolutionLimitExceeded } ) ; const hitRateMessage = cacheAttemptCount ? ` (${ ( resolvedFromCacheCount / cacheAttemptCount * 100 ) . toFixed ( 1 ) }% hit rate)` : "" ; host . log ?. ( `${ logPrefix }: resolved ${ resolvedCount } module specifiers, plus ${ ambientCount } ambient and ${ resolvedFromCacheCount } from cache${ hitRateMessage }` ) ; host . log ?. ( `${ logPrefix }: response is ${ resolutionLimitExceeded ? "incomplete" : "complete" }` ) ; host . log ?. ( `${ logPrefix }: ${ timestamp ( ) - start }` ) ; return result ; function tryResolve ( exportInfo , isFromAmbientModule ) { if ( isFromAmbientModule ) { const result = codefix . getModuleSpecifierForBestExportInfo ( exportInfo , sourceFile , program , host , preferences ) ; if ( result ) { ambientCount ++ ; } return result ; } const shouldResolveModuleSpecifier = isForImportStatementCompletion || preferences . allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit ; const shouldGetModuleSpecifierFromCache = ! shouldResolveModuleSpecifier && preferences . allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit ; const result = ( shouldResolveModuleSpecifier || shouldGetModuleSpecifierFromCache ) ? codefix . getModuleSpecifierForBestExportInfo ( exportInfo , sourceFile , program , host , preferences , shouldGetModuleSpecifierFromCache ) : undefined ; if ( ! shouldResolveModuleSpecifier && ! shouldGetModuleSpecifierFromCache || shouldGetModuleSpecifierFromCache && ! result ) { resolutionLimitExceeded = true ; } resolvedCount += result ?. computedWithoutCacheCount || 0 ; resolvedFromCacheCount += exportInfo . length - resolvedCount ; if ( shouldGetModuleSpecifierFromCache ) { cacheAttemptCount ++ ; } return result ; } } export function getCompletionsAtPosition ( host , program , log , sourceFile , position , preferences , triggerCharacter , completionKind , cancellationToken , formatContext ? ) { const { previousToken } = getRelevantTokens ( position , sourceFile ) ; if ( triggerCharacter && ! isInString ( sourceFile , position , previousToken ) && ! isValidTrigger ( sourceFile , triggerCharacter , previousToken , position ) ) { return undefined ; } if ( triggerCharacter === " " ) { if ( preferences . includeCompletionsForImportStatements && preferences . includeCompletionsWithInsertText ) { return { isGlobalCompletion : true , isMemberCompletion : false , isNewIdentifierLocation : true , isIncomplete : true , entries : [ ] } ; } return undefined ; } const compilerOptions = program . getCompilerOptions ( ) ; const incompleteCompletionsCache = preferences . allowIncompleteCompletions ? host . getIncompleteCompletionsCache ?. ( ) : undefined ; if ( incompleteCompletionsCache && completionKind === CompletionTriggerKind . TriggerForIncompleteCompletions && previousToken && isIdentifier ( previousToken ) ) { const incompleteContinuation = continuePreviousIncompleteResponse ( incompleteCompletionsCache , sourceFile , previousToken , program , host , preferences , cancellationToken ) ; if ( incompleteContinuation ) { return incompleteContinuation ; } } else { incompleteCompletionsCache ?. clear ( ) ; } const stringCompletions = StringCompletions . getStringLiteralCompletions ( sourceFile , position , previousToken , compilerOptions , host , program , log , preferences ) ; if ( stringCompletions ) { return stringCompletions ; } if ( previousToken && isBreakOrContinueStatement ( previousToken . parent ) && ( previousToken . kind === SyntaxKind . BreakKeyword || previousToken . kind === SyntaxKind . ContinueKeyword || previousToken . kind === SyntaxKind . Identifier ) ) { return getLabelCompletionAtPosition ( previousToken . parent ) ; } const completionData = getCompletionData ( program , log , sourceFile , isUncheckedFile ( sourceFile , compilerOptions ) , position , preferences , undefined , host , cancellationToken ) ; if ( ! completionData ) { return undefined ; } switch ( completionData . kind ) { case CompletionDataKind . Data : const response = completionInfoFromData ( sourceFile , host , program , compilerOptions , log , completionData , preferences , formatContext ) ; if ( response ?. isIncomplete ) { incompleteCompletionsCache ?. set ( response ) ; } return response ; case CompletionDataKind . JsDocTagName : return jsdocCompletionInfo ( JsDoc . getJSDocTagNameCompletions ( ) ) ; case CompletionDataKind . JsDocTag : return jsdocCompletionInfo ( JsDoc . getJSDocTagCompletions ( ) ) ; case CompletionDataKind . JsDocParameterName : return jsdocCompletionInfo ( JsDoc . getJSDocParameterNameCompletions ( completionData . tag ) ) ; case CompletionDataKind . Keywords : return specificKeywordCompletionInfo ( completionData . keywordCompletions , completionData . isNewIdentifierLocation ) ; default : return Debug . assertNever ( completionData ) ; } } function compareCompletionEntries ( entryInArray , entryToInsert ) { let result = compareStringsCaseSensitiveUI ( entryInArray . sortText , entryToInsert . sortText ) ; if ( result === Comparison . EqualTo ) { result = compareStringsCaseSensitiveUI ( entryInArray . name , entryToInsert . name ) ; } if ( result === Comparison . EqualTo && entryInArray . data ?. moduleSpecifier && entryToInsert . data ?. moduleSpecifier ) { result = compareNumberOfDirectorySeparators ( ( entryInArray . data as CompletionEntryDataResolved ) . moduleSpecifier , ( entryToInsert . data as CompletionEntryDataResolved ) . moduleSpecifier ) ; } if ( result === Comparison . EqualTo ) { return Comparison . LessThan ; } return result ; } function completionEntryDataIsResolved ( data ) { return ! ! data ?. moduleSpecifier ; } function continuePreviousIncompleteResponse ( cache , file , location , program , host , preferences , cancellationToken ) { const previousResponse = cache . get ( ) ; if ( ! previousResponse ) return undefined ; const lowerCaseTokenText = location . text . toLowerCase ( ) ; const exportMap = getExportInfoMap ( file , host , program , cancellationToken ) ; const newEntries = resolvingModuleSpecifiers ( "continuePreviousIncompleteResponse" , host , program , file , preferences , false , context => { const entries = mapDefined ( previousResponse . entries , entry => { if ( ! entry . hasAction || ! entry . source || ! entry . data || completionEntryDataIsResolved ( entry . data ) ) { return entry ; } if ( ! charactersFuzzyMatchInString ( entry . name , lowerCaseTokenText ) ) { return undefined ; } const { origin } = Debug . checkDefined ( getAutoImportSymbolFromCompletionEntryData ( entry . name , entry . data , program , host ) ) ; const info = exportMap . get ( file . path , entry . data . exportMapKey ) ; const result = info && context . tryResolve ( info , ! isExternalModuleNameRelative ( stripQuotes ( origin . moduleSymbol . name ) ) ) ; if ( ! result ) return entry ; const newOrigin = { ... origin , kind : SymbolOriginInfoKind . ResolvedExport , moduleSpecifier : result . moduleSpecifier , } ; entry . data = originToCompletionEntryData ( newOrigin ) ; entry . source = getSourceFromOrigin ( newOrigin ) ; entry . sourceDisplay = [ textPart ( newOrigin . moduleSpecifier ) ] ; return entry ; } ) ; if ( ! context . resolutionLimitExceeded ( ) ) { previousResponse . isIncomplete = undefined ; } return entries ; } ) ; previousResponse . entries = newEntries ; return previousResponse ; } function jsdocCompletionInfo ( entries ) { return { isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false , entries } ; } function keywordToCompletionEntry ( keyword ) { return { name : tokenToString ( keyword ) ! , kind : ScriptElementKind . keyword , kindModifiers : ScriptElementKindModifier . none , sortText : SortText . GlobalsOrKeywords , } ; } function specificKeywordCompletionInfo ( entries , isNewIdentifierLocation ) { return { isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation , entries : entries . slice ( ) , } ; } function keywordCompletionData ( keywordFilters , filterOutTsOnlyKeywords , isNewIdentifierLocation ) { return { kind : CompletionDataKind . Keywords , keywordCompletions : getKeywordCompletions ( keywordFilters , filterOutTsOnlyKeywords ) , isNewIdentifierLocation , } ; } function keywordFiltersFromSyntaxKind ( keywordCompletion ) { switch ( keywordCompletion ) { case SyntaxKind . TypeKeyword : return KeywordCompletionFilters . TypeKeyword ; default : Debug . fail ( "Unknown mapping from SyntaxKind to KeywordCompletionFilters" ) ; } } function getOptionalReplacementSpan ( location ) { return location ?. kind === SyntaxKind . Identifier ? createTextSpanFromNode ( location ) : undefined ; } function completionInfoFromData ( sourceFile , host , program , compilerOptions , log , completionData , preferences , formatContext ) { const { symbols , contextToken , completionKind , isInSnippetScope , isNewIdentifierLocation , location , propertyAccessToConvert , keywordFilters , literals , symbolToOriginInfoMap , recommendedCompletion , isJsxInitializer , isTypeOnlyLocation , isJsxIdentifierExpected , isRightOfOpenTag , importCompletionNode , insideJsDocTagTypeExpression , symbolToSortTextIdMap , hasUnresolvedAutoImports , } = completionData ; if ( getLanguageVariant ( sourceFile . scriptKind ) === LanguageVariant . JSX ) { const completionInfo = getJsxClosingTagCompletion ( location , sourceFile ) ; if ( completionInfo ) { return completionInfo ; } } const entries = createSortedArray < CompletionEntry > ( ) ; if ( isUncheckedFile ( sourceFile , compilerOptions ) ) { const uniqueNames = getCompletionEntriesFromSymbols ( symbols , entries , undefined , contextToken , location , sourceFile , host , program , getEmitScriptTarget ( compilerOptions ) , log , completionKind , preferences , compilerOptions , formatContext , isTypeOnlyLocation , propertyAccessToConvert , isJsxIdentifierExpected , isJsxInitializer , importCompletionNode , recommendedCompletion , symbolToOriginInfoMap , symbolToSortTextIdMap , isJsxIdentifierExpected , isRightOfOpenTag ) ; getJSCompletionEntries ( sourceFile , location . pos , uniqueNames , getEmitScriptTarget ( compilerOptions ) , entries ) ; } else { if ( ! isNewIdentifierLocation && ( ! symbols || symbols . length === 0 ) && keywordFilters === KeywordCompletionFilters . None ) { return undefined ; } getCompletionEntriesFromSymbols ( symbols , entries , undefined , contextToken , location , sourceFile , host , program , getEmitScriptTarget ( compilerOptions ) , log , completionKind , preferences , compilerOptions , formatContext , isTypeOnlyLocation , propertyAccessToConvert , isJsxIdentifierExpected , isJsxInitializer , importCompletionNode , recommendedCompletion , symbolToOriginInfoMap , symbolToSortTextIdMap , isJsxIdentifierExpected , isRightOfOpenTag ) ; } if ( keywordFilters !== KeywordCompletionFilters . None ) { const entryNames = new Set ( entries . map ( e => e . name ) ) ; for ( const keywordEntry of getKeywordCompletions ( keywordFilters , ! insideJsDocTagTypeExpression && isSourceFileJS ( sourceFile ) ) ) { if ( ! entryNames . has ( keywordEntry . name ) ) { insertSorted ( entries , keywordEntry , compareCompletionEntries , true ) ; } } } for ( const literal of literals ) { insertSorted ( entries , createCompletionEntryForLiteral ( sourceFile , preferences , literal ) , compareCompletionEntries , true ) ; } return { isGlobalCompletion : isInSnippetScope , isIncomplete : preferences . allowIncompleteCompletions && hasUnresolvedAutoImports ? true : undefined , isMemberCompletion : isMemberCompletionKind ( completionKind ) , isNewIdentifierLocation , optionalReplacementSpan : getOptionalReplacementSpan ( location ) , entries } ; } function isUncheckedFile ( sourceFile , compilerOptions ) { return isSourceFileJS ( sourceFile ) && ! isCheckJsEnabledForFile ( sourceFile , compilerOptions ) ; } function isMemberCompletionKind ( kind ) { switch ( kind ) { case CompletionKind . ObjectPropertyDeclaration : case CompletionKind . MemberLike : case CompletionKind . PropertyAccess : return true ; default : return false ; } } function getJsxClosingTagCompletion ( location , sourceFile ) { const jsxClosingElement = findAncestor ( location , node => { switch ( node . kind ) { case SyntaxKind . JsxClosingElement : return true ; case SyntaxKind . SlashToken : case SyntaxKind . GreaterThanToken : case SyntaxKind . Identifier : case SyntaxKind . PropertyAccessExpression : return false ; default : return "quit" ; } } ) as JsxClosingElement | undefined ; if ( jsxClosingElement ) { const hasClosingAngleBracket = ! ! findChildOfKind ( jsxClosingElement , SyntaxKind . GreaterThanToken , sourceFile ) ; const tagName = jsxClosingElement . parent . openingElement . tagName ; const closingTag = tagName . getText ( sourceFile ) ; const fullClosingTag = closingTag + ( hasClosingAngleBracket ? "" : ">" ) ; const replacementSpan = createTextSpanFromNode ( jsxClosingElement . tagName ) ; const entry = { name : fullClosingTag , kind : ScriptElementKind . classElement , kindModifiers : undefined , sortText : SortText . LocationPriority , } ; return { isGlobalCompletion : false , isMemberCompletion : true , isNewIdentifierLocation : false , optionalReplacementSpan : replacementSpan , entries : [ entry ] } ; } return ; } function getJSCompletionEntries ( sourceFile , position , uniqueNames , target , entries ) { getNameTable ( sourceFile ) . forEach ( ( pos , name ) => { if ( pos === position ) { return ; } const realName = unescapeLeadingUnderscores ( name ) ; if ( ! uniqueNames . has ( realName ) && isIdentifierText ( realName , target ) ) { uniqueNames . add ( realName ) ; insertSorted ( entries , { name : realName , kind : ScriptElementKind . warning , kindModifiers : "" , sortText : SortText . JavascriptIdentifiers , isFromUncheckedFile : true } , compareCompletionEntries ) ; } } ) ; } function completionNameForLiteral ( sourceFile , preferences , literal ) { return typeof literal === "object" ? pseudoBigIntToString ( literal ) + "n" : isString ( literal ) ? quote ( sourceFile , preferences , literal ) : JSON . stringify ( literal ) ; } function createCompletionEntryForLiteral ( sourceFile , preferences , literal ) { return { name : completionNameForLiteral ( sourceFile , preferences , literal ) , kind : ScriptElementKind . string , kindModifiers : ScriptElementKindModifier . none , sortText : SortText . LocationPriority } ; } function createCompletionEntry ( symbol , sortText , replacementToken , contextToken , location , sourceFile , host , program , name , needsConvertPropertyAccess , origin , recommendedCompletion , propertyAccessToConvert , isJsxInitializer , importCompletionNode , useSemicolons , options , preferences , completionKind , formatContext , isJsxIdentifierExpected , isRightOfOpenTag ) { let insertText ; let replacementSpan = getReplacementSpanForContextToken ( replacementToken ) ; let data ; let isSnippet ; let source = getSourceFromOrigin ( origin ) ; let sourceDisplay ; let hasAction ; const typeChecker = program . getTypeChecker ( ) ; const insertQuestionDot = origin && originIsNullableMember ( origin ) ; const useBraces = origin && originIsSymbolMember ( origin ) || needsConvertPropertyAccess ; if ( origin && originIsThisType ( origin ) ) { insertText = needsConvertPropertyAccess ? `this${ insertQuestionDot ? "?." : "" }[${ quotePropertyName ( sourceFile , preferences , name ) }]` : `this${ insertQuestionDot ? "?." : "." }${ name }` ; } else if ( ( useBraces || insertQuestionDot ) && propertyAccessToConvert ) { insertText = useBraces ? needsConvertPropertyAccess ? `[${ quotePropertyName ( sourceFile , preferences , name ) }]` : `[${ name }]` : name ; if ( insertQuestionDot || propertyAccessToConvert . questionDotToken ) { insertText = `?.${ insertText }` ; } const dot = findChildOfKind ( propertyAccessToConvert , SyntaxKind . DotToken , sourceFile ) || findChildOfKind ( propertyAccessToConvert , SyntaxKind . QuestionDotToken , sourceFile ) ; if ( ! dot ) { return undefined ; } const end = startsWith ( name , propertyAccessToConvert . name . text ) ? propertyAccessToConvert . name . end : dot . end ; replacementSpan = createTextSpanFromBounds ( dot . getStart ( sourceFile ) , end ) ; } if ( isJsxInitializer ) { if ( insertText === undefined ) insertText = name ; insertText = `{${ insertText }}` ; if ( typeof isJsxInitializer !== "boolean" ) { replacementSpan = createTextSpanFromNode ( isJsxInitializer , sourceFile ) ; } } if ( origin && originIsPromise ( origin ) && propertyAccessToConvert ) { if ( insertText === undefined ) insertText = name ; const precedingToken = findPrecedingToken ( propertyAccessToConvert . pos , sourceFile ) ; let awaitText = "" ; if ( precedingToken && positionIsASICandidate ( precedingToken . end , precedingToken . parent , sourceFile ) ) { awaitText = ";" ; } awaitText += `(await ${ propertyAccessToConvert . expression . getText ( ) })` ; insertText = needsConvertPropertyAccess ? `${ awaitText }${ insertText }` : `${ awaitText }${ insertQuestionDot ? "?." : "." }${ insertText }` ; replacementSpan = createTextSpanFromBounds ( propertyAccessToConvert . getStart ( sourceFile ) , propertyAccessToConvert . end ) ; } if ( originIsResolvedExport ( origin ) ) { sourceDisplay = [ textPart ( origin . moduleSpecifier ) ] ; if ( importCompletionNode ) { ( { insertText , replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion ( name , importCompletionNode , contextToken , origin , useSemicolons , options , preferences ) ) ; isSnippet = preferences . includeCompletionsWithSnippetText ? true : undefined ; } } if ( preferences . includeCompletionsWithClassMemberSnippets && preferences . includeCompletionsWithInsertText && completionKind === CompletionKind . MemberLike && isClassLikeMemberCompletion ( symbol , location ) ) { let importAdder ; ( { insertText , isSnippet , importAdder } = getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken , formatContext ) ) ; if ( importAdder ?. hasFixes ( ) ) { hasAction = true ; source = CompletionSource . ClassMemberSnippet ; } } if ( isJsxIdentifierExpected && ! isRightOfOpenTag && preferences . includeCompletionsWithSnippetText && preferences . jsxAttributeCompletionStyle && preferences . jsxAttributeCompletionStyle !== "none" ) { let useBraces = preferences . jsxAttributeCompletionStyle === "braces" ; const type = typeChecker . getTypeOfSymbolAtLocation ( symbol , location ) ; if ( preferences . jsxAttributeCompletionStyle === "auto" && ! ( type . flags & TypeFlags . BooleanLike ) && ! ( type . flags & TypeFlags . Union && find ( ( type as UnionType ) . types , type => ! ! ( type . flags & TypeFlags . BooleanLike ) ) ) ) { if ( type . flags & TypeFlags . StringLike || ( type . flags & TypeFlags . Union && every ( ( type as UnionType ) . types , type => ! ! ( type . flags & ( TypeFlags . StringLike | TypeFlags . Undefined ) ) ) ) ) { insertText = `${ escapeSnippetText ( name ) }=${ quote ( sourceFile , preferences , "$1" ) }` ; isSnippet = true ; } else { useBraces = true ; } } if ( useBraces ) { insertText = `${ escapeSnippetText ( name ) }={$1}` ; isSnippet = true ; } } if ( insertText !== undefined && ! preferences . includeCompletionsWithInsertText ) { return undefined ; } if ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) { data = originToCompletionEntryData ( origin ) ; hasAction = ! importCompletionNode ; } return { name , kind : SymbolDisplay . getSymbolKind ( typeChecker , symbol , location ) , kindModifiers : SymbolDisplay . getSymbolModifiers ( typeChecker , symbol ) , sortText , source , hasAction : hasAction ? true : undefined , isRecommended : isRecommendedCompletionMatch ( symbol , recommendedCompletion , typeChecker ) || undefined , insertText , replacementSpan , sourceDisplay , isSnippet , isPackageJsonImport : originIsPackageJsonImport ( origin ) || undefined , isImportStatementCompletion : ! ! importCompletionNode || undefined , data , } ; } function isClassLikeMemberCompletion ( symbol , location ) { if ( isInJSFile ( location ) ) { return false ; } const memberFlags = SymbolFlags . ClassMember & SymbolFlags . EnumMemberExcludes ; return ! ! ( symbol . flags & memberFlags ) && ( isClassLike ( location ) || ( location . parent && location . parent . parent && isClassElement ( location . parent ) && location === location . parent . name && isClassLike ( location . parent . parent ) ) || ( location . parent && isSyntaxList ( location ) && isClassLike ( location . parent ) ) ) ; } function getEntryForMemberCompletion ( host , program , options , preferences , name , symbol , location , contextToken , formatContext ) { const classLikeDeclaration = findAncestor ( location , isClassLike ) ; if ( ! classLikeDeclaration ) { return { insertText : name } ; } let isSnippet ; let insertText = name ; const checker = program . getTypeChecker ( ) ; const sourceFile = location . getSourceFile ( ) ; const printer = createSnippetPrinter ( { removeComments : true , module : options . module , target : options . target , omitTrailingSemicolon : false , newLine : getNewLineKind ( getNewLineCharacter ( options , maybeBind ( host , host . getNewLine ) ) ) , } ) ; const importAdder = codefix . createImportAdder ( sourceFile , program , preferences , host ) ; let body ; if ( preferences . includeCompletionsWithSnippetText ) { isSnippet = true ; const emptyStmt = factory . createEmptyStatement ( ) ; body = factory . createBlock ( [ emptyStmt ] , true ) ; setSnippetElement ( emptyStmt , { kind : SnippetKind . TabStop , order : 0 } ) ; } else { body = factory . createBlock ( [ ] , true ) ; } let modifiers = ModifierFlags . None ; const isAbstract = contextToken && isModifierLike ( contextToken ) === SyntaxKind . AbstractKeyword ; const completionNodes = [ ] ; codefix . addNewNodeForMemberSymbol ( symbol , classLikeDeclaration , sourceFile , { program , host } , preferences , importAdder , node => { let requiredModifiers = ModifierFlags . None ; if ( isAbstract ) { requiredModifiers |= ModifierFlags . Abstract ; } if ( isClassElement ( node ) && checker . getMemberOverrideModifierStatus ( classLikeDeclaration , node ) === MemberOverrideStatus . NeedsOverride ) { requiredModifiers |= ModifierFlags . Override ; } let presentModifiers = ModifierFlags . None ; if ( ! completionNodes . length ) { if ( contextToken ) { presentModifiers = getPresentModifiers ( contextToken ) ; } modifiers = node . modifierFlagsCache | requiredModifiers | presentModifiers ; } node = factory . updateModifiers ( node , modifiers & ( ~ presentModifiers ) ) ; completionNodes . push ( node ) ; } , body , codefix . PreserveOptionalFlags . Property , isAbstract ) ; if ( completionNodes . length ) { if ( formatContext ) { const syntheticFile = { text : printer . printSnippetList ( ListFormat . MultiLine | ListFormat . NoTrailingNewLine , factory . createNodeArray ( completionNodes ) , sourceFile ) , getLineAndCharacterOfPosition ( pos ) { return getLineAndCharacterOfPosition ( this , pos ) ; } , } ; const formatOptions = getFormatCodeSettingsForWriting ( formatContext , sourceFile ) ; const changes = flatMap ( completionNodes , node => { const nodeWithPos = textChanges . assignPositionsToNode ( node ) ; return formatting . formatNodeGivenIndentation ( nodeWithPos , syntheticFile , sourceFile . languageVariant , 0 , 0 , { ... formatContext , options : formatOptions } ) ; } ) ; insertText = textChanges . applyChanges ( syntheticFile . text , changes ) ; } else { insertText = printer . printSnippetList ( ListFormat . MultiLine | ListFormat . NoTrailingNewLine , factory . createNodeArray ( completionNodes ) , sourceFile ) ; } } return { insertText , isSnippet , importAdder } ; } function getPresentModifiers ( contextToken ) { let modifiers = ModifierFlags . None ; let contextMod ; if ( contextMod = isModifierLike ( contextToken ) ) { modifiers |= modifierToFlag ( contextMod ) ; } if ( isPropertyDeclaration ( contextToken . parent ) ) { modifiers |= modifiersToFlags ( contextToken . parent . modifiers ) ; } return modifiers ; } function isModifierLike ( node ) { if ( isModifier ( node ) ) { return node . kind ; } if ( isIdentifier ( node ) && node . originalKeywordKind && isModifierKind ( node . originalKeywordKind ) ) { return node . originalKeywordKind ; } return undefined ; } function createSnippetPrinter ( printerOptions ) { const baseWriter = textChanges . createWriter ( getNewLineCharacter ( printerOptions ) ) ; const printer = createPrinter ( printerOptions , baseWriter ) ; const writer = { ... baseWriter , write : s => baseWriter . write ( escapeSnippetText ( s ) ) , nonEscapingWrite : baseWriter . write , writeLiteral : s => baseWriter . writeLiteral ( escapeSnippetText ( s ) ) , writeStringLiteral : s => baseWriter . writeStringLiteral ( escapeSnippetText ( s ) ) , writeSymbol : ( s , symbol ) => baseWriter . writeSymbol ( escapeSnippetText ( s ) , symbol ) , writeParameter : s => baseWriter . writeParameter ( escapeSnippetText ( s ) ) , writeComment : s => baseWriter . writeComment ( escapeSnippetText ( s ) ) , writeProperty : s => baseWriter . writeProperty ( escapeSnippetText ( s ) ) , } ; return { printSnippetList , } ; function printSnippetList ( format , list , sourceFile ) { writer . clear ( ) ; printer . writeList ( format , list , sourceFile , writer ) ; return writer . getText ( ) ; } } function originToCompletionEntryData ( origin ) { const ambientModuleName = origin . fileName ? undefined : stripQuotes ( origin . moduleSymbol . name ) ; const isPackageJsonImport = origin . isFromPackageJson ? true : undefined ; if ( originIsResolvedExport ( origin ) ) { const resolvedData = { exportName : origin . exportName , moduleSpecifier : origin . moduleSpecifier , ambientModuleName , fileName : origin . fileName , isPackageJsonImport , } ; return resolvedData ; } const unresolvedData = { exportName : origin . exportName , exportMapKey : origin . exportMapKey , fileName : origin . fileName , ambientModuleName : origin . fileName ? undefined : stripQuotes ( origin . moduleSymbol . name ) , isPackageJsonImport : origin . isFromPackageJson ? true : undefined , } ; return unresolvedData ; } function completionEntryDataToSymbolOriginInfo ( data , completionName , moduleSymbol ) { const isDefaultExport = data . exportName === InternalSymbolName . Default ; const isFromPackageJson = ! ! data . isPackageJsonImport ; if ( completionEntryDataIsResolved ( data ) ) { const resolvedOrigin = { kind : SymbolOriginInfoKind . ResolvedExport , exportName : data . exportName , moduleSpecifier : data . moduleSpecifier , symbolName : completionName , fileName : data . fileName , moduleSymbol , isDefaultExport , isFromPackageJson , } ; return resolvedOrigin ; } const unresolvedOrigin = { kind : SymbolOriginInfoKind . Export , exportName : data . exportName , exportMapKey : data . exportMapKey , symbolName : completionName , fileName : data . fileName , moduleSymbol , isDefaultExport , isFromPackageJson , } ; return unresolvedOrigin ; } function getInsertTextAndReplacementSpanForImportCompletion ( name , importCompletionNode , contextToken , origin , useSemicolons , options , preferences ) { const sourceFile = importCompletionNode . getSourceFile ( ) ; const replacementSpan = createTextSpanFromNode ( findAncestor ( importCompletionNode , or ( isImportDeclaration , isImportEqualsDeclaration ) ) || importCompletionNode , sourceFile ) ; const quotedModuleSpecifier = quote ( sourceFile , preferences , origin . moduleSpecifier ) ; const exportKind = origin . isDefaultExport ? ExportKind . Default : origin . exportName === InternalSymbolName . ExportEquals ? ExportKind . ExportEquals : ExportKind . Named ; const tabStop = preferences . includeCompletionsWithSnippetText ? "$1" : "" ; const importKind = codefix . getImportKind ( sourceFile , exportKind , options , true ) ; const isTopLevelTypeOnly = tryCast ( importCompletionNode , isImportDeclaration ) ?. importClause ?. isTypeOnly || tryCast ( importCompletionNode , isImportEqualsDeclaration ) ?. isTypeOnly ; const isImportSpecifierTypeOnly = couldBeTypeOnlyImportSpecifier ( importCompletionNode , contextToken ) ; const topLevelTypeOnlyText = isTopLevelTypeOnly ? ` ${ tokenToString ( SyntaxKind . TypeKeyword ) } ` : " " ; const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${ tokenToString ( SyntaxKind . TypeKeyword ) } ` : "" ; const suffix = useSemicolons ? ";" : "" ; switch ( importKind ) { case ImportKind . CommonJS : return { replacementSpan , insertText : `import${ topLevelTypeOnlyText }${ escapeSnippetText ( name ) }${ tabStop } = require(${ quotedModuleSpecifier })${ suffix }` } ; case ImportKind . Default : return { replacementSpan , insertText : `import${ topLevelTypeOnlyText }${ escapeSnippetText ( name ) }${ tabStop } from ${ quotedModuleSpecifier }${ suffix }` } ; case ImportKind . Namespace : return { replacementSpan , insertText : `import${ topLevelTypeOnlyText }* as ${ escapeSnippetText ( name ) } from ${ quotedModuleSpecifier }${ suffix }` } ; case ImportKind . Named : return { replacementSpan , insertText : `import${ topLevelTypeOnlyText }{ ${ importSpecifierTypeOnlyText }${ escapeSnippetText ( name ) }${ tabStop } } from ${ quotedModuleSpecifier }${ suffix }` } ; } } function quotePropertyName ( sourceFile , preferences , name ) { if ( /^\d+$/ . test ( name ) ) { return name ; } return quote ( sourceFile , preferences , name ) ; } function isRecommendedCompletionMatch ( localSymbol , recommendedCompletion , checker ) { return localSymbol === recommendedCompletion || ! ! ( localSymbol . flags & SymbolFlags . ExportValue ) && checker . getExportSymbolOfSymbol ( localSymbol ) === recommendedCompletion ; } function getSourceFromOrigin ( origin ) { if ( originIsExport ( origin ) ) { return stripQuotes ( origin . moduleSymbol . name ) ; } if ( originIsResolvedExport ( origin ) ) { return origin . moduleSpecifier ; } if ( origin ?. kind === SymbolOriginInfoKind . ThisType ) { return CompletionSource . ThisProperty ; } } export function getCompletionEntriesFromSymbols ( symbols , entries , replacementToken , contextToken , location , sourceFile , host , program , target , log , kind , preferences , compilerOptions , formatContext , isTypeOnlyLocation ? , propertyAccessToConvert ? , jsxIdentifierExpected ? , isJsxInitializer ? , importCompletionNode ? , recommendedCompletion ? , symbolToOriginInfoMap ? , symbolToSortTextIdMap ? , isJsxIdentifierExpected ? , isRightOfOpenTag ? ) { const start = timestamp ( ) ; const variableDeclaration = getVariableDeclaration ( location ) ; const useSemicolons = probablyUsesSemicolons ( sourceFile ) ; const typeChecker = program . getTypeChecker ( ) ; const uniques = new Map < string , boolean > ( ) ; for ( let i = 0 ; i < symbols . length ; i ++ ) { const symbol = symbols [ i ] ; const origin = symbolToOriginInfoMap ?. [ i ] ; const info = getCompletionEntryDisplayNameForSymbol ( symbol , target , origin , kind , ! ! jsxIdentifierExpected ) ; if ( ! info || uniques . get ( info . name ) || kind === CompletionKind . Global && symbolToSortTextIdMap && ! shouldIncludeSymbol ( symbol , symbolToSortTextIdMap ) ) { continue ; } const { name , needsConvertPropertyAccess } = info ; const sortTextId = symbolToSortTextIdMap ?. [ getSymbolId ( symbol ) ] ?? SortTextId . LocationPriority ; const sortText = ( isDeprecated ( symbol , typeChecker ) ? SortTextId . DeprecatedOffset + sortTextId : sortTextId ) . toString ( ) as SortText ; const entry = createCompletionEntry ( symbol , sortText , replacementToken , contextToken , location , sourceFile , host , program , name , needsConvertPropertyAccess , origin , recommendedCompletion , propertyAccessToConvert , isJsxInitializer , importCompletionNode , useSemicolons , compilerOptions , preferences , kind , formatContext , isJsxIdentifierExpected , isRightOfOpenTag ) ; if ( ! entry ) { continue ; } /** True for locals; false for globals, module exports from other files, `this.` completions. */ const shouldShadowLaterSymbols = ! origin && ! ( symbol . parent === undefined && ! some ( symbol . declarations , d => d . getSourceFile ( ) === location . getSourceFile ( ) ) ) ; uniques . set ( name , shouldShadowLaterSymbols ) ; insertSorted ( entries , entry , compareCompletionEntries , true ) ; } log ( "getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + ( timestamp ( ) - start ) ) ; return { has : name => uniques . has ( name ) , add : name => uniques . set ( name , true ) , } ; function shouldIncludeSymbol ( symbol , symbolToSortTextIdMap ) { if ( ! isSourceFile ( location ) ) { if ( isExportAssignment ( location . parent ) ) { return true ; } if ( variableDeclaration && symbol . valueDeclaration === variableDeclaration ) { return false ; } const symbolOrigin = skipAlias ( symbol , typeChecker ) ; if ( ! ! sourceFile . externalModuleIndicator && ! compilerOptions . allowUmdGlobalAccess && symbolToSortTextIdMap [ getSymbolId ( symbol ) ] === SortTextId . GlobalsOrKeywords && ( symbolToSortTextIdMap [ getSymbolId ( symbolOrigin ) ] === SortTextId . AutoImportSuggestions || symbolToSortTextIdMap [ getSymbolId ( symbolOrigin ) ] === SortTextId . LocationPriority ) ) { return false ; } symbol = symbolOrigin ; if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) { return ! ! ( symbol . flags & SymbolFlags . Namespace ) ; } if ( isTypeOnlyLocation ) { return symbolCanBeReferencedAtTypeLocation ( symbol , typeChecker ) ; } } return ! ! ( getCombinedLocalAndExportSymbolFlags ( symbol ) & SymbolFlags . Value ) ; } } function getLabelCompletionAtPosition ( node ) { const entries = getLabelStatementCompletions ( node ) ; if ( entries . length ) { return { isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false , entries } ; } } function getLabelStatementCompletions ( node ) { const entries = [ ] ; const uniques = new Map < string , true > ( ) ; let current = node ; while ( current ) { if ( isFunctionLike ( current ) ) { break ; } if ( isLabeledStatement ( current ) ) { const name = current . label . text ; if ( ! uniques . has ( name ) ) { uniques . set ( name , true ) ; entries . push ( { name , kindModifiers : ScriptElementKindModifier . none , kind : ScriptElementKind . label , sortText : SortText . LocationPriority } ) ; } } current = current . parent ; } return entries ; } interface SymbolCompletion { type : "symbol" ; symbol : Symbol ; location : Node ; origin : SymbolOriginInfo | SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | undefined ; previousToken : Node | undefined ; contextToken : Node | undefined ; readonly isJsxInitializer : IsJsxInitializer ; readonly isTypeOnlyLocation : boolean ; } function getSymbolCompletionFromEntryId ( program , log , sourceFile , position , entryId , host , preferences ) { if ( entryId . data ) { const autoImport = getAutoImportSymbolFromCompletionEntryData ( entryId . name , entryId . data , program , host ) ; if ( autoImport ) { const { contextToken , previousToken } = getRelevantTokens ( position , sourceFile ) ; return { type : "symbol" , symbol : autoImport . symbol , location : getTouchingPropertyName ( sourceFile , position ) , previousToken , contextToken , isJsxInitializer : false , isTypeOnlyLocation : false , origin : autoImport . origin , } ; } } const compilerOptions = program . getCompilerOptions ( ) ; const completionData = getCompletionData ( program , log , sourceFile , isUncheckedFile ( sourceFile , compilerOptions ) , position , { includeCompletionsForModuleExports : true , includeCompletionsWithInsertText : true } , entryId , host ) ; if ( ! completionData ) { return { type : "none" } ; } if ( completionData . kind !== CompletionDataKind . Data ) { return { type : "request" , request : completionData } ; } const { symbols , literals , location , completionKind , symbolToOriginInfoMap , contextToken , previousToken , isJsxInitializer , isTypeOnlyLocation } = completionData ; const literal = find ( literals , l => completionNameForLiteral ( sourceFile , preferences , l ) === entryId . name ) ; if ( literal !== undefined ) return { type : "literal" , literal } ; return firstDefined ( symbols , ( symbol , index ) : SymbolCompletion | undefined => { const origin = symbolToOriginInfoMap [ index ] ; const info = getCompletionEntryDisplayNameForSymbol ( symbol , getEmitScriptTarget ( compilerOptions ) , origin , completionKind , completionData . isJsxIdentifierExpected ) ; return info && info . name === entryId . name && ( entryId . source === CompletionSource . ClassMemberSnippet && symbol . flags & SymbolFlags . ClassMember || getSourceFromOrigin ( origin ) === entryId . source ) ? { type : "symbol" as const , symbol , location , origin , contextToken , previousToken , isJsxInitializer , isTypeOnlyLocation } : undefined ; } ) || { type : "none" } ; } export interface CompletionEntryIdentifier { name : string ; source ? : string ; data ? : CompletionEntryData ; } export function getCompletionEntryDetails ( program , log , sourceFile , position , entryId , host , formatContext , preferences , cancellationToken ) { const typeChecker = program . getTypeChecker ( ) ; const compilerOptions = program . getCompilerOptions ( ) ; const { name , source , data } = entryId ; const contextToken = findPrecedingToken ( position , sourceFile ) ; if ( isInString ( sourceFile , position , contextToken ) ) { return StringCompletions . getStringLiteralCompletionDetails ( name , sourceFile , position , contextToken , typeChecker , compilerOptions , host , cancellationToken , preferences ) ; } const symbolCompletion = getSymbolCompletionFromEntryId ( program , log , sourceFile , position , entryId , host , preferences ) ; switch ( symbolCompletion . type ) { case "request" : { const { request } = symbolCompletion ; switch ( request . kind ) { case CompletionDataKind . JsDocTagName : return JsDoc . getJSDocTagNameCompletionDetails ( name ) ; case CompletionDataKind . JsDocTag : return JsDoc . getJSDocTagCompletionDetails ( name ) ; case CompletionDataKind . JsDocParameterName : return JsDoc . getJSDocParameterNameCompletionDetails ( name ) ; case CompletionDataKind . Keywords : return some ( request . keywordCompletions , c => c . name === name ) ? createSimpleDetails ( name , ScriptElementKind . keyword , SymbolDisplayPartKind . keyword ) : undefined ; default : return Debug . assertNever ( request ) ; } } case "symbol" : { const { symbol , location , contextToken , origin , previousToken } = symbolCompletion ; const { codeActions , sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay ( name , location , contextToken , origin , symbol , program , host , compilerOptions , sourceFile , position , previousToken , formatContext , preferences , data , source ) ; return createCompletionDetailsForSymbol ( symbol , typeChecker , sourceFile , location , cancellationToken , codeActions , sourceDisplay ) ; } case "literal" : { const { literal } = symbolCompletion ; return createSimpleDetails ( completionNameForLiteral ( sourceFile , preferences , literal ) , ScriptElementKind . string , typeof literal === "string" ? SymbolDisplayPartKind . stringLiteral : SymbolDisplayPartKind . numericLiteral ) ; } case "none" : return allKeywordsCompletions ( ) . some ( c => c . name === name ) ? createSimpleDetails ( name , ScriptElementKind . keyword , SymbolDisplayPartKind . keyword ) : undefined ; default : Debug . assertNever ( symbolCompletion ) ; } } function createSimpleDetails ( name , kind , kind2 ) { return createCompletionDetails ( name , ScriptElementKindModifier . none , kind , [ displayPart ( name , kind2 ) ] ) ; } export function createCompletionDetailsForSymbol ( symbol , checker , sourceFile , location , cancellationToken , codeActions ? , sourceDisplay ? ) { const { displayParts , documentation , symbolKind , tags } = checker . runWithCancellationToken ( cancellationToken , checker => SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( checker , symbol , sourceFile , location , location , SemanticMeaning . All ) ) ; return createCompletionDetails ( symbol . name , SymbolDisplay . getSymbolModifiers ( checker , symbol ) , symbolKind , displayParts , documentation , tags , codeActions , sourceDisplay ) ; } export function createCompletionDetails ( name , kindModifiers , kind , displayParts , documentation ? , tags ? , codeActions ? , source ? ) { return { name , kindModifiers , kind , displayParts , documentation , tags , codeActions , source , sourceDisplay : source } ; } interface CodeActionsAndSourceDisplay { readonly codeActions : CodeAction [ ] | undefined ; readonly sourceDisplay : SymbolDisplayPart [ ] | undefined ; } function getCompletionEntryCodeActionsAndSourceDisplay ( name , location , contextToken , origin , symbol , program , host , compilerOptions , sourceFile , position , previousToken , formatContext , preferences , data , source ) { if ( data ?. moduleSpecifier ) { const { contextToken , previousToken } = getRelevantTokens ( position , sourceFile ) ; if ( previousToken && getImportStatementCompletionInfo ( contextToken || previousToken ) . replacementNode ) { return { codeActions : undefined , sourceDisplay : [ textPart ( data . moduleSpecifier ) ] } ; } } if ( source === CompletionSource . ClassMemberSnippet ) { const { importAdder } = getEntryForMemberCompletion ( host , program , compilerOptions , preferences , name , symbol , location , contextToken , formatContext ) ; if ( importAdder ) { const changes = textChanges . ChangeTracker . with ( { host , formatContext , preferences } , importAdder . writeFixes ) ; return { sourceDisplay : undefined , codeActions : [ { changes , description : diagnosticToString ( [ Diagnostics . Includes_imports_of_types_referenced_by_0 , name ] ) , } ] , } ; } } if ( ! origin || ! ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) ) { return { codeActions : undefined , sourceDisplay : undefined } ; } const checker = origin . isFromPackageJson ? host . getPackageJsonAutoImportProvider ! ( ) ! . getTypeChecker ( ) : program . getTypeChecker ( ) ; const { moduleSymbol } = origin ; const targetSymbol = checker . getMergedSymbol ( skipAlias ( symbol . exportSymbol || symbol , checker ) ) ; const { moduleSpecifier , codeAction } = codefix . getImportCompletionAction ( targetSymbol , moduleSymbol , sourceFile , getNameForExportedSymbol ( symbol , getEmitScriptTarget ( compilerOptions ) ) , host , program , formatContext , previousToken && isIdentifier ( previousToken ) ? previousToken . getStart ( sourceFile ) : position , preferences ) ; Debug . assert ( ! data ?. moduleSpecifier || moduleSpecifier === data . moduleSpecifier ) ; return { sourceDisplay : [ textPart ( moduleSpecifier ) ] , codeActions : [ codeAction ] } ; } export function getCompletionEntrySymbol ( program , log , sourceFile , position , entryId , host , preferences ) { const completion = getSymbolCompletionFromEntryId ( program , log , sourceFile , position , entryId , host , preferences ) ; return completion . type === "symbol" ? completion . symbol : undefined ; } const enum CompletionDataKind { Data , JsDocTagName , JsDocTag , JsDocParameterName , Keywords } /** true: after the `=` sign but no identifier has been typed yet. Else is the Identifier after the initializer. */ type IsJsxInitializer = boolean | Identifier ; interface CompletionData { readonly kind : CompletionDataKind . Data ; readonly symbols : readonly Symbol [ ] ; readonly completionKind : CompletionKind ; readonly isInSnippetScope : boolean ; /** Note that the presence of this alone doesn't mean that we need a conversion. Only do that if the completion is not an ordinary identifier. */ readonly propertyAccessToConvert : PropertyAccessExpression | undefined ; readonly isNewIdentifierLocation : boolean ; readonly location : Node ; readonly keywordFilters : KeywordCompletionFilters ; readonly literals : readonly ( string | number | PseudoBigInt ) [ ] ; readonly symbolToOriginInfoMap : SymbolOriginInfoMap ; readonly recommendedCompletion : Symbol | undefined ; readonly previousToken : Node | undefined ; readonly contextToken : Node | undefined ; readonly isJsxInitializer : IsJsxInitializer ; readonly insideJsDocTagTypeExpression : boolean ; readonly symbolToSortTextIdMap : SymbolSortTextIdMap ; readonly isTypeOnlyLocation : boolean ; /** In JSX tag name and attribute names, identifiers like "my-tag" or "aria-name" is valid identifier. */ readonly isJsxIdentifierExpected : boolean ; readonly isRightOfOpenTag : boolean ; readonly importCompletionNode ? : Node ; readonly hasUnresolvedAutoImports ? : boolean ; } type Request = { readonly kind : CompletionDataKind . JsDocTagName | CompletionDataKind . JsDocTag ; } | { readonly kind : CompletionDataKind . JsDocParameterName ; tag : JSDocParameterTag ; } | { readonly kind : CompletionDataKind . Keywords ; keywordCompletions : readonly CompletionEntry [ ] ; isNewIdentifierLocation : boolean ; } ; export const enum CompletionKind { ObjectPropertyDeclaration , Global , PropertyAccess , MemberLike , String , None } function getRecommendedCompletion ( previousToken , contextualType , checker ) { return firstDefined ( contextualType && ( contextualType . isUnion ( ) ? contextualType . types : [ contextualType ] ) , type => { const symbol = type && type . symbol ; return symbol && ( symbol . flags & ( SymbolFlags . EnumMember | SymbolFlags . Enum | SymbolFlags . Class ) && ! isAbstractConstructorSymbol ( symbol ) ) ? getFirstSymbolInChain ( symbol , previousToken , checker ) : undefined ; } ) ; } function getContextualType ( previousToken , position , sourceFile , checker ) { const { parent } = previousToken ; switch ( previousToken . kind ) { case SyntaxKind . Identifier : return getContextualTypeFromParent ( previousToken as Identifier , checker ) ; case SyntaxKind . EqualsToken : switch ( parent . kind ) { case SyntaxKind . VariableDeclaration : return checker . getContextualType ( ( parent as VariableDeclaration ) . initializer ! ) ; case SyntaxKind . BinaryExpression : return checker . getTypeAtLocation ( ( parent as BinaryExpression ) . left ) ; case SyntaxKind . JsxAttribute : return checker . getContextualTypeForJsxAttribute ( parent as JsxAttribute ) ; default : return undefined ; } case SyntaxKind . NewKeyword : return checker . getContextualType ( parent as Expression ) ; case SyntaxKind . CaseKeyword : return getSwitchedType ( cast ( parent , isCaseClause ) , checker ) ; case SyntaxKind . OpenBraceToken : return isJsxExpression ( parent ) && ! isJsxElement ( parent . parent ) && ! isJsxFragment ( parent . parent ) ? checker . getContextualTypeForJsxAttribute ( parent . parent ) : undefined ; default : const argInfo = SignatureHelp . getArgumentInfoForCompletions ( previousToken , position , sourceFile ) ; return argInfo ? checker . getContextualTypeForArgumentAtIndex ( argInfo . invocation , argInfo . argumentIndex + ( previousToken . kind === SyntaxKind . CommaToken ? 1 : 0 ) ) : isEqualityOperatorKind ( previousToken . kind ) && isBinaryExpression ( parent ) && isEqualityOperatorKind ( parent . operatorToken . kind ) ? checker . getTypeAtLocation ( parent . left ) : checker . getContextualType ( previousToken as Expression ) ; } } function getFirstSymbolInChain ( symbol , enclosingDeclaration , checker ) { const chain = checker . getAccessibleSymbolChain ( symbol , enclosingDeclaration , SymbolFlags . All , false ) ; if ( chain ) return first ( chain ) ; return symbol . parent && ( isModuleSymbol ( symbol . parent ) ? symbol : getFirstSymbolInChain ( symbol . parent , enclosingDeclaration , checker ) ) ; } function isModuleSymbol ( symbol ) { return ! ! symbol . declarations ?. some ( d => d . kind === SyntaxKind . SourceFile ) ; } function getCompletionData ( program , log , sourceFile , isUncheckedFile , position , preferences , detailsEntryId , host , cancellationToken ? ) { const typeChecker = program . getTypeChecker ( ) ; let start = timestamp ( ) ; let currentToken = getTokenAtPosition ( sourceFile , position ) ; log ( "getCompletionData: Get current token: " + ( timestamp ( ) - start ) ) ; start = timestamp ( ) ; const insideComment = isInComment ( sourceFile , position , currentToken ) ; log ( "getCompletionData: Is inside comment: " + ( timestamp ( ) - start ) ) ; let insideJsDocTagTypeExpression = false ; let isInSnippetScope = false ; if ( insideComment ) { if ( hasDocComment ( sourceFile , position ) ) { if ( sourceFile . text . charCodeAt ( position - 1 ) === CharacterCodes . at ) { return { kind : CompletionDataKind . JsDocTagName } ; } else { const lineStart = getLineStartPositionForPosition ( position , sourceFile ) ; if ( ! /[^\*|\s(/)]/ . test ( sourceFile . text . substring ( lineStart , position ) ) ) { return { kind : CompletionDataKind . JsDocTag } ; } } } const tag = getJsDocTagAtPosition ( currentToken , position ) ; if ( tag ) { if ( tag . tagName . pos <= position && position <= tag . tagName . end ) { return { kind : CompletionDataKind . JsDocTagName } ; } if ( isTagWithTypeExpression ( tag ) && tag . typeExpression && tag . typeExpression . kind === SyntaxKind . JSDocTypeExpression ) { currentToken = getTokenAtPosition ( sourceFile , position ) ; if ( ! currentToken || ( ! isDeclarationName ( currentToken ) && ( currentToken . parent . kind !== SyntaxKind . JSDocPropertyTag || ( currentToken . parent as JSDocPropertyTag ) . name !== currentToken ) ) ) { insideJsDocTagTypeExpression = isCurrentlyEditingNode ( tag . typeExpression ) ; } } if ( ! insideJsDocTagTypeExpression && isJSDocParameterTag ( tag ) && ( nodeIsMissing ( tag . name ) || tag . name . pos <= position && position <= tag . name . end ) ) { return { kind : CompletionDataKind . JsDocParameterName , tag } ; } } if ( ! insideJsDocTagTypeExpression ) { log ( "Returning an empty list because completion was inside a regular comment or plain text part of a JsDoc comment." ) ; return undefined ; } } start = timestamp ( ) ; const isJsOnlyLocation = ! insideJsDocTagTypeExpression && isSourceFileJS ( sourceFile ) ; const tokens = getRelevantTokens ( position , sourceFile ) ; const previousToken = tokens . previousToken ! ; let contextToken = tokens . contextToken ! ; log ( "getCompletionData: Get previous token: " + ( timestamp ( ) - start ) ) ; let node = currentToken ; let propertyAccessToConvert ; let isRightOfDot = false ; let isRightOfQuestionDot = false ; let isRightOfOpenTag = false ; let isStartingCloseTag = false ; let isJsxInitializer = false ; let isJsxIdentifierExpected = false ; let importCompletionNode ; let location = getTouchingPropertyName ( sourceFile , position ) ; let keywordFilters = KeywordCompletionFilters . None ; let isNewIdentifierLocation = false ; if ( contextToken ) { const importStatementCompletion = getImportStatementCompletionInfo ( contextToken ) ; isNewIdentifierLocation = importStatementCompletion . isNewIdentifierLocation ; if ( importStatementCompletion . keywordCompletion ) { if ( importStatementCompletion . isKeywordOnlyCompletion ) { return { kind : CompletionDataKind . Keywords , keywordCompletions : [ keywordToCompletionEntry ( importStatementCompletion . keywordCompletion ) ] , isNewIdentifierLocation , } ; } keywordFilters = keywordFiltersFromSyntaxKind ( importStatementCompletion . keywordCompletion ) ; } if ( importStatementCompletion . replacementNode && preferences . includeCompletionsForImportStatements && preferences . includeCompletionsWithInsertText ) { importCompletionNode = importStatementCompletion . replacementNode ; } if ( ! importCompletionNode && isCompletionListBlocker ( contextToken ) ) { log ( "Returning an empty list because completion was requested in an invalid position." ) ; return keywordFilters ? keywordCompletionData ( keywordFilters , isJsOnlyLocation , isNewIdentifierDefinitionLocation ( ) ) : undefined ; } let parent = contextToken . parent ; if ( contextToken . kind === SyntaxKind . DotToken || contextToken . kind === SyntaxKind . QuestionDotToken ) { isRightOfDot = contextToken . kind === SyntaxKind . DotToken ; isRightOfQuestionDot = contextToken . kind === SyntaxKind . QuestionDotToken ; switch ( parent . kind ) { case SyntaxKind . PropertyAccessExpression : propertyAccessToConvert = parent as PropertyAccessExpression ; node = propertyAccessToConvert . expression ; const leftmostAccessExpression = getLeftmostAccessExpression ( propertyAccessToConvert ) ; if ( nodeIsMissing ( leftmostAccessExpression ) || ( ( isCallExpression ( node ) || isFunctionLike ( node ) ) && node . end === contextToken . pos && node . getChildCount ( sourceFile ) && last ( node . getChildren ( sourceFile ) ) . kind !== SyntaxKind . CloseParenToken ) ) { return undefined ; } break ; case SyntaxKind . QualifiedName : node = ( parent as QualifiedName ) . left ; break ; case SyntaxKind . ModuleDeclaration : node = ( parent as ModuleDeclaration ) . name ; break ; case SyntaxKind . ImportType : node = parent ; break ; case SyntaxKind . MetaProperty : node = parent . getFirstToken ( sourceFile ) ! ; Debug . assert ( node . kind === SyntaxKind . ImportKeyword || node . kind === SyntaxKind . NewKeyword ) ; break ; default : return undefined ; } } else if ( ! importCompletionNode && sourceFile . languageVariant === LanguageVariant . JSX ) { if ( parent && parent . kind === SyntaxKind . PropertyAccessExpression ) { contextToken = parent ; parent = parent . parent ; } if ( currentToken . parent === location ) { switch ( currentToken . kind ) { case SyntaxKind . GreaterThanToken : if ( currentToken . parent . kind === SyntaxKind . JsxElement || currentToken . parent . kind === SyntaxKind . JsxOpeningElement ) { location = currentToken ; } break ; case SyntaxKind . SlashToken : if ( currentToken . parent . kind === SyntaxKind . JsxSelfClosingElement ) { location = currentToken ; } break ; } } switch ( parent . kind ) { case SyntaxKind . JsxClosingElement : if ( contextToken . kind === SyntaxKind . SlashToken ) { isStartingCloseTag = true ; location = contextToken ; } break ; case SyntaxKind . BinaryExpression : if ( ! binaryExpressionMayBeOpenTag ( parent as BinaryExpression ) ) { break ; } case SyntaxKind . JsxSelfClosingElement : case SyntaxKind . JsxElement : case SyntaxKind . JsxOpeningElement : isJsxIdentifierExpected = true ; if ( contextToken . kind === SyntaxKind . LessThanToken ) { isRightOfOpenTag = true ; location = contextToken ; } break ; case SyntaxKind . JsxExpression : case SyntaxKind . JsxSpreadAttribute : if ( previousToken . kind === SyntaxKind . CloseBraceToken && currentToken . kind === SyntaxKind . GreaterThanToken ) { isJsxIdentifierExpected = true ; } break ; case SyntaxKind . JsxAttribute : if ( ( parent as JsxAttribute ) . initializer === previousToken && previousToken . end < position ) { isJsxIdentifierExpected = true ; break ; } switch ( previousToken . kind ) { case SyntaxKind . EqualsToken : isJsxInitializer = true ; break ; case SyntaxKind . Identifier : isJsxIdentifierExpected = true ; if ( parent !== previousToken . parent && ! ( parent as JsxAttribute ) . initializer && findChildOfKind ( parent , SyntaxKind . EqualsToken , sourceFile ) ) { isJsxInitializer = previousToken as Identifier ; } } break ; } } } const semanticStart = timestamp ( ) ; let completionKind = CompletionKind . None ; let isNonContextualObjectLiteral = false ; let hasUnresolvedAutoImports = false ; let symbols = [ ] ; const symbolToOriginInfoMap = [ ] ; const symbolToSortTextIdMap = [ ] ; const seenPropertySymbols = new Map < SymbolId , true > ( ) ; const isTypeOnlyLocation = isTypeOnlyCompletion ( ) ; const getModuleSpecifierResolutionHost = memoizeOne ( ( isFromPackageJson ) => { return createModuleSpecifierResolutionHost ( isFromPackageJson ? host . getPackageJsonAutoImportProvider ! ( ) ! : program , host ) ; } ) ; if ( isRightOfDot || isRightOfQuestionDot ) { getTypeScriptMemberSymbols ( ) ; } else if ( isRightOfOpenTag ) { symbols = typeChecker . getJsxIntrinsicTagNamesAt ( location ) ; Debug . assertEachIsDefined ( symbols , "getJsxIntrinsicTagNames() should all be defined" ) ; tryGetGlobalSymbols ( ) ; completionKind = CompletionKind . Global ; keywordFilters = KeywordCompletionFilters . None ; } else if ( isStartingCloseTag ) { const tagName = ( contextToken . parent . parent as JsxElement ) . openingElement . tagName ; const tagSymbol = typeChecker . getSymbolAtLocation ( tagName ) ; if ( tagSymbol ) { symbols = [ tagSymbol ] ; } completionKind = CompletionKind . Global ; keywordFilters = KeywordCompletionFilters . None ; } else { if ( ! tryGetGlobalSymbols ( ) ) { return keywordFilters ? keywordCompletionData ( keywordFilters , isJsOnlyLocation , isNewIdentifierLocation ) : undefined ; } } log ( "getCompletionData: Semantic work: " + ( timestamp ( ) - semanticStart ) ) ; const contextualType = previousToken && getContextualType ( previousToken , position , sourceFile , typeChecker ) ; const literals = mapDefined ( contextualType && ( contextualType . isUnion ( ) ? contextualType . types : [ contextualType ] ) , t => t . isLiteral ( ) && ! ( t . flags & TypeFlags . EnumLiteral ) ? t . value : undefined ) ; const recommendedCompletion = previousToken && contextualType && getRecommendedCompletion ( previousToken , contextualType , typeChecker ) ; return { kind : CompletionDataKind . Data , symbols , completionKind , isInSnippetScope , propertyAccessToConvert , isNewIdentifierLocation , location , keywordFilters , literals , symbolToOriginInfoMap , recommendedCompletion , previousToken , contextToken , isJsxInitializer , insideJsDocTagTypeExpression , symbolToSortTextIdMap , isTypeOnlyLocation , isJsxIdentifierExpected , isRightOfOpenTag , importCompletionNode , hasUnresolvedAutoImports , } ; type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag ; function isTagWithTypeExpression ( tag ) { switch ( tag . kind ) { case SyntaxKind . JSDocParameterTag : case SyntaxKind . JSDocPropertyTag : case SyntaxKind . JSDocReturnTag : case SyntaxKind . JSDocTypeTag : case SyntaxKind . JSDocTypedefTag : return true ; default : return false ; } } function getTypeScriptMemberSymbols ( ) { completionKind = CompletionKind . PropertyAccess ; const isImportType = isLiteralImportTypeNode ( node ) ; const isTypeLocation = insideJsDocTagTypeExpression || ( isImportType && ! ( node as ImportTypeNode ) . isTypeOf ) || isPartOfTypeNode ( node . parent ) || isPossiblyTypeArgumentPosition ( contextToken , sourceFile , typeChecker ) ; const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration ( node ) ; if ( isEntityName ( node ) || isImportType || isPropertyAccessExpression ( node ) ) { const isNamespaceName = isModuleDeclaration ( node . parent ) ; if ( isNamespaceName ) isNewIdentifierLocation = true ; let symbol = typeChecker . getSymbolAtLocation ( node ) ; if ( symbol ) { symbol = skipAlias ( symbol , typeChecker ) ; if ( symbol . flags & ( SymbolFlags . Module | SymbolFlags . Enum ) ) { const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ; Debug . assertEachIsDefined ( exportedSymbols , "getExportsOfModule() should all be defined" ) ; const isValidValueAccess = ( symbol ) => typeChecker . isValidPropertyAccess ( isImportType ? node as ImportTypeNode : ( node . parent as PropertyAccessExpression ) , symbol . name ) ; const isValidTypeAccess = ( symbol ) => symbolCanBeReferencedAtTypeLocation ( symbol , typeChecker ) ; const isValidAccess = isNamespaceName ? symbol => ! ! ( symbol . flags & SymbolFlags . Namespace ) && ! symbol . declarations ?. every ( d => d . parent === node . parent ) : isRhsOfImportDeclaration ? symbol => isValidTypeAccess ( symbol ) || isValidValueAccess ( symbol ) : isTypeLocation ? isValidTypeAccess : isValidValueAccess ; for ( const exportedSymbol of exportedSymbols ) { if ( isValidAccess ( exportedSymbol ) ) { symbols . push ( exportedSymbol ) ; } } if ( ! isTypeLocation && symbol . declarations && symbol . declarations . some ( d => d . kind !== SyntaxKind . SourceFile && d . kind !== SyntaxKind . ModuleDeclaration && d . kind !== SyntaxKind . EnumDeclaration ) ) { let type = typeChecker . getTypeOfSymbolAtLocation ( symbol , node ) . getNonOptionalType ( ) ; let insertQuestionDot = false ; if ( type . isNullableType ( ) ) { const canCorrectToQuestionDot = isRightOfDot && ! isRightOfQuestionDot && preferences . includeAutomaticOptionalChainCompletions !== false ; if ( canCorrectToQuestionDot || isRightOfQuestionDot ) { type = type . getNonNullableType ( ) ; if ( canCorrectToQuestionDot ) { insertQuestionDot = true ; } } } addTypeProperties ( type , ! ! ( node . flags & NodeFlags . AwaitContext ) , insertQuestionDot ) ; } return ; } } } if ( ! isTypeLocation ) { const container = getThisContainer ( node , false ) ; if ( ! isSourceFile ( container ) && container . parent ) typeChecker . getTypeAtLocation ( container ) ; let type = typeChecker . getTypeAtLocation ( node ) . getNonOptionalType ( ) ; let insertQuestionDot = false ; if ( type . isNullableType ( ) ) { const canCorrectToQuestionDot = isRightOfDot && ! isRightOfQuestionDot && preferences . includeAutomaticOptionalChainCompletions !== false ; if ( canCorrectToQuestionDot || isRightOfQuestionDot ) { type = type . getNonNullableType ( ) ; if ( canCorrectToQuestionDot ) { insertQuestionDot = true ; } } } addTypeProperties ( type , ! ! ( node . flags & NodeFlags . AwaitContext ) , insertQuestionDot ) ; } } function addTypeProperties ( type , insertAwait , insertQuestionDot ) { isNewIdentifierLocation = ! ! type . getStringIndexType ( ) ; if ( isRightOfQuestionDot && some ( type . getCallSignatures ( ) ) ) { isNewIdentifierLocation = true ; } const propertyAccess = node . kind === SyntaxKind . ImportType ? node as ImportTypeNode : node . parent as PropertyAccessExpression | QualifiedName ; if ( isUncheckedFile ) { symbols . push ( ... filter ( getPropertiesForCompletion ( type , typeChecker ) , s => typeChecker . isValidPropertyAccessForCompletions ( propertyAccess , type , s ) ) ) ; } else { for ( const symbol of type . getApparentProperties ( ) ) { if ( typeChecker . isValidPropertyAccessForCompletions ( propertyAccess , type , symbol ) ) { addPropertySymbol ( symbol , false , insertQuestionDot ) ; } } } if ( insertAwait && preferences . includeCompletionsWithInsertText ) { const promiseType = typeChecker . getPromisedTypeOfPromise ( type ) ; if ( promiseType ) { for ( const symbol of promiseType . getApparentProperties ( ) ) { if ( typeChecker . isValidPropertyAccessForCompletions ( propertyAccess , promiseType , symbol ) ) { addPropertySymbol ( symbol , true , insertQuestionDot ) ; } } } } } function addPropertySymbol ( symbol , insertAwait , insertQuestionDot ) { const computedPropertyName = firstDefined ( symbol . declarations , decl => tryCast ( getNameOfDeclaration ( decl ) , isComputedPropertyName ) ) ; if ( computedPropertyName ) { const leftMostName = getLeftMostName ( computedPropertyName . expression ) ; const nameSymbol = leftMostName && typeChecker . getSymbolAtLocation ( leftMostName ) ; const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain ( nameSymbol , contextToken , typeChecker ) ; if ( firstAccessibleSymbol && addToSeen ( seenPropertySymbols , getSymbolId ( firstAccessibleSymbol ) ) ) { const index = symbols . length ; symbols . push ( firstAccessibleSymbol ) ; const moduleSymbol = firstAccessibleSymbol . parent ; if ( ! moduleSymbol || ! isExternalModuleSymbol ( moduleSymbol ) || typeChecker . tryGetMemberInModuleExportsAndProperties ( firstAccessibleSymbol . name , moduleSymbol ) !== firstAccessibleSymbol ) { symbolToOriginInfoMap [ index ] = { kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberNoExport ) } ; } else { const fileName = isExternalModuleNameRelative ( stripQuotes ( moduleSymbol . name ) ) ? getSourceFileOfModule ( moduleSymbol ) ?. fileName : undefined ; const { moduleSpecifier } = codefix . getModuleSpecifierForBestExportInfo ( [ { exportKind : ExportKind . Named , moduleFileName : fileName , isFromPackageJson : false , moduleSymbol , symbol : firstAccessibleSymbol , targetFlags : skipAlias ( firstAccessibleSymbol , typeChecker ) . flags , } ] , sourceFile , program , host , preferences ) || { } ; if ( moduleSpecifier ) { const origin = { kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . SymbolMemberExport ) , moduleSymbol , isDefaultExport : false , symbolName : firstAccessibleSymbol . name , exportName : firstAccessibleSymbol . name , fileName , moduleSpecifier , } ; symbolToOriginInfoMap [ index ] = origin ; } } } else if ( preferences . includeCompletionsWithInsertText ) { addSymbolOriginInfo ( symbol ) ; addSymbolSortInfo ( symbol ) ; symbols . push ( symbol ) ; } } else { addSymbolOriginInfo ( symbol ) ; addSymbolSortInfo ( symbol ) ; symbols . push ( symbol ) ; } function addSymbolSortInfo ( symbol ) { if ( isStaticProperty ( symbol ) ) { symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . LocalDeclarationPriority ; } } function addSymbolOriginInfo ( symbol ) { if ( preferences . includeCompletionsWithInsertText ) { if ( insertAwait && addToSeen ( seenPropertySymbols , getSymbolId ( symbol ) ) ) { symbolToOriginInfoMap [ symbols . length ] = { kind : getNullableSymbolOriginInfoKind ( SymbolOriginInfoKind . Promise ) } ; } else if ( insertQuestionDot ) { symbolToOriginInfoMap [ symbols . length ] = { kind : SymbolOriginInfoKind . Nullable } ; } } } function getNullableSymbolOriginInfoKind ( kind ) { return insertQuestionDot ? kind | SymbolOriginInfoKind . Nullable : kind ; } } /** Given 'a.b.c', returns 'a'. */ function getLeftMostName ( e ) { return isIdentifier ( e ) ? e : isPropertyAccessExpression ( e ) ? getLeftMostName ( e . expression ) : undefined ; } function tryGetGlobalSymbols ( ) { const result = tryGetObjectTypeLiteralInTypeArgumentCompletionSymbols ( ) || tryGetObjectLikeCompletionSymbols ( ) || tryGetImportCompletionSymbols ( ) || tryGetImportOrExportClauseCompletionSymbols ( ) || tryGetLocalNamedExportCompletionSymbols ( ) || tryGetConstructorCompletion ( ) || tryGetClassLikeCompletionSymbols ( ) || tryGetJsxCompletionSymbols ( ) || ( getGlobalCompletions ( ) , GlobalsSearch . Success ) ; return result === GlobalsSearch . Success ; } function tryGetConstructorCompletion ( ) { if ( ! tryGetConstructorLikeCompletionContainer ( contextToken ) ) return GlobalsSearch . Continue ; completionKind = CompletionKind . None ; isNewIdentifierLocation = true ; keywordFilters = KeywordCompletionFilters . ConstructorParameterKeywords ; return GlobalsSearch . Success ; } function tryGetJsxCompletionSymbols ( ) { const jsxContainer = tryGetContainingJsxElement ( contextToken ) ; const attrsType = jsxContainer && typeChecker . getContextualType ( jsxContainer . attributes ) ; if ( ! attrsType ) return GlobalsSearch . Continue ; const completionsType = jsxContainer && typeChecker . getContextualType ( jsxContainer . attributes , ContextFlags . Completions ) ; symbols = concatenate ( symbols , filterJsxAttributes ( getPropertiesForObjectExpression ( attrsType , completionsType , jsxContainer ! . attributes , typeChecker ) , jsxContainer ! . attributes . properties ) ) ; setSortTextToOptionalMember ( ) ; completionKind = CompletionKind . MemberLike ; isNewIdentifierLocation = false ; return GlobalsSearch . Success ; } function tryGetImportCompletionSymbols ( ) { if ( ! importCompletionNode ) return GlobalsSearch . Continue ; isNewIdentifierLocation = true ; collectAutoImports ( ) ; return GlobalsSearch . Success ; } function getGlobalCompletions ( ) { keywordFilters = tryGetFunctionLikeBodyCompletionContainer ( contextToken ) ? KeywordCompletionFilters . FunctionLikeBodyKeywords : KeywordCompletionFilters . All ; completionKind = CompletionKind . Global ; isNewIdentifierLocation = isNewIdentifierDefinitionLocation ( ) ; if ( previousToken !== contextToken ) { Debug . assert ( ! ! previousToken , "Expected 'contextToken' to be defined when different from 'previousToken'." ) ; } const adjustedPosition = previousToken !== contextToken ? previousToken . getStart ( ) : position ; const scopeNode = getScopeNode ( contextToken , adjustedPosition , sourceFile ) || sourceFile ; isInSnippetScope = isSnippetScope ( scopeNode ) ; const symbolMeanings = ( isTypeOnlyLocation ? SymbolFlags . None : SymbolFlags . Value ) | SymbolFlags . Type | SymbolFlags . Namespace | SymbolFlags . Alias ; symbols = concatenate ( symbols , typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ; Debug . assertEachIsDefined ( symbols , "getSymbolsInScope() should all be defined" ) ; for ( const symbol of symbols ) { if ( ! typeChecker . isArgumentsSymbol ( symbol ) && ! some ( symbol . declarations , d => d . getSourceFile ( ) === sourceFile ) ) { symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . GlobalsOrKeywords ; } } if ( preferences . includeCompletionsWithInsertText && scopeNode . kind !== SyntaxKind . SourceFile ) { const thisType = typeChecker . tryGetThisTypeAt ( scopeNode , false ) ; if ( thisType && ! isProbablyGlobalType ( thisType , sourceFile , typeChecker ) ) { for ( const symbol of getPropertiesForCompletion ( thisType , typeChecker ) ) { symbolToOriginInfoMap [ symbols . length ] = { kind : SymbolOriginInfoKind . ThisType } ; symbols . push ( symbol ) ; symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . SuggestedClassMembers ; } } } collectAutoImports ( ) ; if ( isTypeOnlyLocation ) { keywordFilters = contextToken && isAssertionExpression ( contextToken . parent ) ? KeywordCompletionFilters . TypeAssertionKeywords : KeywordCompletionFilters . TypeKeywords ; } } function shouldOfferImportCompletions ( ) { if ( importCompletionNode ) return true ; if ( isNonContextualObjectLiteral ) return false ; if ( ! preferences . includeCompletionsForModuleExports ) return false ; if ( sourceFile . externalModuleIndicator || sourceFile . commonJsModuleIndicator ) return true ; if ( compilerOptionsIndicateEsModules ( program . getCompilerOptions ( ) ) ) return true ; return programContainsModules ( program ) ; } function isSnippetScope ( scopeNode ) { switch ( scopeNode . kind ) { case SyntaxKind . SourceFile : case SyntaxKind . TemplateExpression : case SyntaxKind . JsxExpression : case SyntaxKind . Block : return true ; default : return isStatement ( scopeNode ) ; } } function isTypeOnlyCompletion ( ) { return insideJsDocTagTypeExpression || ! ! importCompletionNode && isTypeOnlyImportOrExportDeclaration ( location . parent ) || ! isContextTokenValueLocation ( contextToken ) && ( isPossiblyTypeArgumentPosition ( contextToken , sourceFile , typeChecker ) || isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ; } function isContextTokenValueLocation ( contextToken ) { return contextToken && ( ( contextToken . kind === SyntaxKind . TypeOfKeyword && ( contextToken . parent . kind === SyntaxKind . TypeQuery || isTypeOfExpression ( contextToken . parent ) ) ) || ( contextToken . kind === SyntaxKind . AssertsKeyword && contextToken . parent . kind === SyntaxKind . TypePredicate ) ) ; } function isContextTokenTypeLocation ( contextToken ) { if ( contextToken ) { const parentKind = contextToken . parent . kind ; switch ( contextToken . kind ) { case SyntaxKind . ColonToken : return parentKind === SyntaxKind . PropertyDeclaration || parentKind === SyntaxKind . PropertySignature || parentKind === SyntaxKind . Parameter || parentKind === SyntaxKind . VariableDeclaration || isFunctionLikeKind ( parentKind ) ; case SyntaxKind . EqualsToken : return parentKind === SyntaxKind . TypeAliasDeclaration ; case SyntaxKind . AsKeyword : return parentKind === SyntaxKind . AsExpression ; case SyntaxKind . LessThanToken : return parentKind === SyntaxKind . TypeReference || parentKind === SyntaxKind . TypeAssertionExpression ; case SyntaxKind . ExtendsKeyword : return parentKind === SyntaxKind . TypeParameter ; } } return false ; } /** Mutates `symbols`, `symbolToOriginInfoMap`, and `symbolToSortTextIdMap` */ function collectAutoImports ( ) { if ( ! shouldOfferImportCompletions ( ) ) return ; Debug . assert ( ! detailsEntryId ?. data , "Should not run 'collectAutoImports' when faster path is available via `data`" ) ; if ( detailsEntryId && ! detailsEntryId . source ) { return ; } const isAfterTypeOnlyImportSpecifierModifier = previousToken === contextToken && importCompletionNode && couldBeTypeOnlyImportSpecifier ( importCompletionNode , contextToken ) ; const lowerCaseTokenText = isAfterTypeOnlyImportSpecifierModifier ? "" : previousToken && isIdentifier ( previousToken ) ? previousToken . text . toLowerCase ( ) : "" ; const moduleSpecifierCache = host . getModuleSpecifierCache ?. ( ) ; const exportInfo = getExportInfoMap ( sourceFile , host , program , cancellationToken ) ; const packageJsonAutoImportProvider = host . getPackageJsonAutoImportProvider ?. ( ) ; const packageJsonFilter = detailsEntryId ? undefined : createPackageJsonImportFilter ( sourceFile , preferences , host ) ; resolvingModuleSpecifiers ( "collectAutoImports" , host , program , sourceFile , preferences , ! ! importCompletionNode , context => { exportInfo . forEach ( sourceFile . path , ( info , symbolName , isFromAmbientModule , exportMapKey ) => { if ( ! isIdentifierText ( symbolName , getEmitScriptTarget ( host . getCompilationSettings ( ) ) ) ) return ; if ( ! detailsEntryId && isStringANonContextualKeyword ( symbolName ) ) return ; if ( ! isTypeOnlyLocation && ! importCompletionNode && ! ( info [ 0 ] . targetFlags & SymbolFlags . Value ) ) return ; if ( isTypeOnlyLocation && ! ( info [ 0 ] . targetFlags & ( SymbolFlags . Module | SymbolFlags . Type ) ) ) return ; const isCompletionDetailsMatch = detailsEntryId && some ( info , i => detailsEntryId . source === stripQuotes ( i . moduleSymbol . name ) ) ; if ( isCompletionDetailsMatch || ! detailsEntryId && charactersFuzzyMatchInString ( symbolName , lowerCaseTokenText ) ) { const defaultExportInfo = find ( info , isImportableExportInfo ) ; if ( ! defaultExportInfo ) { return ; } const { exportInfo = defaultExportInfo , moduleSpecifier } = context . tryResolve ( info , isFromAmbientModule ) || { } ; const isDefaultExport = exportInfo . exportKind === ExportKind . Default ; const symbol = isDefaultExport && getLocalSymbolForExportDefault ( exportInfo . symbol ) || exportInfo . symbol ; pushAutoImportSymbol ( symbol , { kind : moduleSpecifier ? SymbolOriginInfoKind . ResolvedExport : SymbolOriginInfoKind . Export , moduleSpecifier , symbolName , exportMapKey , exportName : exportInfo . exportKind === ExportKind . ExportEquals ? InternalSymbolName . ExportEquals : exportInfo . symbol . name , fileName : exportInfo . moduleFileName , isDefaultExport , moduleSymbol : exportInfo . moduleSymbol , isFromPackageJson : exportInfo . isFromPackageJson , } ) ; } } ) ; hasUnresolvedAutoImports = context . resolutionLimitExceeded ( ) ; } ) ; function isImportableExportInfo ( info ) { const moduleFile = tryCast ( info . moduleSymbol . valueDeclaration , isSourceFile ) ; if ( ! moduleFile ) { const moduleName = stripQuotes ( info . moduleSymbol . name ) ; if ( JsTyping . nodeCoreModules . has ( moduleName ) && startsWith ( moduleName , "node:" ) !== shouldUseUriStyleNodeCoreModules ( sourceFile , program ) ) { return false ; } return packageJsonFilter ? packageJsonFilter . allowsImportingAmbientModule ( info . moduleSymbol , getModuleSpecifierResolutionHost ( info . isFromPackageJson ) ) : true ; } return isImportableFile ( info . isFromPackageJson ? packageJsonAutoImportProvider ! : program , sourceFile , moduleFile , preferences , packageJsonFilter , getModuleSpecifierResolutionHost ( info . isFromPackageJson ) , moduleSpecifierCache ) ; } } function pushAutoImportSymbol ( symbol , origin ) { const symbolId = getSymbolId ( symbol ) ; if ( symbolToSortTextIdMap [ symbolId ] === SortTextId . GlobalsOrKeywords ) { return ; } symbolToOriginInfoMap [ symbols . length ] = origin ; symbolToSortTextIdMap [ symbolId ] = importCompletionNode ? SortTextId . LocationPriority : SortTextId . AutoImportSuggestions ; symbols . push ( symbol ) ; } /**
         * Finds the first node that "embraces" the position, so that one may
         * accurately aggregate locals from the closest containing scope.
         */ function getScopeNode ( initialToken , position , sourceFile ) { let scope = initialToken ; while ( scope && ! positionBelongsToNode ( scope , position , sourceFile ) ) { scope = scope . parent ; } return scope ; } function isCompletionListBlocker ( contextToken ) { const start = timestamp ( ) ; const result = isInStringOrRegularExpressionOrTemplateLiteral ( contextToken ) || isSolelyIdentifierDefinitionLocation ( contextToken ) || isDotOfNumericLiteral ( contextToken ) || isInJsxText ( contextToken ) || isBigIntLiteral ( contextToken ) ; log ( "getCompletionsAtPosition: isCompletionListBlocker: " + ( timestamp ( ) - start ) ) ; return result ; } function isInJsxText ( contextToken ) { if ( contextToken . kind === SyntaxKind . JsxText ) { return true ; } if ( contextToken . kind === SyntaxKind . GreaterThanToken && contextToken . parent ) { if ( contextToken . parent . kind === SyntaxKind . JsxOpeningElement ) { return location . parent . kind !== SyntaxKind . JsxOpeningElement ; } if ( contextToken . parent . kind === SyntaxKind . JsxClosingElement || contextToken . parent . kind === SyntaxKind . JsxSelfClosingElement ) { return ! ! contextToken . parent . parent && contextToken . parent . parent . kind === SyntaxKind . JsxElement ; } } return false ; } function isNewIdentifierDefinitionLocation ( ) { if ( contextToken ) { const containingNodeKind = contextToken . parent . kind ; const tokenKind = keywordForNode ( contextToken ) ; switch ( tokenKind ) { case SyntaxKind . CommaToken : return containingNodeKind === SyntaxKind . CallExpression || containingNodeKind === SyntaxKind . Constructor || containingNodeKind === SyntaxKind . NewExpression || containingNodeKind === SyntaxKind . ArrayLiteralExpression || containingNodeKind === SyntaxKind . BinaryExpression || containingNodeKind === SyntaxKind . FunctionType || containingNodeKind === SyntaxKind . ObjectLiteralExpression ; case SyntaxKind . OpenParenToken : return containingNodeKind === SyntaxKind . CallExpression || containingNodeKind === SyntaxKind . Constructor || containingNodeKind === SyntaxKind . NewExpression || containingNodeKind === SyntaxKind . ParenthesizedExpression || containingNodeKind === SyntaxKind . ParenthesizedType ; case SyntaxKind . OpenBracketToken : return containingNodeKind === SyntaxKind . ArrayLiteralExpression || containingNodeKind === SyntaxKind . IndexSignature || containingNodeKind === SyntaxKind . ComputedPropertyName ; case SyntaxKind . ModuleKeyword : case SyntaxKind . NamespaceKeyword : case SyntaxKind . ImportKeyword : return true ; case SyntaxKind . DotToken : return containingNodeKind === SyntaxKind . ModuleDeclaration ; case SyntaxKind . OpenBraceToken : return containingNodeKind === SyntaxKind . ClassDeclaration || containingNodeKind === SyntaxKind . ObjectLiteralExpression ; case SyntaxKind . EqualsToken : return containingNodeKind === SyntaxKind . VariableDeclaration || containingNodeKind === SyntaxKind . BinaryExpression ; case SyntaxKind . TemplateHead : return containingNodeKind === SyntaxKind . TemplateExpression ; case SyntaxKind . TemplateMiddle : return containingNodeKind === SyntaxKind . TemplateSpan ; case SyntaxKind . AsyncKeyword : return containingNodeKind === SyntaxKind . MethodDeclaration || containingNodeKind === SyntaxKind . ShorthandPropertyAssignment ; case SyntaxKind . AsteriskToken : return containingNodeKind === SyntaxKind . MethodDeclaration ; } if ( isClassMemberCompletionKeyword ( tokenKind ) ) { return true ; } } return false ; } function isInStringOrRegularExpressionOrTemplateLiteral ( contextToken ) { return ( isRegularExpressionLiteral ( contextToken ) || isStringTextContainingNode ( contextToken ) ) && ( rangeContainsPositionExclusive ( createTextRangeFromSpan ( createTextSpanFromNode ( contextToken ) ) , position ) || position === contextToken . end && ( ! ! contextToken . isUnterminated || isRegularExpressionLiteral ( contextToken ) ) ) ; } function tryGetObjectTypeLiteralInTypeArgumentCompletionSymbols ( ) { const typeLiteralNode = tryGetTypeLiteralNode ( contextToken ) ; if ( ! typeLiteralNode ) return GlobalsSearch . Continue ; const intersectionTypeNode = isIntersectionTypeNode ( typeLiteralNode . parent ) ? typeLiteralNode . parent : undefined ; const containerTypeNode = intersectionTypeNode || typeLiteralNode ; const containerExpectedType = getConstraintOfTypeArgumentProperty ( containerTypeNode , typeChecker ) ; if ( ! containerExpectedType ) return GlobalsSearch . Continue ; const containerActualType = typeChecker . getTypeFromTypeNode ( containerTypeNode ) ; const members = getPropertiesForCompletion ( containerExpectedType , typeChecker ) ; const existingMembers = getPropertiesForCompletion ( containerActualType , typeChecker ) ; const existingMemberEscapedNames = new Set ( ) ; existingMembers . forEach ( s => existingMemberEscapedNames . add ( s . escapedName ) ) ; symbols = concatenate ( symbols , filter ( members , s => ! existingMemberEscapedNames . has ( s . escapedName ) ) ) ; completionKind = CompletionKind . ObjectPropertyDeclaration ; isNewIdentifierLocation = true ; return GlobalsSearch . Success ; } returns function tryGetObjectLikeCompletionSymbols ( ) { const objectLikeContainer = tryGetObjectLikeCompletionContainer ( contextToken ) ; if ( ! objectLikeContainer ) return GlobalsSearch . Continue ; completionKind = CompletionKind . ObjectPropertyDeclaration ; let typeMembers ; let existingMembers ; if ( objectLikeContainer . kind === SyntaxKind . ObjectLiteralExpression ) { const instantiatedType = tryGetObjectLiteralContextualType ( objectLikeContainer , typeChecker ) ; if ( instantiatedType === undefined ) { if ( objectLikeContainer . flags & NodeFlags . InWithStatement ) { return GlobalsSearch . Fail ; } isNonContextualObjectLiteral = true ; return GlobalsSearch . Continue ; } const completionsType = typeChecker . getContextualType ( objectLikeContainer , ContextFlags . Completions ) ; const hasStringIndexType = ( completionsType || instantiatedType ) . getStringIndexType ( ) ; const hasNumberIndextype = ( completionsType || instantiatedType ) . getNumberIndexType ( ) ; isNewIdentifierLocation = ! ! hasStringIndexType || ! ! hasNumberIndextype ; typeMembers = getPropertiesForObjectExpression ( instantiatedType , completionsType , objectLikeContainer , typeChecker ) ; existingMembers = objectLikeContainer . properties ; if ( typeMembers . length === 0 ) { if ( ! hasNumberIndextype ) { isNonContextualObjectLiteral = true ; return GlobalsSearch . Continue ; } } } else { Debug . assert ( objectLikeContainer . kind === SyntaxKind . ObjectBindingPattern ) ; isNewIdentifierLocation = false ; const rootDeclaration = getRootDeclaration ( objectLikeContainer . parent ) ; if ( ! isVariableLike ( rootDeclaration ) ) return Debug . fail ( "Root declaration is not variable-like." ) ; let canGetType = hasInitializer ( rootDeclaration ) || hasType ( rootDeclaration ) || rootDeclaration . parent . parent . kind === SyntaxKind . ForOfStatement ; if ( ! canGetType && rootDeclaration . kind === SyntaxKind . Parameter ) { if ( isExpression ( rootDeclaration . parent ) ) { canGetType = ! ! typeChecker . getContextualType ( rootDeclaration . parent as Expression ) ; } else if ( rootDeclaration . parent . kind === SyntaxKind . MethodDeclaration || rootDeclaration . parent . kind === SyntaxKind . SetAccessor ) { canGetType = isExpression ( rootDeclaration . parent . parent ) && ! ! typeChecker . getContextualType ( rootDeclaration . parent . parent as Expression ) ; } } if ( canGetType ) { const typeForObject = typeChecker . getTypeAtLocation ( objectLikeContainer ) ; if ( ! typeForObject ) return GlobalsSearch . Fail ; typeMembers = typeChecker . getPropertiesOfType ( typeForObject ) . filter ( propertySymbol => { return typeChecker . isPropertyAccessible ( objectLikeContainer , false , false , typeForObject , propertySymbol ) ; } ) ; existingMembers = objectLikeContainer . elements ; } } if ( typeMembers && typeMembers . length > 0 ) { symbols = concatenate ( symbols , filterObjectMembersList ( typeMembers , Debug . checkDefined ( existingMembers ) ) ) ; } setSortTextToOptionalMember ( ) ; return GlobalsSearch . Success ; } /**
         * Aggregates relevant symbols for completion in import clauses and export clauses
         * whose declarations have a module specifier; for instance, symbols will be aggregated for
         *
         *      import { | } from "moduleName";
         *      export { a as foo, | } from "moduleName";
         *
         * but not for
         *
         *      export { | };
         *
         * Relevant symbols are stored in the captured 'symbols' variable.
         */ function tryGetImportOrExportClauseCompletionSymbols ( ) { if ( ! contextToken ) return GlobalsSearch . Continue ; const namedImportsOrExports = contextToken . kind === SyntaxKind . OpenBraceToken || contextToken . kind === SyntaxKind . CommaToken ? tryCast ( contextToken . parent , isNamedImportsOrExports ) : isTypeKeywordTokenOrIdentifier ( contextToken ) ? tryCast ( contextToken . parent . parent , isNamedImportsOrExports ) : undefined ; if ( ! namedImportsOrExports ) return GlobalsSearch . Continue ; if ( ! isTypeKeywordTokenOrIdentifier ( contextToken ) ) { keywordFilters = KeywordCompletionFilters . TypeKeyword ; } const { moduleSpecifier } = namedImportsOrExports . kind === SyntaxKind . NamedImports ? namedImportsOrExports . parent . parent : namedImportsOrExports . parent ; if ( ! moduleSpecifier ) { isNewIdentifierLocation = true ; return namedImportsOrExports . kind === SyntaxKind . NamedImports ? GlobalsSearch . Fail : GlobalsSearch . Continue ; } const moduleSpecifierSymbol = typeChecker . getSymbolAtLocation ( moduleSpecifier ) ; if ( ! moduleSpecifierSymbol ) { isNewIdentifierLocation = true ; return GlobalsSearch . Fail ; } completionKind = CompletionKind . MemberLike ; isNewIdentifierLocation = false ; const exports = typeChecker . getExportsAndPropertiesOfModule ( moduleSpecifierSymbol ) ; const existing = new Set ( ( namedImportsOrExports . elements as NodeArray < ImportOrExportSpecifier > ) . filter ( n => ! isCurrentlyEditingNode ( n ) ) . map ( n => ( n . propertyName || n . name ) . escapedText ) ) ; const uniques = exports . filter ( e => e . escapedName !== InternalSymbolName . Default && ! existing . has ( e . escapedName ) ) ; symbols = concatenate ( symbols , uniques ) ; if ( ! uniques . length ) { keywordFilters = KeywordCompletionFilters . None ; } return GlobalsSearch . Success ; } /**
         * Adds local declarations for completions in named exports:
         *
         *   export { | };
         *
         * Does not check for the absence of a module specifier (`export {} from "./other"`)
         * because `tryGetImportOrExportClauseCompletionSymbols` runs first and handles that,
         * preventing this function from running.
         */ function tryGetLocalNamedExportCompletionSymbols ( ) { const namedExports = contextToken && ( contextToken . kind === SyntaxKind . OpenBraceToken || contextToken . kind === SyntaxKind . CommaToken ) ? tryCast ( contextToken . parent , isNamedExports ) : undefined ; if ( ! namedExports ) { return GlobalsSearch . Continue ; } const localsContainer = findAncestor ( namedExports , or ( isSourceFile , isModuleDeclaration ) ) ! ; completionKind = CompletionKind . None ; isNewIdentifierLocation = false ; localsContainer . locals ?. forEach ( ( symbol , name ) => { symbols . push ( symbol ) ; if ( localsContainer . symbol ?. exports ?. has ( name ) ) { symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . OptionalMember ; } } ) ; return GlobalsSearch . Success ; } /**
         * Aggregates relevant symbols for completion in class declaration
         * Relevant symbols are stored in the captured 'symbols' variable.
         */ function tryGetClassLikeCompletionSymbols ( ) { const decl = tryGetObjectTypeDeclarationCompletionContainer ( sourceFile , contextToken , location , position ) ; if ( ! decl ) return GlobalsSearch . Continue ; completionKind = CompletionKind . MemberLike ; isNewIdentifierLocation = true ; keywordFilters = contextToken . kind === SyntaxKind . AsteriskToken ? KeywordCompletionFilters . None : isClassLike ( decl ) ? KeywordCompletionFilters . ClassElementKeywords : KeywordCompletionFilters . InterfaceElementKeywords ; if ( ! isClassLike ( decl ) ) return GlobalsSearch . Success ; const classElement = contextToken . kind === SyntaxKind . SemicolonToken ? contextToken . parent . parent : contextToken . parent ; let classElementModifierFlags = isClassElement ( classElement ) ? getEffectiveModifierFlags ( classElement ) : ModifierFlags . None ; if ( contextToken . kind === SyntaxKind . Identifier && ! isCurrentlyEditingNode ( contextToken ) ) { switch ( contextToken . getText ( ) ) { case "private" : classElementModifierFlags = classElementModifierFlags | ModifierFlags . Private ; break ; case "static" : classElementModifierFlags = classElementModifierFlags | ModifierFlags . Static ; break ; case "override" : classElementModifierFlags = classElementModifierFlags | ModifierFlags . Override ; break ; } } if ( isClassStaticBlockDeclaration ( classElement ) ) { classElementModifierFlags |= ModifierFlags . Static ; } if ( ! ( classElementModifierFlags & ModifierFlags . Private ) ) { const baseTypeNodes = isClassLike ( decl ) && classElementModifierFlags & ModifierFlags . Override ? singleElementArray ( getEffectiveBaseTypeNode ( decl ) ) : getAllSuperTypeNodes ( decl ) ; const baseSymbols = flatMap ( baseTypeNodes , baseTypeNode => { const type = typeChecker . getTypeAtLocation ( baseTypeNode ) ; return classElementModifierFlags & ModifierFlags . Static ? type ?. symbol && typeChecker . getPropertiesOfType ( typeChecker . getTypeOfSymbolAtLocation ( type . symbol , decl ) ) : type && typeChecker . getPropertiesOfType ( type ) ; } ) ; symbols = concatenate ( symbols , filterClassMembersList ( baseSymbols , decl . members , classElementModifierFlags ) ) ; } return GlobalsSearch . Success ; } /**
         * Returns the immediate owning object literal or binding pattern of a context token,
         * on the condition that one exists and that the context implies completion should be given.
         */ function tryGetObjectLikeCompletionContainer ( contextToken ) { if ( contextToken ) { const { parent } = contextToken ; switch ( contextToken . kind ) { case SyntaxKind . OpenBraceToken : case SyntaxKind . CommaToken : if ( isObjectLiteralExpression ( parent ) || isObjectBindingPattern ( parent ) ) { return parent ; } break ; case SyntaxKind . AsteriskToken : return isMethodDeclaration ( parent ) ? tryCast ( parent . parent , isObjectLiteralExpression ) : undefined ; case SyntaxKind . Identifier : return ( contextToken as Identifier ) . text === "async" && isShorthandPropertyAssignment ( contextToken . parent ) ? contextToken . parent . parent : undefined ; } } return undefined ; } function isConstructorParameterCompletion ( node ) { return ! ! node . parent && isParameter ( node . parent ) && isConstructorDeclaration ( node . parent . parent ) && ( isParameterPropertyModifier ( node . kind ) || isDeclarationName ( node ) ) ; } /**
         * Returns the immediate owning class declaration of a context token,
         * on the condition that one exists and that the context implies completion should be given.
         */ function tryGetConstructorLikeCompletionContainer ( contextToken ) { if ( contextToken ) { const parent = contextToken . parent ; switch ( contextToken . kind ) { case SyntaxKind . OpenParenToken : case SyntaxKind . CommaToken : return isConstructorDeclaration ( contextToken . parent ) ? contextToken . parent : undefined ; default : if ( isConstructorParameterCompletion ( contextToken ) ) { return parent . parent as ConstructorDeclaration ; } } } return undefined ; } function tryGetFunctionLikeBodyCompletionContainer ( contextToken ) { if ( contextToken ) { let prev ; const container = findAncestor ( contextToken . parent , ( node ) => { if ( isClassLike ( node ) ) { return "quit" ; } if ( isFunctionLikeDeclaration ( node ) && prev === node . body ) { return true ; } prev = node ; return false ; } ) ; return container && container as FunctionLikeDeclaration ; } } function tryGetContainingJsxElement ( contextToken ) { if ( contextToken ) { const parent = contextToken . parent ; switch ( contextToken . kind ) { case SyntaxKind . GreaterThanToken : case SyntaxKind . LessThanSlashToken : case SyntaxKind . SlashToken : case SyntaxKind . Identifier : case SyntaxKind . PropertyAccessExpression : case SyntaxKind . JsxAttributes : case SyntaxKind . JsxAttribute : case SyntaxKind . JsxSpreadAttribute : if ( parent && ( parent . kind === SyntaxKind . JsxSelfClosingElement || parent . kind === SyntaxKind . JsxOpeningElement ) ) { if ( contextToken . kind === SyntaxKind . GreaterThanToken ) { const precedingToken = findPrecedingToken ( contextToken . pos , sourceFile , undefined ) ; if ( ! ( parent as JsxOpeningLikeElement ) . typeArguments || ( precedingToken && precedingToken . kind === SyntaxKind . SlashToken ) ) break ; } return parent as JsxOpeningLikeElement ; } else if ( parent . kind === SyntaxKind . JsxAttribute ) { return parent . parent . parent as JsxOpeningLikeElement ; } break ; case SyntaxKind . StringLiteral : if ( parent && ( ( parent . kind === SyntaxKind . JsxAttribute ) || ( parent . kind === SyntaxKind . JsxSpreadAttribute ) ) ) { return parent . parent . parent as JsxOpeningLikeElement ; } break ; case SyntaxKind . CloseBraceToken : if ( parent && parent . kind === SyntaxKind . JsxExpression && parent . parent && parent . parent . kind === SyntaxKind . JsxAttribute ) { return parent . parent . parent . parent as JsxOpeningLikeElement ; } if ( parent && parent . kind === SyntaxKind . JsxSpreadAttribute ) { return parent . parent . parent as JsxOpeningLikeElement ; } break ; } } return undefined ; } returns function isSolelyIdentifierDefinitionLocation ( contextToken ) { const parent = contextToken . parent ; const containingNodeKind = parent . kind ; switch ( contextToken . kind ) { case SyntaxKind . CommaToken : return containingNodeKind === SyntaxKind . VariableDeclaration || isVariableDeclarationListButNotTypeArgument ( contextToken ) || containingNodeKind === SyntaxKind . VariableStatement || containingNodeKind === SyntaxKind . EnumDeclaration || isFunctionLikeButNotConstructor ( containingNodeKind ) || containingNodeKind === SyntaxKind . InterfaceDeclaration || containingNodeKind === SyntaxKind . ArrayBindingPattern || containingNodeKind === SyntaxKind . TypeAliasDeclaration || ( isClassLike ( parent ) && ! ! parent . typeParameters && parent . typeParameters . end >= contextToken . pos ) ; case SyntaxKind . DotToken : return containingNodeKind === SyntaxKind . ArrayBindingPattern ; case SyntaxKind . ColonToken : return containingNodeKind === SyntaxKind . BindingElement ; case SyntaxKind . OpenBracketToken : return containingNodeKind === SyntaxKind . ArrayBindingPattern ; case SyntaxKind . OpenParenToken : return containingNodeKind === SyntaxKind . CatchClause || isFunctionLikeButNotConstructor ( containingNodeKind ) ; case SyntaxKind . OpenBraceToken : return containingNodeKind === SyntaxKind . EnumDeclaration ; case SyntaxKind . LessThanToken : return containingNodeKind === SyntaxKind . ClassDeclaration || containingNodeKind === SyntaxKind . ClassExpression || containingNodeKind === SyntaxKind . InterfaceDeclaration || containingNodeKind === SyntaxKind . TypeAliasDeclaration || isFunctionLikeKind ( containingNodeKind ) ; case SyntaxKind . StaticKeyword : return containingNodeKind === SyntaxKind . PropertyDeclaration && ! isClassLike ( parent . parent ) ; case SyntaxKind . DotDotDotToken : return containingNodeKind === SyntaxKind . Parameter || ( ! ! parent . parent && parent . parent . kind === SyntaxKind . ArrayBindingPattern ) ; case SyntaxKind . PublicKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : return containingNodeKind === SyntaxKind . Parameter && ! isConstructorDeclaration ( parent . parent ) ; case SyntaxKind . AsKeyword : return containingNodeKind === SyntaxKind . ImportSpecifier || containingNodeKind === SyntaxKind . ExportSpecifier || containingNodeKind === SyntaxKind . NamespaceImport ; case SyntaxKind . GetKeyword : case SyntaxKind . SetKeyword : return ! isFromObjectTypeDeclaration ( contextToken ) ; case SyntaxKind . Identifier : if ( containingNodeKind === SyntaxKind . ImportSpecifier && contextToken === ( parent as ImportSpecifier ) . name && ( contextToken as Identifier ) . text === "type" ) { return false ; } break ; case SyntaxKind . ClassKeyword : case SyntaxKind . EnumKeyword : case SyntaxKind . InterfaceKeyword : case SyntaxKind . FunctionKeyword : case SyntaxKind . VarKeyword : case SyntaxKind . ImportKeyword : case SyntaxKind . LetKeyword : case SyntaxKind . ConstKeyword : case SyntaxKind . InferKeyword : return true ; case SyntaxKind . TypeKeyword : return containingNodeKind !== SyntaxKind . ImportSpecifier ; case SyntaxKind . AsteriskToken : return isFunctionLike ( contextToken . parent ) && ! isMethodDeclaration ( contextToken . parent ) ; } if ( isClassMemberCompletionKeyword ( keywordForNode ( contextToken ) ) && isFromObjectTypeDeclaration ( contextToken ) ) { return false ; } if ( isConstructorParameterCompletion ( contextToken ) ) { if ( ! isIdentifier ( contextToken ) || isParameterPropertyModifier ( keywordForNode ( contextToken ) ) || isCurrentlyEditingNode ( contextToken ) ) { return false ; } } switch ( keywordForNode ( contextToken ) ) { case SyntaxKind . AbstractKeyword : case SyntaxKind . ClassKeyword : case SyntaxKind . ConstKeyword : case SyntaxKind . DeclareKeyword : case SyntaxKind . EnumKeyword : case SyntaxKind . FunctionKeyword : case SyntaxKind . InterfaceKeyword : case SyntaxKind . LetKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : case SyntaxKind . PublicKeyword : case SyntaxKind . StaticKeyword : case SyntaxKind . VarKeyword : return true ; case SyntaxKind . AsyncKeyword : return isPropertyDeclaration ( contextToken . parent ) ; } const ancestorClassLike = findAncestor ( contextToken . parent , isClassLike ) ; if ( ancestorClassLike && contextToken === previousToken && isPreviousPropertyDeclarationTerminated ( contextToken , position ) ) { return false ; } const ancestorPropertyDeclaraion = getAncestor ( contextToken . parent , SyntaxKind . PropertyDeclaration ) ; if ( ancestorPropertyDeclaraion && contextToken !== previousToken && isClassLike ( previousToken . parent . parent ) && position <= previousToken . end ) { if ( isPreviousPropertyDeclarationTerminated ( contextToken , previousToken . end ) ) { return false ; } else if ( contextToken . kind !== SyntaxKind . EqualsToken && ( isInitializedProperty ( ancestorPropertyDeclaraion as PropertyDeclaration ) || hasType ( ancestorPropertyDeclaraion ) ) ) { return true ; } } return isDeclarationName ( contextToken ) && ! isShorthandPropertyAssignment ( contextToken . parent ) && ! isJsxAttribute ( contextToken . parent ) && ! ( isClassLike ( contextToken . parent ) && ( contextToken !== previousToken || position > previousToken . end ) ) ; } function isPreviousPropertyDeclarationTerminated ( contextToken , position ) { return contextToken . kind !== SyntaxKind . EqualsToken && ( contextToken . kind === SyntaxKind . SemicolonToken || ! positionsAreOnSameLine ( contextToken . end , position , sourceFile ) ) ; } function isFunctionLikeButNotConstructor ( kind ) { return isFunctionLikeKind ( kind ) && kind !== SyntaxKind . Constructor ; } function isDotOfNumericLiteral ( contextToken ) { if ( contextToken . kind === SyntaxKind . NumericLiteral ) { const text = contextToken . getFullText ( ) ; return text . charAt ( text . length - 1 ) === "." ; } return false ; } function isVariableDeclarationListButNotTypeArgument ( node ) { return node . parent . kind === SyntaxKind . VariableDeclarationList && ! isPossiblyTypeArgumentPosition ( node , sourceFile , typeChecker ) ; } returns function filterObjectMembersList ( contextualMemberSymbols , existingMembers ) { if ( existingMembers . length === 0 ) { return contextualMemberSymbols ; } const membersDeclaredBySpreadAssignment = new Set < string > ( ) ; const existingMemberNames = new Set < __String > ( ) ; for ( const m of existingMembers ) { if ( m . kind !== SyntaxKind . PropertyAssignment && m . kind !== SyntaxKind . ShorthandPropertyAssignment && m . kind !== SyntaxKind . BindingElement && m . kind !== SyntaxKind . MethodDeclaration && m . kind !== SyntaxKind . GetAccessor && m . kind !== SyntaxKind . SetAccessor && m . kind !== SyntaxKind . SpreadAssignment ) { continue ; } if ( isCurrentlyEditingNode ( m ) ) { continue ; } let existingName ; if ( isSpreadAssignment ( m ) ) { setMembersDeclaredBySpreadAssignment ( m , membersDeclaredBySpreadAssignment ) ; } else if ( isBindingElement ( m ) && m . propertyName ) { if ( m . propertyName . kind === SyntaxKind . Identifier ) { existingName = m . propertyName . escapedText ; } } else { const name = getNameOfDeclaration ( m ) ; existingName = name && isPropertyNameLiteral ( name ) ? getEscapedTextOfIdentifierOrLiteral ( name ) : undefined ; } if ( existingName !== undefined ) { existingMemberNames . add ( existingName ) ; } } const filteredSymbols = contextualMemberSymbols . filter ( m => ! existingMemberNames . has ( m . escapedName ) ) ; setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , filteredSymbols ) ; return filteredSymbols ; } function setMembersDeclaredBySpreadAssignment ( declaration , membersDeclaredBySpreadAssignment ) { const expression = declaration . expression ; const symbol = typeChecker . getSymbolAtLocation ( expression ) ; const type = symbol && typeChecker . getTypeOfSymbolAtLocation ( symbol , expression ) ; const properties = type && ( type as ObjectType ) . properties ; if ( properties ) { properties . forEach ( property => { membersDeclaredBySpreadAssignment . add ( property . name ) ; } ) ; } } function setSortTextToOptionalMember ( ) { symbols . forEach ( m => { if ( m . flags & SymbolFlags . Optional ) { const symbolId = getSymbolId ( m ) ; symbolToSortTextIdMap [ symbolId ] = symbolToSortTextIdMap [ symbolId ] ?? SortTextId . OptionalMember ; } } ) ; } function setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , contextualMemberSymbols ) { if ( membersDeclaredBySpreadAssignment . size === 0 ) { return ; } for ( const contextualMemberSymbol of contextualMemberSymbols ) { if ( membersDeclaredBySpreadAssignment . has ( contextualMemberSymbol . name ) ) { symbolToSortTextIdMap [ getSymbolId ( contextualMemberSymbol ) ] = SortTextId . MemberDeclaredBySpreadAssignment ; } } } returns function filterClassMembersList ( baseSymbols , existingMembers , currentClassElementModifierFlags ) { const existingMemberNames = new Set < __String > ( ) ; for ( const m of existingMembers ) { if ( m . kind !== SyntaxKind . PropertyDeclaration && m . kind !== SyntaxKind . MethodDeclaration && m . kind !== SyntaxKind . GetAccessor && m . kind !== SyntaxKind . SetAccessor ) { continue ; } if ( isCurrentlyEditingNode ( m ) ) { continue ; } if ( hasEffectiveModifier ( m , ModifierFlags . Private ) ) { continue ; } if ( isStatic ( m ) !== ! ! ( currentClassElementModifierFlags & ModifierFlags . Static ) ) { continue ; } const existingName = getPropertyNameForPropertyNameNode ( m . name ! ) ; if ( existingName ) { existingMemberNames . add ( existingName ) ; } } return baseSymbols . filter ( propertySymbol => ! existingMemberNames . has ( propertySymbol . escapedName ) && ! ! propertySymbol . declarations && ! ( getDeclarationModifierFlagsFromSymbol ( propertySymbol ) & ModifierFlags . Private ) && ! ( propertySymbol . valueDeclaration && isPrivateIdentifierClassElementDeclaration ( propertySymbol . valueDeclaration ) ) ) ; } returns function filterJsxAttributes ( symbols , attributes ) { const seenNames = new Set < __String > ( ) ; const membersDeclaredBySpreadAssignment = new Set < string > ( ) ; for ( const attr of attributes ) { if ( isCurrentlyEditingNode ( attr ) ) { continue ; } if ( attr . kind === SyntaxKind . JsxAttribute ) { seenNames . add ( attr . name . escapedText ) ; } else if ( isJsxSpreadAttribute ( attr ) ) { setMembersDeclaredBySpreadAssignment ( attr , membersDeclaredBySpreadAssignment ) ; } } const filteredSymbols = symbols . filter ( a => ! seenNames . has ( a . escapedName ) ) ; setSortTextToMemberDeclaredBySpreadAssignment ( membersDeclaredBySpreadAssignment , filteredSymbols ) ; return filteredSymbols ; } function isCurrentlyEditingNode ( node ) { return node . getStart ( sourceFile ) <= position && position <= node . getEnd ( ) ; } } function getRelevantTokens ( position , sourceFile ) { const previousToken = findPrecedingToken ( position , sourceFile ) ; if ( previousToken && position <= previousToken . end && ( isMemberName ( previousToken ) || isKeyword ( previousToken . kind ) ) ) { const contextToken = findPrecedingToken ( previousToken . getFullStart ( ) , sourceFile , undefined ) ! ; return { contextToken , previousToken } ; } return { contextToken : previousToken as Node , previousToken : previousToken as Node } ; } function getAutoImportSymbolFromCompletionEntryData ( name , data , program , host ) { const containingProgram = data . isPackageJsonImport ? host . getPackageJsonAutoImportProvider ! ( ) ! : program ; const checker = containingProgram . getTypeChecker ( ) ; const moduleSymbol = data . ambientModuleName ? checker . tryFindAmbientModule ( data . ambientModuleName ) : data . fileName ? checker . getMergedSymbol ( Debug . checkDefined ( containingProgram . getSourceFile ( data . fileName ) ) . symbol ) : undefined ; if ( ! moduleSymbol ) return undefined ; let symbol = data . exportName === InternalSymbolName . ExportEquals ? checker . resolveExternalModuleSymbol ( moduleSymbol ) : checker . tryGetMemberInModuleExportsAndProperties ( data . exportName , moduleSymbol ) ; if ( ! symbol ) return undefined ; const isDefaultExport = data . exportName === InternalSymbolName . Default ; symbol = isDefaultExport && getLocalSymbolForExportDefault ( symbol ) || symbol ; return { symbol , origin : completionEntryDataToSymbolOriginInfo ( data , name , moduleSymbol ) } ; } interface CompletionEntryDisplayNameForSymbol { readonly name : string ; readonly needsConvertPropertyAccess : boolean ; } function getCompletionEntryDisplayNameForSymbol ( symbol , target , origin , kind , jsxIdentifierExpected ) { const name = originIncludesSymbolName ( origin ) ? origin . symbolName : symbol . name ; if ( name === undefined || symbol . flags & SymbolFlags . Module && isSingleOrDoubleQuote ( name . charCodeAt ( 0 ) ) || isKnownSymbol ( symbol ) ) { return undefined ; } const validNameResult = { name , needsConvertPropertyAccess : false } ; if ( isIdentifierText ( name , target , jsxIdentifierExpected ? LanguageVariant . JSX : LanguageVariant . Standard ) || symbol . valueDeclaration && isPrivateIdentifierClassElementDeclaration ( symbol . valueDeclaration ) ) { return validNameResult ; } switch ( kind ) { case CompletionKind . MemberLike : return undefined ; case CompletionKind . ObjectPropertyDeclaration : return { name : JSON . stringify ( name ) , needsConvertPropertyAccess : false } ; case CompletionKind . PropertyAccess : case CompletionKind . Global : return name . charCodeAt ( 0 ) === CharacterCodes . space ? undefined : { name , needsConvertPropertyAccess : true } ; case CompletionKind . None : case CompletionKind . String : return validNameResult ; default : Debug . assertNever ( kind ) ; } } const _keywordCompletions = [ ] ; const allKeywordsCompletions = memoize ( ( ) => { const res = [ ] ; for ( let i = SyntaxKind . FirstKeyword ; i <= SyntaxKind . LastKeyword ; i ++ ) { res . push ( { name : tokenToString ( i ) ! , kind : ScriptElementKind . keyword , kindModifiers : ScriptElementKindModifier . none , sortText : SortText . GlobalsOrKeywords } ) ; } return res ; } ) ; function getKeywordCompletions ( keywordFilter , filterOutTsOnlyKeywords ) { if ( ! filterOutTsOnlyKeywords ) return getTypescriptKeywordCompletions ( keywordFilter ) ; const index = keywordFilter + KeywordCompletionFilters . Last + 1 ; return _keywordCompletions [ index ] || ( _keywordCompletions [ index ] = getTypescriptKeywordCompletions ( keywordFilter ) . filter ( entry => ! isTypeScriptOnlyKeyword ( stringToToken ( entry . name ) ! ) ) ) ; } function getTypescriptKeywordCompletions ( keywordFilter ) { return _keywordCompletions [ keywordFilter ] || ( _keywordCompletions [ keywordFilter ] = allKeywordsCompletions ( ) . filter ( entry => { const kind = stringToToken ( entry . name ) ! ; switch ( keywordFilter ) { case KeywordCompletionFilters . None : return false ; case KeywordCompletionFilters . All : return isFunctionLikeBodyKeyword ( kind ) || kind === SyntaxKind . DeclareKeyword || kind === SyntaxKind . ModuleKeyword || kind === SyntaxKind . TypeKeyword || kind === SyntaxKind . NamespaceKeyword || kind === SyntaxKind . AbstractKeyword || isTypeKeyword ( kind ) && kind !== SyntaxKind . UndefinedKeyword ; case KeywordCompletionFilters . FunctionLikeBodyKeywords : return isFunctionLikeBodyKeyword ( kind ) ; case KeywordCompletionFilters . ClassElementKeywords : return isClassMemberCompletionKeyword ( kind ) ; case KeywordCompletionFilters . InterfaceElementKeywords : return isInterfaceOrTypeLiteralCompletionKeyword ( kind ) ; case KeywordCompletionFilters . ConstructorParameterKeywords : return isParameterPropertyModifier ( kind ) ; case KeywordCompletionFilters . TypeAssertionKeywords : return isTypeKeyword ( kind ) || kind === SyntaxKind . ConstKeyword ; case KeywordCompletionFilters . TypeKeywords : return isTypeKeyword ( kind ) ; case KeywordCompletionFilters . TypeKeyword : return kind === SyntaxKind . TypeKeyword ; default : return Debug . assertNever ( keywordFilter ) ; } } ) ) ; } function isTypeScriptOnlyKeyword ( kind ) { switch ( kind ) { case SyntaxKind . AbstractKeyword : case SyntaxKind . AnyKeyword : case SyntaxKind . BigIntKeyword : case SyntaxKind . BooleanKeyword : case SyntaxKind . DeclareKeyword : case SyntaxKind . EnumKeyword : case SyntaxKind . GlobalKeyword : case SyntaxKind . ImplementsKeyword : case SyntaxKind . InferKeyword : case SyntaxKind . InterfaceKeyword : case SyntaxKind . IsKeyword : case SyntaxKind . KeyOfKeyword : case SyntaxKind . ModuleKeyword : case SyntaxKind . NamespaceKeyword : case SyntaxKind . NeverKeyword : case SyntaxKind . NumberKeyword : case SyntaxKind . ObjectKeyword : case SyntaxKind . OverrideKeyword : case SyntaxKind . PrivateKeyword : case SyntaxKind . ProtectedKeyword : case SyntaxKind . PublicKeyword : case SyntaxKind . ReadonlyKeyword : case SyntaxKind . StringKeyword : case SyntaxKind . SymbolKeyword : case SyntaxKind . TypeKeyword : case SyntaxKind . UniqueKeyword : case SyntaxKind . UnknownKeyword : return true ; default : return false ; } } function isInterfaceOrTypeLiteralCompletionKeyword ( kind ) { return kind === SyntaxKind . ReadonlyKeyword ; } function isClassMemberCompletionKeyword ( kind ) { switch ( kind ) { case SyntaxKind . AbstractKeyword : case SyntaxKind . ConstructorKeyword : case SyntaxKind . GetKeyword : case SyntaxKind . SetKeyword : case SyntaxKind . AsyncKeyword : case SyntaxKind . DeclareKeyword : case SyntaxKind . OverrideKeyword : return true ; default : return isClassMemberModifier ( kind ) ; } } function isFunctionLikeBodyKeyword ( kind ) { return kind === SyntaxKind . AsyncKeyword || kind === SyntaxKind . AwaitKeyword || kind === SyntaxKind . AsKeyword || ! isContextualKeyword ( kind ) && ! isClassMemberCompletionKeyword ( kind ) ; } function keywordForNode ( node ) { return isIdentifier ( node ) ? node . originalKeywordKind || SyntaxKind . Unknown : node . kind ; } /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ function getJsDocTagAtPosition ( node , position ) { return findAncestor ( node , n => isJSDocTag ( n ) && rangeContainsPosition ( n , position ) ? true : isJSDoc ( n ) ? "quit" : false ) as JSDocTag | undefined ; } export function getPropertiesForObjectExpression ( contextualType , completionsType , obj , checker ) { const hasCompletionsType = completionsType && completionsType !== contextualType ; const type = hasCompletionsType && ! ( completionsType ! . flags & TypeFlags . AnyOrUnknown ) ? checker . getUnionType ( [ contextualType , completionsType ! ] ) : contextualType ; const properties = getApparentProperties ( type , obj , checker ) ; return type . isClass ( ) && containsNonPublicProperties ( properties ) ? [ ] : hasCompletionsType ? filter ( properties , hasDeclarationOtherThanSelf ) : properties ; function hasDeclarationOtherThanSelf ( member ) { if ( ! length ( member . declarations ) ) return true ; return some ( member . declarations , decl => decl . parent !== obj ) ; } } function getApparentProperties ( type , node , checker ) { if ( ! type . isUnion ( ) ) return type . getApparentProperties ( ) ; return checker . getAllPossiblePropertiesOfTypes ( filter ( type . types , memberType => ! ( memberType . flags & TypeFlags . Primitive || checker . isArrayLikeType ( memberType ) || checker . isTypeInvalidDueToUnionDiscriminant ( memberType , node ) || typeHasCallOrConstructSignatures ( memberType , checker ) || memberType . isClass ( ) && containsNonPublicProperties ( memberType . getApparentProperties ( ) ) ) ) ) ; } function containsNonPublicProperties ( props ) { return some ( props , p => ! ! ( getDeclarationModifierFlagsFromSymbol ( p ) & ModifierFlags . NonPublicAccessibilityModifier ) ) ; } /**
     * Gets all properties on a type, but if that type is a union of several types,
     * excludes array-like types or callable/constructable types.
     */ function getPropertiesForCompletion ( type , checker ) { return type . isUnion ( ) ? Debug . checkEachDefined ( checker . getAllPossiblePropertiesOfTypes ( type . types ) , "getAllPossiblePropertiesOfTypes() should all be defined" ) : Debug . checkEachDefined ( type . getApparentProperties ( ) , "getApparentProperties() should all be defined" ) ; } /**
     * Returns the immediate owning class declaration of a context token,
     * on the condition that one exists and that the context implies completion should be given.
     */ function tryGetObjectTypeDeclarationCompletionContainer ( sourceFile , contextToken , location , position ) { switch ( location . kind ) { case SyntaxKind . SyntaxList : return tryCast ( location . parent , isObjectTypeDeclaration ) ; case SyntaxKind . EndOfFileToken : const cls = tryCast ( lastOrUndefined ( cast ( location . parent , isSourceFile ) . statements ) , isObjectTypeDeclaration ) ; if ( cls && ! findChildOfKind ( cls , SyntaxKind . CloseBraceToken , sourceFile ) ) { return cls ; } break ; case SyntaxKind . Identifier : { if ( isPropertyDeclaration ( location . parent ) && location . parent . initializer === location ) { return undefined ; } if ( isFromObjectTypeDeclaration ( location ) ) { return findAncestor ( location , isObjectTypeDeclaration ) ; } } } if ( ! contextToken ) return undefined ; if ( location . kind === SyntaxKind . ConstructorKeyword || ( isIdentifier ( contextToken ) && isPropertyDeclaration ( contextToken . parent ) && isClassLike ( location ) ) ) { return findAncestor ( contextToken , isClassLike ) as ObjectTypeDeclaration ; } switch ( contextToken . kind ) { case SyntaxKind . EqualsToken : return undefined ; case SyntaxKind . SemicolonToken : case SyntaxKind . CloseBraceToken : return isFromObjectTypeDeclaration ( location ) && ( location . parent as ClassElement | TypeElement ) . name === location ? location . parent . parent as ObjectTypeDeclaration : tryCast ( location , isObjectTypeDeclaration ) ; case SyntaxKind . OpenBraceToken : case SyntaxKind . CommaToken : return tryCast ( contextToken . parent , isObjectTypeDeclaration ) ; default : if ( ! isFromObjectTypeDeclaration ( contextToken ) ) { if ( getLineAndCharacterOfPosition ( sourceFile , contextToken . getEnd ( ) ) . line !== getLineAndCharacterOfPosition ( sourceFile , position ) . line && isObjectTypeDeclaration ( location ) ) { return location ; } return undefined ; } const isValidKeyword = isClassLike ( contextToken . parent . parent ) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword ; return ( isValidKeyword ( contextToken . kind ) || contextToken . kind === SyntaxKind . AsteriskToken || isIdentifier ( contextToken ) && isValidKeyword ( stringToToken ( contextToken . text ) ! ) ) ? contextToken . parent . parent as ObjectTypeDeclaration : undefined ; } } function tryGetTypeLiteralNode ( node ) { if ( ! node ) return undefined ; const parent = node . parent ; switch ( node . kind ) { case SyntaxKind . OpenBraceToken : if ( isTypeLiteralNode ( parent ) ) { return parent ; } break ; case SyntaxKind . SemicolonToken : case SyntaxKind . CommaToken : case SyntaxKind . Identifier : if ( parent . kind === SyntaxKind . PropertySignature && isTypeLiteralNode ( parent . parent ) ) { return parent . parent ; } break ; } return undefined ; } function getConstraintOfTypeArgumentProperty ( node , checker ) { if ( ! node ) return undefined ; if ( isTypeNode ( node ) && isTypeReferenceType ( node . parent ) ) { return checker . getTypeArgumentConstraint ( node ) ; } const t = getConstraintOfTypeArgumentProperty ( node . parent , checker ) ; if ( ! t ) return undefined ; switch ( node . kind ) { case SyntaxKind . PropertySignature : return checker . getTypeOfPropertyOfContextualType ( t , node . symbol . escapedName ) ; case SyntaxKind . IntersectionType : case SyntaxKind . TypeLiteral : case SyntaxKind . UnionType : return t ; } } function isFromObjectTypeDeclaration ( node ) { return node . parent && isClassOrTypeElement ( node . parent ) && isObjectTypeDeclaration ( node . parent . parent ) ; } function isValidTrigger ( sourceFile , triggerCharacter , contextToken , position ) { switch ( triggerCharacter ) { case "." : case "@" : return true ; case '"' : case "'" : case "`" : return ! ! contextToken && isStringLiteralOrTemplate ( contextToken ) && position === contextToken . getStart ( sourceFile ) + 1 ; case "#" : return ! ! contextToken && isPrivateIdentifier ( contextToken ) && ! ! getContainingClass ( contextToken ) ; case "<" : return ! ! contextToken && contextToken . kind === SyntaxKind . LessThanToken && ( ! isBinaryExpression ( contextToken . parent ) || binaryExpressionMayBeOpenTag ( contextToken . parent ) ) ; case "/" : return ! ! contextToken && ( isStringLiteralLike ( contextToken ) ? ! ! tryGetImportFromModuleSpecifier ( contextToken ) : contextToken . kind === SyntaxKind . SlashToken && isJsxClosingElement ( contextToken . parent ) ) ; case " " : return ! ! contextToken && isImportKeyword ( contextToken ) && contextToken . parent . kind === SyntaxKind . SourceFile ; default : return Debug . assertNever ( triggerCharacter ) ; } } function binaryExpressionMayBeOpenTag ( { left } ) { return nodeIsMissing ( left ) ; } /** Determines if a type is exactly the same type resolved by the global 'self', 'global', or 'globalThis'. */ function isProbablyGlobalType ( type , sourceFile , checker ) { const selfSymbol = checker . resolveName ( "self" , undefined , SymbolFlags . Value , false ) ; if ( selfSymbol && checker . getTypeOfSymbolAtLocation ( selfSymbol , sourceFile ) === type ) { return true ; } const globalSymbol = checker . resolveName ( "global" , undefined , SymbolFlags . Value , false ) ; if ( globalSymbol && checker . getTypeOfSymbolAtLocation ( globalSymbol , sourceFile ) === type ) { return true ; } const globalThisSymbol = checker . resolveName ( "globalThis" , undefined , SymbolFlags . Value , false ) ; if ( globalThisSymbol && checker . getTypeOfSymbolAtLocation ( globalThisSymbol , sourceFile ) === type ) { return true ; } return false ; } function isStaticProperty ( symbol ) { return ! ! ( symbol . valueDeclaration && getEffectiveModifierFlags ( symbol . valueDeclaration ) & ModifierFlags . Static && isClassLike ( symbol . valueDeclaration . parent ) ) ; } function tryGetObjectLiteralContextualType ( node , typeChecker ) { const type = typeChecker . getContextualType ( node ) ; if ( type ) { return type ; } if ( isBinaryExpression ( node . parent ) && node . parent . operatorToken . kind === SyntaxKind . EqualsToken && node === node . parent . left ) { return typeChecker . getTypeAtLocation ( node . parent ) ; } return undefined ; } interface ImportStatementCompletionInfo { isKeywordOnlyCompletion : boolean ; keywordCompletion : TokenSyntaxKind | undefined ; isNewIdentifierLocation : boolean ; replacementNode : ImportEqualsDeclaration | ImportDeclaration | ImportSpecifier | Token < SyntaxKind . ImportKeyword > | undefined ; } function getImportStatementCompletionInfo ( contextToken ) { let keywordCompletion ; let isKeywordOnlyCompletion = false ; const candidate = getCandidate ( ) ; return { isKeywordOnlyCompletion , keywordCompletion , isNewIdentifierLocation : ! ! ( candidate || keywordCompletion === SyntaxKind . TypeKeyword ) , replacementNode : candidate && rangeIsOnSingleLine ( candidate , candidate . getSourceFile ( ) ) ? candidate : undefined } ; function getCandidate ( ) { const parent = contextToken . parent ; if ( isImportEqualsDeclaration ( parent ) ) { keywordCompletion = contextToken . kind === SyntaxKind . TypeKeyword ? undefined : SyntaxKind . TypeKeyword ; return isModuleSpecifierMissingOrEmpty ( parent . moduleReference ) ? parent : undefined ; } if ( couldBeTypeOnlyImportSpecifier ( parent , contextToken ) && canCompleteFromNamedBindings ( parent . parent ) ) { return parent ; } if ( isNamedImports ( parent ) || isNamespaceImport ( parent ) ) { if ( ! parent . parent . isTypeOnly && ( contextToken . kind === SyntaxKind . OpenBraceToken || contextToken . kind === SyntaxKind . ImportKeyword || contextToken . kind === SyntaxKind . CommaToken ) ) { keywordCompletion = SyntaxKind . TypeKeyword ; } if ( canCompleteFromNamedBindings ( parent ) ) { if ( contextToken . kind === SyntaxKind . CloseBraceToken || contextToken . kind === SyntaxKind . Identifier ) { isKeywordOnlyCompletion = true ; keywordCompletion = SyntaxKind . FromKeyword ; } else { return parent . parent . parent ; } } return undefined ; } if ( isImportKeyword ( contextToken ) && isSourceFile ( parent ) ) { keywordCompletion = SyntaxKind . TypeKeyword ; return contextToken as Token < SyntaxKind . ImportKeyword > ; } if ( isImportKeyword ( contextToken ) && isImportDeclaration ( parent ) ) { keywordCompletion = SyntaxKind . TypeKeyword ; return isModuleSpecifierMissingOrEmpty ( parent . moduleSpecifier ) ? parent : undefined ; } return undefined ; } } function couldBeTypeOnlyImportSpecifier ( importSpecifier , contextToken ) { return isImportSpecifier ( importSpecifier ) && ( importSpecifier . isTypeOnly || contextToken === importSpecifier . name && isTypeKeywordTokenOrIdentifier ( contextToken ) ) ; } function canCompleteFromNamedBindings ( namedBindings ) { return isModuleSpecifierMissingOrEmpty ( namedBindings . parent . parent . moduleSpecifier ) && ( isNamespaceImport ( namedBindings ) || namedBindings . elements . length < 2 ) && ! namedBindings . parent . name ; } function isModuleSpecifierMissingOrEmpty ( specifier ) { if ( nodeIsMissing ( specifier ) ) return true ; return ! tryCast ( isExternalModuleReference ( specifier ) ? specifier . expression : specifier , isStringLiteralLike ) ?. text ; } function getVariableDeclaration ( property ) { const variableDeclaration = findAncestor ( property , node => isFunctionBlock ( node ) || isArrowFunctionBody ( node ) || isBindingPattern ( node ) ? "quit" : isVariableDeclaration ( node ) ) ; return variableDeclaration as VariableDeclaration | undefined ; } function isArrowFunctionBody ( node ) { return node . parent && isArrowFunction ( node . parent ) && node . parent . body === node ; } ; /** True if symbol is a type or a module containing at least one type. */ function symbolCanBeReferencedAtTypeLocation ( symbol , checker , seenModules = new Map < SymbolId , true > ( ) ) { const sym = skipAlias ( symbol . exportSymbol || symbol , checker ) ; return ! ! ( sym . flags & SymbolFlags . Type ) || checker . isUnknownSymbol ( sym ) || ! ! ( sym . flags & SymbolFlags . Module ) && addToSeen ( seenModules , getSymbolId ( sym ) ) && checker . getExportsOfModule ( sym ) . some ( e => symbolCanBeReferencedAtTypeLocation ( e , checker , seenModules ) ) ; } function isDeprecated ( symbol , checker ) { const declarations = skipAlias ( symbol , checker ) . declarations ; return ! ! length ( declarations ) && every ( declarations , isDeprecatedDeclaration ) ; } /**
     * True if the first character of `lowercaseCharacters` is the first character
     * of some "word" in `identiferString` (where the string is split into "words"
     * by camelCase and snake_case segments), then if the remaining characters of
     * `lowercaseCharacters` appear, in order, in the rest of `identifierString`.
     *
     * True:
     * 'state' in 'useState'
     * 'sae' in 'useState'
     * 'viable' in 'ENVIRONMENT_VARIABLE'
     *
     * False:
     * 'staet' in 'useState'
     * 'tate' in 'useState'
     * 'ment' in 'ENVIRONMENT_VARIABLE'
     */ function charactersFuzzyMatchInString ( identifierString , lowercaseCharacters ) { if ( lowercaseCharacters . length === 0 ) { return true ; } let matchedFirstCharacter = false ; let prevChar ; let characterIndex = 0 ; const len = identifierString . length ; for ( let strIndex = 0 ; strIndex < len ; strIndex ++ ) { const strChar = identifierString . charCodeAt ( strIndex ) ; const testChar = lowercaseCharacters . charCodeAt ( characterIndex ) ; if ( strChar === testChar || strChar === toUpperCharCode ( testChar ) ) { matchedFirstCharacter ||= prevChar === undefined || CharacterCodes . a <= prevChar && prevChar <= CharacterCodes . z && CharacterCodes . A <= strChar && strChar <= CharacterCodes . Z || prevChar === CharacterCodes . _ && strChar !== CharacterCodes . _ ; if ( matchedFirstCharacter ) { characterIndex ++ ; } if ( characterIndex === lowercaseCharacters . length ) { return true ; } } prevChar = strChar ; } return false ; } function toUpperCharCode ( charCode ) { if ( CharacterCodes . a <= charCode && charCode <= CharacterCodes . z ) { return charCode - 32 ; } return charCode ; } }