Skip to content

Commit 15c2120

Browse files
authored
Update affected files pending emit when emitting using SemanticDignosticsBuilderProgram (#48519)
* Update affected files pending emit when emitting using SemanticDignosticsBuilderProgram * Saving of affected files pending emit is not needed any more * PR feedback
1 parent a7d818b commit 15c2120

File tree

4 files changed

+343
-66
lines changed

4 files changed

+343
-66
lines changed

src/compiler/builder.ts

+40-46
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,12 @@ namespace ts {
403403
}
404404
}
405405

406+
function clearAffectedFilesPendingEmit(state: BuilderProgramState) {
407+
state.affectedFilesPendingEmit = undefined;
408+
state.affectedFilesPendingEmitKind = undefined;
409+
state.affectedFilesPendingEmitIndex = undefined;
410+
}
411+
406412
/**
407413
* Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
408414
*/
@@ -422,9 +428,7 @@ namespace ts {
422428
}
423429
}
424430
}
425-
state.affectedFilesPendingEmit = undefined;
426-
state.affectedFilesPendingEmitKind = undefined;
427-
state.affectedFilesPendingEmitIndex = undefined;
431+
clearAffectedFilesPendingEmit(state);
428432
}
429433
return undefined;
430434
}
@@ -1101,57 +1105,47 @@ namespace ts {
11011105
* in that order would be used to write the files
11021106
*/
11031107
function emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
1104-
let restorePendingEmitOnHandlingNoEmitSuccess = false;
1105-
let savedAffectedFilesPendingEmit;
1106-
let savedAffectedFilesPendingEmitKind;
1107-
let savedAffectedFilesPendingEmitIndex;
1108-
// Backup and restore affected pendings emit state for non emit Builder if noEmitOnError is enabled and emitBuildInfo could be written in case there are errors
1109-
// This ensures pending files to emit is updated in tsbuildinfo
1110-
// Note that when there are no errors, emit proceeds as if everything is emitted as it is callers reponsibility to write the files to disk if at all (because its builder that doesnt track files to emit)
1111-
if (kind !== BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram &&
1112-
!targetSourceFile &&
1113-
!outFile(state.compilerOptions) &&
1114-
!state.compilerOptions.noEmit &&
1115-
state.compilerOptions.noEmitOnError) {
1116-
restorePendingEmitOnHandlingNoEmitSuccess = true;
1117-
savedAffectedFilesPendingEmit = state.affectedFilesPendingEmit && state.affectedFilesPendingEmit.slice();
1118-
savedAffectedFilesPendingEmitKind = state.affectedFilesPendingEmitKind && new Map(state.affectedFilesPendingEmitKind);
1119-
savedAffectedFilesPendingEmitIndex = state.affectedFilesPendingEmitIndex;
1120-
}
1121-
11221108
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
11231109
assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile);
11241110
}
11251111
const result = handleNoEmitOptions(builderProgram, targetSourceFile, writeFile, cancellationToken);
11261112
if (result) return result;
11271113

