@@ -321,13 +321,14 @@ namespace ts.Completions.StringCompletions {
321
321
322
322
interface ExtensionOptions {
323
323
readonly extensions : readonly Extension [ ] ;
324
- readonly includeExtensions : boolean ;
324
+ readonly includeExtensionsOption : IncludeExtensionsOption ;
325
325
}
326
- function getExtensionOptions ( compilerOptions : CompilerOptions , includeExtensions = false ) : ExtensionOptions {
327
- return { extensions : getSupportedExtensionsForModuleResolution ( compilerOptions ) , includeExtensions } ;
326
+ function getExtensionOptions ( compilerOptions : CompilerOptions , includeExtensionsOption = IncludeExtensionsOption . Exclude ) : ExtensionOptions {
327
+ return { extensions : getSupportedExtensionsForModuleResolution ( compilerOptions ) , includeExtensionsOption } ;
328
328
}
329
329
function getCompletionEntriesForRelativeModules ( literalValue : string , scriptDirectory : string , compilerOptions : CompilerOptions , host : LanguageServiceHost , scriptPath : Path , preferences : UserPreferences ) {
330
- const extensionOptions = getExtensionOptions ( compilerOptions , preferences . importModuleSpecifierEnding === "js" ) ;
330
+ const includeExtensions = preferences . importModuleSpecifierEnding === "js" ? IncludeExtensionsOption . ModuleSpecifierCompletion : IncludeExtensionsOption . Exclude ;
331
+ const extensionOptions = getExtensionOptions ( compilerOptions , includeExtensions ) ;
331
332
if ( compilerOptions . rootDirs ) {
332
333
return getCompletionEntriesForDirectoryFragmentWithRootDirs (
333
334
compilerOptions . rootDirs , literalValue , scriptDirectory , extensionOptions , compilerOptions , host , scriptPath ) ;
@@ -370,10 +371,15 @@ namespace ts.Completions.StringCompletions {
370
371
return flatMap ( baseDirectories , baseDirectory => getCompletionEntriesForDirectoryFragment ( fragment , baseDirectory , extensionOptions , host , exclude ) ) ;
371
372
}
372
373
374
+ const enum IncludeExtensionsOption {
375
+ Exclude ,
376
+ Include ,
377
+ ModuleSpecifierCompletion ,
378
+ }
373
379
/**
374
380
* Given a path ending at a directory, gets the completions for the path, and filters for those entries containing the basename.
375
381
*/
376
- function getCompletionEntriesForDirectoryFragment ( fragment : string , scriptPath : string , { extensions, includeExtensions } : ExtensionOptions , host : LanguageServiceHost , exclude ?: string , result : NameAndKind [ ] = [ ] ) : NameAndKind [ ] {
382
+ function getCompletionEntriesForDirectoryFragment ( fragment : string , scriptPath : string , { extensions, includeExtensionsOption } : ExtensionOptions , host : LanguageServiceHost , exclude ?: string , result : NameAndKind [ ] = [ ] ) : NameAndKind [ ] {
377
383
if ( fragment === undefined ) {
378
384
fragment = "" ;
379
385
}
@@ -407,7 +413,7 @@ namespace ts.Completions.StringCompletions {
407
413
if ( files ) {
408
414
/**
409
415
* Multiple file entries might map to the same truncated name once we remove extensions
410
- * (happens iff includeExtensions === false) so we use a set-like data structure. Eg:
416
+ * (happens iff includeExtensionsOption === includeExtensionsOption.Exclude) so we use a set-like data structure. Eg:
411
417
*
412
418
* both foo.ts and foo.tsx become foo
413
419
*/
@@ -418,8 +424,20 @@ namespace ts.Completions.StringCompletions {
418
424
continue ;
419
425
}
420
426
421
- const foundFileName = includeExtensions || fileExtensionIs ( filePath , Extension . Json ) ? getBaseFileName ( filePath ) : removeFileExtension ( getBaseFileName ( filePath ) ) ;
422
- foundFiles . set ( foundFileName , tryGetExtensionFromPath ( filePath ) ) ;
427
+ let foundFileName : string ;
428
+ const outputExtension = moduleSpecifiers . tryGetJSExtensionForFile ( filePath , host . getCompilationSettings ( ) ) ;
429
+ if ( includeExtensionsOption === IncludeExtensionsOption . Exclude && ! fileExtensionIs ( filePath , Extension . Json ) ) {
430
+ foundFileName = removeFileExtension ( getBaseFileName ( filePath ) ) ;
431
+ foundFiles . set ( foundFileName , tryGetExtensionFromPath ( filePath ) ) ;
432
+ }
433
+ else if ( includeExtensionsOption === IncludeExtensionsOption . ModuleSpecifierCompletion && outputExtension ) {
434
+ foundFileName = changeExtension ( getBaseFileName ( filePath ) , outputExtension ) ;
435
+ foundFiles . set ( foundFileName , outputExtension ) ;
436
+ }
437
+ else {
438
+ foundFileName = getBaseFileName ( filePath ) ;
439
+ foundFiles . set ( foundFileName , tryGetExtensionFromPath ( filePath ) ) ;
440
+ }
423
441
}
424
442
425
443
foundFiles . forEach ( ( ext , foundFile ) => {
@@ -635,7 +653,7 @@ namespace ts.Completions.StringCompletions {
635
653
636
654
const [ , prefix , kind , toComplete ] = match ;
637
655
const scriptPath = getDirectoryPath ( sourceFile . path ) ;
638
- const names = kind === "path" ? getCompletionEntriesForDirectoryFragment ( toComplete , scriptPath , getExtensionOptions ( compilerOptions , /*includeExtensions*/ true ) , host , sourceFile . path )
656
+ const names = kind === "path" ? getCompletionEntriesForDirectoryFragment ( toComplete , scriptPath , getExtensionOptions ( compilerOptions , IncludeExtensionsOption . Include ) , host , sourceFile . path )
639
657
: kind === "types" ? getCompletionEntriesFromTypings ( host , compilerOptions , scriptPath , getFragmentDirectory ( toComplete ) , getExtensionOptions ( compilerOptions ) )
640
658
: Debug . fail ( ) ;
641
659
return addReplacementSpans ( toComplete , range . pos + prefix . length , names ) ;
0 commit comments