Skip to content

Commit 42d1004

Browse files
committed
Create Types for ProgramFromBuildInfo
1 parent c670444 commit 42d1004

File tree

6 files changed

+147
-42
lines changed

6 files changed

+147
-42
lines changed

src/compiler/builder.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ namespace ts {
261261
return state;
262262
}
263263

264-
function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: Program, getCanonicalFileName: GetCanonicalFileName): readonly Diagnostic[] {
264+
export type ConvertToDiagnosticsProgram = Pick<Program, "getCompilerOptions" | "getCurrentDirectory" | "getSourceFileByPath">;
265+
export function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: ConvertToDiagnosticsProgram, getCanonicalFileName: GetCanonicalFileName): readonly Diagnostic[] {
265266
if (!diagnostics.length) return emptyArray;
266267
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(newProgram.getCompilerOptions())!, newProgram.getCurrentDirectory()));
267268
return diagnostics.map(diagnostic => {
@@ -284,7 +285,7 @@ namespace ts {
284285
}
285286
}
286287

287-
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
288+
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: ConvertToDiagnosticsProgram, toPath: (path: string) => Path): DiagnosticRelatedInformation {
288289
const { file } = diagnostic;
289290
return {
290291
...diagnostic,

src/compiler/core.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,9 @@ namespace ts {
848848
return true;
849849
}
850850

851-
export function arrayIsEqualTo<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
851+
export function arrayIsEqualTo<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer?: (a: T, b: T, index: number) => boolean): boolean;
852+
export function arrayIsEqualTo<T, U>(array1: readonly T[] | undefined, array2: readonly U[] | undefined, equalityComparer: (a: T, b: U, index: number) => boolean): boolean;
853+
export function arrayIsEqualTo<T, U = T>(array1: readonly T[] | undefined, array2: readonly U[] | undefined, equalityComparer: (a: T, b: U, index: number) => boolean = equateValues as any): boolean {
852854
if (!array1 || !array2) {
853855
return array1 === array2;
854856
}

src/compiler/program.ts

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -661,10 +661,14 @@ namespace ts {
661661
configFileParseResult.errors;
662662
}
663663

664+
function isProgramFromBuildInfo(program: Program | ProgramFromBuildInfo): program is ProgramFromBuildInfo {
665+
return !!(program as ProgramFromBuildInfo).programFromBuildInfo;
666+
}
667+
664668
/**
665669
* Determine if source file needs to be re-created even if its text hasn't changed
666670
*/
667-
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions): boolean {
671+
function shouldProgramCreateNewSourceFiles(program: Program | ProgramFromBuildInfo | undefined, newOptions: CompilerOptions): boolean {
668672
if (!program) return false;
669673
// If any compiler options change, we can't reuse old source file even if version match
670674
// The change in options like these could result in change in syntax tree or `sourceFile.bindDiagnostics`.
@@ -692,6 +696,8 @@ namespace ts {
692696
* @returns A 'Program' object.
693697
*/
694698
export function createProgram(createProgramOptions: CreateProgramOptions): Program;
699+
/*@internal*/
700+
export function createProgram(createProgramOptions: CreateProgramOptionsWithProgramFromBuildInfo): Program; // eslint-disable-line @typescript-eslint/unified-signatures
695701
/**
696702
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
697703
* that represent a compilation unit.
@@ -707,7 +713,7 @@ namespace ts {
707713
* @returns A 'Program' object.
708714
*/
709715
export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program;
710-
export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program {
716+
export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions | CreateProgramOptionsWithProgramFromBuildInfo, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program {
711717
const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217
712718
const { rootNames, options, configFileParsingDiagnostics, projectReferences } = createProgramOptions;
713719
let { oldProgram } = createProgramOptions;
@@ -812,7 +818,7 @@ namespace ts {
812818
// Map from a stringified PackageId to the source file with that id.
813819
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
814820
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
815-
const packageIdToSourceFile = new Map<string, SourceFile>();
821+
let packageIdToSourceFile = new Map<string, SourceFile>();
816822
// Maps from a SourceFile's `.path` to the name of the package it was imported with.
817823
let sourceFileToPackageName = new Map<string, string>();
818824
// Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it.
@@ -824,11 +830,11 @@ namespace ts {
824830
* - false if sourceFile missing for source of project reference redirect
825831
* - undefined otherwise
826832
*/
827-
const filesByName = new Map<string, SourceFile | false | 0>();
833+
const filesByName = new Map<Path, SourceFile | false | 0>();
828834
let missingFilePaths: readonly Path[] | undefined;
829835
// stores 'filename -> file association' ignoring case
830836
// used to track cases when two file names differ only in casing
831-
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? new Map<string, SourceFile>() : undefined;
837+
let filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? new Map<string, SourceFile>() : undefined;
832838

833839
// A parallel array to projectReferences storing the results of reading in the referenced tsconfig files
834840
let resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined;
@@ -921,17 +927,19 @@ namespace ts {
921927
}
922928
}
923929

924-
missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === 0 ? path as Path : undefined));
930+
missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === 0 ? path : undefined));
925931
files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
926932
processingDefaultLibFiles = undefined;
927933
processingOtherFiles = undefined;
934+
packageIdToSourceFile = undefined!;
935+
filesByNameIgnoreCase = undefined!;
928936
}
929937

930938
Debug.assert(!!missingFilePaths);
931939

932940
// Release any files we have acquired in the old program but are
933941
// not part of the new program.
934-
if (oldProgram && host.onReleaseOldSourceFile) {
942+
if (oldProgram && !isProgramFromBuildInfo(oldProgram) && host.onReleaseOldSourceFile) {
935943
const oldSourceFiles = oldProgram.getSourceFiles();
936944
for (const oldSourceFile of oldSourceFiles) {
937945
const newFile = getSourceFileByPath(oldSourceFile.resolvedPath);
@@ -987,6 +995,7 @@ namespace ts {
987995
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
988996
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
989997
isSourceFileFromExternalLibrary,
998+
isSourceFileFromExternalLibraryPath,
990999
isSourceFileDefaultLibrary,
9911000
dropDiagnosticsProducingTypeChecker,
9921001
getSourceFileFromReference,
@@ -1283,13 +1292,13 @@ namespace ts {
12831292
}
12841293

12851294
function canReuseProjectReferences(): boolean {
1286-
let seenResolvedRefs: ResolvedProjectReference[] | undefined;
1295+
let seenResolvedRefs: ResolvedProjectReferenceOfProgramFromBuildInfo[] | undefined;
12871296
return !hasChangedReferences(oldProgram!.getProjectReferences(), oldProgram!.getResolvedProjectReferences(), /*parent*/ undefined);
12881297

12891298
function hasChangedReferences(
12901299
oldProjectReferences: readonly ProjectReference[] | undefined,
1291-
oldResolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
1292-
parent: ResolvedProjectReference | undefined,
1300+
oldResolvedProjectReferences: readonly (ResolvedProjectReferenceOfProgramFromBuildInfo | undefined)[] | undefined,
1301+
parent: ResolvedProjectReferenceOfProgramFromBuildInfo | undefined,
12931302
): boolean | undefined {
12941303

12951304
// Visit project references first
@@ -1310,13 +1319,13 @@ namespace ts {
13101319
}
13111320
}
13121321

1313-
function hasChangedProjectReferences(oldProjectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) {
1322+
function hasChangedProjectReferences(oldProjectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReferenceOfProgramFromBuildInfo | undefined) {
13141323
// If array of references is changed, we cant resue old program
13151324
const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences;
13161325
return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo);
13171326
}
13181327

1319-
function hasChangedResolvedProjectReferences(oldResolvedRef: ResolvedProjectReference | undefined, index: number, parent: ResolvedProjectReference | undefined) {
1328+
function hasChangedResolvedProjectReferences(oldResolvedRef: ResolvedProjectReferenceOfProgramFromBuildInfo | undefined, index: number, parent: ResolvedProjectReferenceOfProgramFromBuildInfo | undefined) {
13201329
const newRef = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
13211330
const newResolvedRef = parseProjectReferenceConfigFile(newRef);
13221331
if (oldResolvedRef) {
@@ -1395,7 +1404,7 @@ namespace ts {
13951404
return StructureIsReused.Not;
13961405
}
13971406
// redirect target should already be present
1398-
Debug.checkDefined(find(newSourceFiles, f => f.path === oldSourceFile.redirectInfo?.redirectTarget.path));
1407+
Debug.checkDefined(find(newSourceFiles, f => f.path === oldSourceFile.redirectInfo!.redirectTarget.path));
13991408
// Add to the newSourceFiles for now and handle redirect if program is used completely
14001409
newSourceFiles.push(newSourceFile);
14011410
continue;
@@ -1544,8 +1553,8 @@ namespace ts {
15441553
const oldSourceFile = oldProgram!.getSourceFiles()[index];
15451554
if (oldSourceFile.redirectInfo) {
15461555
const newRedirectTarget = filesByName.get(oldSourceFile.redirectInfo.redirectTarget.path) as SourceFile;
1547-
newSourceFile = newRedirectTarget === oldSourceFile.redirectInfo.redirectTarget ?
1548-
oldSourceFile :
1556+
newSourceFile = !isProgramFromBuildInfo(oldProgram!) && newRedirectTarget === oldSourceFile.redirectInfo.redirectTarget ?
1557+
oldSourceFile as SourceFile :
15491558
// Create new redirect file
15501559
createRedirectSourceFile(newRedirectTarget, newSourceFile, oldSourceFile.fileName, oldSourceFile.path, oldSourceFile.resolvedPath, oldSourceFile.originalFileName);
15511560
newSourceFiles[index] = newSourceFile;
@@ -1555,27 +1564,43 @@ namespace ts {
15551564
filesByName.set(newSourceFile.path, newSourceFile);
15561565
}
15571566
});
1558-
const oldFilesByNameMap = oldProgram.getFilesByNameMap();
1567+
const oldFilesByNameMap = oldProgram.getFilesByNameMap() as ESMap<Path, SourceFile | Path | false | 0>;
15591568
oldFilesByNameMap.forEach((oldFile, path) => {
15601569
if (!oldFile) {
1561-
filesByName.set(path, oldFile);
1570+
filesByName.set(path, oldFile as false | 0);
15621571
return;
15631572
}
1564-
if (oldFile.path === path) {
1573+
const oldPath = !isString(oldFile) ? oldFile.path : oldFile;
1574+
if (oldPath === path) {
15651575
// Set the file as found during node modules search if it was found that way in old progra,
1566-
if (oldProgram!.isSourceFileFromExternalLibrary(oldFile)) {
1567-
sourceFilesFoundSearchingNodeModules.set(oldFile.path, true);
1576+
if (oldProgram!.isSourceFileFromExternalLibraryPath(oldPath)) {
1577+
sourceFilesFoundSearchingNodeModules.set(oldPath, true);
15681578
}
15691579
return;
15701580
}
1571-
filesByName.set(path, filesByName.get(oldFile.path)!);
1581+
filesByName.set(path, filesByName.get(oldPath)!);
15721582
});
15731583

15741584
files = newSourceFiles;
1575-
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
15761585

1577-
for (const modifiedFile of modifiedSourceFiles || emptyArray) {
1578-
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile);
1586+
if (!isProgramFromBuildInfo(oldProgram)) {
1587+
fileProcessingDiagnostics = oldProgram.getFileProcessingDiagnostics();
1588+
for (const modifiedFile of modifiedSourceFiles || emptyArray) {
1589+
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile);
1590+
}
1591+
}
1592+
else {
1593+
convertToDiagnostics(
1594+
oldProgram.getFileProcessingDiagnostics(),
1595+
{
1596+
getCurrentDirectory: () => currentDirectory,
1597+
getCompilerOptions: () => options,
1598+
getSourceFileByPath
1599+
},
1600+
getCanonicalFileName
1601+
).forEach(
1602+
d => fileProcessingDiagnostics.add(d)
1603+
);
15791604
}
15801605
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
15811606
perFileModuleResolutions = oldProgram.getPerFileModuleResolutions();
@@ -1665,7 +1690,11 @@ namespace ts {
16651690
}
16661691

16671692
function isSourceFileFromExternalLibrary(file: SourceFile): boolean {
1668-
return !!sourceFilesFoundSearchingNodeModules.get(file.path);
1693+
return isSourceFileFromExternalLibraryPath(file.path);
1694+
}
1695+
1696+
function isSourceFileFromExternalLibraryPath(file: Path): boolean {
1697+
return !!sourceFilesFoundSearchingNodeModules.get(file);
16691698
}
16701699

16711700
function isSourceFileDefaultLibrary(file: SourceFile): boolean {
@@ -2215,14 +2244,14 @@ namespace ts {
22152244
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined);
22162245
}
22172246

2218-
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
2219-
return a.fileName === b.fileName;
2247+
function fileReferenceIsEqualTo(oldReference: FileReference | string, newReference: FileReference): boolean {
2248+
return (!isString(oldReference) ? oldReference.fileName : oldReference) === newReference.fileName;
22202249
}
22212250

2222-
function moduleNameIsEqualTo(a: StringLiteralLike | Identifier, b: StringLiteralLike | Identifier): boolean {
2223-
return a.kind === SyntaxKind.Identifier
2224-
? b.kind === SyntaxKind.Identifier && a.escapedText === b.escapedText
2225-
: b.kind === SyntaxKind.StringLiteral && a.text === b.text;
2251+
function moduleNameIsEqualTo(oldName: StringLiteralLike | Identifier | ModuleNameOfProgramFromBuildInfo, newName: StringLiteralLike | Identifier): boolean {
2252+
return oldName.kind === SyntaxKind.Identifier
2253+
? newName.kind === SyntaxKind.Identifier && oldName.escapedText === newName.escapedText
2254+
: newName.kind === SyntaxKind.StringLiteral && oldName.text === newName.text;
22262255
}
22272256

22282257
function collectExternalModuleReferences(file: SourceFile): void {

0 commit comments

Comments
 (0)