Skip to content

Commit 98f2c12

Browse files
Take into account peerDependency versions when calculating packageId (microsoft#57029)
Co-authored-by: TypeScript Bot <typescriptbot@microsoft.com>
1 parent e0d9d46 commit 98f2c12

File tree

60 files changed

+750
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+750
-13
lines changed

src/compiler/diagnosticMessages.json

+12
Original file line numberDiff line numberDiff line change
@@ -5455,6 +5455,18 @@
54555455
"category": "Message",
54565456
"code": 6280
54575457
},
5458+
"'package.json' has a 'peerDependencies' field.": {
5459+
"category": "Message",
5460+
"code": 6281
5461+
},
5462+
"Found peerDependency '{0}' with '{1}' version.": {
5463+
"category": "Message",
5464+
"code": 6282
5465+
},
5466+
"Failed to find peerDependency '{0}'.": {
5467+
"category": "Message",
5468+
"code": 6283
5469+
},
54585470

54595471
"Enable project compilation": {
54605472
"category": "Message",

src/compiler/moduleNameResolver.ts

+46-11
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export function isTraceEnabled(compilerOptions: CompilerOptions, host: ModuleRes
120120
return !!compilerOptions.traceResolution && host.trace !== undefined;
121121
}
122122

123-
function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined): Resolved | undefined {
123+
function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined, state: ModuleResolutionState): Resolved | undefined {
124124
let packageId: PackageId | undefined;
125125
if (r && packageInfo) {
126126
const packageJsonContent = packageInfo.contents.packageJsonContent as PackageJson;
@@ -129,14 +129,15 @@ function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExten
129129
name: packageJsonContent.name,
130130
subModuleName: r.path.slice(packageInfo.packageDirectory.length + directorySeparator.length),
131131
version: packageJsonContent.version,
132+
peerDependencies: getPeerDependenciesOfPackageJsonInfo(packageInfo, state),
132133
};
133134
}
134135
}
135136
return r && { path: r.path, extension: r.ext, packageId, resolvedUsingTsExtension: r.resolvedUsingTsExtension };
136137
}
137138

138139
function noPackageId(r: PathAndExtension | undefined): Resolved | undefined {
139-
return withPackageId(/*packageInfo*/ undefined, r);
140+
return withPackageId(/*packageInfo*/ undefined, r, /*state*/ undefined!); // State will not be used so no need to pass
140141
}
141142

142143
function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
@@ -346,6 +347,7 @@ export interface PackageJsonPathFields {
346347
interface PackageJson extends PackageJsonPathFields {
347348
name?: string;
348349
version?: string;
350+
peerDependencies?: MapLike<string>;
349351
}
350352

351353
function readPackageJsonField<K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
@@ -669,7 +671,7 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
669671
if (resolvedFromFile) {
670672
const packageDirectory = parseNodeModuleFromPath(resolvedFromFile.path);
671673
const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, moduleResolutionState) : undefined;
672-
return resolvedTypeScriptOnly(withPackageId(packageInfo, resolvedFromFile));
674+
return resolvedTypeScriptOnly(withPackageId(packageInfo, resolvedFromFile, moduleResolutionState));
673675
}
674676
}
675677
return resolvedTypeScriptOnly(
@@ -1984,7 +1986,7 @@ function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string,
19841986
if (resolvedFromFile) {
19851987
const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile.path) : undefined;
19861988
const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined;
1987-
return withPackageId(packageInfo, resolvedFromFile);
1989+
return withPackageId(packageInfo, resolvedFromFile, state);
19881990
}
19891991
}
19901992
if (!onlyRecordFailures) {
@@ -2200,7 +2202,7 @@ function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string,
22002202
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, onlyRecordFailures, state) : undefined;
22012203
const packageJsonContent = packageInfo && packageInfo.contents.packageJsonContent;
22022204
const versionPaths = packageInfo && getVersionPathsOfPackageJsonInfo(packageInfo, state);
2203-
return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
2205+
return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths), state);
22042206
}
22052207

22062208
/** @internal */
@@ -2372,6 +2374,8 @@ export interface PackageJsonInfoContents {
23722374
versionPaths: VersionPaths | false | undefined;
23732375
/** false: resolved to nothing. undefined: not yet resolved */
23742376
resolvedEntrypoints: string[] | false | undefined;
2377+
/** false: peerDependencies are not present. undefined: not yet resolved */
2378+
peerDependencies: string | false | undefined;
23752379
}
23762380

