Skip to content

Commit d05151a

Browse files
committed
Store program to persist in buildinfo and clean it as part of cleanResolutions
1 parent 3cc5959 commit d05151a

26 files changed

+14845
-1661
lines changed

src/compiler/builder.ts

+478-8
Large diffs are not rendered by default.

src/compiler/program.ts

+11-24
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,11 @@ namespace ts {
597597
}
598598

599599
/*@internal*/
600-
export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile {
600+
export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile;
601+
/*@internal*/
602+
export function isReferencedFile(reason: FileIncludeReason | PersistedProgramFileIncludeReason | undefined): reason is PersistedProgramReferencedFile;
603+
/*@internal*/
604+
export function isReferencedFile(reason: FileIncludeReason | PersistedProgramFileIncludeReason | undefined): reason is ReferencedFile | PersistedProgramReferencedFile {
601605
switch (reason?.kind) {
602606
case FileIncludeKind.Import:
603607
case FileIncludeKind.ReferenceFile:
@@ -832,7 +836,7 @@ namespace ts {
832836
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
833837

834838
let resolvedTypeReferenceDirectives = new Map<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>();
835-
let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
839+
let fileProcessingDiagnostics: FilePreprocessingDiagnostic[] | undefined;
836840

837841
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
838842
// This works as imported modules are discovered recursively in a depth first manner, specifically:
@@ -1677,7 +1681,7 @@ namespace ts {
16771681
newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames;
16781682
}
16791683
}
1680-
const oldFilesByNameMap = oldProgram.getFilesByNameMap() as ESMap<Path, SourceFile | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>;
1684+
const oldFilesByNameMap = oldProgram.getFilesByNameMap() as ESMap<Path, SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>;
16811685
oldFilesByNameMap.forEach((oldFile, path) => {
16821686
if (!oldFile) {
16831687
filesByName.set(path, oldFile as false | 0);
@@ -1696,25 +1700,7 @@ namespace ts {
16961700

16971701
files = newSourceFiles;
16981702
fileReasons = oldProgram.getFileIncludeReasons();
1699-
if (!isProgramFromBuildInfo(oldProgram)) {
1700-
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
1701-
}
1702-
else {
1703-
const reusableDiagnostics = oldProgram.getFileProcessingDiagnostics();
1704-
if (reusableDiagnostics) {
1705-
const toPath = getToPathForBuildInfoFilePath(options, currentDirectory, getCanonicalFileName);
1706-
fileProcessingDiagnostics = map(reusableDiagnostics, reusable => ({
1707-
...reusable,
1708-
diagnostic: Diagnostics[reusable.diagnostic],
1709-
file: (reusable as ReusableFilePreprocessingFileExplainingDiagnostic).file !== undefined ?
1710-
toPath((reusable as ReusableFilePreprocessingFileExplainingDiagnostic).file!) :
1711-
undefined
1712-
}));
1713-
}
1714-
else {
1715-
fileProcessingDiagnostics = undefined;
1716-
}
1717-
}
1703+
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
17181704
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
17191705

17201706
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
@@ -2882,7 +2868,8 @@ namespace ts {
28822868
function processTypeReferenceDirectives(file: SourceFile) {
28832869
// We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
28842870
const typeDirectives = map(file.typeReferenceDirectives, ref => toFileNameLowerCase(ref.fileName));
2885-
if (!typeDirectives) {
2871+
if (!typeDirectives?.length) {
2872+
file.resolvedTypeReferenceDirectiveNames = undefined;
28862873
return;
28872874
}
28882875

@@ -2902,7 +2889,7 @@ namespace ts {
29022889
resolved: ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
29032890
reason: FileIncludeReason
29042891
): void {
2905-
tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolveModuleNamesReusingOldState, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
2892+
tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolved.resolvedTypeReferenceDirective, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined });
29062893
processTypeReferenceDirectiveWorker(typeReferenceDirective, resolved, reason);
29072894
tracing?.pop();
29082895
}

src/compiler/resolutionCache.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace ts {
2727
clear(): void;
2828
}
2929

30-
interface ResolutionWithFailedLookupLocations {
30+
export interface ResolutionWithFailedLookupLocations {
3131
readonly failedLookupLocations: string[];
3232
isInvalidated?: boolean;
3333
refCount?: number;

src/compiler/types.ts

+13-13
Original file line numberDiff line numberDiff line change
@@ -3485,7 +3485,7 @@ namespace ts {
34853485
// It is used to resolve module names in the checker.
34863486
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
34873487
/* @internal */ resolvedModules?: ESMap<string, ResolvedModuleWithFailedLookupLocations>;
3488-
/* @internal */ resolvedTypeReferenceDirectiveNames: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
3488+
/* @internal */ resolvedTypeReferenceDirectiveNames?: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
34893489
/* @internal */ imports: readonly StringLiteralLike[];
34903490
// Identifier only if `declare global`
34913491
/* @internal */ moduleAugmentations: readonly (StringLiteral | Identifier)[];
@@ -3769,7 +3769,7 @@ namespace ts {
37693769
}
37703770

37713771
/*@internal*/
3772-
export type FilePreprocessingDiagnostics = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic;
3772+
export type FilePreprocessingDiagnostic = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic;
37733773

37743774
/*@internal*/
37753775
export const missingSourceOfProjectReferenceRedirect = false;
@@ -3847,7 +3847,7 @@ namespace ts {
38473847
getInstantiationCount(): number;
38483848
getRelationCacheSizes(): { assignable: number, identity: number, subtype: number, strictSubtype: number };
38493849

3850-
/* @internal */ getFileProcessingDiagnostics(): FilePreprocessingDiagnostics[] | undefined;
3850+
/* @internal */ getFileProcessingDiagnostics(): FilePreprocessingDiagnostic[] | undefined;
38513851
/* @internal */ getResolvedTypeReferenceDirectives(): ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
38523852
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
38533853
/* @internal */ isSourceFileFromExternalLibraryPath(path: Path): boolean;
@@ -3903,14 +3903,13 @@ namespace ts {
39033903
/*@internal*/
39043904
export interface IdentifierOfProgramFromBuildInfo {
39053905
kind: SyntaxKind.Identifier;
3906-
escapedText: string;
3906+
escapedText: __String;
39073907
}
39083908

39093909
/*@internal*/
39103910
export interface StringLiteralLikeOfProgramFromBuildInfo {
39113911
kind: SyntaxKind.StringLiteral | SyntaxKind.NoSubstitutionTemplateLiteral;
39123912
text: string;
3913-
escapedText: string;
39143913
}
39153914

39163915
/*@internal*/
@@ -3922,19 +3921,21 @@ namespace ts {
39223921
originalFileName: string;
39233922
path: Path;
39243923
resolvedPath: Path;
3924+
// This currently is set to sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags but cant be set in type
3925+
// Change this if it changes in reusing program
39253926
flags: NodeFlags;
39263927
version: string;
39273928

39283929
typeReferenceDirectives: readonly string[];
39293930
libReferenceDirectives: readonly string[];
39303931
referencedFiles: readonly string[];
39313932
imports: readonly StringLiteralLikeOfProgramFromBuildInfo[];
3932-
moduleAugmentations: ModuleNameOfProgramFromBuildInfo[];
3933+
moduleAugmentations: readonly ModuleNameOfProgramFromBuildInfo[];
39333934
ambientModuleNames: readonly string[];
39343935
hasNoDefaultLib: boolean;
39353936

39363937
resolvedModules?: ESMap<string, ResolvedModuleWithFailedLookupLocations>;
3937-
resolvedTypeReferenceDirectiveNames: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
3938+
resolvedTypeReferenceDirectiveNames?: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
39383939
redirectInfo?: RedirectInfoOfProgramFromBuildInfo;
39393940
}
39403941

@@ -3944,20 +3945,19 @@ namespace ts {
39443945

39453946
getCompilerOptions(): CompilerOptions;
39463947
getRootFileNames(): readonly string[];
3947-
getSourceFiles(): SourceFileOfProgramFromBuildInfo[];
3948+
getSourceFiles(): readonly SourceFileOfProgramFromBuildInfo[];
39483949
getSourceFileByPath(path: Path): SourceFileOfProgramFromBuildInfo | undefined;
39493950
getProjectReferences(): readonly ProjectReference[] | undefined;
3950-
getResolvedProjectReferences(): readonly ResolvedProjectReferenceOfProgramFromBuildInfo[] | undefined;
3951+
getResolvedProjectReferences(): readonly (ResolvedProjectReferenceOfProgramFromBuildInfo | undefined)[] | undefined;
39513952
getMissingFilePaths(): readonly Path[];
39523953
getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
39533954
getResolvedTypeReferenceDirectives(): ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
3954-
getFilesByNameMap(): ESMap<Path, Path | false | 0>;
3955+
getFilesByNameMap(): ESMap<Path, SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>;
39553956
isSourceFileFromExternalLibraryPath(path: Path): boolean;
3956-
getFileProcessingDiagnostics(): readonly ReusableFilePreprocessingDiagnostics[] | undefined;
3957+
getFileProcessingDiagnostics(): FilePreprocessingDiagnostic[] | undefined;
39573958

39583959
redirectTargetsMap: MultiMap<Path, string>;
39593960
sourceFileToPackageName: ESMap<Path, string>;
3960-
structureIsReused?: StructureIsReused;
39613961
}
39623962

39633963
/*@internal*/
@@ -3978,7 +3978,7 @@ namespace ts {
39783978
}
39793979

39803980
/*@internal*/
3981-
export type ReusableFilePreprocessingDiagnostics = ReusableFilePreprocessingReferencedDiagnostic | ReusableFilePreprocessingFileExplainingDiagnostic;
3981+
export type ReusableFilePreprocessingDiagnostic = ReusableFilePreprocessingReferencedDiagnostic | ReusableFilePreprocessingFileExplainingDiagnostic;
39823982

39833983
/* @internal */
39843984
export type RedirectTargetsMap = ReadonlyESMap<Path, readonly string[]>;

src/compiler/watchPublic.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ namespace ts {
2828
if (!content) return emitSkippedWithNoDiagnostics;
2929
const buildInfo = getBuildInfo(content);
3030
if (buildInfo.version !== version) return emitSkippedWithNoDiagnostics;
31-
if (!buildInfo.program) return emitSkippedWithNoDiagnostics;
32-
// TODO:: Clean the actual program
33-
let newContent = content;
31+
if (!buildInfo.program?.peristedProgram) return emitSkippedWithNoDiagnostics;
32+
const { program: { peristedProgram, ...program } } = buildInfo;
33+
buildInfo.program = program;
3434

3535
// Actual writeFile with new program
3636
const emitDiagnostics = createDiagnosticCollection();
37-
writeFile(host, emitDiagnostics, buildInfoPath, newContent, /*writeByteOrderMark*/ false);
37+
writeFile(host, emitDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false);
3838
return {
3939
emitSkipped: false,
4040
diagnostics: emitDiagnostics.getDiagnostics(),

src/services/services.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ namespace ts {
639639
public identifiers!: ESMap<string, string>;
640640
public nameTable: UnderscoreEscapedMap<number> | undefined;
641641
public resolvedModules: ESMap<string, ResolvedModuleWithFailedLookupLocations> | undefined;
642-
public resolvedTypeReferenceDirectiveNames!: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
642+
public resolvedTypeReferenceDirectiveNames: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations> | undefined;
643643
public imports!: readonly StringLiteralLike[];
644644
public moduleAugmentations!: StringLiteral[];
645645
private namedDeclarations: ESMap<string, Declaration[]> | undefined;

src/testRunner/unittests/tsbuild/persistResolutions.ts

+36
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,35 @@ namespace ts {
4646
subScenario: "Write file that could not be resolved",
4747
buildKind: BuildKind.IncrementalDtsChange,
4848
modifyFs: fs => fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "export function something2() { return 20; }"),
49+
// when doing clean build, fileNotFound.ts would be resolved so the output order in outFile.js would change
50+
// In build mode the out is generated only when there are no errors
51+
// Outputs are generated, buildinfo is updated to report no errors
52+
cleanBuildDiscrepancies: () => new Map([
53+
[`/src/project/src/filePresent.js`, CleanBuildDescrepancy.CleanFilePresent],
54+
[`/src/project/src/filePresent.d.ts`, CleanBuildDescrepancy.CleanFilePresent],
55+
[`/src/project/src/fileNotFound.js`, CleanBuildDescrepancy.CleanFilePresent],
56+
[`/src/project/src/fileNotFound.d.ts`, CleanBuildDescrepancy.CleanFilePresent],
57+
[`/src/project/src/anotherFileReusingResolution.js`, CleanBuildDescrepancy.CleanFilePresent],
58+
[`/src/project/src/anotherFileReusingResolution.d.ts`, CleanBuildDescrepancy.CleanFilePresent],
59+
[`/src/project/src/main.js`, CleanBuildDescrepancy.CleanFilePresent],
60+
[`/src/project/src/main.d.ts`, CleanBuildDescrepancy.CleanFilePresent],
61+
[`/src/project/src/newFile.js`, CleanBuildDescrepancy.CleanFilePresent],
62+
[`/src/project/src/newFile.d.ts`, CleanBuildDescrepancy.CleanFilePresent],
63+
[`/src/project/tsconfig.tsbuildinfo`, CleanBuildDescrepancy.CleanFileTextDifferent],
64+
]),
4965
},
5066
{
5167
subScenario: "Clean resolutions",
5268
buildKind: BuildKind.IncrementalDtsChange,
5369
modifyFs: noop,
5470
commandLineArgs: ["--b", "src/project", "--cleanPersistedProgram"]
5571
},
72+
{
73+
subScenario: "Clean resolutions again",
74+
buildKind: BuildKind.IncrementalDtsChange,
75+
modifyFs: noop,
76+
commandLineArgs: ["--b", "src/project", "--cleanPersistedProgram"]
77+
},
5678
noChangeRun,
5779
{
5880
subScenario: "Modify main file",
@@ -87,13 +109,27 @@ namespace ts {
87109
subScenario: "Write file that could not be resolved",
88110
buildKind: BuildKind.IncrementalDtsChange,
89111
modifyFs: fs => fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "export function something2() { return 20; }"),
112+
// when doing clean build, fileNotFound.ts would be resolved so the output order in outFile.js would change
113+
// In build mode the out is generated only when there are no errors
114+
cleanBuildDiscrepancies: () => new Map([
115+
["/src/project/outFile.tsbuildinfo", CleanBuildDescrepancy.CleanFileTextDifferent],
116+
["/src/project/outFile.js", CleanBuildDescrepancy.CleanFilePresent],
117+
["/src/project/outFile.d.ts", CleanBuildDescrepancy.CleanFilePresent],
118+
["/src/project/outFile.tsbuildinfo.baseline.txt", CleanBuildDescrepancy.CleanFilePresent],
119+
]),
90120
},
91121
{
92122
subScenario: "Clean resolutions",
93123
buildKind: BuildKind.IncrementalDtsChange,
94124
modifyFs: noop,
95125
commandLineArgs: ["--b", "src/project", "--cleanPersistedProgram"]
96126
},
127+
{
128+
subScenario: "Clean resolutions again",
129+
buildKind: BuildKind.IncrementalDtsChange,
130+
modifyFs: noop,
131+
commandLineArgs: ["--b", "src/project", "--cleanPersistedProgram"]
132+
},
97133
noChangeRun,
98134
{
99135
subScenario: "Modify main file",

src/testRunner/unittests/tsbuild/sample.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -516,13 +516,19 @@ class someClass2 { }`),
516516
subScenario: "persistResolutions",
517517
baselinePrograms: true,
518518
fs: () => projFs,
519-
modifyFs: fs => fs.writeFileSync("/src/core/tsconfig.json", JSON.stringify({
520-
compilerOptions: {
521-
composite: true,
522-
skipDefaultLibCheck: true,
523-
persistResolutions: true,
519+
modifyFs: fs => {
520+
persistResolutions("/src/core/tsconfig.json");
521+
persistResolutions("/src/logic/tsconfig.json");
522+
persistResolutions("/src/tests/tsconfig.json");
523+
function persistResolutions(file: string) {
524+
const content = JSON.parse(fs.readFileSync(file, "utf-8"));
525+
content.compilerOptions = {
526+
...content.compilerOptions || {},
527+
persistResolutions: true
528+
};
529+
fs.writeFileSync(file, JSON.stringify(content, /*replacer*/ undefined, 4));
524530
}
525-
})),
531+
},
526532
commandLineArgs: ["--b", "/src/tests"],
527533
incrementalScenarios: [
528534
...coreChanges,

0 commit comments

Comments
 (0)