1128-
if (restorePendingEmitOnHandlingNoEmitSuccess) {
1129-
state.affectedFilesPendingEmit = savedAffectedFilesPendingEmit;
1130-
state.affectedFilesPendingEmitKind = savedAffectedFilesPendingEmitKind;
1131-
state.affectedFilesPendingEmitIndex = savedAffectedFilesPendingEmitIndex;
1132-
}
1133-
11341114
// Emit only affected files if using builder for emit
1135-
if (!targetSourceFile && kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
1136-
// Emit and report any errors we ran into.
1137-
let sourceMaps: SourceMapEmitResult[] = [];
1138-
let emitSkipped = false;
1139-
let diagnostics: Diagnostic[] | undefined;
1140-
let emittedFiles: string[] = [];
1141-
1142-
let affectedEmitResult: AffectedFileResult<EmitResult>;
1143-
while (affectedEmitResult = emitNextAffectedFile(writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)) {
1144-
emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped;
1145-
diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics);
1146-
emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles);
1147-
sourceMaps = addRange(sourceMaps, affectedEmitResult.result.sourceMaps);
1115+
if (!targetSourceFile) {
1116+
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
1117+
// Emit and report any errors we ran into.
1118+
let sourceMaps: SourceMapEmitResult[] = [];
1119+
let emitSkipped = false;
1120+
let diagnostics: Diagnostic[] | undefined;
1121+
let emittedFiles: string[] = [];
1122+
1123+
let affectedEmitResult: AffectedFileResult<EmitResult>;
1124+
while (affectedEmitResult = emitNextAffectedFile(writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)) {
1125+
emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped;
1126+
diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics);
1127+
emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles);
1128+
sourceMaps = addRange(sourceMaps, affectedEmitResult.result.sourceMaps);
1129+
}
1130+
return {
1131+
emitSkipped,
1132+
diagnostics: diagnostics || emptyArray,
1133+
emittedFiles,
1134+
sourceMaps
1135+
};
1136+
}
1137+
// In non Emit builder, clear affected files pending emit
1138+
else if (state.affectedFilesPendingEmitKind?.size) {
1139+
Debug.assert(kind === BuilderProgramKind.SemanticDiagnosticsBuilderProgram);
1140+
// State can clear affected files pending emit if
1141+
if (!emitOnlyDtsFiles // If we are doing complete emit, affected files pending emit can be cleared
1142+
// If every file pending emit is pending on only dts emit
1143+
|| every(state.affectedFilesPendingEmit, (path, index) =>
1144+
index < state.affectedFilesPendingEmitIndex! ||
1145+
state.affectedFilesPendingEmitKind!.get(path) === BuilderFileEmit.DtsOnly)) {
1146+
clearAffectedFilesPendingEmit(state);
1147+
}
11481148
}
1149-
return {
1150-
emitSkipped,
1151-
diagnostics: diagnostics || emptyArray,
1152-
emittedFiles,
1153-
sourceMaps
1154-
};
11551149
}
11561150
return Debug.checkDefined(state.program).emit(targetSourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers);
11571151
}

src/testRunner/unittests/tscWatch/watchApi.ts

