Skip to content

Commit 62584b7

Browse files
committed
Emit buildinfo when there are errors with noEmitOnError?
TODO: --build mode
1 parent bfbc388 commit 62584b7

File tree

12 files changed

+1249
-302
lines changed

12 files changed

+1249
-302
lines changed

src/compiler/builder.ts

+36-7
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ namespace ts {
148148
/**
149149
* true if build info is emitted
150150
*/
151-
emittedBuildInfo?: boolean;
151+
buildInfoEmitPending: boolean;
152152
/**
153153
* Already seen emitted files
154154
*/
@@ -250,14 +250,14 @@ namespace ts {
250250
BuilderState.getAllFilesExcludingDefaultLibraryFile(state, newProgram, /*firstSourceFile*/ undefined)
251251
.forEach(file => state.changedFilesSet.set(file.resolvedPath, true));
252252
}
253-
else if (oldCompilerOptions && compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions)) {
253+
else if (oldCompilerOptions && !outFile(compilerOptions) && compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions)) {
254254
// Add all files to affectedFilesPendingEmit since emit changed
255255
newProgram.getSourceFiles().forEach(f => addToAffectedFilesPendingEmit(state, f.resolvedPath, BuilderFileEmit.Full));
256256
Debug.assert(!state.seenAffectedFiles || !state.seenAffectedFiles.size);
257257
state.seenAffectedFiles = state.seenAffectedFiles || createMap<true>();
258258
}
259259

260-
state.emittedBuildInfo = !state.changedFilesSet.size && !state.affectedFilesPendingEmit;
260+
state.buildInfoEmitPending = !!state.changedFilesSet.size;
261261
return state;
262262
}
263263

