Skip to content

Commit 052bb69

Browse files
author
Andy Hanson
committed
When loading a module from node_modules, get packageId even in the loadModuleFromFile case
1 parent e294b23 commit 052bb69

38 files changed

+351
-107
lines changed

src/compiler/moduleNameResolver.ts

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ namespace ts {
675675
if (extension !== undefined) {
676676
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
677677
if (path !== undefined) {
678-
return { path, extension, packageId: undefined };
678+
return noPackageId({ path, ext: extension });
679679
}
680680
}
681681

@@ -875,38 +875,49 @@ namespace ts {
875875
return undefined;
876876
}
877877

878-
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
879-
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
880-
881-
let packageId: PackageId | undefined;
882-
883-
if (considerPackageJson) {
884-
const packageJsonPath = pathToPackageJson(candidate);
885-
if (directoryExists && state.host.fileExists(packageJsonPath)) {
886-
if (state.traceEnabled) {
887-
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
888-
}
889-
const jsonContent = readJson(packageJsonPath, state.host);
878+
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
879+
const { packageJsonContent, packageId } = considerPackageJson
880+
? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state)
881+
: { packageJsonContent: undefined, packageId: undefined };
882+
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
883+
}
890884

891-
if (typeof jsonContent.name === "string" && typeof jsonContent.version === "string") {
892-
packageId = { name: jsonContent.name, version: jsonContent.version };
893-
}
885+
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJson | undefined): PathAndExtension | undefined {
886+
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
887+
if (fromPackageJson) {
888+
return fromPackageJson;
889+
}
890+
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
891+
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
892+
}
894893

895-
const fromPackageJson = loadModuleFromPackageJson(jsonContent, extensions, candidate, failedLookupLocations, state);
896-
if (fromPackageJson) {
897-
return withPackageId(packageId, fromPackageJson);
898-
}
894+
function getPackageJsonInfo(
895+
nodeModuleDirectory: string,
896+
subModuleName: string,
897+
failedLookupLocations: Push<string>,
898+
onlyRecordFailures: boolean,
899+
{ host, traceEnabled }: ModuleResolutionState,
900+
): { packageJsonContent: PackageJson | undefined, packageId: PackageId | undefined } {
901+
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
902+
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
903+
if (directoryExists && host.fileExists(packageJsonPath)) {
904+
if (traceEnabled) {
905+
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
899906
}
900-
else {
901-
if (directoryExists && state.traceEnabled) {
902-
trace(state.host, Diagnostics.File_0_does_not_exist, packageJsonPath);
903-
}
904-
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
905-
failedLookupLocations.push(packageJsonPath);
907+
const packageJsonContent = readJson(packageJsonPath, host);
908+
const packageId: PackageId = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
909+
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
910+
: undefined;
911+
return { packageJsonContent, packageId };
912+
}
913+
else {
914+
if (directoryExists && traceEnabled) {
915+
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
906916
}
917+
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
918+
failedLookupLocations.push(packageJsonPath);
919+
return { packageJsonContent: undefined, packageId: undefined };
907920
}
908-
909-
return withPackageId(packageId, loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state));
910921
}
911922

912923
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
@@ -961,10 +972,18 @@ namespace ts {
961972
}
962973

963974
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
975+
const { top, rest } = getNameOfTopDirectory(moduleName);
976+
const packageRootPath = combinePaths(nodeModulesFolder, top);
977+
const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state);
964978
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
979+
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
980+
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
981+
return withPackageId(packageId, pathAndExtension);
982+
}
965983

966-
return loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
967-
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
984+
function getNameOfTopDirectory(name: string): { top: string, rest: string } {
985+
const idx = name.indexOf(directorySeparator);
986+
return idx === -1 ? { top: name, rest: "" } : { top: name.slice(0, idx), rest: name.slice(idx + 1) };
968987
}
969988

970989
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult<Resolved> {

src/compiler/program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1675,7 +1675,7 @@ namespace ts {
16751675
});
16761676

