1
- // Used by importFixes to synthesize import module specifiers.
1
+ // Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
2
2
/* @internal */
3
3
namespace ts . moduleSpecifiers {
4
4
export interface ModuleSpecifierPreferences {
@@ -17,10 +17,22 @@ namespace ts.moduleSpecifiers {
17
17
redirectTargetsMap : RedirectTargetsMap ,
18
18
) : string {
19
19
const info = getInfo ( compilerOptions , importingSourceFile , importingSourceFileName , host ) ;
20
- const modulePaths = getAllModulePaths ( files , toFileName , info . getCanonicalFileName , host , redirectTargetsMap ) ;
20
+ const modulePaths = getAllModulePaths ( files , importingSourceFileName , toFileName , info . getCanonicalFileName , host , redirectTargetsMap ) ;
21
21
return firstDefined ( modulePaths , moduleFileName => getGlobalModuleSpecifier ( moduleFileName , info , host , compilerOptions ) ) ||
22
22
first ( getLocalModuleSpecifiers ( toFileName , info , compilerOptions , preferences ) ) ;
23
23
}
24
+
25
+ export function getModuleSpecifierForDeclarationFile (
26
+ moduleSymbol : Symbol ,
27
+ compilerOptions : CompilerOptions ,
28
+ importingSourceFile : SourceFile ,
29
+ host : ModuleSpecifierResolutionHost ,
30
+ files : ReadonlyArray < SourceFile > ,
31
+ preferences : ModuleSpecifierPreferences ,
32
+ redirectTargetsMap : RedirectTargetsMap ,
33
+ ) : string {
34
+ return first ( first ( getModuleSpecifiers ( moduleSymbol , compilerOptions , importingSourceFile , host , files , preferences , redirectTargetsMap ) ) ) ;
35
+ }
24
36
25
37
// For each symlink/original for a module, returns a list of ways to import that file.
26
38
export function getModuleSpecifiers (
@@ -40,7 +52,7 @@ namespace ts.moduleSpecifiers {
40
52
return Debug . fail ( "Files list must be present to resolve symlinks in specifier resolution" ) ;
41
53
}
42
54
const moduleSourceFile = getSourceFileOfNode ( moduleSymbol . valueDeclaration ) ;
43
- const modulePaths = getAllModulePaths ( files , moduleSourceFile . fileName , info . getCanonicalFileName , host , redirectTargetsMap ) ;
55
+ const modulePaths = getAllModulePaths ( files , importingSourceFile . path , moduleSourceFile . fileName , info . getCanonicalFileName , host , redirectTargetsMap ) ;
44
56
45
57
const global = mapDefined ( modulePaths , moduleFileName => getGlobalModuleSpecifier ( moduleFileName , info , host , compilerOptions ) ) ;
46
58
return global . length ? global . map ( g => [ g ] ) : modulePaths . map ( moduleFileName =>
@@ -149,11 +161,16 @@ namespace ts.moduleSpecifiers {
149
161
return getCanonicalFileName ( a ) === getCanonicalFileName ( b ) ;
150
162
}
151
163
164
+ // KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink.
165
+ // ALso, don't assume that an `@foo` directory is linked. More likely the contents of that are linked.
166
+ function isNodeModulesOrScopedPackageDirectory ( s : string ) : boolean {
167
+ return s === "node_modules" || startsWith ( s , "@" ) ;
168
+ }
169
+
152
170
function guessDirectorySymlink ( a : string , b : string , cwd : string , getCanonicalFileName : GetCanonicalFileName ) : [ string , string ] {
153
171
const aParts = getPathComponents ( toPath ( a , cwd , getCanonicalFileName ) ) ;
154
172
const bParts = getPathComponents ( toPath ( b , cwd , getCanonicalFileName ) ) ;
155
- // KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink.
156
- while ( ( aParts [ aParts . length - 2 ] ) !== "node_modules" && bParts [ bParts . length - 2 ] !== "node_modules" && stringsEqual ( aParts [ aParts . length - 1 ] , bParts [ bParts . length - 1 ] , getCanonicalFileName ) ) {
173
+ while ( ! isNodeModulesOrScopedPackageDirectory ( aParts [ aParts . length - 2 ] ) && ! isNodeModulesOrScopedPackageDirectory ( bParts [ bParts . length - 2 ] ) && stringsEqual ( aParts [ aParts . length - 1 ] , bParts [ bParts . length - 1 ] , getCanonicalFileName ) ) {
157
174
aParts . pop ( ) ;
158
175
bParts . pop ( ) ;
159
176
}
@@ -176,7 +193,7 @@ namespace ts.moduleSpecifiers {
176
193
* Looks for existing imports that use symlinks to this module.
177
194
* Symlinks will be returned first so they are preferred over the real path.
178
195
*/
179
- function getAllModulePaths ( files : ReadonlyArray < SourceFile > , importedFileName : string , getCanonicalFileName : ( file : string ) => string , host : ModuleSpecifierResolutionHost , redirectTargetsMap : RedirectTargetsMap ) : ReadonlyArray < string > {
196
+ function getAllModulePaths ( files : ReadonlyArray < SourceFile > , importingFileName : string , importedFileName : string , getCanonicalFileName : GetCanonicalFileName , host : ModuleSpecifierResolutionHost , redirectTargetsMap : RedirectTargetsMap ) : ReadonlyArray < string > {
180
197
const redirects = redirectTargetsMap . get ( importedFileName ) ;
181
198
const importedFileNames = redirects ? [ ...redirects , importedFileName ] : [ importedFileName ] ;
182
199
const cwd = host . getCurrentDirectory ? host . getCurrentDirectory ( ) : "" ;
@@ -186,6 +203,10 @@ namespace ts.moduleSpecifiers {
186
203
const result : string [ ] = [ ] ;
187
204
const compareStrings = ( ! host . useCaseSensitiveFileNames || host . useCaseSensitiveFileNames ( ) ) ? compareStringsCaseSensitive : compareStringsCaseInsensitive ;
188
205
links . forEach ( ( resolved , path ) => {
206
+ if ( startsWithDirectory ( importingFileName , resolved , getCanonicalFileName ) ) {
207
+ return ; // Don't want to a package to globally import from itself
208
+ }
209
+
189
210
const target = targets . find ( t => compareStrings ( t . slice ( 0 , resolved . length + 1 ) , resolved + "/" ) === Comparison . EqualTo ) ;
190
211
if ( target === undefined ) return ;
191
212
0 commit comments