@@ -27,16 +27,9 @@ namespace ts.Completions {
2727
2828 const enum GlobalsSearch { Continue , Success , Fail }
2929
30- export function getCompletionsAtPosition (
31- host : LanguageServiceHost ,
32- typeChecker : TypeChecker ,
33- log : Log ,
34- compilerOptions : CompilerOptions ,
35- sourceFile : SourceFile ,
36- position : number ,
37- allSourceFiles : ReadonlyArray < SourceFile > ,
38- preferences : UserPreferences ,
39- ) : CompletionInfo | undefined {
30+ export function getCompletionsAtPosition ( host : LanguageServiceHost , program : Program , log : Log , sourceFile : SourceFile , position : number , preferences : UserPreferences ) : CompletionInfo | undefined {
31+ const typeChecker = program . getTypeChecker ( ) ;
32+ const compilerOptions = program . getCompilerOptions ( ) ;
4033 if ( isInReferenceComment ( sourceFile , position ) ) {
4134 const entries = PathCompletions . getTripleSlashReferenceCompletion ( sourceFile , position , compilerOptions , host ) ;
4235 return entries && convertPathCompletions ( entries ) ;
@@ -55,7 +48,7 @@ namespace ts.Completions {
5548 return getLabelCompletionAtPosition ( contextToken . parent ) ;
5649 }
5750
58- const completionData = getCompletionData ( typeChecker , log , sourceFile , position , allSourceFiles , preferences , compilerOptions . target ) ;
51+ const completionData = getCompletionData ( program , log , sourceFile , position , preferences ) ;
5952 if ( ! completionData ) {
6053 return undefined ;
6154 }
@@ -480,16 +473,9 @@ namespace ts.Completions {
480473 previousToken : Node ;
481474 readonly isJsxInitializer : IsJsxInitializer ;
482475 }
483- function getSymbolCompletionFromEntryId (
484- typeChecker : TypeChecker ,
485- log : ( message : string ) => void ,
486- compilerOptions : CompilerOptions ,
487- sourceFile : SourceFile ,
488- position : number ,
489- { name, source } : CompletionEntryIdentifier ,
490- allSourceFiles : ReadonlyArray < SourceFile > ,
476+ function getSymbolCompletionFromEntryId ( program : Program , log : Log , sourceFile : SourceFile , position : number , { name, source } : CompletionEntryIdentifier ,
491477 ) : SymbolCompletion | { type : "request" , request : Request } | { type : "none" } {
492- const completionData = getCompletionData ( typeChecker , log , sourceFile , position , allSourceFiles , { includeCompletionsForModuleExports : true , includeCompletionsWithInsertText : true } , compilerOptions . target ) ;
478+ const completionData = getCompletionData ( program , log , sourceFile , position , { includeCompletionsForModuleExports : true , includeCompletionsWithInsertText : true } ) ;
493479 if ( ! completionData ) {
494480 return { type : "none" } ;
495481 }
@@ -505,7 +491,7 @@ namespace ts.Completions {
505491 // completion entry.
506492 return firstDefined < Symbol , SymbolCompletion > ( symbols , ( symbol ) : SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632)
507493 const origin = symbolToOriginInfoMap [ getSymbolId ( symbol ) ] ;
508- const info = getCompletionEntryDisplayNameForSymbol ( symbol , compilerOptions . target , origin , completionKind ) ;
494+ const info = getCompletionEntryDisplayNameForSymbol ( symbol , program . getCompilerOptions ( ) . target , origin , completionKind ) ;
509495 return info && info . name === name && getSourceFromOrigin ( origin ) === source ? { type : "symbol" as "symbol" , symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined ;
510496 } ) || { type : "none" } ;
511497 }
@@ -525,18 +511,17 @@ namespace ts.Completions {
525511
526512 export function getCompletionEntryDetails (
527513 program : Program ,
528- log : ( message : string ) => void ,
529- compilerOptions : CompilerOptions ,
514+ log : Log ,
530515 sourceFile : SourceFile ,
531516 position : number ,
532517 entryId : CompletionEntryIdentifier ,
533- allSourceFiles : ReadonlyArray < SourceFile > ,
534518 host : LanguageServiceHost ,
535519 formatContext : formatting . FormatContext ,
536520 getCanonicalFileName : GetCanonicalFileName ,
537521 preferences : UserPreferences ,
538522 ) : CompletionEntryDetails {
539523 const typeChecker = program . getTypeChecker ( ) ;
524+ const compilerOptions = program . getCompilerOptions ( ) ;
540525 const { name } = entryId ;
541526
542527 const contextToken = findPrecedingToken ( position , sourceFile ) ;
@@ -548,7 +533,7 @@ namespace ts.Completions {
548533 }
549534
550535 // Compute all the completion symbols again.
551- const symbolCompletion = getSymbolCompletionFromEntryId ( typeChecker , log , compilerOptions , sourceFile , position , entryId , allSourceFiles ) ;
536+ const symbolCompletion = getSymbolCompletionFromEntryId ( program , log , sourceFile , position , entryId ) ;
552537 switch ( symbolCompletion . type ) {
553538 case "request" : {
554539 const { request } = symbolCompletion ;
@@ -565,7 +550,7 @@ namespace ts.Completions {
565550 }
566551 case "symbol" : {
567552 const { symbol, location, symbolToOriginInfoMap, previousToken } = symbolCompletion ;
568- const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay ( symbolToOriginInfoMap , symbol , program , typeChecker , host , compilerOptions , sourceFile , previousToken , formatContext , getCanonicalFileName , allSourceFiles , preferences ) ;
553+ const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay ( symbolToOriginInfoMap , symbol , program , typeChecker , host , compilerOptions , sourceFile , previousToken , formatContext , getCanonicalFileName , program . getSourceFiles ( ) , preferences ) ;
569554 return createCompletionDetailsForSymbol ( symbol , typeChecker , sourceFile , location , codeActions , sourceDisplay ) ;
570555 }
571556 case "none" :
@@ -642,16 +627,8 @@ namespace ts.Completions {
642627 return { sourceDisplay : [ textPart ( moduleSpecifier ) ] , codeActions : [ codeAction ] } ;
643628 }
644629
645- export function getCompletionEntrySymbol (
646- typeChecker : TypeChecker ,
647- log : ( message : string ) => void ,
648- compilerOptions : CompilerOptions ,
649- sourceFile : SourceFile ,
650- position : number ,
651- entryId : CompletionEntryIdentifier ,
652- allSourceFiles : ReadonlyArray < SourceFile > ,
653- ) : Symbol | undefined {
654- const completion = getSymbolCompletionFromEntryId ( typeChecker , log , compilerOptions , sourceFile , position , entryId , allSourceFiles ) ;
630+ export function getCompletionEntrySymbol ( program : Program , log : Log , sourceFile : SourceFile , position : number , entryId : CompletionEntryIdentifier ) : Symbol | undefined {
631+ const completion = getSymbolCompletionFromEntryId ( program , log , sourceFile , position , entryId ) ;
655632 return completion . type === "symbol" ? completion . symbol : undefined ;
656633 }
657634
@@ -760,14 +737,14 @@ namespace ts.Completions {
760737 }
761738
762739 function getCompletionData (
763- typeChecker : TypeChecker ,
740+ program : Program ,
764741 log : ( message : string ) => void ,
765742 sourceFile : SourceFile ,
766743 position : number ,
767- allSourceFiles : ReadonlyArray < SourceFile > ,
768744 preferences : Pick < UserPreferences , "includeCompletionsForModuleExports" | "includeCompletionsWithInsertText" > ,
769- target : ScriptTarget ,
770745 ) : CompletionData | Request | undefined {
746+ const typeChecker = program . getTypeChecker ( ) ;
747+
771748 let start = timestamp ( ) ;
772749 let currentToken = getTokenAtPosition ( sourceFile , position , /*includeJsDocComment*/ false ) ; // TODO: GH#15853
773750 // We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.)
@@ -1168,13 +1145,30 @@ namespace ts.Completions {
11681145 }
11691146 }
11701147
1171- // Don't suggest import completions for a commonjs-only module
1172- if ( preferences . includeCompletionsForModuleExports && ! ( sourceFile . commonJsModuleIndicator && ! sourceFile . externalModuleIndicator ) ) {
1173- getSymbolsFromOtherSourceFileExports ( symbols , previousToken && isIdentifier ( previousToken ) ? previousToken . text : "" , target ) ;
1148+ if ( shouldOfferImportCompletions ( ) ) {
1149+ getSymbolsFromOtherSourceFileExports ( symbols , previousToken && isIdentifier ( previousToken ) ? previousToken . text : "" , program . getCompilerOptions ( ) . target ) ;
11741150 }
11751151 filterGlobalCompletion ( symbols ) ;
11761152 }
11771153
1154+ function shouldOfferImportCompletions ( ) : boolean {
1155+ // If not already a module, must have modules enabled and not currently be in a commonjs module. (TODO: import completions for commonjs)
1156+ if ( ! preferences . includeCompletionsForModuleExports ) return false ;
1157+ // If already using ES6 modules, OK to continue using them.
1158+ if ( sourceFile . externalModuleIndicator ) return true ;
1159+ // If already using commonjs, don't introduce ES6.
1160+ if ( sourceFile . commonJsModuleIndicator ) return false ;
1161+ // If some file is using ES6 modules, assume that it's OK to add more.
1162+ if ( program . getSourceFiles ( ) . some ( s => ! s . isDeclarationFile && ! program . isSourceFileFromExternalLibrary ( s ) && ! ! s . externalModuleIndicator ) ) {
1163+ return true ;
1164+ }
1165+ // For JS, stay on the safe side.
1166+ if ( isSourceFileJavaScript ( sourceFile ) ) return false ;
1167+ // If module transpilation is enabled or we're targeting es6 or above, or not emitting, OK.
1168+ const compilerOptions = program . getCompilerOptions ( ) ;
1169+ return ! ! compilerOptions . module || compilerOptions . target >= ScriptTarget . ES2015 || ! ! compilerOptions . noEmit ;
1170+ }
1171+
11781172 function isSnippetScope ( scopeNode : Node ) : boolean {
11791173 switch ( scopeNode . kind ) {
11801174 case SyntaxKind . SourceFile :
@@ -1268,7 +1262,7 @@ namespace ts.Completions {
12681262 function getSymbolsFromOtherSourceFileExports ( symbols : Symbol [ ] , tokenText : string , target : ScriptTarget ) : void {
12691263 const tokenTextLowerCase = tokenText . toLowerCase ( ) ;
12701264
1271- codefix . forEachExternalModuleToImportFrom ( typeChecker , sourceFile , allSourceFiles , moduleSymbol => {
1265+ codefix . forEachExternalModuleToImportFrom ( typeChecker , sourceFile , program . getSourceFiles ( ) , moduleSymbol => {
12721266 for ( let symbol of typeChecker . getExportsOfModule ( moduleSymbol ) ) {
12731267 // Don't add a completion for a re-export, only for the original.
12741268 // The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
0 commit comments