+50-7
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ namespace ts.tscWatch {
204204
function createWatch<T extends BuilderProgram>(
205205
baseline: string[],
206206
config: File,
207-
optionsToExtend: CompilerOptions | undefined,
208207
sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles,
209-
createProgram: CreateProgram<T>
208+
createProgram: CreateProgram<T>,
209+
optionsToExtend?: CompilerOptions,
210210
) {
211211
const { cb, getPrograms } = commandLineCallbacks(sys);
212212
baseline.push(`tsc --w${optionsToExtend?.noEmit ? " --noEmit" : ""}`);
@@ -251,9 +251,9 @@ namespace ts.tscWatch {
251251
change: (sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles) => void,
252252
caption: string
253253
) {
254-
// Change file
255-
applyChange(sys, baseline, change, caption);
256-
applyChange(emitSys, emitBaseline, change, caption);
254+
// Change file
255+
applyChange(sys, baseline, change, caption);
256+
applyChange(emitSys, emitBaseline, change, caption);
257257
}
258258

259259
function verifyBuilder<T extends BuilderProgram>(
@@ -264,8 +264,8 @@ namespace ts.tscWatch {
264264
emitSys: TestFSWithWatch.TestServerHostTrackingWrittenFiles,
265265
createProgram: CreateProgram<T>,
266266
optionsToExtend?: CompilerOptions) {
267-
createWatch(baseline, config, optionsToExtend, sys, createProgram);
268-
createWatch(emitBaseline, config, optionsToExtend, emitSys, createEmitAndSemanticDiagnosticsBuilderProgram);
267+
createWatch(baseline, config, sys, createProgram, optionsToExtend);
268+
createWatch(emitBaseline, config, emitSys, createEmitAndSemanticDiagnosticsBuilderProgram, optionsToExtend);
269269
verifyOutputs(baseline, sys, emitSys);
270270
}
271271

@@ -375,6 +375,49 @@ namespace ts.tscWatch {
375375
Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmitOnError-with-composite-with-emit-builder.js`, emitBaseline.join("\r\n"));
376376
});
377377
});
378+
379+
it("SemanticDiagnosticsBuilderProgram emitDtsOnly does not update affected files pending emit", () => {
380+
// Initial
381+
const { sys, baseline, config, mainFile } = createSystem(JSON.stringify({ compilerOptions: { composite: true, noEmitOnError: true } }), "export const x: string = 10;");
382+
createWatch(baseline, config, sys, createSemanticDiagnosticsBuilderProgram);
383+
384+
// Fix error and emit
385+
applyChange(sys, baseline, sys => sys.writeFile(mainFile.path, "export const x = 10;"), "Fix error");
386+
387+
const { cb, getPrograms } = commandLineCallbacks(sys);
388+
const oldSnap = sys.snap();
389+
const reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
390+
const reportWatchStatus = createWatchStatusReporter(sys, /*pretty*/ true);
391+
const host = createWatchCompilerHostOfConfigFile({
392+
configFileName: config.path,
393+
createProgram: createSemanticDiagnosticsBuilderProgram,
394+
system: sys,
395+
reportDiagnostic,
396+
reportWatchStatus,
397+
});
398+
host.afterProgramCreate = program => {
399+
const diagnostics = sortAndDeduplicateDiagnostics(program.getSemanticDiagnostics());
400+
diagnostics.forEach(reportDiagnostic);
401+
// Buildinfo should still have affectedFilesPendingEmit since we are only emitting dts files
402+
program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDts*/ true);
403+
reportWatchStatus(
404+
createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(diagnostics.length), diagnostics.length),
405+
sys.newLine,
406+
program.getCompilerOptions(),
407+
diagnostics.length
408+
);
409+
cb(program);
410+
};
411+
createWatchProgram(host);
412+
watchBaseline({
413+
baseline,
414+
getPrograms,
415+
oldPrograms: emptyArray,
416+
sys,
417+
oldSnap,
418+
});
419+
Harness.Baseline.runBaseline(`tscWatch/watchApi/semantic-builder-emitOnlyDts.js`, baseline.join("\r\n"));
420+
});
378421
});
379422

380423
describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implemented", () => {

tests/baselines/reference/tscWatch/watchApi/noEmitOnError-with-composite-with-semantic-builder.js

+3-13
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ FsWatchesRecursive::
325325
exitCode:: ExitStatus.undefined
326326

327327
//// [/user/username/projects/myproject/tsconfig.tsbuildinfo]
328-
{"program":{"fileNames":["../../../../a/lib/lib.d.ts","./main.ts","./other.ts"],"fileInfos":[{"version":"-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }","affectsGlobalScope":true},{"version":"-10726455937-export const x = 10;","signature":"-6821242887-export declare const x = 10;\n"},"-13729955264-export const y = 10;"],"options":{"composite":true,"noEmitOnError":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2,3],"affectedFilesPendingEmit":[[2,1],[3,1]]},"version":"FakeTSVersion"}
328+
{"program":{"fileNames":["../../../../a/lib/lib.d.ts","./main.ts","./other.ts"],"fileInfos":[{"version":"-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }","affectsGlobalScope":true},{"version":"-10726455937-export const x = 10;","signature":"-6821242887-export declare const x = 10;\n"},"-13729955264-export const y = 10;"],"options":{"composite":true,"noEmitOnError":true},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2,3]},"version":"FakeTSVersion"}
329329

330330
//// [/user/username/projects/myproject/tsconfig.tsbuildinfo.readable.baseline.txt]
331331
{
@@ -360,20 +360,10 @@ exitCode:: ExitStatus.undefined
360360
"../../../../a/lib/lib.d.ts",
361361
"./main.ts",
362362
"./other.ts"
363-
],
364-
"affectedFilesPendingEmit": [
365-
[
366-
"./main.ts",
367-
"Full"
368-
],
369-
[
370-
"./other.ts",
371-
"Full"
372-
]
373363
]
374364
},
375365
"version": "FakeTSVersion",
376-
"size": 832
366+
"size": 791
377367
}
378368

379369
//// [/user/username/projects/myproject/main.js]
@@ -404,4 +394,4 @@ Output file text for /user/username/projects/myproject/main.js is same:: true
404394
Output file text for /user/username/projects/myproject/main.d.ts is same:: true
405395
Output file text for /user/username/projects/myproject/other.js is same:: true
406396
Output file text for /user/username/projects/myproject/other.d.ts is same:: true
407-
Output file text for /user/username/projects/myproject/tsconfig.tsbuildinfo is same:: false
397+
Output file text for /user/username/projects/myproject/tsconfig.tsbuildinfo is same:: true

0 commit comments

Comments
 (0)