Skip to content

Commit edc8d58

Browse files
committed
Cache packagejson scopes per directory
1 parent 911873b commit edc8d58

File tree

47 files changed

+23479
-12914
lines changed

Some content is hidden

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

47 files changed

+23479
-12914
lines changed

src/compiler/builder.ts

+60-22
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
getOriginalOrResolvedModuleFileName,
5656
getOriginalOrResolvedTypeReferenceFileName,
5757
getOwnKeys,
58+
getPackageJsonLocationFromScope,
5859
getRelativePathFromDirectory,
5960
getTsBuildInfoEmitOutputFilePath,
6061
handleNoEmitOptions,
@@ -66,7 +67,6 @@ import {
6667
isJsonSourceFile,
6768
isNumber,
6869
isString,
69-
last,
7070
map,
7171
mapDefined,
7272
maybeBind,
@@ -78,8 +78,9 @@ import {
7878
OldBuildInfoProgramConstructor,
7979
OldBuildInfoProgramHost,
8080
outFile,
81-
PackageJsonInfo,
8281
PackageJsonInfoCache,
82+
PackageJsonInfoContents,
83+
PackageJsonScope,
8384
Path,
8485
PerDirectoryAndNonRelativeNameCache,
8586
PerNonRelativeNameCache,
@@ -187,7 +188,7 @@ export interface ReusableBuilderProgramState extends BuilderState {
187188
modules: PerDirectoryAndNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations> | undefined;
188189
typeRefs: PerDirectoryAndNonRelativeNameCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations> | undefined;
189190
packageJsons: Map<Path, string> | undefined;
190-
nonRelativePackageJsonsCache: PerNonRelativeNameCache<string> | undefined;
191+
packageJsonScopes: PerNonRelativeNameCache<PackageJsonScope> | undefined;
191192
packageJsonCache: PackageJsonInfoCache | undefined;
192193
};
193194
resuableCacheResolutions?: {
@@ -1472,20 +1473,19 @@ function getCacheResolutions(state: BuilderProgramState) {
14721473
let modules: PerDirectoryAndNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations> | undefined;
14731474
let typeRefs: PerDirectoryAndNonRelativeNameCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations> | undefined;
14741475
let packageJsons: Map<Path, string> | undefined;
1475-
let nonRelativePackageJsonsCache: PerNonRelativeNameCache<string> | undefined;
1476+
let packageJsonScopes: PerNonRelativeNameCache<PackageJsonScope> | undefined;
14761477
for (const f of state.program!.getSourceFiles()) {
14771478
modules = toPerDirectoryAndNonRelativeNameCache(state, modules, getOriginalOrResolvedModuleFileName, f.resolvedModules, f);
14781479
typeRefs = toPerDirectoryAndNonRelativeNameCache(state, typeRefs, getOriginalOrResolvedTypeReferenceFileName, f.resolvedTypeReferenceDirectiveNames, f);
1479-
if (f.packageJsonScope) {
1480+
if (f.packageJsonScope?.contents) {
14801481
const dirPath = getDirectoryPath(f.resolvedPath);
1481-
if (!nonRelativePackageJsonsCache?.getWithPath(dirPath)) {
1482-
const result = last(f.packageJsonLocations!);
1483-
(packageJsons ??= new Map()).set(dirPath, result);
1484-
(nonRelativePackageJsonsCache ??= createPerNonRelativeNameCache(
1482+
if (!packageJsonScopes?.getWithPath(dirPath)) {
1483+
(packageJsons ??= new Map()).set(dirPath, getPackageJsonLocationFromScope(f.packageJsonScope));
1484+
(packageJsonScopes ??= createPerNonRelativeNameCache(
14851485
state.program!.getCurrentDirectory(),
14861486
state.program!.getCanonicalFileName,
1487-
identity,
1488-
)).setWithPath(dirPath, result, ancestorPath => packageJsons!.delete(ancestorPath));
1487+
getPackageJsonLocationFromScope,
1488+
)).setWithPath(dirPath, f.packageJsonScope, ancestorPath => packageJsons!.delete(ancestorPath));
14891489
}
14901490
}
14911491
}
@@ -1498,7 +1498,7 @@ function getCacheResolutions(state: BuilderProgramState) {
14981498
modules,
14991499
typeRefs,
15001500
packageJsons,
1501-
nonRelativePackageJsonsCache,
1501+
packageJsonScopes,
15021502
packageJsonCache: state.program!.getModuleResolutionCache()?.getPackageJsonInfoCache().clone(),
15031503
};
15041504
}
@@ -2158,6 +2158,7 @@ export function createOldBuildInfoProgram(
21582158
if (!cacheResolutions && !resuableCacheResolutions) return undefined;
21592159
const fileExistsMap = new Map<string, boolean>();
21602160
const affectingLoationsSameMap = new Map<string, boolean>();
2161+
const packageJsonInfoContentsMap = new Map<string, PackageJsonInfoContents | false>();
21612162

21622163
type Resolution = ResolvedModuleWithFailedLookupLocations & ResolvedTypeReferenceDirectiveWithFailedLookupLocations;
21632164
type ResolutionEntry = [name: string, resolutionId: ProgramBuildInfoResolutionId, mode: ResolutionMode];
@@ -2168,6 +2169,7 @@ export function createOldBuildInfoProgram(
21682169
const reusableResolvedModules = intializeReusableResolutionsCache(resuableCacheResolutions?.cache.modules);
21692170
const reusableResolvedTypeRefs = intializeReusableResolutionsCache(resuableCacheResolutions?.cache.typeRefs);
21702171
let decodedPackageJsons: PerNonRelativeNameCache<string> | undefined;
2172+
let packageJsonScopes: Map<string, PackageJsonScope | false> | undefined;
21712173
let decodedHashes: Map<ProgramBuildInfoAbsoluteFileId, string | undefined> | undefined;
21722174
let resolutions: (Resolution | false)[] | undefined;
21732175
let originalPathOrResolvedFileNames: string[] | undefined;
@@ -2194,7 +2196,7 @@ export function createOldBuildInfoProgram(
21942196
dirPath,
21952197
redirectedReference,
21962198
),
2197-
getPackageJsonPath,
2199+
getPackageJsonScope,
21982200
};
21992201

22002202
function intializeReusableResolutionsCache(reusable: ProgramBuildInfoResolutionCacheWithRedirects | undefined): ReusableResolutionsCache | undefined {
@@ -2209,7 +2211,7 @@ export function createOldBuildInfoProgram(
22092211

22102212
function affectingLocationsSame(
22112213
fileName: string,
2212-
expected: PackageJsonInfo | boolean | string | undefined
2214+
expected: PackageJsonInfoContents | string | undefined
22132215
): boolean {
22142216
let result = affectingLoationsSameMap.get(fileName);
22152217
if (result !== undefined) return result;
@@ -2219,17 +2221,34 @@ export function createOldBuildInfoProgram(
22192221
result = !!currentText && (host.createHash ?? generateDjb2Hash)(currentText) === expected;
22202222
}
22212223
else {
2222-
const expectedText = typeof expected === "object" ? expected.contents.packageJsonText : undefined;
2223-
result = currentText === expectedText;
2224+
result = currentText === expected?.packageJsonText;
22242225
}
22252226
affectingLoationsSameMap.set(fileName, result);
22262227
return result;
22272228
}
22282229

2229-
function getPackageJsonPath(dir: string) {
2230-
const fromCache = cacheResolutions?.nonRelativePackageJsonsCache?.get(dir);
2230+
function getPackageJsonInfoContents(fileName: string) {
2231+
let result = packageJsonInfoContentsMap.get(fileName);
2232+
if (result === undefined) packageJsonInfoContentsMap.set(fileName, result = host.getPackageJsonInfo(fileName)?.contents || false);
2233+
return result || undefined;
2234+
}
2235+
2236+
function getPackageJsonScope(dir: string): PackageJsonScope | undefined{
2237+
const fromCache = cacheResolutions?.packageJsonScopes?.get(dir);
22312238
if (fromCache) {
2232-
return fileExists(fromCache) ? fromCache : undefined;
2239+
const packageJson = getPackageJsonLocationFromScope(fromCache)!;
2240+
let result = packageJsonScopes?.get(packageJson);
2241+
if (result === undefined) {
2242+
(packageJsonScopes ??= new Map()).set(
2243+
packageJson,
2244+
result = affectingLocationsSame(packageJson, fromCache.contents) ?
2245+
fromCache :
2246+
fileExists(packageJson) ?
2247+
{ contents: getPackageJsonInfoContents(packageJson), affectingLocations: [packageJson] } :
2248+
false
2249+
);
2250+
}
2251+
return result || undefined;
22332252
}
22342253
if (!resuableCacheResolutions?.cache.packageJsons) return;
22352254
if (!decodedPackageJsons) {
@@ -2252,8 +2271,27 @@ export function createOldBuildInfoProgram(
22522271
decodedPackageJsons.setWithPath(dirPath, packageJson, noop);
22532272
}
22542273
}
2255-
const fromDecoded = decodedPackageJsons.get(dir);
2256-
return fromDecoded && fileExists(fromDecoded) ? fromDecoded : undefined;
2274+
return toPackageJsonScope(decodedPackageJsons.get(dir));
2275+
}
2276+
2277+
function toPackageJsonScope(file: string | undefined): PackageJsonScope | undefined {
2278+
if (!file) return undefined;
2279+
let result = packageJsonScopes?.get(file);
2280+
if (result !== undefined) return result || undefined;
2281+
(packageJsonScopes ??= new Map());
2282+
if (fileExists(file)) {
2283+
result = {
2284+
contents: getPackageJsonInfoContents(file),
2285+
affectingLocations: [file]
2286+
};
2287+
}
2288+
packageJsonScopes.set(file, result || false);
2289+
return result;
2290+
}
2291+
2292+
function getPackageJsonContentsFromCachedResolutions(fileName: string) {
2293+
const info = cacheResolutions!.packageJsonCache?.getPackageJsonInfo(fileName);
2294+
return typeof info === "object" ? info.contents : undefined;
22572295
}
22582296

22592297
function getResolvedFromCache<T extends ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations>(
@@ -2277,7 +2315,7 @@ export function createOldBuildInfoProgram(
22772315
fromCache.affectingLocations,
22782316
fileName => affectingLocationsSame(
22792317
fileName,
2280-
cacheResolutions!.packageJsonCache?.getPackageJsonInfo(fileName)
2318+
getPackageJsonContentsFromCachedResolutions(fileName)
22812319
)
22822320
) ? fromCache : undefined;
22832321
}

src/compiler/checker.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ import {
6767
ClassLikeDeclaration,
6868
ClassStaticBlockDeclaration,
6969
clear,
70-
combinePaths,
7170
compareDiagnostics,
7271
comparePaths,
7372
compareValues,
@@ -1012,6 +1011,7 @@ import {
10121011
WideningContext,
10131012
WithStatement,
10141013
YieldExpression,
1014+
getPackageJsonLocationFromScope,
10151015
} from "./_namespaces/ts";
10161016
import * as performance from "./_namespaces/ts.performance";
10171017
import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers";
@@ -4730,19 +4730,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47304730
if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) {
47314731
const scope = currentSourceFile.packageJsonScope;
47324732
const targetExt = ext === Extension.Ts ? Extension.Mts : ext === Extension.Js ? Extension.Mjs : undefined;
4733-
if (scope && !scope.contents.packageJsonContent.type) {
4733+
if (scope?.contents && !scope.contents.packageJsonContent.type) {
47344734
if (targetExt) {
47354735
diagnosticDetails = chainDiagnosticMessages(
47364736
/*details*/ undefined,
47374737
Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1,
47384738
targetExt,
4739-
combinePaths(scope.packageDirectory, "package.json"));
4739+
getPackageJsonLocationFromScope(scope));
47404740
}
47414741
else {
47424742
diagnosticDetails = chainDiagnosticMessages(
47434743
/*details*/ undefined,
47444744
Diagnostics.To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0,
4745-
combinePaths(scope.packageDirectory, "package.json"));
4745+
getPackageJsonLocationFromScope(scope));
47464746
}
47474747
}
47484748
else {

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -5154,6 +5154,14 @@
51545154
"category": "Message",
51555155
"code": 6261
51565156
},
5157+
"Directory '{0}' resolves to '{1}' scope according to cache.": {
5158+
"category": "Message",
5159+
"code": 6263
5160+
},
5161+
"Directory '{0}' has no containing package.json scope according to cache.": {
5162+
"category": "Message",
5163+
"code": 6264
5164+
},
51575165

51585166
"Directory '{0}' has no containing package.json scope. Imports will not resolve.": {
51595167
"category": "Message",

0 commit comments

Comments
 (0)