Skip to content

Commit

Permalink
During cacheResolutions dont watch failed lookups and dont look at th…
Browse files Browse the repository at this point in the history
…ose package.json if one exists per buildInfo
  • Loading branch information
sheetalkamat committed Dec 9, 2022
1 parent 592a8bd commit df70939
Show file tree
Hide file tree
Showing 13 changed files with 2,886 additions and 6,390 deletions.
40 changes: 37 additions & 3 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ export interface ReusableBuilderProgramState extends BuilderState {
modules: PerDirectoryAndNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations> | undefined;
typeRefs: PerDirectoryAndNonRelativeNameCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations> | undefined;
packageJsons: Map<Path, string> | undefined;
nonRelativePackageJsonsCache: PerNonRelativeNameCache<string> | undefined;
packageJsonCache: PackageJsonInfoCache | undefined;
};
resuableCacheResolutions?: {
Expand Down Expand Up @@ -1475,16 +1476,16 @@ function getCacheResolutions(state: BuilderProgramState) {
let modules: PerDirectoryAndNonRelativeNameCache<ResolvedModuleWithFailedLookupLocations> | undefined;
let typeRefs: PerDirectoryAndNonRelativeNameCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations> | undefined;
let packageJsons: Map<Path, string> | undefined;
let nonRelativePackageJsons: PerNonRelativeNameCache<string> | undefined;
let nonRelativePackageJsonsCache: PerNonRelativeNameCache<string> | undefined;
for (const f of state.program!.getSourceFiles()) {
modules = toPerDirectoryAndNonRelativeNameCache(state, modules, getOriginalOrResolvedModuleFileName, f.resolvedModules, f);
typeRefs = toPerDirectoryAndNonRelativeNameCache(state, typeRefs, getOriginalOrResolvedTypeReferenceFileName, f.resolvedTypeReferenceDirectiveNames, f);
if (f.packageJsonScope) {
const dirPath = getDirectoryPath(f.resolvedPath);
if (!nonRelativePackageJsons?.getWithPath(dirPath)) {
if (!nonRelativePackageJsonsCache?.getWithPath(dirPath)) {
const result = last(f.packageJsonLocations!);
(packageJsons ??= new Map()).set(dirPath, result);
(nonRelativePackageJsons ??= createPerNonRelativeNameCache(
(nonRelativePackageJsonsCache ??= createPerNonRelativeNameCache(
state.program!.getCurrentDirectory(),
state.program!.getCanonicalFileName,
identity,
Expand All @@ -1501,6 +1502,7 @@ function getCacheResolutions(state: BuilderProgramState) {
modules,
typeRefs,
packageJsons,
nonRelativePackageJsonsCache,
packageJsonCache: state.program!.getModuleResolutionCache()?.getPackageJsonInfoCache().clone(),
};
}
Expand Down Expand Up @@ -2169,6 +2171,7 @@ export function createOldBuildInfoProgram(
}
const reusableResolvedModules = intializeReusableResolutionsCache(resuableCacheResolutions?.cache.modules);
const reusableResolvedTypeRefs = intializeReusableResolutionsCache(resuableCacheResolutions?.cache.typeRefs);
let decodedPackageJsons: PerNonRelativeNameCache<string> | undefined;
let decodedHashes: Map<ProgramBuildInfoAbsoluteFileId, string | undefined> | undefined;
let resolutions: (Resolution | false)[] | undefined;
let originalPathOrResolvedFileNames: string[] | undefined;
Expand All @@ -2195,6 +2198,7 @@ export function createOldBuildInfoProgram(
dirPath,
redirectedReference,
),
getPackageJsonPath,
};

function intializeReusableResolutionsCache(reusable: ProgramBuildInfoResolutionCacheWithRedirects | undefined): ReusableResolutionsCache | undefined {
Expand Down Expand Up @@ -2226,6 +2230,36 @@ export function createOldBuildInfoProgram(
return result;
}

function getPackageJsonPath(dir: string) {
const fromCache = cacheResolutions?.nonRelativePackageJsonsCache?.get(dir);
if (fromCache) {
return fileExists(fromCache) ? fromCache : undefined;
}
if (!resuableCacheResolutions?.cache.packageJsons) return;
if (!decodedPackageJsons) {
decodedPackageJsons = createPerNonRelativeNameCache(
resuableCacheResolutions.getProgramBuildInfoFilePathDecoder().currentDirectory,
resuableCacheResolutions.getProgramBuildInfoFilePathDecoder().getCanonicalFileName,
identity,
);
const filePathDecoder = resuableCacheResolutions.getProgramBuildInfoFilePathDecoder();
for (const dirIdOrDirAndPackageJson of resuableCacheResolutions.cache.packageJsons) {
let dirPath: Path, packageJson: string;
if (isArray(dirIdOrDirAndPackageJson)) {
dirPath = filePathDecoder.toFilePath(dirIdOrDirAndPackageJson[0]);
packageJson = filePathDecoder.toFileAbsolutePath(dirIdOrDirAndPackageJson[1]);
}
else {
packageJson = filePathDecoder.toFileAbsolutePath(dirIdOrDirAndPackageJson);
dirPath = getDirectoryPath(toPath(packageJson, filePathDecoder.currentDirectory, filePathDecoder.getCanonicalFileName));
}
decodedPackageJsons.setWithPath(dirPath, packageJson, noop);
}
}
const fromDecoded = decodedPackageJsons.get(dir);
return fromDecoded && fileExists(fromDecoded) ? fromDecoded : undefined;
}

function getResolvedFromCache<T extends ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations>(
cache: PerDirectoryAndNonRelativeNameCache<T> | undefined,
getResolvedFileName: (resolution: T) => string | undefined,
Expand Down
12 changes: 10 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,12 @@ function gatherPossibleChildren(node: Node) {
}
}

/** @internal */
export interface SourceFilePackageJsonInfo {
packageJsonLocations?: readonly string[];
packageJsonScope?: PackageJsonInfo;
}

export interface CreateSourceFileOptions {
languageVersion: ScriptTarget;
/**
Expand All @@ -1315,8 +1321,10 @@ export interface CreateSourceFileOptions {
* check specified by `isFileProbablyExternalModule` will be used to set the field.
*/
setExternalModuleIndicator?: (file: SourceFile) => void;
/** @internal */ packageJsonLocations?: readonly string[];
/** @internal */ packageJsonScope?: PackageJsonInfo;
}

/** @internal */
export interface CreateSourceFileOptions extends SourceFilePackageJsonInfo {
}

function setExternalModuleIndicator(sourceFile: SourceFile) {
Expand Down
28 changes: 21 additions & 7 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCom
* @returns `undefined` if the path has no relevant implied format, `ModuleKind.ESNext` for esm format, and `ModuleKind.CommonJS` for cjs format
*/
export function getImpliedNodeFormatForFile(fileName: Path, packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ResolutionMode {
const result = getImpliedNodeFormatForFileWorker(fileName, packageJsonInfoCache, host, options);
const result = getImpliedNodeFormatForFileWorker(fileName, packageJsonInfoCache, host, options, /*oldBuildInfoProgram*/ undefined);
return typeof result === "object" ? result.impliedNodeFormat : result;
}

Expand All @@ -1263,6 +1263,7 @@ export function getImpliedNodeFormatForFileWorker(
packageJsonInfoCache: PackageJsonInfoCache | undefined,
host: ModuleResolutionHost,
options: CompilerOptions,
oldBuildInfoProgram: OldBuildInfoProgram | undefined,
) {
switch (getEmitModuleResolutionKind(options)) {
case ModuleResolutionKind.Node16:
Expand All @@ -1279,9 +1280,16 @@ export function getImpliedNodeFormatForFileWorker(
const packageJsonLocations: string[] = [];
state.failedLookupLocations = packageJsonLocations;
state.affectingLocations = packageJsonLocations;
const packageJsonScope = getPackageScopeForPath(fileName, state);
const fromOld = oldBuildInfoProgram?.getPackageJsonPath(getDirectoryPath(fileName));
const packageJsonScope = fromOld ?
getPackageJsonInfo(getDirectoryPath(fromOld), /*onlyRecordFailures*/ false, state) :
getPackageScopeForPath(fileName, state);
const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS;
return { impliedNodeFormat, packageJsonLocations, packageJsonScope };
return {
impliedNodeFormat,
packageJsonLocations: packageJsonLocations.length ? packageJsonLocations : undefined,
packageJsonScope
};
}
}

Expand Down Expand Up @@ -2374,7 +2382,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (!newSourceFile) {
return StructureIsReused.Not;
}
newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations;
newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope;

Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
Expand Down Expand Up @@ -3452,7 +3460,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
redirect.resolvedPath = resolvedPath;
redirect.originalFileName = originalFileName;
redirect.redirectInfo = { redirectTarget, unredirected };
redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations;
redirect.packageJsonScope = sourceFileOptions.packageJsonScope;
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
Object.defineProperties(redirect, {
Expand Down Expand Up @@ -3484,7 +3492,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache
// and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way
// to the check and emit steps would be bad - so we much prefer detecting and storing the format information on the source file node upfront.
const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options);
const result = getImpliedNodeFormatForFileWorker(
getNormalizedAbsolutePath(fileName, currentDirectory),
moduleResolutionCache?.getPackageJsonInfoCache(),
host,
options,
oldBuildInfoProgram,
);
const languageVersion = getEmitScriptTarget(options);
const setExternalModuleIndicator = getSetExternalModuleIndicator(options);
return typeof result === "object" ?
Expand Down Expand Up @@ -3618,7 +3632,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
file.path = path;
file.resolvedPath = toPath(fileName);
file.originalFileName = originalFileName;
file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined;
file.packageJsonLocations = sourceFileOptions.packageJsonLocations;
file.packageJsonScope = sourceFileOptions.packageJsonScope;
addFileIncludeReason(file, reason);

Expand Down
44 changes: 32 additions & 12 deletions src/compiler/resolutionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
isRootedDiskPath,
isString,
isTraceEnabled,
last,
loadModuleFromGlobalCache,
memoize,
MinimalResolutionCacheHost,
Expand Down Expand Up @@ -467,18 +468,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
getResolvedTypeReferenceDirective,
);
}
const expected = isExternalOrCommonJsModule(newFile) ? newFile.packageJsonLocations?.length ?? 0 : 0;
const existing = impliedFormatPackageJsons.get(newFile.path) ?? emptyArray;
for (let i = existing.length; i < expected; i++) {
createFileWatcherOfAffectingLocation(newFile.packageJsonLocations![i], /*forResolution*/ false);
}
if (existing.length > expected) {
for (let i = expected; i < existing.length; i++) {
fileWatchesOfAffectingLocations.get(existing[i])!.files--;
}
}
if (expected) impliedFormatPackageJsons.set(newFile.path, newFile.packageJsonLocations!);
else impliedFormatPackageJsons.delete(newFile.path);
ensurePackageJsonWatchesForFile(newProgram, newFile);
}
if (needsResolutionUpdate) {
const newProgramAutoTypeRefContainingFile = resolutionHost.toPath(newProgram.getAutomaticTypeDirectiveContainingFile());
Expand Down Expand Up @@ -521,6 +511,36 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
});
}

function ensurePackageJsonWatchesForFile(newProgram: Program, newFile: SourceFile) {
const options = newProgram.getCompilerOptions();
const existing = impliedFormatPackageJsons.get(newFile.path) ?? emptyArray;
let expected = isExternalOrCommonJsModule(newFile) ? newFile.packageJsonLocations ?? emptyArray : emptyArray;
if (!options.cacheResolutions) {
for (let i = existing.length; i < expected.length; i++) {
createFileWatcherOfAffectingLocation(expected[i], /*forResolution*/ false);
}
if (existing.length > expected.length) {
for (let i = expected.length; i < existing.length; i++) {
fileWatchesOfAffectingLocations.get(existing[i])!.files--;
}
}
}
else {
// Do not watch failed lookups for source file's package.json when caching resolutions
expected = expected.length && newFile.packageJsonScope ? [last(expected)] : expected;
if (expected.length !== 1 || existing.length !== 1 || expected[0] !== existing[0]) {
for (const location of expected) {
createFileWatcherOfAffectingLocation(location, /*forResolution*/ false);
}
for (const location of existing) {
fileWatchesOfAffectingLocations.get(location)!.files--;
}
}
}
if (expected.length) impliedFormatPackageJsons.set(newFile.path, expected);
else impliedFormatPackageJsons.delete(newFile.path);
}

function ensureResolutionsOfFile<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
newProgram: Program,
perDirCache: PerDirectoryAndNonRelativeNameCache<T> | undefined,
Expand Down
8 changes: 6 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Pattern,
ProgramBuildInfo,
Push,
SourceFilePackageJsonInfo,
SymlinkCache,
TypeReferenceDirectiveResolutionCache,
} from "./_namespaces/ts";
Expand Down Expand Up @@ -4062,8 +4063,6 @@ export interface SourceFile extends Declaration {
* CommonJS-output-format by the node module transformer and type checker, regardless of extension or context.
*/
impliedNodeFormat?: ResolutionMode;
/** @internal */ packageJsonLocations?: readonly string[];
/** @internal */ packageJsonScope?: PackageJsonInfo;

/** @internal */ scriptKind: ScriptKind;

Expand Down Expand Up @@ -4135,6 +4134,10 @@ export interface SourceFile extends Declaration {
/** @internal */ endFlowNode?: FlowNode;
}

/** @internal */
export interface SourceFile extends SourceFilePackageJsonInfo {
}

/** @internal */
export interface CommentDirective {
range: TextRange;
Expand Down Expand Up @@ -6979,6 +6982,7 @@ export interface OldBuildInfoProgram {
getCompilerOptions(): CompilerOptions;
getResolvedModule(name: string, mode: ResolutionMode, dirPath: Path, redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations | undefined;
getResolvedTypeReferenceDirective(name: string, mode: ResolutionMode, dirPath: Path, redirectedReference: ResolvedProjectReference | undefined): ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined;
getPackageJsonPath(dir: string): string | undefined;
}

/** @internal */
Expand Down
Loading

0 comments on commit df70939

Please sign in to comment.