Skip to content

Commit bafc3b7

Browse files
committed
Always emit tsbuild info even if there are non syntax errors in tsc --build mode
1 parent 62584b7 commit bafc3b7

13 files changed

+1296
-107
lines changed

src/compiler/tsbuildPublic.ts

+82-58
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,18 @@ namespace ts {
699699
};
700700
}
701701

702+
enum BuildStep {
703+
CreateProgram,
704+
SyntaxDiagnostics,
705+
SemanticDiagnostics,
706+
Emit,
707+
EmitBundle,
708+
EmitBuildInfo,
709+
BuildInvalidatedProjectOfBundle,
710+
QueueReferencingProjects,
711+
Done
712+
}
713+
702714
function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
703715
kind: InvalidatedProjectKind.Build | InvalidatedProjectKind.UpdateBundle,
704716
state: SolutionBuilderState<T>,
@@ -708,18 +720,7 @@ namespace ts {
708720
config: ParsedCommandLine,
709721
buildOrder: readonly ResolvedConfigFileName[],
710722
): BuildInvalidedProject<T> | UpdateBundleProject<T> {
711-
enum Step {
712-
CreateProgram,
713-
SyntaxDiagnostics,
714-
SemanticDiagnostics,
715-
Emit,
716-
EmitBundle,
717-
BuildInvalidatedProjectOfBundle,
718-
QueueReferencingProjects,
719-
Done
720-
}
721-
722-
let step = kind === InvalidatedProjectKind.Build ? Step.CreateProgram : Step.EmitBundle;
723+
let step = kind === InvalidatedProjectKind.Build ? BuildStep.CreateProgram : BuildStep.EmitBundle;
723724
let program: T | undefined;
724725
let buildResult: BuildResultFlags | undefined;
725726
let invalidatedProjectOfBundle: BuildInvalidedProject<T> | undefined;
@@ -781,8 +782,11 @@ namespace ts {
781782
program => program.emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)
782783
);
783784
}
784-
executeSteps(Step.SemanticDiagnostics, cancellationToken);
785-
if (step !== Step.Emit) return undefined;
785+
executeSteps(BuildStep.SemanticDiagnostics, cancellationToken);
786+
if (step === BuildStep.EmitBuildInfo) {
787+
return emitBuildInfo(writeFile, cancellationToken);
788+
}
789+
if (step !== BuildStep.Emit) return undefined;
786790
return emit(writeFile, cancellationToken, customTransformers);
787791
},
788792
done
@@ -795,19 +799,19 @@ namespace ts {
795799
getCompilerOptions: () => config.options,
796800
getCurrentDirectory: () => state.currentDirectory,
797801
emit: (writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined) => {
798-
if (step !== Step.EmitBundle) return invalidatedProjectOfBundle;
802+
if (step !== BuildStep.EmitBundle) return invalidatedProjectOfBundle;
799803
return emitBundle(writeFile, customTransformers);
800804
},
801805
done,
802806
};
803807

804808
function done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) {
805-
executeSteps(Step.Done, cancellationToken, writeFile, customTransformers);
809+
executeSteps(BuildStep.Done, cancellationToken, writeFile, customTransformers);
806810
return doneInvalidatedProject(state, projectPath);
807811
}
808812

809813
function withProgramOrUndefined<U>(action: (program: T) => U | undefined): U | undefined {
810-
executeSteps(Step.CreateProgram);
814+
executeSteps(BuildStep.CreateProgram);
811815
return program && action(program);
812816
}
813817

