mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-30 15:15:38 -05:00
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
This commit is contained in:
@@ -298,14 +298,12 @@ namespace ts {
|
||||
|
||||
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
if (resolved) {
|
||||
if (!options.preserveSymlinks) {
|
||||
resolved = { ...resolved, fileName: realPath(resolved.fileName, host, traceEnabled) };
|
||||
}
|
||||
|
||||
const { fileName, packageId } = resolved;
|
||||
const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved.fileName, primary);
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, primary);
|
||||
}
|
||||
resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved.fileName, packageId: resolved.packageId };
|
||||
resolvedTypeReferenceDirective = { primary, resolvedFileName, packageId, isExternalLibraryImport: pathContainsNodeModules(fileName) };
|
||||
}
|
||||
|
||||
return { resolvedTypeReferenceDirective, failedLookupLocations };
|
||||
@@ -316,7 +314,7 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolving_with_primary_search_path_0, typeRoots.join(", "));
|
||||
}
|
||||
return forEach(typeRoots, typeRoot => {
|
||||
return firstDefined(typeRoots, typeRoot => {
|
||||
const candidate = combinePaths(typeRoot, typeReferenceDirectiveName);
|
||||
const candidateDirectory = getDirectoryPath(candidate);
|
||||
const directoryExists = directoryProbablyExists(candidateDirectory, host);
|
||||
@@ -343,15 +341,16 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
|
||||
}
|
||||
let result: SearchResult<Resolved> | undefined;
|
||||
let result: Resolved | undefined;
|
||||
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
|
||||
result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined);
|
||||
const searchResult = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined);
|
||||
result = searchResult && searchResult.value;
|
||||
}
|
||||
else {
|
||||
const { path: candidate } = normalizePathAndParts(combinePaths(initialLocationForSecondaryLookup, typeReferenceDirectiveName));
|
||||
result = toSearchResult(nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true));
|
||||
result = nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true);
|
||||
}
|
||||
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
|
||||
const resolvedFile = resolvedTypeScriptOnly(result);
|
||||
if (!resolvedFile && traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
|
||||
}
|
||||
@@ -883,7 +882,7 @@ namespace ts {
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
|
||||
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
|
||||
if (resolved) {
|
||||
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
|
||||
return toSearchResult({ resolved, isExternalLibraryImport: pathContainsNodeModules(resolved.path) });
|
||||
}
|
||||
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
@@ -960,6 +959,10 @@ namespace ts {
|
||||
|
||||
/*@internal*/
|
||||
export const nodeModulesPathPart = "/node_modules/";
|
||||
/*@internal*/
|
||||
export function pathContainsNodeModules(path: string): boolean {
|
||||
return stringContains(path, nodeModulesPathPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will be called on the successfully resolved path from `loadModuleFromFile`.
|
||||
|
||||
@@ -2345,6 +2345,8 @@ namespace ts {
|
||||
}
|
||||
let saveResolution = true;
|
||||
if (resolvedTypeReferenceDirective) {
|
||||
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth++;
|
||||
|
||||
if (resolvedTypeReferenceDirective.primary) {
|
||||
// resolved from the primary path
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
@@ -2373,6 +2375,8 @@ namespace ts {
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, Diagnostics.Cannot_find_type_definition_file_for_0, typeReferenceDirective)); // TODO: GH#18217
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace ts {
|
||||
|
||||
function getDirectoryToWatchFromFailedLookupLocationDirectory(dir: string, dirPath: Path) {
|
||||
// If directory path contains node module, get the most parent node_modules directory for watching
|
||||
while (stringContains(dirPath, nodeModulesPathPart)) {
|
||||
while (pathContainsNodeModules(dirPath)) {
|
||||
dir = getDirectoryPath(dir);
|
||||
dirPath = getDirectoryPath(dirPath);
|
||||
}
|
||||
|
||||
@@ -4942,6 +4942,8 @@ namespace ts {
|
||||
// The location of the .d.ts file we located, or undefined if resolution failed
|
||||
resolvedFileName: string | undefined;
|
||||
packageId?: PackageId;
|
||||
/** True if `resolvedFileName` comes from `node_modules`. */
|
||||
isExternalLibraryImport?: boolean;
|
||||
}
|
||||
|
||||
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
|
||||
@@ -113,12 +113,23 @@ namespace ts {
|
||||
|
||||
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], cwd: "/" });
|
||||
const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }));
|
||||
|
||||
for (const file of [a, bar, barFooIndex, fooIndex]) {
|
||||
const isExternalExpected = file !== a;
|
||||
const isExternalActual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!);
|
||||
assert.equal(isExternalActual, isExternalExpected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${isExternalExpected}, got ${isExternalActual}`);
|
||||
}
|
||||
assertIsExternal(program, [a, bar, barFooIndex, fooIndex], f => f !== a);
|
||||
});
|
||||
|
||||
it('works on `/// <reference types="" />`', () => {
|
||||
const a = new documents.TextDocument("/a.ts", '/// <reference types="foo" />');
|
||||
const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", "declare const foo: number;");
|
||||
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, fooIndex], cwd: "/" });
|
||||
const program = createProgram(["/a.ts"], emptyOptions, new fakes.CompilerHost(fs, { newLine: NewLineKind.LineFeed }));
|
||||
assertIsExternal(program, [a, fooIndex], f => f !== a);
|
||||
});
|
||||
|
||||
function assertIsExternal(program: Program, files: ReadonlyArray<documents.TextDocument>, isExternalExpected: (file: documents.TextDocument) => boolean): void {
|
||||
for (const file of files) {
|
||||
const actual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!);
|
||||
const expected = isExternalExpected(file);
|
||||
assert.equal(actual, expected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2670,6 +2670,8 @@ declare namespace ts {
|
||||
primary: boolean;
|
||||
resolvedFileName: string | undefined;
|
||||
packageId?: PackageId;
|
||||
/** True if `resolvedFileName` comes from `node_modules`. */
|
||||
isExternalLibraryImport?: boolean;
|
||||
}
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
|
||||
@@ -2670,6 +2670,8 @@ declare namespace ts {
|
||||
primary: boolean;
|
||||
resolvedFileName: string | undefined;
|
||||
packageId?: PackageId;
|
||||
/** True if `resolvedFileName` comes from `node_modules`. */
|
||||
isExternalLibraryImport?: boolean;
|
||||
}
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
|
||||
@@ -32,14 +32,6 @@ import { m } from "mquery";
|
||||
j + k + l + m;
|
||||
|
||||
|
||||
//// [lquery.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.l = 2;
|
||||
//// [index.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.m = 3;
|
||||
//// [a.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
||||
Reference in New Issue
Block a user