Skip to content

Commit 025d826

Browse files
authored
Merge pull request #30513 from Microsoft/incrementalFromCommandLine
Allow --incremental from command line
2 parents 17cedda + cf8b308 commit 025d826

File tree

35 files changed

+237
-26
lines changed

35 files changed

+237
-26
lines changed

src/compiler/builder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ namespace ts {
792792
state,
793793
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
794794
// Otherwise just affected file
795-
affected.emitBuildInfo(writeFile || host.writeFile, cancellationToken),
795+
affected.emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken),
796796
affected,
797797
/*isPendingEmitFile*/ false,
798798
/*isBuildInfoEmit*/ true
@@ -820,7 +820,7 @@ namespace ts {
820820
state,
821821
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
822822
// Otherwise just affected file
823-
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers),
823+
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers),
824824
affected,
825825
isPendingEmitFile
826826
);
@@ -862,7 +862,7 @@ namespace ts {
862862
};
863863
}
864864
}
865-
return Debug.assertDefined(state.program).emit(targetSourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
865+
return Debug.assertDefined(state.program).emit(targetSourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers);
866866
}
867867

868868
/**

src/compiler/commandLineParser.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ namespace ts {
136136
category: Diagnostics.Advanced_Options,
137137
description: Diagnostics.Show_verbose_diagnostic_information
138138
},
139+
{
140+
name: "incremental",
141+
shortName: "i",
142+
type: "boolean",
143+
category: Diagnostics.Basic_Options,
144+
description: Diagnostics.Enable_incremental_compilation,
145+
},
139146
];
140147

141148
/* @internal */
@@ -331,19 +338,11 @@ namespace ts {
331338
category: Diagnostics.Basic_Options,
332339
description: Diagnostics.Enable_project_compilation,
333340
},
334-
{
335-
name: "incremental",
336-
type: "boolean",
337-
isTSConfigOnly: true,
338-
category: Diagnostics.Basic_Options,
339-
description: Diagnostics.Enable_incremental_compilation,
340-
},
341341
{
342342
name: "tsBuildInfoFile",
343343
type: "string",
344344
isFilePath: true,
345345
paramType: Diagnostics.FILE,
346-
isTSConfigOnly: true,
347346
category: Diagnostics.Basic_Options,
348347
description: Diagnostics.Specify_file_to_store_incremental_compilation_information,
349348
},

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,6 +3072,10 @@
30723072
"category": "Error",
30733073
"code": 5073
30743074
},
3075+
"Option '--incremental' can only be specified using tsconfig, emitting to single file or when option `--tsBuildInfoFile` is specified.": {
3076+
"category": "Error",
3077+
"code": 5074
3078+
},
30753079

30763080
"Generates a sourcemap for each corresponding '.d.ts' file.": {
30773081
"category": "Message",

src/compiler/emitter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ namespace ts {
5454
/*@internal*/
5555
export function getOutputPathForBuildInfo(options: CompilerOptions) {
5656
const configFile = options.configFilePath;
57-
if (!configFile || !isIncrementalCompilation(options)) return undefined;
57+
if (!isIncrementalCompilation(options)) return undefined;
5858
if (options.tsBuildInfoFile) return options.tsBuildInfoFile;
5959
const outPath = options.outFile || options.out;
6060
let buildInfoExtensionLess: string;
6161
if (outPath) {
6262
buildInfoExtensionLess = removeFileExtension(outPath);
6363
}
6464
else {
65+
if (!configFile) return undefined;
6566
const configFileExtensionLess = removeFileExtension(configFile);
6667
buildInfoExtensionLess = options.outDir ?
6768
options.rootDir ?

src/compiler/program.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ namespace ts {
193193
getDirectories: (path: string) => system.getDirectories(path),
194194
realpath,
195195
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
196-
createDirectory: d => system.createDirectory(d)
196+
createDirectory: d => system.createDirectory(d),
197+
createHash: maybeBind(system, system.createHash)
197198
};
198199
return compilerHost;
199200
}
@@ -315,7 +316,10 @@ namespace ts {
315316
};
316317
}
317318

318-
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
319+
// tslint:disable unified-signatures
320+
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
321+
/*@internal*/ export function getPreEmitDiagnostics(program: BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
322+
export function getPreEmitDiagnostics(program: Program | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
319323
const diagnostics = [
320324
...program.getConfigFileParsingDiagnostics(),
321325
...program.getOptionsDiagnostics(cancellationToken),
@@ -330,6 +334,7 @@ namespace ts {
330334

331335
return sortAndDeduplicateDiagnostics(diagnostics);
332336
}
337+
// tslint:enable unified-signatures
333338

334339
export interface FormatDiagnosticsHost {
335340
getCurrentDirectory(): string;
@@ -2730,6 +2735,9 @@ namespace ts {
27302735
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite");
27312736
}
27322737
}
2738+
else if (options.incremental && !options.outFile && !options.out && !options.configFilePath) {
2739+
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
2740+
}
27332741

27342742
verifyProjectReferences();
27352743

src/compiler/tsbuild.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ namespace ts {
3030
listEmittedFiles?: boolean;
3131
listFiles?: boolean;
3232
pretty?: boolean;
33+
incremental?: boolean;
3334

3435
traceResolution?: boolean;
3536
/* @internal */ diagnostics?: boolean;
@@ -363,7 +364,7 @@ namespace ts {
363364
function getCompilerOptionsOfBuildOptions(buildOptions: BuildOptions): CompilerOptions {
364365
const result = {} as CompilerOptions;
365366
commonOptionsWithBuild.forEach(option => {
366-
result[option.name] = buildOptions[option.name];
367+
if (hasProperty(buildOptions, option.name)) result[option.name] = buildOptions[option.name];
367368
});
368369
return result;
369370
}

src/testRunner/unittests/config/commandLineParsing.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,26 @@ namespace ts {
365365
}
366366
});
367367
});
368+
369+
it("parse --incremental", () => {
370+
// --lib es6 0.ts
371+
assertParseResult(["--incremental", "0.ts"],
372+
{
373+
errors: [],
374+
fileNames: ["0.ts"],
375+
options: { incremental: true }
376+
});
377+
});
378+
379+
it("parse --tsBuildInfoFile", () => {
380+
// --lib es6 0.ts
381+
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "0.ts"],
382+
{
383+
errors: [],
384+
fileNames: ["0.ts"],
385+
options: { tsBuildInfoFile: "build.tsbuildinfo" }
386+
});
387+
});
368388
});
369389

