Skip to content

Commit 0cb980d

Browse files
committed
Add api to build referenced projects
1 parent 629bc0c commit 0cb980d

File tree

4 files changed

+48
-11
lines changed

4 files changed

+48
-11
lines changed

src/compiler/tsbuild.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ namespace ts {
275275
export interface SolutionBuilder<T extends BuilderProgram> {
276276
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
277277
clean(project?: string): ExitStatus;
278+
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
279+
cleanReferences(project?: string): ExitStatus;
278280
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
279281

280282
// Currently used for testing but can be made public if needed:
@@ -565,7 +567,7 @@ namespace ts {
565567
(state.buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f))));
566568
}
567569

568-
function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined) {
570+
function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) {
569571
const resolvedProject = project && resolveProjectName(state, project);
570572
if (resolvedProject) {
571573
const projectPath = toResolvedConfigFilePath(state, resolvedProject);
@@ -575,7 +577,10 @@ namespace ts {
575577
);
576578
if (projectIndex === -1) return undefined;
577579
}
578-
return resolvedProject ? createBuildOrder(state, [resolvedProject]) : getBuildOrder(state);
580+
const buildOrder = resolvedProject ? createBuildOrder(state, [resolvedProject]) : getBuildOrder(state);
581+
Debug.assert(!onlyReferences || resolvedProject !== undefined);
582+
Debug.assert(!onlyReferences || buildOrder[buildOrder.length - 1] === resolvedProject);
583+
return onlyReferences ? buildOrder.slice(0, buildOrder.length - 1) : buildOrder;
579584
}
580585

581586
function enableCache(state: SolutionBuilderState) {
@@ -653,7 +658,6 @@ namespace ts {
653658
if (state.options.watch) { reportWatchStatus(state, Diagnostics.Starting_compilation_in_watch_mode); }
654659
enableCache(state);
655660
const buildOrder = getBuildOrder(state);
656-
reportBuildQueue(state, buildOrder);
657661
buildOrder.forEach(configFileName =>
658662
state.projectPendingBuild.set(
659663
toResolvedConfigFilePath(state, configFileName),
@@ -1186,7 +1190,11 @@ namespace ts {
11861190
!isIncrementalCompilation(config.options);
11871191
}
11881192

1189-
function getNextInvalidatedProject<T extends BuilderProgram>(state: SolutionBuilderState<T>, buildOrder: readonly ResolvedConfigFileName[]): InvalidatedProject<T> | undefined {
1193+
function getNextInvalidatedProject<T extends BuilderProgram>(
1194+
state: SolutionBuilderState<T>,
1195+
buildOrder: readonly ResolvedConfigFileName[],
1196+
reportQueue: boolean
1197+
): InvalidatedProject<T> | undefined {
11901198
if (!state.projectPendingBuild.size) return undefined;
11911199
if (state.currentInvalidatedProject) {
11921200
// Only if same buildOrder the currentInvalidated project can be sent again
@@ -1202,6 +1210,11 @@ namespace ts {
12021210
const reloadLevel = state.projectPendingBuild.get(projectPath);
12031211
if (reloadLevel === undefined) continue;
12041212

1213+
if (reportQueue) {
1214+
reportQueue = false;
1215+
reportBuildQueue(state, buildOrder);
1216+
}
1217+
12051218
const config = parseConfigFile(state, project, projectPath);
12061219
if (!config) {
12071220
reportParseConfigFileDiagnostic(state, projectPath);
@@ -1678,17 +1691,19 @@ namespace ts {
16781691
}
16791692
}
16801693

1681-
function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken): ExitStatus {
1682-
const buildOrder = getBuildOrderFor(state, project);
1694+
function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, onlyReferences?: boolean): ExitStatus {
1695+
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
16831696
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
16841697

16851698
setupInitialBuild(state, cancellationToken);
16861699

1700+
let reportQueue = true;
16871701
let successfulProjects = 0;
16881702
let errorProjects = 0;
16891703
while (true) {
1690-
const invalidatedProject = getNextInvalidatedProject(state, buildOrder);
1704+
const invalidatedProject = getNextInvalidatedProject(state, buildOrder, reportQueue);
16911705
if (!invalidatedProject) break;
1706+
reportQueue = false;
16921707
invalidatedProject.done(cancellationToken);
16931708
if (state.diagnostics.has(invalidatedProject.projectPath)) {
16941709
errorProjects++;
@@ -1709,8 +1724,8 @@ namespace ts {
17091724
ExitStatus.Success;
17101725
}
17111726

1712-
function clean(state: SolutionBuilderState, project?: string) {
1713-
const buildOrder = getBuildOrderFor(state, project);
1727+
function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean) {
1728+
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
17141729
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
17151730

17161731
const { options, host } = state;
@@ -1783,7 +1798,7 @@ namespace ts {
17831798
state.projectErrorsReported.clear();
17841799
reportWatchStatus(state, Diagnostics.File_change_detected_Starting_incremental_compilation);
17851800
}
1786-
const invalidatedProject = getNextInvalidatedProject(state, getBuildOrder(state));
1801+
const invalidatedProject = getNextInvalidatedProject(state, getBuildOrder(state), /*reportQueue*/ false);
17871802
if (invalidatedProject) {
17881803
invalidatedProject.done();
17891804
if (state.projectPendingBuild.size) {
@@ -1923,9 +1938,11 @@ namespace ts {
19231938
return {
19241939
build: (project, cancellationToken) => build(state, project, cancellationToken),
19251940
clean: project => clean(state, project),
1941+
buildReferences: (project, cancellationToken) => build(state, project, cancellationToken, /*onlyReferences*/ true),
1942+
cleanReferences: project => clean(state, project, /*onlyReferences*/ true),
19261943
getNextInvalidatedProject: cancellationToken => {
19271944
setupInitialBuild(state, cancellationToken);
1928-
return getNextInvalidatedProject(state, getBuildOrder(state));
1945+
return getNextInvalidatedProject(state, getBuildOrder(state), /*reportQueue*/ false);
19291946
},
19301947
getBuildOrder: () => getBuildOrder(state),
19311948
getUpToDateStatusOfProject: project => {

src/testRunner/unittests/tsbuild/sample.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,22 @@ namespace ts {
417417
verifyOutputsAbsent(fs, absentOutputs);
418418
}
419419
});
420+
421+
it("building using buildReferencedProject", () => {
422+
const fs = projFs.shadow();
423+
const host = new fakes.SolutionBuilderHost(fs);
424+
const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true });
425+
builder.buildReferences("/src/tests");
426+
host.assertDiagnosticMessages(
427+
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json"),
428+
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"],
429+
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
430+
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"],
431+
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
432+
);
433+
verifyOutputsPresent(fs, [...coreOutputs, ...logicOutputs]);
434+
verifyOutputsAbsent(fs, testsOutputs);
435+
});
420436
});
421437

422438
describe("downstream-blocked compilations", () => {

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,6 +4610,8 @@ declare namespace ts {
46104610
interface SolutionBuilder<T extends BuilderProgram> {
46114611
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
46124612
clean(project?: string): ExitStatus;
4613+
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
4614+
cleanReferences(project?: string): ExitStatus;
46134615
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
46144616
}
46154617
/**

tests/baselines/reference/api/typescript.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,6 +4610,8 @@ declare namespace ts {
46104610
interface SolutionBuilder<T extends BuilderProgram> {
46114611
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
46124612
clean(project?: string): ExitStatus;
4613+
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
4614+
cleanReferences(project?: string): ExitStatus;
46134615
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
46144616
}
46154617
/**

0 commit comments

Comments
 (0)