Some refactoring so we arent checking undefined on program or asserting it so much (#58782)

This commit is contained in:
Sheetal Nandi
2024-06-05 16:42:36 -07:00
committed by GitHub
parent f5238c328e
commit b9d96df61f
7 changed files with 352 additions and 144 deletions
+231 -104
View File
@@ -252,6 +252,17 @@ export interface BuilderProgramState extends BuilderState, ReusableBuilderProgra
seenProgramEmit: BuilderFileEmit | undefined;
}
interface BuilderProgramStateWithDefinedProgram extends BuilderProgramState {
program: Program;
}
function isBuilderProgramStateWithDefinedProgram(state: ReusableBuilderProgramState): state is BuilderProgramStateWithDefinedProgram {
return state.program !== undefined;
}
function toBuilderProgramStateWithDefinedProgram(state: ReusableBuilderProgramState): BuilderProgramStateWithDefinedProgram {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
return state;
}
/** @internal */
export type SavedBuildProgramEmitState =
& Pick<
@@ -289,7 +300,10 @@ export function getBuilderFileEmit(options: CompilerOptions) {
*
* @internal
*/
export function getPendingEmitKind(optionsOrEmitKind: CompilerOptions | BuilderFileEmit, oldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined): BuilderFileEmit {
export function getPendingEmitKind(
optionsOrEmitKind: CompilerOptions | BuilderFileEmit,
oldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined,
): BuilderFileEmit {
const oldEmitKind = oldOptionsOrEmitKind && (isNumber(oldOptionsOrEmitKind) ? oldOptionsOrEmitKind : getBuilderFileEmit(oldOptionsOrEmitKind));
const emitKind = isNumber(optionsOrEmitKind) ? optionsOrEmitKind : getBuilderFileEmit(optionsOrEmitKind);
if (oldEmitKind === emitKind) return BuilderFileEmit.None;
@@ -303,7 +317,10 @@ export function getPendingEmitKind(optionsOrEmitKind: CompilerOptions | BuilderF
return result;
}
function hasSameKeys(map1: ReadonlyCollection<string> | undefined, map2: ReadonlyCollection<string> | undefined): boolean {
function hasSameKeys(
map1: ReadonlyCollection<string> | undefined,
map2: ReadonlyCollection<string> | undefined,
): boolean {
// Has same size and every key is present in both maps
return map1 === map2 || map1 !== undefined && map2 !== undefined && map1.size === map2.size && !forEachKey(map1, key => !map2.has(key));
}
@@ -311,7 +328,10 @@ function hasSameKeys(map1: ReadonlyCollection<string> | undefined, map2: Readonl
/**
* Create the state so that we can iterate on changedFiles/affected files
*/
function createBuilderProgramState(newProgram: Program, oldState: Readonly<ReusableBuilderProgramState> | undefined): BuilderProgramState {
function createBuilderProgramState(
newProgram: Program,
oldState: Readonly<ReusableBuilderProgramState> | undefined,
): BuilderProgramState {
const state = BuilderState.create(newProgram, oldState, /*disableUseFileVersionAsSignature*/ false) as BuilderProgramState;
state.program = newProgram;
const compilerOptions = newProgram.getCompilerOptions();
@@ -489,7 +509,11 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
* Covert to Emit signature based on oldOptions and EmitSignature format
* If d.ts map options differ then swap the format, otherwise use as is
*/
function getEmitSignatureFromOldSignature(options: CompilerOptions, oldOptions: CompilerOptions, oldEmitSignature: EmitSignature): EmitSignature {
function getEmitSignatureFromOldSignature(
options: CompilerOptions,
oldOptions: CompilerOptions,
oldEmitSignature: EmitSignature,
): EmitSignature {
return !!options.declarationMap === !!oldOptions.declarationMap ?
// Use same format of signature
oldEmitSignature :
@@ -497,7 +521,10 @@ function getEmitSignatureFromOldSignature(options: CompilerOptions, oldOptions:
isString(oldEmitSignature) ? [oldEmitSignature] : oldEmitSignature[0];
}
function repopulateDiagnostics(diagnostics: readonly Diagnostic[], newProgram: Program): readonly Diagnostic[] {
function repopulateDiagnostics(
diagnostics: readonly Diagnostic[],
newProgram: Program,
): readonly Diagnostic[] {
if (!diagnostics.length) return diagnostics;
return sameMap(diagnostics, diag => {
if (isString(diag.messageText)) return diag;
@@ -534,7 +561,11 @@ function convertOrRepopulateDiagnosticMessageChainArray<T extends DiagnosticMess
return sameMap(array, chain => convertOrRepopulateDiagnosticMessageChain(chain, sourceFile, newProgram, repopulateInfo));
}
function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], diagnosticFilePath: Path, newProgram: Program): readonly Diagnostic[] {
function convertToDiagnostics(
diagnostics: readonly ReusableDiagnostic[],
diagnosticFilePath: Path,
newProgram: Program,
): readonly Diagnostic[] {
if (!diagnostics.length) return emptyArray;
let buildInfoDirectory: string | undefined;
return diagnostics.map(diagnostic => {
@@ -558,7 +589,12 @@ function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], diagno
}
}
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, diagnosticFilePath: Path, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
function convertToDiagnosticRelatedInformation(
diagnostic: ReusableDiagnosticRelatedInformation,
diagnosticFilePath: Path,
newProgram: Program,
toPath: (path: string) => Path,
): DiagnosticRelatedInformation {
const { file } = diagnostic;
const sourceFile = file !== false ?
newProgram.getSourceFileByPath(file ? toPath(file) : diagnosticFilePath) :
@@ -580,7 +616,9 @@ function releaseCache(state: BuilderProgramState) {
state.program = undefined;
}
function backupBuilderProgramEmitState(state: Readonly<BuilderProgramState>): SavedBuildProgramEmitState {
function backupBuilderProgramEmitState(
state: Readonly<BuilderProgramState>,
): SavedBuildProgramEmitState {
const outFilePath = state.compilerOptions.outFile;
// Only in --out changeFileSet is kept around till emit
Debug.assert(!state.changedFilesSet.size || outFilePath);
@@ -599,7 +637,10 @@ function backupBuilderProgramEmitState(state: Readonly<BuilderProgramState>): Sa
};
}
function restoreBuilderProgramEmitState(state: BuilderProgramState, savedEmitState: SavedBuildProgramEmitState) {
function restoreBuilderProgramEmitState(
state: BuilderProgramState,
savedEmitState: SavedBuildProgramEmitState,
) {
state.affectedFilesPendingEmit = savedEmitState.affectedFilesPendingEmit;
state.seenEmittedFiles = savedEmitState.seenEmittedFiles;
state.seenProgramEmit = savedEmitState.seenProgramEmit;
@@ -631,7 +672,7 @@ function assertSourceFileOkWithoutNextAffectedCall(state: BuilderProgramState, s
* eg. if during diagnostics check cancellation token ends up cancelling the request, the affected file should be retained
*/
function getNextAffectedFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
cancellationToken: CancellationToken | undefined,
host: BuilderProgramHost,
): SourceFile | Program | undefined {
@@ -645,7 +686,11 @@ function getNextAffectedFile(
if (!seenAffectedFiles.has(affectedFile.resolvedPath)) {
// Set the next affected file as seen and remove the cached semantic diagnostics
state.affectedFilesIndex = affectedFilesIndex;
addToAffectedFilesPendingEmit(state, affectedFile.resolvedPath, getBuilderFileEmit(state.compilerOptions));
addToAffectedFilesPendingEmit(
state,
affectedFile.resolvedPath,
getBuilderFileEmit(state.compilerOptions),
);
handleDtsMayChangeOfAffectedFile(
state,
affectedFile,
@@ -674,14 +719,13 @@ function getNextAffectedFile(
// With --out or --outFile all outputs go into single file
// so operations are performed directly on program, return program
const program = Debug.checkDefined(state.program);
const compilerOptions = program.getCompilerOptions();
if (compilerOptions.outFile) return program;
const compilerOptions = state.program.getCompilerOptions();
if (compilerOptions.outFile) return state.program;
// Get next batch of affected files
state.affectedFiles = BuilderState.getFilesAffectedByWithOldState(
state,
program,
state.program,
nextKey.value,
cancellationToken,
host,
@@ -715,11 +759,14 @@ function clearAffectedFilesPendingEmit(state: BuilderProgramState, emitOnlyDtsFi
/**
* Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
*/
function getNextAffectedFilePendingEmit(state: BuilderProgramState, emitOnlyDtsFiles: boolean | undefined) {
function getNextAffectedFilePendingEmit(
state: BuilderProgramStateWithDefinedProgram,
emitOnlyDtsFiles: boolean | undefined,
) {
if (!state.affectedFilesPendingEmit?.size) return undefined;
return forEachEntry(state.affectedFilesPendingEmit, (emitKind, path) => {
const affectedFile = state.program!.getSourceFileByPath(path);
if (!affectedFile || !sourceFileMayBeEmitted(affectedFile, state.program!)) {
const affectedFile = state.program.getSourceFileByPath(path);
if (!affectedFile || !sourceFileMayBeEmitted(affectedFile, state.program)) {
state.affectedFilesPendingEmit!.delete(path);
return undefined;
}
@@ -730,11 +777,11 @@ function getNextAffectedFilePendingEmit(state: BuilderProgramState, emitOnlyDtsF
});
}
function getNextPendingEmitDiagnosticsFile(state: BuilderProgramState) {
function getNextPendingEmitDiagnosticsFile(state: BuilderProgramStateWithDefinedProgram) {
if (!state.emitDiagnosticsPerFile?.size) return undefined;
return forEachEntry(state.emitDiagnosticsPerFile, (diagnostics, path) => {
const affectedFile = state.program!.getSourceFileByPath(path);
if (!affectedFile || !sourceFileMayBeEmitted(affectedFile, state.program!)) {
const affectedFile = state.program.getSourceFileByPath(path);
if (!affectedFile || !sourceFileMayBeEmitted(affectedFile, state.program)) {
state.emitDiagnosticsPerFile!.delete(path);
return undefined;
}
@@ -743,14 +790,13 @@ function getNextPendingEmitDiagnosticsFile(state: BuilderProgramState) {
});
}
function removeDiagnosticsOfLibraryFiles(state: BuilderProgramState) {
function removeDiagnosticsOfLibraryFiles(state: BuilderProgramStateWithDefinedProgram) {
if (!state.cleanedDiagnosticsOfLibFiles) {
state.cleanedDiagnosticsOfLibFiles = true;
const program = Debug.checkDefined(state.program);
const options = program.getCompilerOptions();
forEach(program.getSourceFiles(), f =>
program.isSourceFileDefaultLibrary(f) &&
!skipTypeChecking(f, options, program) &&
const options = state.program.getCompilerOptions();
forEach(state.program.getSourceFiles(), f =>
state.program.isSourceFileDefaultLibrary(f) &&
!skipTypeChecking(f, options, state.program) &&
removeSemanticDiagnosticsOf(state, f.resolvedPath));
}
}
@@ -760,7 +806,7 @@ function removeDiagnosticsOfLibraryFiles(state: BuilderProgramState) {
* This is because even though js emit doesnt change, dts emit / type used can change resulting in need for dts emit and js change
*/
function handleDtsMayChangeOfAffectedFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
affectedFile: SourceFile,
cancellationToken: CancellationToken | undefined,
host: BuilderProgramHost,
@@ -775,7 +821,7 @@ function handleDtsMayChangeOfAffectedFile(
// To avoid this, ensure that we update the signature for any affected file in this scenario.
BuilderState.updateShapeSignature(
state,
Debug.checkDefined(state.program),
state.program,
affectedFile,
cancellationToken,
host,
@@ -796,7 +842,7 @@ function handleDtsMayChangeOfAffectedFile(
* Also we need to make sure signature is updated for these files
*/
function handleDtsMayChangeOf(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
path: Path,
invalidateJsFiles: boolean,
cancellationToken: CancellationToken | undefined,
@@ -805,8 +851,7 @@ function handleDtsMayChangeOf(
removeSemanticDiagnosticsOf(state, path);
if (!state.changedFilesSet.has(path)) {
const program = Debug.checkDefined(state.program);
const sourceFile = program.getSourceFileByPath(path);
const sourceFile = state.program.getSourceFileByPath(path);
if (sourceFile) {
// Even though the js emit doesnt change and we are already handling dts emit and semantic diagnostics
// we need to update the signature to reflect correctness of the signature(which is output d.ts emit) of this file
@@ -815,7 +860,7 @@ function handleDtsMayChangeOf(
// But we avoid expensive full shape computation, as using file version as shape is enough for correctness.
BuilderState.updateShapeSignature(
state,
program,
state.program,
sourceFile,
cancellationToken,
host,
@@ -823,10 +868,18 @@ function handleDtsMayChangeOf(
);
// If not dts emit, nothing more to do
if (invalidateJsFiles) {
addToAffectedFilesPendingEmit(state, path, getBuilderFileEmit(state.compilerOptions));
addToAffectedFilesPendingEmit(
state,
path,
getBuilderFileEmit(state.compilerOptions),
);
}
else if (getEmitDeclarations(state.compilerOptions)) {
addToAffectedFilesPendingEmit(state, path, state.compilerOptions.declarationMap ? BuilderFileEmit.AllDts : BuilderFileEmit.Dts);
addToAffectedFilesPendingEmit(
state,
path,
state.compilerOptions.declarationMap ? BuilderFileEmit.AllDts : BuilderFileEmit.Dts,
);
}
}
}
@@ -852,7 +905,7 @@ function isChangedSignature(state: BuilderProgramState, path: Path) {
}
function handleDtsMayChangeOfGlobalScope(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
filePath: Path,
invalidateJsFiles: boolean,
cancellationToken: CancellationToken | undefined,
@@ -860,16 +913,19 @@ function handleDtsMayChangeOfGlobalScope(
): boolean {
if (!state.fileInfos.get(filePath)?.affectsGlobalScope) return false;
// Every file needs to be handled
BuilderState.getAllFilesExcludingDefaultLibraryFile(state, state.program!, /*firstSourceFile*/ undefined)
.forEach(file =>
handleDtsMayChangeOf(
state,
file.resolvedPath,
invalidateJsFiles,
cancellationToken,
host,
)
);
BuilderState.getAllFilesExcludingDefaultLibraryFile(
state,
state.program,
/*firstSourceFile*/ undefined,
).forEach(file =>
handleDtsMayChangeOf(
state,
file.resolvedPath,
invalidateJsFiles,
cancellationToken,
host,
)
);
removeDiagnosticsOfLibraryFiles(state);
return true;
}
@@ -878,7 +934,7 @@ function handleDtsMayChangeOfGlobalScope(
* Iterate on referencing modules that export entities from affected file and delete diagnostics and add pending emit
*/
function handleDtsMayChangeOfReferencingExportOfAffectedFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
affectedFile: SourceFile,
cancellationToken: CancellationToken | undefined,
host: BuilderProgramHost,
@@ -909,7 +965,7 @@ function handleDtsMayChangeOfReferencingExportOfAffectedFile(
) return;
handleDtsMayChangeOf(state, currentPath, /*invalidateJsFiles*/ false, cancellationToken, host);
if (isChangedSignature(state, currentPath)) {
const currentSourceFile = Debug.checkDefined(state.program).getSourceFileByPath(currentPath)!;
const currentSourceFile = state.program.getSourceFileByPath(currentPath)!;
queue.push(...BuilderState.getReferencedByPaths(state, currentSourceFile.resolvedPath));
}
}
@@ -922,7 +978,7 @@ function handleDtsMayChangeOfReferencingExportOfAffectedFile(
affectedFile.symbol.exports,
exported => {
if ((exported.flags & SymbolFlags.ConstEnum) !== 0) return true;
const aliased = skipAlias(exported, state.program!.getTypeChecker());
const aliased = skipAlias(exported, state.program.getTypeChecker());
if (aliased === exported) return false;
return (aliased.flags & SymbolFlags.ConstEnum) !== 0 &&
some(aliased.declarations, d => getSourceFileOfNode(d) === affectedFile);
@@ -949,7 +1005,7 @@ function handleDtsMayChangeOfReferencingExportOfAffectedFile(
* return true when all work is done and we can exit handling dts emit and semantic diagnostics
*/
function handleDtsMayChangeOfFileAndExportsOfFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
filePath: Path,
invalidateJsFiles: boolean,
seenFileAndExportsOfFile: Set<string>,
@@ -980,14 +1036,14 @@ function handleDtsMayChangeOfFileAndExportsOfFile(
* bindAndCheckDiagnostics (from cache) and program diagnostics
*/
function getSemanticDiagnosticsOfFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
sourceFile: SourceFile,
cancellationToken: CancellationToken | undefined,
semanticDiagnosticsPerFile?: BuilderProgramState["semanticDiagnosticsPerFile"],
): readonly Diagnostic[] {
return concatenate(
getBinderAndCheckerDiagnosticsOfFile(state, sourceFile, cancellationToken, semanticDiagnosticsPerFile),
Debug.checkDefined(state.program).getProgramDiagnostics(sourceFile),
state.program.getProgramDiagnostics(sourceFile),
);
}
@@ -996,7 +1052,7 @@ function getSemanticDiagnosticsOfFile(
* Note that it is assumed that when asked about binder and checker diagnostics, the file has been taken out of affected files/changed file set
*/
function getBinderAndCheckerDiagnosticsOfFile(
state: BuilderProgramState,
state: BuilderProgramStateWithDefinedProgram,
sourceFile: SourceFile,
cancellationToken: CancellationToken | undefined,
semanticDiagnosticsPerFile: BuilderProgramState["semanticDiagnosticsPerFile"] | undefined,
@@ -1010,7 +1066,7 @@ function getBinderAndCheckerDiagnosticsOfFile(
}
// Diagnostics werent cached, get them from program, and cache the result
const diagnostics = Debug.checkDefined(state.program).getBindAndCheckDiagnostics(sourceFile, cancellationToken);
const diagnostics = state.program.getBindAndCheckDiagnostics(sourceFile, cancellationToken);
semanticDiagnosticsPerFile.set(path, diagnostics);
return filterSemanticDiagnostics(diagnostics, state.compilerOptions);
}
@@ -1126,14 +1182,14 @@ export function isProgramBundleEmitBuildInfo(info: ProgramBuildInfo): info is Pr
/**
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
*/
function getBuildInfo(state: BuilderProgramState): BuildInfo {
const currentDirectory = Debug.checkDefined(state.program).getCurrentDirectory();
function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo {
const currentDirectory = state.program.getCurrentDirectory();
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory));
// Convert the file name to Path here if we set the fileName instead to optimize multiple d.ts file emits and having to compute Canonical path
const latestChangedDtsFile = state.latestChangedDtsFile ? relativeToBuildInfoEnsuringAbsolutePath(state.latestChangedDtsFile) : undefined;
const fileNames: string[] = [];
const fileNameToFileId = new Map<string, ProgramBuildInfoFileId>();
const rootFileNames = new Set(state.program!.getRootFileNames().map(f => toPath(f, currentDirectory, state.program!.getCanonicalFileName)));
const rootFileNames = new Set(state.program.getRootFileNames().map(f => toPath(f, currentDirectory, state.program.getCanonicalFileName)));
const root: ProgramBuildInfoRoot[] = [];
if (state.compilerOptions.outFile) {
// Copy all fileInfo, version and impliedFormat
@@ -1177,8 +1233,8 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
const oldSignature = state.oldSignatures?.get(key);
const actualSignature = oldSignature !== undefined ? oldSignature || undefined : value.signature;
if (state.compilerOptions.composite) {
const file = state.program!.getSourceFileByPath(key)!;
if (!isJsonSourceFile(file) && sourceFileMayBeEmitted(file, state.program!)) {
const file = state.program.getSourceFileByPath(key)!;
if (!isJsonSourceFile(file) && sourceFileMayBeEmitted(file, state.program)) {
const emitSignature = state.emitSignatures?.get(key);
if (emitSignature !== actualSignature) {
emitSignatures = append(
@@ -1222,8 +1278,8 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
const seenFiles = new Set<Path>();
for (const path of arrayFrom(state.affectedFilesPendingEmit.keys()).sort(compareStringsCaseSensitive)) {
if (tryAddToSet(seenFiles, path)) {
const file = state.program!.getSourceFileByPath(path);
if (!file || !sourceFileMayBeEmitted(file, state.program!)) continue;
const file = state.program.getSourceFileByPath(path);
if (!file || !sourceFileMayBeEmitted(file, state.program)) continue;
const fileId = toFileId(path), pendingEmit = state.affectedFilesPendingEmit.get(path)!;
affectedFilesPendingEmit = append(
affectedFilesPendingEmit,
@@ -1259,7 +1315,7 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
}
function relativeToBuildInfo(path: string) {
return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, state.program!.getCanonicalFileName));
return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, state.program.getCanonicalFileName));
}
function toFileId(path: Path): ProgramBuildInfoFileId {
@@ -1283,8 +1339,8 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
}
function tryAddRoot(path: Path, fileId: ProgramBuildInfoFileId) {
const file = state.program!.getSourceFile(path)!;
if (!state.program!.getFileIncludeReasons().get(file.path)!.some(r => r.kind === FileIncludeKind.RootFile)) return;
const file = state.program.getSourceFile(path)!;
if (!state.program.getFileIncludeReasons().get(file.path)!.some(r => r.kind === FileIncludeKind.RootFile)) return;
// First fileId as is
if (!root.length) return root.push(fileId);
const last = root[root.length - 1];
@@ -1304,7 +1360,7 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
function toResolvedRoot(): ProgramBuildInfoResolvedRoot[] | undefined {
let result: ProgramBuildInfoResolvedRoot[] | undefined;
rootFileNames.forEach(path => {
const file = state.program!.getSourceFileByPath(path);
const file = state.program.getSourceFileByPath(path);
if (file && path !== file.resolvedPath) {
result = append(result, [toFileId(file.resolvedPath), toFileId(path)]);
}
@@ -1538,34 +1594,47 @@ export function computeSignature(text: string, host: HostForComputeHash, data?:
}
/** @internal */
export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(
kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram,
builderCreationParameters: BuilderCreationParameters,
): SemanticDiagnosticsBuilderProgram;
/** @internal */
export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram;
export function createBuilderProgram(
kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram,
builderCreationParameters: BuilderCreationParameters,
): EmitAndSemanticDiagnosticsBuilderProgram;
/** @internal */
export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) {
export function createBuilderProgram(
kind: BuilderProgramKind,
{ newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters,
) {
// Return same program if underlying program doesnt change
let oldState = oldProgram && oldProgram.getState();
let oldState = oldProgram && oldProgram.state;
if (oldState && newProgram === oldState.program && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics()) {
newProgram = undefined!; // TODO: GH#18217
newProgram = undefined!;
oldState = undefined;
return oldProgram;
}
const state = createBuilderProgramState(newProgram, oldState);
newProgram.getBuildInfo = () => getBuildInfo(state);
newProgram.getBuildInfo = () => getBuildInfo(toBuilderProgramStateWithDefinedProgram(state));
// To ensure that we arent storing any references to old program or new program without state
newProgram = undefined!; // TODO: GH#18217
newProgram = undefined!;
oldProgram = undefined;
oldState = undefined;
const getState = () => state;
const builderProgram = createRedirectedBuilderProgram(getState, configFileParsingDiagnostics);
builderProgram.getState = getState;
const builderProgram = createRedirectedBuilderProgram(state, configFileParsingDiagnostics);
builderProgram.state = state;
builderProgram.saveEmitState = () => backupBuilderProgramEmitState(state);
builderProgram.restoreEmitState = saved => restoreBuilderProgramEmitState(state, saved);
builderProgram.hasChangedEmitSignature = () => !!state.hasChangedEmitSignature;
builderProgram.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile);
builderProgram.getAllDependencies = sourceFile =>
BuilderState.getAllDependencies(
state,
Debug.checkDefined(state.program),
sourceFile,
);
builderProgram.getSemanticDiagnostics = getSemanticDiagnostics;
builderProgram.emit = emit;
builderProgram.releaseProgram = () => releaseCache(state);
@@ -1581,12 +1650,18 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
else {
notImplemented();
}
return builderProgram;
function emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
function emitBuildInfo(
writeFile: WriteFileCallback | undefined,
cancellationToken: CancellationToken | undefined,
): EmitResult {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
if (state.buildInfoEmitPending) {
const result = Debug.checkDefined(state.program).emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken);
const result = state.program.emitBuildInfo(
writeFile || maybeBind(host, host.writeFile),
cancellationToken,
);
state.buildInfoEmitPending = false;
return result;
}
@@ -1598,7 +1673,13 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
* in that order would be used to write the files
*/
function emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult<EmitResult> {
function emitNextAffectedFile(
writeFile: WriteFileCallback | undefined,
cancellationToken: CancellationToken | undefined,
emitOnlyDtsFiles: boolean | undefined,
customTransformers: CustomTransformers | undefined,
): AffectedFileResult<EmitResult> {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
let affected = getNextAffectedFile(state, cancellationToken, host);
const programEmitKind = getBuilderFileEmit(state.compilerOptions);
let emitKind: BuilderFileEmit = emitOnlyDtsFiles ?
@@ -1637,7 +1718,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
state.emitDiagnosticsPerFile.forEach(d => addRange(diagnostics, d));
return {
result: { emitSkipped: true, diagnostics },
affected: state.program!,
affected: state.program,
};
}
}
@@ -1646,8 +1727,11 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
if (!affected) {
// Emit buildinfo if pending
if (!state.buildInfoEmitPending) return undefined;
const affected = state.program!;
const result = affected.emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken);
const affected = state.program;
const result = affected.emitBuildInfo(
writeFile || maybeBind(host, host.writeFile),
cancellationToken,
);
state.buildInfoEmitPending = false;
return { result, affected };
}
@@ -1657,7 +1741,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
if (emitKind & BuilderFileEmit.AllJs) emitOnly = EmitOnly.Js;
if (emitKind & BuilderFileEmit.AllDts) emitOnly = emitOnly === undefined ? EmitOnly.Dts : undefined;
// Actual emit without buildInfo as we want to emit it later so the state is updated
const result = state.program!.emit(
const result = state.program.emit(
affected === state.program ? undefined : affected as SourceFile,
getWriteFileCallback(writeFile, customTransformers),
cancellationToken,
@@ -1707,7 +1791,11 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
return { result, affected };
}
function getWriteFileCallback(writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined): WriteFileCallback | undefined {
function getWriteFileCallback(
writeFile: WriteFileCallback | undefined,
customTransformers: CustomTransformers | undefined,
): WriteFileCallback | undefined {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
if (!getEmitDeclarations(state.compilerOptions)) return writeFile || maybeBind(host, host.writeFile);
return (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
if (isDeclarationFileName(fileName)) {
@@ -1719,7 +1807,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
const info = state.fileInfos.get(file.resolvedPath)!;
if (info.signature === file.version) {
const signature = computeSignatureWithDiagnostics(
state.program!,
state.program,
file,
text,
host,
@@ -1761,7 +1849,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
}
if (writeFile) writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
else if (host.writeFile) host.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
else state.program!.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
else state.program.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
/**
* Compare to existing computed signature and store it or handle the changes in d.ts map option from before
@@ -1799,7 +1887,14 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
* in that order would be used to write the files
*/
function emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
function emit(
targetSourceFile: SourceFile | undefined,
writeFile: WriteFileCallback | undefined,
cancellationToken: CancellationToken | undefined,
emitOnlyDtsFiles: boolean | undefined,
customTransformers: CustomTransformers | undefined,
): EmitResult {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile);
}
@@ -1816,7 +1911,14 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
let emittedFiles: string[] = [];
let affectedEmitResult: AffectedFileResult<EmitResult>;
while (affectedEmitResult = emitNextAffectedFile(writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)) {
while (
affectedEmitResult = emitNextAffectedFile(
writeFile,
cancellationToken,
emitOnlyDtsFiles,
customTransformers,
)
) {
emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped;
diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics);
emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles);
@@ -1834,7 +1936,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
clearAffectedFilesPendingEmit(state, emitOnlyDtsFiles);
}
}
return Debug.checkDefined(state.program).emit(
return state.program.emit(
targetSourceFile,
getWriteFileCallback(writeFile, customTransformers),
cancellationToken,
@@ -1847,7 +1949,11 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
* Return the semantic diagnostics for the next affected file or undefined if iteration is complete
* If provided ignoreSourceFile would be called before getting the diagnostics and would ignore the sourceFile if the returned value was true
*/
function getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult<readonly Diagnostic[]> {
function getSemanticDiagnosticsOfNextAffectedFile(
cancellationToken: CancellationToken | undefined,
ignoreSourceFile?: (sourceFile: SourceFile) => boolean,
): AffectedFileResult<readonly Diagnostic[]> {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
while (true) {
const affected = getNextAffectedFile(state, cancellationToken, host);
let result;
@@ -1897,7 +2003,11 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
* In case of SemanticDiagnosticsBuilderProgram if the source file is not provided,
* it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics
*/
function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
function getSemanticDiagnostics(
sourceFile: SourceFile | undefined,
cancellationToken: CancellationToken | undefined,
): readonly Diagnostic[] {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
assertSourceFileOkWithoutNextAffectedCall(state, sourceFile);
if (sourceFile) {
return getSemanticDiagnosticsOfFile(state, sourceFile, cancellationToken);
@@ -1913,14 +2023,18 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos
}
let diagnostics: Diagnostic[] | undefined;
for (const sourceFile of Debug.checkDefined(state.program).getSourceFiles()) {
for (const sourceFile of state.program.getSourceFiles()) {
diagnostics = addRange(diagnostics, getSemanticDiagnosticsOfFile(state, sourceFile, cancellationToken));
}
return diagnostics || emptyArray;
}
}
function addToAffectedFilesPendingEmit(state: BuilderProgramState, affectedFilePendingEmit: Path, kind: BuilderFileEmit) {
function addToAffectedFilesPendingEmit(
state: BuilderProgramState,
affectedFilePendingEmit: Path,
kind: BuilderFileEmit,
) {
const existingKind = state.affectedFilesPendingEmit?.get(affectedFilePendingEmit) || BuilderFileEmit.None;
(state.affectedFilesPendingEmit ??= new Map()).set(affectedFilePendingEmit, existingKind | kind);
state.emitDiagnosticsPerFile?.delete(affectedFilePendingEmit);
@@ -1936,17 +2050,27 @@ export function toBuilderStateFileInfoForMultiEmit(fileInfo: ProgramMultiFileEmi
}
/** @internal */
export function toBuilderFileEmit(value: ProgramBuilderInfoFilePendingEmit, fullEmitForOptions: BuilderFileEmit): BuilderFileEmit {
export function toBuilderFileEmit(
value: ProgramBuilderInfoFilePendingEmit,
fullEmitForOptions: BuilderFileEmit,
): BuilderFileEmit {
return isNumber(value) ? fullEmitForOptions : value[1] || BuilderFileEmit.Dts;
}
/** @internal */
export function toProgramEmitPending(value: ProgramBuildInfoBundlePendingEmit, options: CompilerOptions | undefined): BuilderFileEmit | undefined {
export function toProgramEmitPending(
value: ProgramBuildInfoBundlePendingEmit,
options: CompilerOptions | undefined,
): BuilderFileEmit | undefined {
return !value ? getBuilderFileEmit(options || {}) : value;
}
/** @internal */
export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, buildInfoPath: string, host: ReadBuildProgramHost): EmitAndSemanticDiagnosticsBuilderProgram {
export function createBuilderProgramUsingProgramBuildInfo(
buildInfo: BuildInfo,
buildInfoPath: string,
host: ReadBuildProgramHost,
): EmitAndSemanticDiagnosticsBuilderProgram {
const program = buildInfo.program!;
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()));
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
@@ -2012,7 +2136,7 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo,
}
return {
getState: () => state,
state,
saveEmitState: noop as BuilderProgram["saveEmitState"],
restoreEmitState: noop,
getProgram: notImplemented,
@@ -2127,15 +2251,18 @@ export function getBuildInfoFileVersionMap(
}
/** @internal */
export function createRedirectedBuilderProgram(getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: readonly Diagnostic[]): BuilderProgram {
export function createRedirectedBuilderProgram(
state: Pick<ReusableBuilderProgramState, "program" | "compilerOptions">,
configFileParsingDiagnostics: readonly Diagnostic[],
): BuilderProgram {
return {
getState: notImplemented,
state: undefined!,
saveEmitState: noop as BuilderProgram["saveEmitState"],
restoreEmitState: noop,
getProgram,
getProgramOrUndefined: () => getState().program,
releaseProgram: () => getState().program = undefined,
getCompilerOptions: () => getState().compilerOptions,
getProgramOrUndefined: () => state.program,
releaseProgram: () => state.program = undefined,
getCompilerOptions: () => state.compilerOptions,
getSourceFile: fileName => getProgram().getSourceFile(fileName),
getSourceFiles: () => getProgram().getSourceFiles(),
getOptionsDiagnostics: cancellationToken => getProgram().getOptionsDiagnostics(cancellationToken),
@@ -2152,6 +2279,6 @@ export function createRedirectedBuilderProgram(getState: () => { program?: Progr
};
function getProgram() {
return Debug.checkDefined(getState().program);
return Debug.checkDefined(state.program);
}
}
+101 -14
View File
@@ -46,7 +46,7 @@ export type HostForComputeHash = Pick<BuilderProgramHost, "createHash" | "storeS
*/
export interface BuilderProgram {
/** @internal */
getState(): ReusableBuilderProgramState;
state: ReusableBuilderProgramState;
/** @internal */
saveEmitState(): SavedBuildProgramEmitState;
/** @internal */
@@ -164,28 +164,115 @@ export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagno
/**
* Create the builder to manage semantic diagnostics and cache them
*/
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
export function createSemanticDiagnosticsBuilderProgram(
newProgram: Program,
host: BuilderProgramHost,
oldProgram?: SemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(
rootNames: readonly string[] | undefined,
options: CompilerOptions | undefined,
host?: CompilerHost,
oldProgram?: SemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(
newProgramOrRootNames: Program | readonly string[] | undefined,
hostOrOptions: BuilderProgramHost | CompilerOptions | undefined,
oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram,
configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
) {
return createBuilderProgram(
BuilderProgramKind.SemanticDiagnosticsBuilderProgram,
getBuilderCreationParameters(
newProgramOrRootNames,
hostOrOptions,
oldProgramOrHost,
configFileParsingDiagnosticsOrOldProgram,
configFileParsingDiagnostics,
projectReferences,
),
);
}
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
export function createEmitAndSemanticDiagnosticsBuilderProgram(
newProgram: Program,
host: BuilderProgramHost,
oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(
rootNames: readonly string[] | undefined,
options: CompilerOptions | undefined,
host?: CompilerHost,
oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(
newProgramOrRootNames: Program | readonly string[] | undefined,
hostOrOptions: BuilderProgramHost | CompilerOptions | undefined,
oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram,
configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
) {
return createBuilderProgram(
BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram,
getBuilderCreationParameters(
newProgramOrRootNames,
hostOrOptions,
oldProgramOrHost,
configFileParsingDiagnosticsOrOldProgram,
configFileParsingDiagnostics,
projectReferences,
),
);
}
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): BuilderProgram;
export function createAbstractBuilder(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram;
export function createAbstractBuilder(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram {
const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
return createRedirectedBuilderProgram(() => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), newConfigFileParsingDiagnostics);
export function createAbstractBuilder(
newProgram: Program,
host: BuilderProgramHost,
oldProgram?: BuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
): BuilderProgram;
export function createAbstractBuilder(
rootNames: readonly string[] | undefined,
options: CompilerOptions | undefined,
host?: CompilerHost,
oldProgram?: BuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
): BuilderProgram;
export function createAbstractBuilder(
newProgramOrRootNames: Program | readonly string[] | undefined,
hostOrOptions: BuilderProgramHost | CompilerOptions | undefined,
oldProgramOrHost?: CompilerHost | BuilderProgram,
configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram,
configFileParsingDiagnostics?: readonly Diagnostic[],
projectReferences?: readonly ProjectReference[],
): BuilderProgram {
const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(
newProgramOrRootNames,
hostOrOptions,
oldProgramOrHost,
configFileParsingDiagnosticsOrOldProgram,
configFileParsingDiagnostics,
projectReferences,
);
return createRedirectedBuilderProgram(
{ program: newProgram, compilerOptions: newProgram.getCompilerOptions() },
newConfigFileParsingDiagnostics,
);
}
+2 -2
View File
@@ -329,8 +329,8 @@ function createTabularErrorsDisplay(filesInError: (ReportFileInError | undefined
}
/** @internal */
export function isBuilderProgram(program: Program | BuilderProgram): program is BuilderProgram {
return !!(program as BuilderProgram).getState;
export function isBuilderProgram<T extends BuilderProgram>(program: Program | BuilderProgram): program is T {
return !!(program as T).state;
}
/** @internal */
+2 -5
View File
@@ -30,6 +30,7 @@ import {
identity,
insertSorted,
isArray,
isBuilderProgram,
isDeclarationFileName,
isExcludedFile,
isSupportedSourceFileName,
@@ -627,7 +628,7 @@ export function isIgnoredFileFromWildCardWatching({
return realProgram ?
!!realProgram.getSourceFileByPath(file) :
builderProgram ?
builderProgram.getState().fileInfos.has(file) :
builderProgram.state.fileInfos.has(file) :
!!find(program as readonly string[], rootFile => toPath(rootFile) === file);
}
@@ -651,10 +652,6 @@ export function isIgnoredFileFromWildCardWatching({
}
}
function isBuilderProgram<T extends BuilderProgram>(program: Program | T): program is T {
return !!(program as T).getState;
}
/** @internal */
export function isEmittedFileOfProgram(program: Program | undefined, file: string) {
if (!program) {
+3 -4
View File
@@ -72,9 +72,8 @@ function baselineProgram(baseline: string[], [program, builderProgram]: CommandL
if (!builderProgram) return;
if (builderProgram !== oldProgram?.[1]) {
const state = builderProgram.getState();
const internalState = state as unknown as ts.BuilderProgramState;
if (state.semanticDiagnosticsPerFile.size) {
const internalState = builderProgram.state as ts.BuilderProgramState;
if (builderProgram.state.semanticDiagnosticsPerFile.size) {
baseline.push("Semantic diagnostics in builder refreshed for::");
for (const file of program.getSourceFiles()) {
if (!internalState.semanticDiagnosticsFromOldState || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath)) {
@@ -90,7 +89,7 @@ function baselineProgram(baseline: string[], [program, builderProgram]: CommandL
if (internalState.hasCalledUpdateShapeSignature?.size) {
baseline.push("Shape signatures in builder refreshed for::");
internalState.hasCalledUpdateShapeSignature.forEach((path: ts.Path) => {
const info = state.fileInfos.get(path);
const info = builderProgram.state.fileInfos.get(path);
const signatureInfo = internalState.signatureInfo?.get(path)!;
switch (signatureInfo) {
case ts.SignatureInfo.ComputedDts:
+1 -2
View File
@@ -180,8 +180,7 @@ function storeDtsSignatures(sys: TscCompileSystem, programs: readonly CommandLin
sys.dtsSignaures ??= new Map();
const dtsSignatureData = new Map<string, string>();
sys.dtsSignaures.set(`${toPathWithSystem(sys, buildInfoPath)}.readable.baseline.txt` as ts.Path, dtsSignatureData);
const state = builderProgram.getState();
state.hasCalledUpdateShapeSignature?.forEach(resolvedPath => {
builderProgram.state.hasCalledUpdateShapeSignature?.forEach(resolvedPath => {
const file = program.getSourceFileByPath(resolvedPath);
if (!file || file.isDeclarationFile) return;
// Compute dts and exported map and store it
@@ -170,42 +170,41 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => {
host: ts.createIncrementalCompilerHost(command.options, system),
});
const state = builderProgram.getState();
assert.equal(state.changedFilesSet!.size, 0, "changes");
assert.equal(builderProgram.state.changedFilesSet!.size, 0, "changes");
assert.equal(state.fileInfos.size, 3, "FileInfo size");
assert.deepEqual(state.fileInfos.get(libFile.path as ts.Path), {
assert.equal(builderProgram.state.fileInfos.size, 3, "FileInfo size");
assert.deepEqual(builderProgram.state.fileInfos.get(libFile.path as ts.Path), {
version: system.createHash(libFile.content),
signature: system.createHash(libFile.content),
affectsGlobalScope: true,
impliedFormat: ts.ModuleKind.CommonJS,
});
assert.deepEqual(state.fileInfos.get(file1.path as ts.Path), {
assert.deepEqual(builderProgram.state.fileInfos.get(file1.path as ts.Path), {
version: system.createHash(file1.content),
signature: system.createHash(file1.content),
affectsGlobalScope: undefined,
impliedFormat: ts.ModuleKind.CommonJS,
});
assert.deepEqual(state.fileInfos.get(file2.path as ts.Path), {
assert.deepEqual(builderProgram.state.fileInfos.get(file2.path as ts.Path), {
version: system.createHash(fileModified.content),
signature: system.createHash(fileModified.content),
affectsGlobalScope: undefined,
impliedFormat: ts.ModuleKind.CommonJS,
});
assert.deepEqual(state.compilerOptions, {
assert.deepEqual(builderProgram.state.compilerOptions, {
incremental: true,
module: ts.ModuleKind.AMD,
configFilePath: config.path,
});
assert.equal(ts.arrayFrom(state.referencedMap!.keys()).length, 0);
assert.equal(ts.arrayFrom(builderProgram.state.referencedMap!.keys()).length, 0);
assert.equal(state.semanticDiagnosticsPerFile.size, 3);
assert.deepEqual(state.semanticDiagnosticsPerFile.get(libFile.path as ts.Path), ts.emptyArray);
assert.deepEqual(state.semanticDiagnosticsPerFile.get(file1.path as ts.Path), ts.emptyArray);
assert.deepEqual(state.semanticDiagnosticsPerFile.get(file2.path as ts.Path), [{
file: state.program!.getSourceFileByPath(file2.path as ts.Path)!,
assert.equal(builderProgram.state.semanticDiagnosticsPerFile.size, 3);
assert.deepEqual(builderProgram.state.semanticDiagnosticsPerFile.get(libFile.path as ts.Path), ts.emptyArray);
assert.deepEqual(builderProgram.state.semanticDiagnosticsPerFile.get(file1.path as ts.Path), ts.emptyArray);
assert.deepEqual(builderProgram.state.semanticDiagnosticsPerFile.get(file2.path as ts.Path), [{
file: builderProgram.state.program!.getSourceFileByPath(file2.path as ts.Path)!,
start: 13,
length: 1,
code: ts.Diagnostics.Type_0_is_not_assignable_to_type_1.code,