3
3
namespace ts . moduleSpecifiers {
4
4
export interface ModuleSpecifierPreferences {
5
5
importModuleSpecifierPreference ?: "relative" | "non-relative" ;
6
- includeExtensionInImports ?: Extension . Js | Extension . Jsx ;
6
+ includeExtensionInImports ?: boolean ;
7
7
}
8
8
9
9
// Note: fromSourceFile is just for usesJsExtensionOnImports
10
- export function getModuleSpecifier ( compilerOptions : CompilerOptions , fromSourceFile : SourceFile , fromSourceFileName : string , toFileName : string , host : ModuleSpecifierResolutionHost , preferences : ModuleSpecifierPreferences = { } ) {
11
- const info = getInfo ( compilerOptions , fromSourceFile , fromSourceFileName , host , preferences ) ;
12
- return getGlobalModuleSpecifier ( toFileName , info , host , compilerOptions ) ||
10
+ export function getModuleSpecifier ( compilerOptions : CompilerOptions , fromSourceFileName : string , toFileName : string , host : ModuleSpecifierResolutionHost , preferences : ModuleSpecifierPreferences = { } ) {
11
+ const info = getInfo ( compilerOptions , fromSourceFileName , host ) ;
12
+ return getGlobalModuleSpecifier ( toFileName , info , host , compilerOptions , preferences ) ||
13
13
first ( getLocalModuleSpecifiers ( toFileName , info , compilerOptions , preferences ) ) ;
14
14
}
15
15
16
16
// For each symlink/original for a module, returns a list of ways to import that file.
17
17
export function getModuleSpecifiers (
18
18
moduleSymbol : Symbol ,
19
19
compilerOptions : CompilerOptions ,
20
- importingSourceFile : SourceFile ,
20
+ importingSourceFileName : string ,
21
21
host : ModuleSpecifierResolutionHost ,
22
22
files : ReadonlyArray < SourceFile > ,
23
23
preferences : ModuleSpecifierPreferences ,
24
24
) : ReadonlyArray < ReadonlyArray < string > > {
25
25
const ambient = tryGetModuleNameFromAmbientModule ( moduleSymbol ) ;
26
26
if ( ambient ) return [ [ ambient ] ] ;
27
27
28
- const info = getInfo ( compilerOptions , importingSourceFile , importingSourceFile . path , host , preferences ) ;
28
+ const info = getInfo ( compilerOptions , importingSourceFileName , host ) ;
29
29
if ( ! files ) {
30
30
return Debug . fail ( "Files list must be present to resolve symlinks in specifier resolution" ) ;
31
31
}
32
32
const modulePaths = getAllModulePaths ( files , getSourceFileOfNode ( moduleSymbol . valueDeclaration ) , info . getCanonicalFileName , host ) ;
33
33
34
- const global = mapDefined ( modulePaths , moduleFileName => getGlobalModuleSpecifier ( moduleFileName , info , host , compilerOptions ) ) ;
34
+ const global = mapDefined ( modulePaths , moduleFileName => getGlobalModuleSpecifier ( moduleFileName , info , host , compilerOptions , preferences ) ) ;
35
35
return global . length ? global . map ( g => [ g ] ) : modulePaths . map ( moduleFileName =>
36
36
getLocalModuleSpecifiers ( moduleFileName , info , compilerOptions , preferences ) ) ;
37
37
}
38
38
39
39
interface Info {
40
40
readonly moduleResolutionKind : ModuleResolutionKind ;
41
- readonly addExtension : Extension . Js | Extension . Jsx | undefined ;
42
41
readonly getCanonicalFileName : GetCanonicalFileName ;
43
42
readonly sourceDirectory : string ;
44
43
}
45
- // importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
46
- function getInfo ( compilerOptions : CompilerOptions , importingSourceFile : SourceFile , importingSourceFileName : string , host : ModuleSpecifierResolutionHost , preferences : ModuleSpecifierPreferences ) : Info {
44
+
45
+ function getInfo ( compilerOptions : CompilerOptions , importingSourceFileName : string , host : ModuleSpecifierResolutionHost ) : Info {
47
46
const moduleResolutionKind = getEmitModuleResolutionKind ( compilerOptions ) ;
48
- const addExtension = usesExtensionOnImports ( importingSourceFile , preferences ) ;
49
47
const getCanonicalFileName = createGetCanonicalFileName ( host . useCaseSensitiveFileNames ? host . useCaseSensitiveFileNames ( ) : true ) ;
50
48
const sourceDirectory = getDirectoryPath ( importingSourceFileName ) ;
51
- return { moduleResolutionKind, addExtension , getCanonicalFileName, sourceDirectory } ;
49
+ return { moduleResolutionKind, getCanonicalFileName, sourceDirectory } ;
52
50
}
53
51
54
52
function getGlobalModuleSpecifier (
55
53
moduleFileName : string ,
56
- { addExtension , getCanonicalFileName, sourceDirectory } : Info ,
54
+ { getCanonicalFileName, sourceDirectory } : Info ,
57
55
host : ModuleSpecifierResolutionHost ,
58
56
compilerOptions : CompilerOptions ,
57
+ preferences : ModuleSpecifierPreferences ,
59
58
) {
60
- return tryGetModuleNameFromTypeRoots ( compilerOptions , host , getCanonicalFileName , moduleFileName , addExtension )
59
+ return tryGetModuleNameFromTypeRoots ( compilerOptions , host , getCanonicalFileName , moduleFileName , preferences )
61
60
|| tryGetModuleNameAsNodeModule ( compilerOptions , moduleFileName , host , getCanonicalFileName , sourceDirectory )
62
61
|| compilerOptions . rootDirs && tryGetModuleNameFromRootDirs ( compilerOptions . rootDirs , moduleFileName , sourceDirectory , getCanonicalFileName ) ;
63
62
}
64
63
65
64
function getLocalModuleSpecifiers (
66
65
moduleFileName : string ,
67
- { moduleResolutionKind, addExtension , getCanonicalFileName, sourceDirectory } : Info ,
66
+ { moduleResolutionKind, getCanonicalFileName, sourceDirectory } : Info ,
68
67
compilerOptions : CompilerOptions ,
69
68
preferences : ModuleSpecifierPreferences ,
70
69
) {
71
70
const { baseUrl, paths } = compilerOptions ;
72
71
73
- const relativePath = removeExtensionAndIndexPostFix ( ensurePathIsNonModuleName ( getRelativePathFromDirectory ( sourceDirectory , moduleFileName , getCanonicalFileName ) ) , moduleResolutionKind , addExtension ) ;
72
+ const relativePath = removeExtensionAndIndexPostFix ( ensurePathIsNonModuleName ( getRelativePathFromDirectory ( sourceDirectory , moduleFileName , getCanonicalFileName ) ) , moduleResolutionKind , preferences ) ;
74
73
if ( ! baseUrl || preferences . importModuleSpecifierPreference === "relative" ) {
75
74
return [ relativePath ] ;
76
75
}
@@ -80,7 +79,7 @@ namespace ts.moduleSpecifiers {
80
79
return [ relativePath ] ;
81
80
}
82
81
83
- const importRelativeToBaseUrl = removeExtensionAndIndexPostFix ( relativeToBaseUrl , moduleResolutionKind , addExtension ) ;
82
+ const importRelativeToBaseUrl = removeExtensionAndIndexPostFix ( relativeToBaseUrl , moduleResolutionKind , preferences ) ;
84
83
if ( paths ) {
85
84
const fromPaths = tryGetModuleNameFromPaths ( removeFileExtension ( relativeToBaseUrl ) , importRelativeToBaseUrl , paths ) ;
86
85
if ( fromPaths ) {
@@ -130,16 +129,6 @@ namespace ts.moduleSpecifiers {
130
129
return relativeFirst ? [ relativePath , importRelativeToBaseUrl ] : [ importRelativeToBaseUrl , relativePath ] ;
131
130
}
132
131
133
- function tryGetFileExtension ( text : string ) {
134
- return pathIsRelative ( text ) && fileExtensionIsOneOf ( text , [ Extension . Js , Extension . Jsx ] ) ? (
135
- fileExtensionIs ( text , Extension . Js ) ? Extension . Js : Extension . Jsx
136
- ) : undefined ;
137
- }
138
-
139
- function usesExtensionOnImports ( { imports } : SourceFile , preferences : ModuleSpecifierPreferences ) : Extension . Js | Extension . Jsx | undefined {
140
- return preferences . includeExtensionInImports === undefined ? firstDefined ( imports , ( { text } ) => tryGetFileExtension ( text ) ) : preferences . includeExtensionInImports ;
141
- }
142
-
143
132
function discoverProbableSymlinks ( files : ReadonlyArray < SourceFile > , getCanonicalFileName : ( file : string ) => string , host : ModuleSpecifierResolutionHost ) {
144
133
const symlinks = mapDefined ( files , sf =>
145
134
sf . resolvedModules && firstDefinedIterator ( sf . resolvedModules . values ( ) , res =>
@@ -251,14 +240,14 @@ namespace ts.moduleSpecifiers {
251
240
host : GetEffectiveTypeRootsHost ,
252
241
getCanonicalFileName : ( file : string ) => string ,
253
242
moduleFileName : string ,
254
- addExtension : Extension . Js | Extension . Jsx | undefined ,
243
+ preferences : ModuleSpecifierPreferences
255
244
) : string | undefined {
256
245
const roots = getEffectiveTypeRoots ( options , host ) ;
257
246
return firstDefined ( roots , unNormalizedTypeRoot => {
258
247
const typeRoot = toPath ( unNormalizedTypeRoot , /*basePath*/ undefined , getCanonicalFileName ) ;
259
248
if ( startsWith ( moduleFileName , typeRoot ) ) {
260
249
// For a type definition, we can strip `/index` even with classic resolution.
261
- return removeExtensionAndIndexPostFix ( moduleFileName . substring ( typeRoot . length + 1 ) , ModuleResolutionKind . NodeJs , addExtension ) ;
250
+ return removeExtensionAndIndexPostFix ( moduleFileName . substring ( typeRoot . length + 1 ) , ModuleResolutionKind . NodeJs , preferences ) ;
262
251
}
263
252
} ) ;
264
253
}
@@ -403,10 +392,21 @@ namespace ts.moduleSpecifiers {
403
392
} ) ;
404
393
}
405
394
406
- function removeExtensionAndIndexPostFix ( fileName : string , moduleResolutionKind : ModuleResolutionKind , addExtension : Extension . Js | Extension . Jsx | undefined ) : string {
395
+ function tryGetActualExtension ( text : string ) {
396
+ return pathIsRelative ( text ) && (
397
+ fileExtensionIsOneOf ( text , [ Extension . Js , Extension . Ts ] )
398
+ ? Extension . Js
399
+ : fileExtensionIsOneOf ( text , [ Extension . Jsx , Extension . Tsx ] )
400
+ ? Extension . Jsx
401
+ : undefined
402
+ ) ;
403
+ }
404
+
405
+ function removeExtensionAndIndexPostFix ( fileName : string , moduleResolutionKind : ModuleResolutionKind , preferences : ModuleSpecifierPreferences ) : string {
407
406
const noExtension = removeFileExtension ( fileName ) ;
408
- return addExtension
409
- ? noExtension + addExtension
407
+ const actualExtension = tryGetActualExtension ( fileName ) ;
408
+ return ( preferences . includeExtensionInImports && actualExtension )
409
+ ? noExtension + actualExtension
410
410
: moduleResolutionKind === ModuleResolutionKind . NodeJs
411
411
? removeSuffix ( noExtension , "/index" )
412
412
: noExtension ;
0 commit comments