Skip to content

Commit 686e9a4

Browse files
committed
Do not emit .js files if only d.ts file will be impacted.
1 parent 11fd654 commit 686e9a4

File tree

2 files changed

+74
-26
lines changed

2 files changed

+74
-26
lines changed

src/compiler/builder.ts

+74-25
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ namespace ts {
6060
* Files pending to be emitted
6161
*/
6262
affectedFilesPendingEmit?: ReadonlyArray<Path> | undefined;
63+
/**
64+
* Files pending to be emitted kind.
65+
*/
66+
affectedFilesPendingEmitKind?: ReadonlyMap<BuilderFileEmit> | undefined;
6367
/**
6468
* Current index to retrieve pending affected file
6569
*/
@@ -70,6 +74,11 @@ namespace ts {
7074
hasReusableDiagnostic?: true;
7175
}
7276

77+
export const enum BuilderFileEmit {
78+
DtsOnly,
79+
Full
80+
}
81+
7382
/**
7483
* State to store the changed files, affected files and cache semantic diagnostics
7584
*/
@@ -127,7 +136,11 @@ namespace ts {
127136
/**
128137
* Files pending to be emitted
129138
*/
130-
affectedFilesPendingEmit: ReadonlyArray<Path> | undefined;
139+
affectedFilesPendingEmit: Path[] | undefined;
140+
/**
141+
* Files pending to be emitted kind.
142+
*/
143+
affectedFilesPendingEmitKind: Map<BuilderFileEmit> | undefined;
131144
/**
132145
* Current index to retrieve pending affected file
133146
*/
@@ -139,7 +152,7 @@ namespace ts {
139152
/**
140153
* Already seen emitted files
141154
*/
142-
seenEmittedFiles: Map<true> | undefined;
155+
seenEmittedFiles: Map<BuilderFileEmit> | undefined;
143156
/**
144157
* true if program has been emitted
145158
*/
@@ -186,7 +199,8 @@ namespace ts {
186199
copyEntries(changedFilesSet, state.changedFilesSet);
187200
}
188201
if (!compilerOptions.outFile && !compilerOptions.out && oldState!.affectedFilesPendingEmit) {
189-
state.affectedFilesPendingEmit = oldState!.affectedFilesPendingEmit;
202+
state.affectedFilesPendingEmit = oldState!.affectedFilesPendingEmit.slice();
203+
state.affectedFilesPendingEmitKind = cloneMapOrUndefined(oldState!.affectedFilesPendingEmitKind);
190204
state.affectedFilesPendingEmitIndex = oldState!.affectedFilesPendingEmitIndex;
191205
}
192206
}
@@ -233,7 +247,7 @@ namespace ts {
233247

234248
if (oldCompilerOptions && compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions)) {
235249
// Add all files to affectedFilesPendingEmit since emit changed
236-
addToAffectedFilesPendingEmit(state, newProgram.getSourceFiles().map(f => f.path));
250+
newProgram.getSourceFiles().forEach(f => addToAffectedFilesPendingEmit(state, f.path, BuilderFileEmit.Full));
237251
Debug.assert(state.seenAffectedFiles === undefined);
238252
state.seenAffectedFiles = createMap<true>();
239253
}
@@ -295,7 +309,8 @@ namespace ts {
295309
newState.semanticDiagnosticsFromOldState = cloneMapOrUndefined(state.semanticDiagnosticsFromOldState);
296310
newState.program = state.program;
297311
newState.compilerOptions = state.compilerOptions;
298-
newState.affectedFilesPendingEmit = state.affectedFilesPendingEmit;
312+
newState.affectedFilesPendingEmit = state.affectedFilesPendingEmit && state.affectedFilesPendingEmit.slice();
313+
newState.affectedFilesPendingEmitKind = cloneMapOrUndefined(state.affectedFilesPendingEmitKind);
299314
newState.affectedFilesPendingEmitIndex = state.affectedFilesPendingEmitIndex;
300315
newState.seenEmittedFiles = cloneMapOrUndefined(state.seenEmittedFiles);
301316
newState.programEmitComplete = state.programEmitComplete;
@@ -373,19 +388,24 @@ namespace ts {
373388
/**
374389
* Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
375390
*/
376-
function getNextAffectedFilePendingEmit(state: BuilderProgramState): SourceFile | undefined {
391+
function getNextAffectedFilePendingEmit(state: BuilderProgramState) {
377392
const { affectedFilesPendingEmit } = state;
378393
if (affectedFilesPendingEmit) {
379394
const seenEmittedFiles = state.seenEmittedFiles || (state.seenEmittedFiles = createMap());
380395
for (let i = state.affectedFilesPendingEmitIndex!; i < affectedFilesPendingEmit.length; i++) {
381396
const affectedFile = Debug.assertDefined(state.program).getSourceFileByPath(affectedFilesPendingEmit[i]);
382-
if (affectedFile && !seenEmittedFiles.has(affectedFile.path)) {
383-
// emit this file
384-
state.affectedFilesPendingEmitIndex = i;
385-
return affectedFile;
397+
if (affectedFile) {
398+
const seenKind = seenEmittedFiles.get(affectedFile.path);
399+
const emitKind = Debug.assertDefined(Debug.assertDefined(state.affectedFilesPendingEmitKind).get(affectedFile.path));
400+
if (seenKind === undefined || seenKind < emitKind) {
401+
// emit this file
402+
state.affectedFilesPendingEmitIndex = i;
403+
return { affectedFile, emitKind };
404+
}
386405
}
387406
}
388407
state.affectedFilesPendingEmit = undefined;
408+
state.affectedFilesPendingEmitKind = undefined;
389409
state.affectedFilesPendingEmitIndex = undefined;
390410
}
391411
return undefined;
@@ -442,7 +462,7 @@ namespace ts {
442462
);
443463
// If not dts emit, nothing more to do
444464
if (getEmitDeclarations(state.compilerOptions)) {
445-
addToAffectedFilesPendingEmit(state, [path]);
465+
addToAffectedFilesPendingEmit(state, path, BuilderFileEmit.DtsOnly);
446466
}
447467
}
448468
}
@@ -548,7 +568,13 @@ namespace ts {
548568
* This is called after completing operation on the next affected file.
549569
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly
550570
*/
551-
function doneWithAffectedFile(state: BuilderProgramState, affected: SourceFile | Program, isPendingEmit?: boolean, isBuildInfoEmit?: boolean, isEmitResult?: boolean) {
571+
function doneWithAffectedFile(
572+
state: BuilderProgramState,
573+
affected: SourceFile | Program,
574+
emitKind?: BuilderFileEmit,
575+
isPendingEmit?: boolean,
576+
isBuildInfoEmit?: boolean
577+
) {
552578
if (isBuildInfoEmit) {
553579
state.emittedBuildInfo = true;
554580
}
@@ -558,8 +584,8 @@ namespace ts {
558584
}
559585
else {
560586
state.seenAffectedFiles!.set((affected as SourceFile).path, true);
561-
if (isEmitResult) {
562-
(state.seenEmittedFiles || (state.seenEmittedFiles = createMap())).set((affected as SourceFile).path, true);
587+
if (emitKind !== undefined) {
588+
(state.seenEmittedFiles || (state.seenEmittedFiles = createMap())).set((affected as SourceFile).path, emitKind);
563589
}
564590
if (isPendingEmit) {
565591
state.affectedFilesPendingEmitIndex!++;
@@ -573,16 +599,23 @@ namespace ts {
573599
/**
574600
* Returns the result with affected file
575601
*/
576-
function toAffectedFileResult<T>(state: BuilderProgramState, result: T, affected: SourceFile | Program, isPendingEmit?: boolean, isBuildInfoEmit?: boolean): AffectedFileResult<T> {
577-
doneWithAffectedFile(state, affected, isPendingEmit, isBuildInfoEmit);
602+
function toAffectedFileResult<T>(state: BuilderProgramState, result: T, affected: SourceFile | Program): AffectedFileResult<T> {
603+
doneWithAffectedFile(state, affected);
578604
return { result, affected };
579605
}
580606

581607
/**
582608
* Returns the result with affected file
583609
*/
584-
function toAffectedFileEmitResult(state: BuilderProgramState, result: EmitResult, affected: SourceFile | Program, isPendingEmit?: boolean, isBuildInfoEmit?: boolean): AffectedFileResult<EmitResult> {
585-
doneWithAffectedFile(state, affected, isPendingEmit, isBuildInfoEmit, /*isEmitResult*/ true);
610+
function toAffectedFileEmitResult(
611+
state: BuilderProgramState,
612+
result: EmitResult,
613+
affected: SourceFile | Program,
614+
emitKind: BuilderFileEmit,
615+
isPendingEmit?: boolean,
616+
isBuildInfoEmit?: boolean
617+
): AffectedFileResult<EmitResult> {
618+
doneWithAffectedFile(state, affected, emitKind, isPendingEmit, isBuildInfoEmit);
586619
return { result, affected };
587620
}
588621

@@ -849,11 +882,12 @@ namespace ts {
849882
*/
850883
function emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult<EmitResult> {
851884
let affected = getNextAffectedFile(state, cancellationToken, computeHash);
885+
let emitKind = BuilderFileEmit.Full;
852886
let isPendingEmitFile = false;
853887
if (!affected) {
854888
if (!state.compilerOptions.out && !state.compilerOptions.outFile) {
855-
affected = getNextAffectedFilePendingEmit(state);
856-
if (!affected) {
889+
const pendingAffectedFile = getNextAffectedFilePendingEmit(state);
890+
if (!pendingAffectedFile) {
857891
if (state.emittedBuildInfo) {
858892
return undefined;
859893
}
@@ -865,10 +899,12 @@ namespace ts {
865899
// Otherwise just affected file
866900
affected.emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken),
867901
affected,
902+
/*emitKind*/ BuilderFileEmit.Full,
868903
/*isPendingEmitFile*/ false,
869904
/*isBuildInfoEmit*/ true
870905
);
871906
}
907+
({ affectedFile: affected, emitKind } = pendingAffectedFile);
872908
isPendingEmitFile = true;
873909
}
874910
else {
@@ -886,10 +922,17 @@ namespace ts {
886922
state,
887923
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
888924
// Otherwise just affected file
889-
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers),
925+
Debug.assertDefined(state.program).emit(
926+
affected === state.program ? undefined : affected as SourceFile,
927+
writeFile || maybeBind(host, host.writeFile),
928+
cancellationToken,
929+
emitOnlyDtsFiles || emitKind === BuilderFileEmit.DtsOnly,
930+
customTransformers
931+
),
890932
affected,
933+
emitKind,
891934
isPendingEmitFile,
892-
);
935+
);
893936
}
894937

895938
/**
@@ -953,7 +996,7 @@ namespace ts {
953996

954997
// Add file to affected file pending emit to handle for later emit time
955998
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
956-
addToAffectedFilesPendingEmit(state, [(affected as SourceFile).path]);
999+
addToAffectedFilesPendingEmit(state, (affected as SourceFile).path, BuilderFileEmit.Full);
9571000
}
9581001

9591002
// Get diagnostics for the affected file if its not ignored
@@ -1006,8 +1049,14 @@ namespace ts {
10061049
}
10071050
}
10081051

1009-
function addToAffectedFilesPendingEmit(state: BuilderProgramState, affectedFilesPendingEmit: readonly Path[]) {
1010-
state.affectedFilesPendingEmit = concatenate(state.affectedFilesPendingEmit, affectedFilesPendingEmit);
1052+
function addToAffectedFilesPendingEmit(state: BuilderProgramState, affectedFilePendingEmit: Path, kind: BuilderFileEmit) {
1053+
if (!state.affectedFilesPendingEmit) state.affectedFilesPendingEmit = [];
1054+
if (!state.affectedFilesPendingEmitKind) state.affectedFilesPendingEmitKind = createMap();
1055+
1056+
const existingKind = state.affectedFilesPendingEmitKind.get(affectedFilePendingEmit);
1057+
state.affectedFilesPendingEmit.push(affectedFilePendingEmit);
1058+
state.affectedFilesPendingEmitKind.set(affectedFilePendingEmit, existingKind || kind);
1059+
10111060
// affectedFilesPendingEmitIndex === undefined
10121061
// - means the emit state.affectedFilesPendingEmit was undefined before adding current affected files
10131062
// so start from 0 as array would be affectedFilesPendingEmit

tests/baselines/reference/tsbuild/inferredTypeFromTransitiveModule/incremental-declaration-changes/inferred-type-from-transitive-module.js

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import { LazyAction } from './bundling';
2626
export declare const lazyBar: LazyAction<() => void, typeof import("./lazyIndex")>;
2727

2828

29-
//// [/src/obj/index.js] file written with same contents
3029
//// [/src/obj/lazyIndex.d.ts] file written with same contents
3130
//// [/src/obj/lazyIndex.js] file written with same contents
3231
//// [/src/obj/tsconfig.tsbuildinfo]

0 commit comments

Comments
 (0)