16771677
if (packageId) {
1678-
const packageIdKey = `${packageId.name}@${packageId.version}`;
1678+
const packageIdKey = `${packageId.name}/${packageId.subModuleName}@${packageId.version}`;
16791679
const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
16801680
if (fileFromPackageId) {
16811681
// Some other SourceFile already exists with this package name and version.

src/compiler/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,11 @@ namespace ts {
40104010
* If accessing a non-index file, this should include its name e.g. "foo/bar".
40114011
*/
40124012
name: string;
4013+
/**
4014+
* Name of a submodule within this package.
4015+
* May be "".
4016+
*/
4017+
subModuleName: string;
40134018
/** Version of the package, e.g. "1.2.3" */
40144019
version: string;
40154020
}

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ namespace ts {
106106
}
107107

108108
function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean {
109-
return a === b || a && b && a.name === b.name && a.version === b.version;
109+
return a === b || a && b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version;
110110
}
111111

112112
export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean {

src/harness/unittests/moduleResolution.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -198,33 +198,34 @@ namespace ts {
198198
const moduleFile = { name: "/a/b/node_modules/foo.ts" };
199199
const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile));
200200
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [
201+
"/a/b/c/d/node_modules/foo/package.json",
201202
"/a/b/c/d/node_modules/foo.ts",
202203
"/a/b/c/d/node_modules/foo.tsx",
203204
"/a/b/c/d/node_modules/foo.d.ts",
204-
"/a/b/c/d/node_modules/foo/package.json",
205205

206206
"/a/b/c/d/node_modules/foo/index.ts",
207207
"/a/b/c/d/node_modules/foo/index.tsx",
208208
"/a/b/c/d/node_modules/foo/index.d.ts",
209209

210-
"/a/b/c/d/node_modules/@types/foo.d.ts",
211210
"/a/b/c/d/node_modules/@types/foo/package.json",
211+
"/a/b/c/d/node_modules/@types/foo.d.ts",
212212

213213
"/a/b/c/d/node_modules/@types/foo/index.d.ts",
214214

215+
"/a/b/c/node_modules/foo/package.json",
215216
"/a/b/c/node_modules/foo.ts",
216217
"/a/b/c/node_modules/foo.tsx",
217218
"/a/b/c/node_modules/foo.d.ts",
218-
"/a/b/c/node_modules/foo/package.json",
219219

220220
"/a/b/c/node_modules/foo/index.ts",
221221
"/a/b/c/node_modules/foo/index.tsx",
222222
"/a/b/c/node_modules/foo/index.d.ts",
223223

224-
"/a/b/c/node_modules/@types/foo.d.ts",
225224
"/a/b/c/node_modules/@types/foo/package.json",
225+
"/a/b/c/node_modules/@types/foo.d.ts",
226226

227227
"/a/b/c/node_modules/@types/foo/index.d.ts",
228+
"/a/b/node_modules/foo/package.json",
228229
]);
229230
}
230231
});
@@ -250,52 +251,52 @@ namespace ts {
250251
const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" };
251252
const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile));
252253
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [
254+
"/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json",
253255
"/a/node_modules/b/c/node_modules/d/node_modules/foo.ts",
254256
"/a/node_modules/b/c/node_modules/d/node_modules/foo.tsx",
255257
"/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts",
256-
"/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json",
257258

258259
"/a/node_modules/b/c/node_modules/d/node_modules/foo/index.ts",
259260
"/a/node_modules/b/c/node_modules/d/node_modules/foo/index.tsx",
260261
"/a/node_modules/b/c/node_modules/d/node_modules/foo/index.d.ts",
261262

262-
"/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts",
263263
"/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/package.json",
264+
"/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts",
264265

265266
"/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/index.d.ts",
266267

268+
"/a/node_modules/b/c/node_modules/foo/package.json",
267269
"/a/node_modules/b/c/node_modules/foo.ts",
268270
"/a/node_modules/b/c/node_modules/foo.tsx",
269271
"/a/node_modules/b/c/node_modules/foo.d.ts",
270-
"/a/node_modules/b/c/node_modules/foo/package.json",
271272

272273
"/a/node_modules/b/c/node_modules/foo/index.ts",
273274
"/a/node_modules/b/c/node_modules/foo/index.tsx",
274275
"/a/node_modules/b/c/node_modules/foo/index.d.ts",
275276

276-
"/a/node_modules/b/c/node_modules/@types/foo.d.ts",
277277
"/a/node_modules/b/c/node_modules/@types/foo/package.json",
278+
"/a/node_modules/b/c/node_modules/@types/foo.d.ts",
278279

279280
"/a/node_modules/b/c/node_modules/@types/foo/index.d.ts",
280281

282+
"/a/node_modules/b/node_modules/foo/package.json",
281283
"/a/node_modules/b/node_modules/foo.ts",
282284
"/a/node_modules/b/node_modules/foo.tsx",
283285
"/a/node_modules/b/node_modules/foo.d.ts",
284-
"/a/node_modules/b/node_modules/foo/package.json",
285286

286287
"/a/node_modules/b/node_modules/foo/index.ts",
287288
"/a/node_modules/b/node_modules/foo/index.tsx",
288289
"/a/node_modules/b/node_modules/foo/index.d.ts",
289290

290-
"/a/node_modules/b/node_modules/@types/foo.d.ts",
291291
"/a/node_modules/b/node_modules/@types/foo/package.json",
292+
"/a/node_modules/b/node_modules/@types/foo.d.ts",
292293

293294
"/a/node_modules/b/node_modules/@types/foo/index.d.ts",
294295

296+
"/a/node_modules/foo/package.json",
295297
"/a/node_modules/foo.ts",
296298
"/a/node_modules/foo.tsx",
297299
"/a/node_modules/foo.d.ts",
298-
"/a/node_modules/foo/package.json",
299300

300301
"/a/node_modules/foo/index.ts",
301302
"/a/node_modules/foo/index.tsx"
@@ -707,21 +708,23 @@ import b = require("./moduleB");
707708
"/root/generated/file6/index.d.ts",
708709

709710
// fallback to standard node behavior
711+
"/root/folder1/node_modules/file6/package.json",
712+
710713
// load from file
711714
"/root/folder1/node_modules/file6.ts",
712715
"/root/folder1/node_modules/file6.tsx",
713716
"/root/folder1/node_modules/file6.d.ts",
714717

715718
// load from folder
716-
"/root/folder1/node_modules/file6/package.json",
717719
"/root/folder1/node_modules/file6/index.ts",
718720
"/root/folder1/node_modules/file6/index.tsx",
719721
"/root/folder1/node_modules/file6/index.d.ts",
720722

721-
"/root/folder1/node_modules/@types/file6.d.ts",
722-
723723
"/root/folder1/node_modules/@types/file6/package.json",
724+
"/root/folder1/node_modules/@types/file6.d.ts",
724725
"/root/folder1/node_modules/@types/file6/index.d.ts",
726+
727+
"/root/node_modules/file6/package.json",
725728
// success on /root/node_modules/file6.ts
726729
], /*isExternalLibraryImport*/ true);
727730

0 commit comments

Comments
 (0)