Skip to content

Commit 72244c5

Browse files
author
Andy
authored
Support 'isSourceFileFromExternalLibrary' for source files from '/// <reference types="" />'' (#28004)
* Support 'isSourceFileFromExternalLibrary' for source files from '/// <reference types="" />'' * Calculate `isExternalLibraryImport` at the end * Calculate isExternalLibraryImport with symlink path
1 parent 424fcdd commit 72244c5

File tree

8 files changed

+42
-26
lines changed

8 files changed

+42
-26
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,12 @@ namespace ts {
298298

299299
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
300300
if (resolved) {
301-
if (!options.preserveSymlinks) {
302-
resolved = { ...resolved, fileName: realPath(resolved.fileName, host, traceEnabled) };
303-
}
304-
301+
const { fileName, packageId } = resolved;
302+
const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
305303
if (traceEnabled) {
306-
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved.fileName, primary);
304+
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, primary);
307305
}
308-
resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved.fileName, packageId: resolved.packageId };
306+
resolvedTypeReferenceDirective = { primary, resolvedFileName, packageId, isExternalLibraryImport: pathContainsNodeModules(fileName) };
309307
}
310308

311309
return { resolvedTypeReferenceDirective, failedLookupLocations };
@@ -316,7 +314,7 @@ namespace ts {
316314
if (traceEnabled) {
317315
trace(host, Diagnostics.Resolving_with_primary_search_path_0, typeRoots.join(", "));
318316
}
319-
return forEach(typeRoots, typeRoot => {
317+
return firstDefined(typeRoots, typeRoot => {
320318
const candidate = combinePaths(typeRoot, typeReferenceDirectiveName);
321319
const candidateDirectory = getDirectoryPath(candidate);
322320
const directoryExists = directoryProbablyExists(candidateDirectory, host);
@@ -343,15 +341,16 @@ namespace ts {
343341
if (traceEnabled) {
344342
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
345343
}
346-
let result: SearchResult<Resolved> | undefined;
344+
let result: Resolved | undefined;
347345
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
348-
result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined);
346+
const searchResult = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined);
347+
result = searchResult && searchResult.value;
349348
}
350349
else {
351350
const { path: candidate } = normalizePathAndParts(combinePaths(initialLocationForSecondaryLookup, typeReferenceDirectiveName));
352-
result = toSearchResult(nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true));
351+
result = nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true);
353352
}
354-
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
353+
const resolvedFile = resolvedTypeScriptOnly(result);
355354
if (!resolvedFile && traceEnabled) {
356355
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
357356
}
@@ -883,7 +882,7 @@ namespace ts {
883882
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
884883
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
885884
if (resolved) {
886-
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
885+
return toSearchResult({ resolved, isExternalLibraryImport: pathContainsNodeModules(resolved.path) });
887886
}
888887

889888
if (!isExternalModuleNameRelative(moduleName)) {
@@ -960,6 +959,10 @@ namespace ts {
960959

961960
/*@internal*/
962961
export const nodeModulesPathPart = "/node_modules/";
962+
/*@internal*/
963+
export function pathContainsNodeModules(path: string): boolean {
964+
return stringContains(path, nodeModulesPathPart);
965+
}
963966

964967
/**
965968
* This will be called on the successfully resolved path from `loadModuleFromFile`.

src/compiler/program.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,8 @@ namespace ts {
23452345
}
23462346
let saveResolution = true;
23472347
if (resolvedTypeReferenceDirective) {
2348+
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth++;
2349+
23482350
if (resolvedTypeReferenceDirective.primary) {
23492351
// resolved from the primary path
23502352
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
@@ -2373,6 +2375,8 @@ namespace ts {
23732375
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
23742376
}
23752377
}
2378+
2379+
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
23762380
}
23772381
else {
23782382
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, Diagnostics.Cannot_find_type_definition_file_for_0, typeReferenceDirective)); // TODO: GH#18217

src/compiler/resolutionCache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ namespace ts {
432432

433433
function getDirectoryToWatchFromFailedLookupLocationDirectory(dir: string, dirPath: Path) {
434434
// If directory path contains node module, get the most parent node_modules directory for watching
435-
while (stringContains(dirPath, nodeModulesPathPart)) {
435+
while (pathContainsNodeModules(dirPath)) {
436436
dir = getDirectoryPath(dir);
437437
dirPath = getDirectoryPath(dirPath);
438438
}

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4942,6 +4942,8 @@ namespace ts {
49424942
// The location of the .d.ts file we located, or undefined if resolution failed
49434943
resolvedFileName: string | undefined;
49444944
packageId?: PackageId;
4945+
/** True if `resolvedFileName` comes from `node_modules`. */
4946+
isExternalLibraryImport?: boolean;
49454947
}
49464948

49474949
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {

src/testRunner/unittests/programMissingFiles.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,23 @@ namespace ts {
113113

114114
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], cwd: "/" });
115115
const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }));
116+
assertIsExternal(program, [a, bar, barFooIndex, fooIndex], f => f !== a);
117+
});
116118

117-
for (const file of [a, bar, barFooIndex, fooIndex]) {
118-
const isExternalExpected = file !== a;
119-
const isExternalActual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!);
120-
assert.equal(isExternalActual, isExternalExpected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${isExternalExpected}, got ${isExternalActual}`);
121-
}
119+
it('works on `/// <reference types="" />`', () => {
120+
const a = new documents.TextDocument("/a.ts", '/// <reference types="foo" />');
121+
const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", "declare const foo: number;");
122+
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, fooIndex], cwd: "/" });
123+
const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }));
124+
assertIsExternal(program, [a, fooIndex], f => f !== a);
122125
});
126+
127+
function assertIsExternal(program: Program, files: ReadonlyArray<documents.TextDocument>, isExternalExpected: (file: documents.TextDocument) => boolean): void {
128+
for (const file of files) {
129+
const actual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!);
130+
const expected = isExternalExpected(file);
131+
assert.equal(actual, expected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`);
132+
}
133+
}
123134
});
124135
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,8 @@ declare namespace ts {
26702670
primary: boolean;
26712671
resolvedFileName: string | undefined;
26722672
packageId?: PackageId;
2673+
/** True if `resolvedFileName` comes from `node_modules`. */
2674+
isExternalLibraryImport?: boolean;
26732675
}
26742676
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
26752677
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,8 @@ declare namespace ts {
26702670
primary: boolean;
26712671
resolvedFileName: string | undefined;
26722672
packageId?: PackageId;
2673+
/** True if `resolvedFileName` comes from `node_modules`. */
2674+
isExternalLibraryImport?: boolean;
26732675
}
26742676
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
26752677
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;

tests/baselines/reference/typingsLookup4.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,6 @@ import { m } from "mquery";
3232
j + k + l + m;
3333

3434

35-
//// [lquery.js]
36-
"use strict";
37-
exports.__esModule = true;
38-
exports.l = 2;
39-
//// [index.js]
40-
"use strict";
41-
exports.__esModule = true;
42-
exports.m = 3;
4335
//// [a.js]
4436
"use strict";
4537
exports.__esModule = true;

0 commit comments

Comments
 (0)