Add api to build referenced projects

This commit is contained in:
Sheetal Nandi 2019-05-15 14:56:06 -07:00
parent 629bc0c04d
commit 0cb980dd6e
4 changed files with 48 additions and 11 deletions

View File

@ -275,6 +275,8 @@ namespace ts {
export interface SolutionBuilder<T extends BuilderProgram> {
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
clean(project?: string): ExitStatus;
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
cleanReferences(project?: string): ExitStatus;
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
// Currently used for testing but can be made public if needed:
@ -565,7 +567,7 @@ namespace ts {
(state.buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f))));
}
function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined) {
function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) {
const resolvedProject = project && resolveProjectName(state, project);
if (resolvedProject) {
const projectPath = toResolvedConfigFilePath(state, resolvedProject);
@ -575,7 +577,10 @@ namespace ts {
);
if (projectIndex === -1) return undefined;
}
return resolvedProject ? createBuildOrder(state, [resolvedProject]) : getBuildOrder(state);
const buildOrder = resolvedProject ? createBuildOrder(state, [resolvedProject]) : getBuildOrder(state);
Debug.assert(!onlyReferences || resolvedProject !== undefined);
Debug.assert(!onlyReferences || buildOrder[buildOrder.length - 1] === resolvedProject);
return onlyReferences ? buildOrder.slice(0, buildOrder.length - 1) : buildOrder;
}
function enableCache(state: SolutionBuilderState) {
@ -653,7 +658,6 @@ namespace ts {
if (state.options.watch) { reportWatchStatus(state, Diagnostics.Starting_compilation_in_watch_mode); }
enableCache(state);
const buildOrder = getBuildOrder(state);
reportBuildQueue(state, buildOrder);
buildOrder.forEach(configFileName =>
state.projectPendingBuild.set(
toResolvedConfigFilePath(state, configFileName),
@ -1186,7 +1190,11 @@ namespace ts {
!isIncrementalCompilation(config.options);
}
function getNextInvalidatedProject<T extends BuilderProgram>(state: SolutionBuilderState<T>, buildOrder: readonly ResolvedConfigFileName[]): InvalidatedProject<T> | undefined {
function getNextInvalidatedProject<T extends BuilderProgram>(
state: SolutionBuilderState<T>,
buildOrder: readonly ResolvedConfigFileName[],
reportQueue: boolean
): InvalidatedProject<T> | undefined {
if (!state.projectPendingBuild.size) return undefined;
if (state.currentInvalidatedProject) {
// Only if same buildOrder the currentInvalidated project can be sent again
@ -1202,6 +1210,11 @@ namespace ts {
const reloadLevel = state.projectPendingBuild.get(projectPath);
if (reloadLevel === undefined) continue;
if (reportQueue) {
reportQueue = false;
reportBuildQueue(state, buildOrder);
}
const config = parseConfigFile(state, project, projectPath);
if (!config) {
reportParseConfigFileDiagnostic(state, projectPath);
@ -1678,17 +1691,19 @@ namespace ts {
}
}
function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken): ExitStatus {
const buildOrder = getBuildOrderFor(state, project);
function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, onlyReferences?: boolean): ExitStatus {
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
setupInitialBuild(state, cancellationToken);
let reportQueue = true;
let successfulProjects = 0;
let errorProjects = 0;
while (true) {
const invalidatedProject = getNextInvalidatedProject(state, buildOrder);
const invalidatedProject = getNextInvalidatedProject(state, buildOrder, reportQueue);
if (!invalidatedProject) break;
reportQueue = false;
invalidatedProject.done(cancellationToken);
if (state.diagnostics.has(invalidatedProject.projectPath)) {
errorProjects++;
@ -1709,8 +1724,8 @@ namespace ts {
ExitStatus.Success;
}
function clean(state: SolutionBuilderState, project?: string) {
const buildOrder = getBuildOrderFor(state, project);
function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean) {
const buildOrder = getBuildOrderFor(state, project, onlyReferences);
if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped;
const { options, host } = state;
@ -1783,7 +1798,7 @@ namespace ts {
state.projectErrorsReported.clear();
reportWatchStatus(state, Diagnostics.File_change_detected_Starting_incremental_compilation);
}
const invalidatedProject = getNextInvalidatedProject(state, getBuildOrder(state));
const invalidatedProject = getNextInvalidatedProject(state, getBuildOrder(state), /*reportQueue*/ false);
if (invalidatedProject) {
invalidatedProject.done();
if (state.projectPendingBuild.size) {
@ -1923,9 +1938,11 @@ namespace ts {
return {
build: (project, cancellationToken) => build(state, project, cancellationToken),
clean: project => clean(state, project),
buildReferences: (project, cancellationToken) => build(state, project, cancellationToken, /*onlyReferences*/ true),
cleanReferences: project => clean(state, project, /*onlyReferences*/ true),
getNextInvalidatedProject: cancellationToken => {
setupInitialBuild(state, cancellationToken);
return getNextInvalidatedProject(state, getBuildOrder(state));
return getNextInvalidatedProject(state, getBuildOrder(state), /*reportQueue*/ false);
},
getBuildOrder: () => getBuildOrder(state),
getUpToDateStatusOfProject: project => {

View File

@ -417,6 +417,22 @@ namespace ts {
verifyOutputsAbsent(fs, absentOutputs);
}
});
it("building using buildReferencedProject", () => {
const fs = projFs.shadow();
const host = new fakes.SolutionBuilderHost(fs);
const builder = createSolutionBuilder(host, ["/src/tests"], { verbose: true });
builder.buildReferences("/src/tests");
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/logic/tsconfig.json"),
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/core/anotherModule.js"],
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/logic/tsconfig.json", "src/logic/index.js"],
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
);
verifyOutputsPresent(fs, [...coreOutputs, ...logicOutputs]);
verifyOutputsAbsent(fs, testsOutputs);
});
});
describe("downstream-blocked compilations", () => {

View File

@ -4610,6 +4610,8 @@ declare namespace ts {
interface SolutionBuilder<T extends BuilderProgram> {
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
clean(project?: string): ExitStatus;
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
cleanReferences(project?: string): ExitStatus;
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
}
/**

View File

@ -4610,6 +4610,8 @@ declare namespace ts {
interface SolutionBuilder<T extends BuilderProgram> {
build(project?: string, cancellationToken?: CancellationToken): ExitStatus;
clean(project?: string): ExitStatus;
buildReferences(project: string, cancellationToken?: CancellationToken): ExitStatus;
cleanReferences(project?: string): ExitStatus;
getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject<T> | undefined;
}
/**