23772381
/**
@@ -2399,6 +2403,37 @@ function getVersionPathsOfPackageJsonInfo(packageJsonInfo: PackageJsonInfo, stat
23992403
return packageJsonInfo.contents.versionPaths || undefined;
24002404
}
24012405

2406+
function getPeerDependenciesOfPackageJsonInfo(packageJsonInfo: PackageJsonInfo, state: ModuleResolutionState): string | undefined {
2407+
if (packageJsonInfo.contents.peerDependencies === undefined) {
2408+
packageJsonInfo.contents.peerDependencies = readPackageJsonPeerDependencies(packageJsonInfo, state) || false;
2409+
}
2410+
return packageJsonInfo.contents.peerDependencies || undefined;
2411+
}
2412+
2413+
function readPackageJsonPeerDependencies(packageJsonInfo: PackageJsonInfo, state: ModuleResolutionState): string | undefined {
2414+
const peerDependencies = readPackageJsonField(packageJsonInfo.contents.packageJsonContent, "peerDependencies", "object", state);
2415+
if (peerDependencies === undefined) return undefined;
2416+
if (state.traceEnabled) trace(state.host, Diagnostics.package_json_has_a_peerDependencies_field);
2417+
const packageDirectory = realPath(packageJsonInfo.packageDirectory, state.host, state.traceEnabled);
2418+
const nodeModules = packageDirectory.substring(0, packageDirectory.lastIndexOf("node_modules") + "node_modules".length) + directorySeparator;
2419+
let result = "";
2420+
for (const key in peerDependencies) {
2421+
if (hasProperty(peerDependencies, key)) {
2422+
const peerPackageJson = getPackageJsonInfo(nodeModules + key, /*onlyRecordFailures*/ false, state);
2423+
if (peerPackageJson) {
2424+
const version = (peerPackageJson.contents.packageJsonContent as PackageJson).version;
2425+
result += `+${key}@${version}`;
2426+
if (state.traceEnabled) trace(state.host, Diagnostics.Found_peerDependency_0_with_1_version, key, version);
2427+
}
2428+
else {
2429+
// Read the dependency version
2430+
if (state.traceEnabled) trace(state.host, Diagnostics.Failed_to_find_peerDependency_0, key);
2431+
}
2432+
}
2433+
}
2434+
return result;
2435+
}
2436+
24022437
/** @internal */
24032438
export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
24042439
const { host, traceEnabled } = state;
@@ -2429,7 +2464,7 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures:
24292464
if (traceEnabled) {
24302465
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
24312466
}
2432-
const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined } };
2467+
const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined, peerDependencies: undefined } };
24332468
if (state.packageJsonInfoCache && !state.packageJsonInfoCache.isReadonly) state.packageJsonInfoCache.setPackageJsonInfo(packageJsonPath, result);
24342469
state.affectingLocations?.push(packageJsonPath);
24352470
return result;
@@ -2755,7 +2790,7 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo
27552790
const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath);
27562791
const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports);
27572792
if (inputLink) return inputLink;
2758-
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state)));
2793+
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state), state));
27592794
}
27602795
else if (typeof target === "object" && target !== null) { // eslint-disable-line no-null/no-null
27612796
if (!Array.isArray(target)) {
@@ -2901,7 +2936,7 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo
29012936
if (!extensionIsOk(extensions, possibleExt)) continue;
29022937
const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames(state));
29032938
if (state.host.fileExists(possibleInputWithInputExtension)) {
2904-
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state)));
2939+
return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state), state));
29052940
}
29062941
}
29072942
}
@@ -3037,7 +3072,7 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu
30373072
packageInfo.contents.packageJsonContent,
30383073
getVersionPathsOfPackageJsonInfo(packageInfo, state),
30393074
);
3040-
return withPackageId(packageInfo, fromDirectory);
3075+
return withPackageId(packageInfo, fromDirectory, state);
30413076
}
30423077

30433078
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
@@ -3060,7 +3095,7 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu
30603095
// a default `index.js` entrypoint if no `main` or `exports` are present
30613096
pathAndExtension = loadModuleFromFile(extensions, combinePaths(candidate, "index.js"), onlyRecordFailures, state);
30623097
}
3063-
return withPackageId(packageInfo, pathAndExtension);
3098+
return withPackageId(packageInfo, pathAndExtension, state);
30643099
};
30653100

30663101
if (rest !== "") {
@@ -3260,7 +3295,7 @@ function resolveFromTypeRoot(moduleName: string, state: ModuleResolutionState) {
32603295
if (resolvedFromFile) {
32613296
const packageDirectory = parseNodeModuleFromPath(resolvedFromFile.path);
32623297
const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined;
3263-
return toSearchResult(withPackageId(packageInfo, resolvedFromFile));
3298+
return toSearchResult(withPackageId(packageInfo, resolvedFromFile, state));
32643299
}
32653300
const resolved = loadNodeModuleFromDirectory(Extensions.Declaration, candidate, !directoryExists, state);
32663301
if (resolved) return toSearchResult(resolved);

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7675,6 +7675,7 @@ export interface PackageId {
76757675
subModuleName: string;
76767676
/** Version of the package, e.g. "1.2.3" */
76777677
version: string;
7678+
/** @internal*/ peerDependencies?: string;
76787679
}
76797680

76807681
export const enum Extension {

src/compiler/utilities.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ export function createModuleNotFoundChain(sourceFile: SourceFile, host: TypeChec
809809
}
810810

811811
function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean {
812-
return a === b || !!a && !!b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version;
812+
return a === b || !!a && !!b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version && a.peerDependencies === b.peerDependencies;
813813
}
814814

815815
/** @internal */
@@ -819,7 +819,7 @@ export function packageIdToPackageName({ name, subModuleName }: PackageId): stri
819819

820820
/** @internal */
821821
export function packageIdToString(packageId: PackageId): string {
822-
return `${packageIdToPackageName(packageId)}@${packageId.version}`;
822+
return `${packageIdToPackageName(packageId)}@${packageId.version}${packageId.peerDependencies ?? ""}`;
823823
}
824824

825825
/** @internal */

0 commit comments

Comments
 (0)