370390
describe("unittests:: config:: commandLineParsing:: parseBuildOptions", () => {
@@ -456,6 +476,33 @@ namespace ts {
456476
});
457477
});
458478

479+
it("parse build with --incremental", () => {
480+
// --lib es6 0.ts
481+
assertParseResult(["--incremental", "tests"],
482+
{
483+
errors: [],
484+
projects: ["tests"],
485+
buildOptions: { incremental: true }
486+
});
487+
});
488+
489+
it("parse build with --tsBuildInfoFile", () => {
490+
// --lib es6 0.ts
491+
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "tests"],
492+
{
493+
errors: [{
494+
messageText: "Unknown build option '--tsBuildInfoFile'.",
495+
category: Diagnostics.Unknown_build_option_0.category,
496+
code: Diagnostics.Unknown_build_option_0.code,
497+
file: undefined,
498+
start: undefined,
499+
length: undefined
500+
}],
501+
projects: ["build.tsbuildinfo", "tests"],
502+
buildOptions: { }
503+
});
504+
});
505+
459506
describe("Combining options that make no sense together", () => {
460507
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
461508
it(`--${flag1} and --${flag2} together is invalid`, () => {

src/testRunner/unittests/tsbuild/outFile.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ namespace ts {
197197
dtsUnchangedExpectedReadFilesDependOrdered = undefined!;
198198
});
199199

200-
function createSolutionBuilder(host: fakes.SolutionBuilderHost) {
201-
return ts.createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: true });
200+
function createSolutionBuilder(host: fakes.SolutionBuilderHost, baseOptions?: BuildOptions) {
201+
return ts.createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: true, ...(baseOptions || {}) });
202202
}
203203

204204
function getInitialExpectedReadFiles(additionalSourceFiles?: ReadonlyArray<string>) {
@@ -446,6 +446,49 @@ namespace ts {
446446
);
447447
});
448448