@@ -611,7 +611,7 @@ namespace ts {
611611
isBuildInfoEmit?: boolean
612612
) {
613613
if (isBuildInfoEmit) {
614-
state.emittedBuildInfo = true;
614+
state.buildInfoEmitPending = false;
615615
}
616616
else if (affected === state.program) {
617617
state.changedFilesSet.clear();
@@ -624,6 +624,7 @@ namespace ts {
624624
}
625625
if (isPendingEmit) {
626626
state.affectedFilesPendingEmitIndex!++;
627+
state.buildInfoEmitPending = true;
627628
}
628629
else {
629630
state.affectedFilesIndex!++;
@@ -688,12 +689,14 @@ namespace ts {
688689
}
689690

690691
export type ProgramBuildInfoDiagnostic = string | [string, readonly ReusableDiagnostic[]];
692+
export type ProgramBuilderInfoFilePendingEmit = [string, BuilderFileEmit];
691693
export interface ProgramBuildInfo {
692694
fileInfos: MapLike<BuilderState.FileInfo>;
693695
options: CompilerOptions;
694696
referencedMap?: MapLike<string[]>;
695697
exportedModulesMap?: MapLike<string[]>;
696698
semanticDiagnosticsPerFile?: ProgramBuildInfoDiagnostic[];
699+
affectedFilesPendingEmit?: ProgramBuilderInfoFilePendingEmit[];
697700
}
698701

699702
/**
@@ -751,6 +754,17 @@ namespace ts {
751754
result.semanticDiagnosticsPerFile = semanticDiagnosticsPerFile;
752755
}
753756

757+
if (state.affectedFilesPendingEmit) {
758+
const affectedFilesPendingEmit: ProgramBuilderInfoFilePendingEmit[] = [];
759+
const seenFiles = createMap<true>();
760+
for (let i = state.affectedFilesPendingEmitIndex!; i < state.affectedFilesPendingEmit.length; i++) {
761+
const path = state.affectedFilesPendingEmit[i];
762+
if (!addToSeen(seenFiles, path)) continue;
763+
affectedFilesPendingEmit.push([relativeToBuildInfo(path), state.affectedFilesPendingEmitKind!.get(path)!]);
764+
}
765+
result.affectedFilesPendingEmit = affectedFilesPendingEmit;
766+
}
767+
754768
return result;
755769

756770
function relativeToBuildInfoEnsuringAbsolutePath(path: string) {
@@ -916,13 +930,23 @@ namespace ts {
916930
else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
917931
(builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
918932
(builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile;
933+
builderProgram.emitBuildInfo = emitBuildInfo;
919934
}
920935
else {
921936
notImplemented();
922937
}
923938

924939
return builderProgram;
925940

941+
function emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
942+
if (state.buildInfoEmitPending) {
943+
const result = Debug.checkDefined(state.program).emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken);
944+
state.buildInfoEmitPending = false;
945+
return result;
946+
}
947+
return emitSkippedWithNoDiagnostics;
948+
}
949+
926950
/**
927951
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
928952
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
@@ -936,7 +960,7 @@ namespace ts {
936960
if (!outFile(state.compilerOptions)) {
937961
const pendingAffectedFile = getNextAffectedFilePendingEmit(state);
938962
if (!pendingAffectedFile) {
939-
if (state.emittedBuildInfo) {
963+
if (!state.buildInfoEmitPending) {
940964
return undefined;
941965
}
942966

@@ -993,7 +1017,7 @@ namespace ts {
9931017
function emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
9941018
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
9951019
assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile);
996-
const result = handleNoEmitOptions(builderProgram, targetSourceFile, cancellationToken);
1020+
const result = handleNoEmitOptions(builderProgram, targetSourceFile, writeFile, cancellationToken);
9971021
if (result) return result;
9981022
if (!targetSourceFile) {
9991023
// Emit and report any errors we ran into.
@@ -1142,7 +1166,10 @@ namespace ts {
11421166
referencedMap: getMapOfReferencedSet(program.referencedMap, toPath),
11431167
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap, toPath),
11441168
semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => toPath(isString(value) ? value : value[0]), value => isString(value) ? emptyArray : value[1]),
1145-
hasReusableDiagnostic: true
1169+
hasReusableDiagnostic: true,
1170+
affectedFilesPendingEmit: map(program.affectedFilesPendingEmit, value => toPath(value[0])),
1171+
affectedFilesPendingEmitKind: program.affectedFilesPendingEmit && arrayToMap(program.affectedFilesPendingEmit, value => toPath(value[0]), value => value[1]),
1172+
affectedFilesPendingEmitIndex: program.affectedFilesPendingEmit && 0,
11461173
};
11471174
return {
11481175
getState: () => state,
@@ -1165,6 +1192,7 @@ namespace ts {
11651192
getCurrentDirectory: notImplemented,
11661193
emitNextAffectedFile: notImplemented,
11671194
getSemanticDiagnosticsOfNextAffectedFile: notImplemented,
1195+
emitBuildInfo: notImplemented,
11681196
close: noop,
11691197
};
11701198

@@ -1195,6 +1223,7 @@ namespace ts {
11951223
getDeclarationDiagnostics: (sourceFile, cancellationToken) => getProgram().getDeclarationDiagnostics(sourceFile, cancellationToken),
11961224
getSemanticDiagnostics: (sourceFile, cancellationToken) => getProgram().getSemanticDiagnostics(sourceFile, cancellationToken),
11971225
emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => getProgram().emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers),
1226+
emitBuildInfo: (writeFile, cancellationToken) => getProgram().emitBuildInfo(writeFile, cancellationToken),
11981227
getAllDependencies: notImplemented,
11991228
getCurrentDirectory: () => getProgram().getCurrentDirectory(),
12001229
close: noop,

src/compiler/builderPublic.ts

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ namespace ts {
9999
* in that order would be used to write the files
100100
*/
101101
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
102+
/*@internal*/
103+
emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
102104
/**
103105
* Get the current directory of the program
104106
*/

src/compiler/program.ts

+19-8
Original file line numberDiff line numberDiff line change
@@ -1585,7 +1585,7 @@ namespace ts {
15851585

15861586
function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
15871587
if (!forceDtsEmit) {
1588-
const result = handleNoEmitOptions(program, sourceFile, cancellationToken);
1588+
const result = handleNoEmitOptions(program, sourceFile, writeFileCallback, cancellationToken);
15891589
if (result) return result;
15901590
}
15911591

@@ -3638,11 +3638,17 @@ namespace ts {
36383638
}
36393639

36403640
/*@internal*/
3641-
export function handleNoEmitOptions(program: ProgramToEmitFilesAndReportErrors, sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): EmitResult | undefined {
3641+
export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
3642+
3643+
/*@internal*/
3644+
export function handleNoEmitOptions(
3645+
program: ProgramToEmitFilesAndReportErrors,
3646+
sourceFile: SourceFile | undefined,
3647+
writeFile: WriteFileCallback | undefined,
3648+
cancellationToken: CancellationToken | undefined
3649+
): EmitResult | undefined {
36423650
const options = program.getCompilerOptions();
3643-
if (options.noEmit) {
3644-
return { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
3645-
}
3651+
if (options.noEmit) return emitSkippedWithNoDiagnostics;
36463652

36473653
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
36483654
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
@@ -3659,9 +3665,14 @@ namespace ts {
36593665
diagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
36603666
}
36613667

3662-
return diagnostics.length > 0 ?
3663-
{ diagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true } :
3664-
undefined;
3668+
if (!diagnostics.length) return undefined;
3669+
let emittedFiles: string[] | undefined;
3670+
if (!sourceFile && !outFile(options)) {
3671+
const emitResult = program.emitBuildInfo(writeFile, cancellationToken);
3672+
if (emitResult.diagnostics) diagnostics = [...diagnostics, ...emitResult.diagnostics];
3673+
emittedFiles = emitResult.emittedFiles;
3674+
}
3675+
return { diagnostics, sourceMaps: undefined, emittedFiles, emitSkipped: true };
36653676
}
36663677

36673678
/*@internal*/

src/compiler/watch.ts

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ namespace ts {
127127
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[];
128128
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
129129
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
130+
emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
130131
}
131132

132133
export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) {

tests/baselines/reference/tsc/incremental/initial-build/with-noEmitOnError-semantic-errors.js

+74-7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,80 @@ Semantic diagnostics in builder refreshed for::
6464
/src/src/other.ts
6565

6666

67+
//// [/src/dev-build/tsconfig.tsbuildinfo]
68+
{
69+
"program": {
70+
"fileInfos": {
71+
"../../lib/lib.d.ts": {
72+
"version": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
73+
"signature": "3858781397-/// <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; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
74+
"affectsGlobalScope": true
75+
},
76+
"../shared/types/db.ts": {
77+
"version": "-9621097780-export interface A {\r\n name: string;\r\n}",
78+
"signature": "-6245214333-export interface A {\r\n name: string;\r\n}\r\n",
79+
"affectsGlobalScope": false
80+
},
81+
"../src/main.ts": {
82+
"version": "-11111345725-import { A } from \"../shared/types/db\";\nconst a: string = 10;",
83+
"signature": "-4882119183-export {};\r\n",
84+
"affectsGlobalScope": false
85+
},
86+
"../src/other.ts": {
87+
"version": "11373096570-console.log(\"hi\");\r\nexport { }",
88+
"signature": "-4882119183-export {};\r\n",
89+
"affectsGlobalScope": false
90+
}
91+
},
92+
"options": {
93+
"outDir": "./",
94+
"noEmitOnError": true,
95+
"incremental": true,
96+
"project": "..",
97+
"configFilePath": "../tsconfig.json"
98+
},
99+
"referencedMap": {
100+
"../src/main.ts": [
101+
"../shared/types/db.ts"
102+
]
103+
},
104+
"exportedModulesMap": {},
105+
"semanticDiagnosticsPerFile": [
106+
"../../lib/lib.d.ts",
107+
"../shared/types/db.ts",
108+
[
109+
"../src/main.ts",
110+
[
111+
{
112+
"file": "../src/main.ts",
113+
"start": 46,
114+
"length": 1,
115+
"code": 2322,
116+
"category": 1,
117+
"messageText": "Type 'number' is not assignable to type 'string'."
118+
}
119+
]
120+
],
121+
"../src/other.ts"
122+
],
123+
"affectedFilesPendingEmit": [
124+
[
125+
"../shared/types/db.ts",
126+
1
127+
],
128+
[
129+
"../src/main.ts",
130+
1
131+
],
132+
[
133+
"../src/other.ts",
134+
1
135+
]
136+
]
137+
},
138+
"version": "FakeTSVersion"
139+
}
140+
67141

68142

69143
Change:: no-change-run
@@ -90,10 +164,6 @@ Program files::
90164
/src/src/other.ts
91165

92166
Semantic diagnostics in builder refreshed for::
93-
/lib/lib.d.ts
94-
/src/shared/types/db.ts
95-
/src/src/main.ts
96-
/src/src/other.ts
97167

98168

99169

@@ -118,10 +188,7 @@ Program files::
118188
/src/src/other.ts
119189

120190
Semantic diagnostics in builder refreshed for::
121-
/lib/lib.d.ts
122-
/src/shared/types/db.ts
123191
/src/src/main.ts
124-
/src/src/other.ts
125192

126193

127194
//// [/src/dev-build/shared/types/db.js]

0 commit comments

Comments
 (0)