@@ -821,7 +825,7 @@ namespace ts {
821825
if (state.options.dry) {
822826
reportStatus(state, Diagnostics.A_non_dry_build_would_build_project_0, project);
823827
buildResult = BuildResultFlags.Success;
824-
step = Step.QueueReferencingProjects;
828+
step = BuildStep.QueueReferencingProjects;
825829
return;
826830
}
827831

@@ -831,7 +835,7 @@ namespace ts {
831835
reportAndStoreErrors(state, projectPath, getConfigFileParsingDiagnostics(config));
832836
// Nothing to build - must be a solution file, basically
833837
buildResult = BuildResultFlags.None;
834-
step = Step.QueueReferencingProjects;
838+
step = BuildStep.QueueReferencingProjects;
835839
return;
836840
}
837841

@@ -854,16 +858,15 @@ namespace ts {
854858

855859
function handleDiagnostics(diagnostics: readonly Diagnostic[], errorFlags: BuildResultFlags, errorType: string) {
856860
if (diagnostics.length) {
857-
buildResult = buildErrors(
861+
({ buildResult, step } = buildErrors(
858862
state,
859863
projectPath,
860864
program,
861865
config,
862866
diagnostics,
863867
errorFlags,
864868
errorType
865-
);
866-
step = Step.QueueReferencingProjects;
869+
));
867870
}
868871
else {
869872
step++;
@@ -894,7 +897,7 @@ namespace ts {
894897

895898
function emit(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitResult {
896899
Debug.assertIsDefined(program);
897-
Debug.assert(step === Step.Emit);
900+
Debug.assert(step === BuildStep.Emit);
898901
// Before emitting lets backup state, so we can revert it back if there are declaration errors to handle emit and declaration errors correctly
899902
program.backupState();
900903
let declDiagnostics: Diagnostic[] | undefined;
@@ -913,16 +916,15 @@ namespace ts {
913916
// Don't emit .d.ts if there are decl file errors
914917
if (declDiagnostics) {
915918
program.restoreState();
916-
buildResult = buildErrors(
919+
({ buildResult, step } = buildErrors(
917920
state,
918921
projectPath,
919922
program,
920923
config,
921924
declDiagnostics,
922925
BuildResultFlags.DeclarationEmitErrors,
923926
"Declaration file"
924-
);
925-
step = Step.QueueReferencingProjects;
927+
));
926928
return {
927929
emitSkipped: true,
928930
diagnostics: emitResult.diagnostics
@@ -967,6 +969,24 @@ namespace ts {
967969
return emitResult;
968970
}
969971

972+
function emitBuildInfo(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
973+
Debug.assertIsDefined(program);
974+
Debug.assert(step === BuildStep.EmitBuildInfo);
975+
const emitResult = program.emitBuildInfo(writeFileCallback, cancellationToken);
976+
if (emitResult.diagnostics.length) {
977+
reportErrors(state, emitResult.diagnostics);
978+
state.diagnostics.set(projectPath, [...state.diagnostics.get(projectPath)!, ...emitResult.diagnostics]);
979+
buildResult = BuildResultFlags.EmitErrors & buildResult!;
980+
}
981+
982+
if (emitResult.emittedFiles && state.writeFileName) {
983+
emitResult.emittedFiles.forEach(name => listEmittedFile(state, config, name));
984+
}
985+
afterProgramDone(state, projectPath, program, config);
986+
step = BuildStep.QueueReferencingProjects;
987+
return emitResult;
988+
}
989+
970990
function finishEmit(
971991
emitterDiagnostics: DiagnosticCollection,
972992
emittedOutputs: FileMap<string>,
@@ -977,22 +997,20 @@ namespace ts {
977997
) {
978998
const emitDiagnostics = emitterDiagnostics.getDiagnostics();
979999
if (emitDiagnostics.length) {
980-
buildResult = buildErrors(
1000+
({ buildResult, step } = buildErrors(
9811001
state,
9821002
projectPath,
9831003
program,
9841004
config,
9851005
emitDiagnostics,
9861006
BuildResultFlags.EmitErrors,
9871007
"Emit"
988-
);
989-
step = Step.QueueReferencingProjects;
1008+
));
9901009
return emitDiagnostics;
9911010
}
9921011

9931012
if (state.writeFileName) {
9941013
emittedOutputs.forEach(name => listEmittedFile(state, config, name));
995-
if (program) listFiles(program, state.writeFileName);
9961014
}
9971015

9981016
// Update time stamps for rest of the outputs
@@ -1006,8 +1024,7 @@ namespace ts {
10061024
oldestOutputFileName
10071025
});
10081026
afterProgramDone(state, projectPath, program, config);
1009-
state.projectCompilerOptions = state.baseCompilerOptions;
1010-
step = Step.QueueReferencingProjects;
1027+
step = BuildStep.QueueReferencingProjects;
10111028
buildResult = resultFlags;
10121029
return emitDiagnostics;
10131030
}
@@ -1017,7 +1034,7 @@ namespace ts {
10171034
if (state.options.dry) {
10181035
reportStatus(state, Diagnostics.A_non_dry_build_would_update_output_of_project_0, project);
10191036
buildResult = BuildResultFlags.Success;
1020-
step = Step.QueueReferencingProjects;
1037+
step = BuildStep.QueueReferencingProjects;
10211038
return undefined;
10221039
}
10231040

@@ -1038,7 +1055,7 @@ namespace ts {
10381055

10391056
if (isString(outputFiles)) {
10401057
reportStatus(state, Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, project, relName(state, outputFiles));
1041-
step = Step.BuildInvalidatedProjectOfBundle;
1058+
step = BuildStep.BuildInvalidatedProjectOfBundle;
10421059
return invalidatedProjectOfBundle = createBuildOrUpdateInvalidedProject(
10431060
InvalidatedProjectKind.Build,
10441061
state,
@@ -1070,44 +1087,48 @@ namespace ts {
10701087
return { emitSkipped: false, diagnostics: emitDiagnostics };
10711088
}
10721089

1073-
function executeSteps(till: Step, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) {
1074-
while (step <= till && step < Step.Done) {
1090+
function executeSteps(till: BuildStep, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) {
1091+
while (step <= till && step < BuildStep.Done) {
10751092
const currentStep = step;
10761093
switch (step) {
1077-
case Step.CreateProgram:
1094+
case BuildStep.CreateProgram:
10781095
createProgram();
10791096
break;
10801097

1081-
case Step.SyntaxDiagnostics:
1098+
case BuildStep.SyntaxDiagnostics:
10821099
getSyntaxDiagnostics(cancellationToken);
10831100
break;
10841101

1085-
case Step.SemanticDiagnostics:
1102+
case BuildStep.SemanticDiagnostics:
10861103
getSemanticDiagnostics(cancellationToken);
10871104
break;
10881105

1089-
case Step.Emit:
1106+
case BuildStep.Emit:
10901107
emit(writeFile, cancellationToken, customTransformers);
10911108
break;
10921109

1093-
case Step.EmitBundle:
1110+
case BuildStep.EmitBuildInfo:
1111+
emitBuildInfo(writeFile, cancellationToken);
1112+
break;
1113+
1114+
case BuildStep.EmitBundle:
10941115
emitBundle(writeFile, customTransformers);
10951116
break;
10961117

1097-
case Step.BuildInvalidatedProjectOfBundle:
1118+
case BuildStep.BuildInvalidatedProjectOfBundle:
10981119
Debug.checkDefined(invalidatedProjectOfBundle).done(cancellationToken);
1099-
step = Step.Done;
1120+
step = BuildStep.Done;
11001121
break;
11011122

1102-
case Step.QueueReferencingProjects:
1123+
case BuildStep.QueueReferencingProjects:
11031124
queueReferencingProjects(state, project, projectPath, projectIndex, config, buildOrder, Debug.checkDefined(buildResult));
11041125
step++;
11051126
break;
11061127

11071128
// Should never be done
1108-
case Step.Done:
1129+
case BuildStep.Done:
11091130
default:
1110-
assertType<Step.Done>(step);
1131+
assertType<BuildStep.Done>(step);
11111132

11121133
}
11131134
Debug.assert(step > currentStep);
@@ -1247,23 +1268,25 @@ namespace ts {
12471268
}
12481269

12491270
function afterProgramDone<T extends BuilderProgram>(
1250-
{ host, watch, builderPrograms }: SolutionBuilderState<T>,
1271+
state: SolutionBuilderState<T>,
12511272
proj: ResolvedConfigFilePath,
12521273
program: T | undefined,
12531274
config: ParsedCommandLine
12541275
) {
12551276
if (program) {
1256-
if (host.afterProgramEmitAndDiagnostics) {
1257-
host.afterProgramEmitAndDiagnostics(program);
1277+
if (program && state.writeFileName) listFiles(program, state.writeFileName);
1278+
if (state.host.afterProgramEmitAndDiagnostics) {
1279+
state.host.afterProgramEmitAndDiagnostics(program);
12581280
}
1259-
if (watch) {
1281+
if (state.watch) {
12601282
program.releaseProgram();
1261-
builderPrograms.set(proj, program);
1283+
state.builderPrograms.set(proj, program);
12621284
}
12631285
}
1264-
else if (host.afterEmitBundle) {
1265-
host.afterEmitBundle(config);
1286+
else if (state.host.afterEmitBundle) {
1287+
state.host.afterEmitBundle(config);
12661288
}
1289+
state.projectCompilerOptions = state.baseCompilerOptions;
12671290
}
12681291

12691292
function buildErrors<T extends BuilderProgram>(
@@ -1272,16 +1295,17 @@ namespace ts {
12721295
program: T | undefined,
12731296
config: ParsedCommandLine,
12741297
diagnostics: readonly Diagnostic[],
1275-
errorFlags: BuildResultFlags,
1276-
errorType: string
1298+
buildResult: BuildResultFlags,
1299+
errorType: string,
12771300
) {
1301+
const canEmitBuildInfo = !(buildResult & BuildResultFlags.SyntaxErrors) && program && !outFile(program.getCompilerOptions());
1302+
12781303
reportAndStoreErrors(state, resolvedPath, diagnostics);
12791304
// List files if any other build error using program (emit errors already report files)
1280-
if (program && state.writeFileName) listFiles(program, state.writeFileName);
12811305
state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` });
1306+
if (canEmitBuildInfo) return { buildResult, step: BuildStep.EmitBuildInfo };
12821307
afterProgramDone(state, resolvedPath, program, config);
1283-
state.projectCompilerOptions = state.baseCompilerOptions;
1284-
return errorFlags;
1308+
return { buildResult, step: BuildStep.QueueReferencingProjects };
12851309
}
12861310

12871311
function updateModuleResolutionCache(

0 commit comments

Comments
 (0)