449+
it("rebuilds completely when command line incremental flag changes between non dts changes", () => {
450+
const fs = outFileFs.shadow();
451+
// Make non composite third project
452+
replaceText(fs, sources[project.third][source.config], `"composite": true,`, "");
453+
454+
// Build with command line incremental
455+
const host = new fakes.SolutionBuilderHost(fs);
456+
const builder = createSolutionBuilder(host, { incremental: true });
457+
builder.buildAllProjects();
458+
host.assertDiagnosticMessages(...initialExpectedDiagnostics);
459+
host.clearDiagnostics();
460+
tick();
461+
462+
// Make non incremental build with change in file that doesnt affect dts
463+
appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);");
464+
builder.resetBuildContext({ verbose: true });
465+
builder.buildAllProjects();
466+
host.assertDiagnosticMessages(getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]),
467+
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.first][source.config], relOutputFiles[project.first][ext.js], relSources[project.first][source.ts][part.one]],
468+
[Diagnostics.Building_project_0, sources[project.first][source.config]],
469+
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, relSources[project.second][source.config], relSources[project.second][source.ts][part.one], relOutputFiles[project.second][ext.js]],
470+
[Diagnostics.Project_0_is_out_of_date_because_output_of_its_dependency_1_has_changed, relSources[project.third][source.config], "src/first"],
471+
[Diagnostics.Building_project_0, sources[project.third][source.config]]
472+
);
473+
host.clearDiagnostics();
474+
tick();
475+
476+
// Make incremental build with change in file that doesnt affect dts
477+
appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);");
478+
builder.resetBuildContext({ verbose: true, incremental: true });
479+
builder.buildAllProjects();
480+
// Builds completely because tsbuildinfo is old.
481+
host.assertDiagnosticMessages(
482+
getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]),
483+
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.first][source.config], relOutputFiles[project.first][ext.js], relSources[project.first][source.ts][part.one]],
484+
[Diagnostics.Building_project_0, sources[project.first][source.config]],
485+
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, relSources[project.second][source.config], relSources[project.second][source.ts][part.one], relOutputFiles[project.second][ext.js]],
486+
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.third][source.config], relOutputFiles[project.third][ext.buildinfo], "src/first"],
487+
[Diagnostics.Building_project_0, sources[project.third][source.config]]
488+
);
489+
host.clearDiagnostics();
490+
});
491+
449492
describe("Prepend output with .tsbuildinfo", () => {
450493
// Prologues
451494
describe("Prologues", () => {

src/tsc/tsc.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ namespace ts {
165165
reportWatchModeWithoutSysSupport();
166166
createWatchOfFilesAndCompilerOptions(commandLine.fileNames, commandLineOptions);
167167
}
168+
else if (isIncrementalCompilation(commandLineOptions)) {
169+
performIncrementalCompilation(commandLine);
170+
}
168171
else {
169172
performCompilation(commandLine.fileNames, /*references*/ undefined, commandLineOptions);
170173
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//// [a.ts]
2+
const x = 10;
3+
4+
5+
//// [a.js]
6+
var x = 10;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
=== /a.ts ===
2+
const x = 10;
3+
>x : Symbol(x, Decl(a.ts, 0, 5))
4+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== /a.ts ===
2+
const x = 10;
3+
>x : 10
4+
>10 : 10
5+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error TS5074: Option '--incremental' can only be specified using tsconfig, emitting to single file or when option `--tsBuildInfoFile` is specified.
2+
3+
4+
!!! error TS5074: Option '--incremental' can only be specified using tsconfig, emitting to single file or when option `--tsBuildInfoFile` is specified.
5+
==== tests/cases/compiler/incrementalInvalid.ts (0 errors) ====
6+
const x = 10;
7+
8+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [incrementalInvalid.ts]
2+
const x = 10;
3+
4+
5+
6+
//// [incrementalInvalid.js]
7+
var x = 10;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/compiler/incrementalInvalid.ts ===
2+
const x = 10;
3+
>x : Symbol(x, Decl(incrementalInvalid.ts, 0, 5))
4+
5+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== tests/cases/compiler/incrementalInvalid.ts ===
2+
const x = 10;
3+
>x : 10
4+
>10 : 10
5+
6+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [incrementalOut.ts]
2+
const x = 10;
3+
4+
5+
6+
//// [output.js]
7+
var x = 10;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/compiler/incrementalOut.ts ===
2+
const x = 10;
3+
>x : Symbol(x, Decl(incrementalOut.ts, 0, 5))
4+
5+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== tests/cases/compiler/incrementalOut.ts ===
2+
const x = 10;
3+
>x : 10
4+
>10 : 10
5+
6+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [a.ts]
2+
const x = 10;
3+
4+
5+
6+
7+
//// [a.js]
8+
var x = 10;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
=== /a.ts ===
2+
const x = 10;
3+
>x : Symbol(x, Decl(a.ts, 0, 5))
4+
5+
6+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
=== /a.ts ===
2+
const x = 10;
3+
>x : 10
4+
>10 : 10
5+
6+
7+

tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"compilerOptions": {
33
/* Basic Options */
4+
// "incremental": true, /* Enable incremental compilation */
45
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
56
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
67
// "lib": [], /* Specify library files to be included in the compilation. */
@@ -14,7 +15,6 @@
1415
// "outDir": "./", /* Redirect output structure to the directory. */
1516
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
1617
// "composite": true, /* Enable project compilation */
17-
// "incremental": true, /* Enable incremental compilation */
1818
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
1919
// "removeComments": true, /* Do not emit comments to output. */
2020
// "noEmit": true, /* Do not emit outputs. */

0 commit comments

Comments
 (0)