Handle prepend output to be emitted in downstream project even if declaration file doesnt change

This commit is contained in:
Sheetal Nandi 2018-09-12 15:38:23 -07:00
parent 0319f103f2
commit 5696384a9f
2 changed files with 89 additions and 14 deletions

View File

@ -13,7 +13,8 @@ namespace ts {
interface DependencyGraph {
buildQueue: ResolvedConfigFileName[];
referencingProjectsMap: ConfigFileMap<ConfigFileMap<true>>;
/** value in config File map is true if project is referenced using prepend */
referencingProjectsMap: ConfigFileMap<ConfigFileMap<boolean>>;
}
export interface BuildOptions {
@ -907,17 +908,16 @@ namespace ts {
}
const buildResult = buildSingleProject(resolved);
// If declaration output changed then only queue in build for downstream projects
if (!(buildResult & BuildResultFlags.DeclarationOutputUnchanged)) {
const dependencyGraph = getGlobalDependencyGraph();
const referencingProjects = dependencyGraph.referencingProjectsMap.getValue(resolved);
if (!referencingProjects) return;
// Always use build order to queue projects
for (const project of dependencyGraph.buildQueue) {
// Can skip circular references
if (referencingProjects.hasKey(project)) {
addProjToQueue(project);
}
const dependencyGraph = getGlobalDependencyGraph();
const referencingProjects = dependencyGraph.referencingProjectsMap.getValue(resolved);
if (!referencingProjects) return;
// Always use build order to queue projects
for (const project of dependencyGraph.buildQueue) {
const prepend = referencingProjects.getValue(project);
// If the project is referenced with prepend, always build downstream projectm,
// otherwise queue it only if declaration output changed
if (prepend || (prepend !== undefined && !(buildResult & BuildResultFlags.DeclarationOutputUnchanged))) {
addProjToQueue(project);
}
}
}
@ -927,7 +927,7 @@ namespace ts {
const permanentMarks = createFileMap<true>(toPath);
const circularityReportStack: string[] = [];
const buildOrder: ResolvedConfigFileName[] = [];
const referencingProjectsMap = createFileMap<ConfigFileMap<true>>(toPath);
const referencingProjectsMap = createFileMap<ConfigFileMap<boolean>>(toPath);
for (const root of roots) {
visit(root);
}
@ -958,7 +958,7 @@ namespace ts {
visit(resolvedRefPath, inCircularContext || ref.circular);
// Get projects referencing resolvedRefPath and add projPath to it
const referencingProjects = getOrCreateValueFromConfigFileMap(referencingProjectsMap, resolvedRefPath, () => createFileMap(toPath));
referencingProjects.setValue(projPath, true);
referencingProjects.setValue(projPath, !!ref.prepend);
}
}

View File

@ -276,6 +276,81 @@ export class someClass2 { }`);
verifyWatches(host);
});
it("when referenced using prepend, builds referencing project even for non local change", () => {
const coreTsConfig: File = {
path: core[0].path,
content: JSON.stringify({
compilerOptions: { composite: true, declaration: true, outFile: "index.js" }
})
};
const coreIndex: File = {
path: core[1].path,
content: `function foo() { return 10; }`
};
const logicTsConfig: File = {
path: logic[0].path,
content: JSON.stringify({
compilerOptions: { composite: true, declaration: true, outFile: "index.js" },
references: [{ path: "../core", prepend: true }]
})
};
const logicIndex: File = {
path: logic[1].path,
content: `function bar() { return foo() + 1 };`
};
const projectFiles = [coreTsConfig, coreIndex, logicTsConfig, logicIndex];
const host = createWatchedSystem([libFile, ...projectFiles], { currentDirectory: projectsLocation });
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.logic}`]);
verifyWatches();
checkOutputErrorsInitial(host, emptyArray);
const outputFileStamps = getOutputFileStamps();
for (const stamp of outputFileStamps) {
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
}
// Make non local change
verifyChangeInCore(`${coreIndex.content}
function myFunc() { return 10; }`);
// Make local change to function bar
verifyChangeInCore(`${coreIndex.content}
function myFunc() { return 100; }`);
function verifyChangeInCore(content: string) {
const outputFileStamps = getOutputFileStamps();
host.writeFile(coreIndex.path, content);
host.checkTimeoutQueueLengthAndRun(1); // Builds core
const changedCore = getOutputFileStamps();
verifyChangedFiles(changedCore, outputFileStamps, [
...getOutputFileNames(SubProject.core, "index")
]);
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
const changedLogic = getOutputFileStamps();
verifyChangedFiles(changedLogic, changedCore, [
...getOutputFileNames(SubProject.logic, "index")
]);
host.checkTimeoutQueueLength(0);
checkOutputErrorsIncremental(host, emptyArray);
verifyWatches();
}
function getOutputFileStamps(): OutputFileStamp[] {
const result = [
...getOutputStamps(host, SubProject.core, "index"),
...getOutputStamps(host, SubProject.logic, "index"),
];
return result;
}
function verifyWatches() {
checkWatchedFiles(host, projectFiles.map(f => f.path));
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
}
});
// TODO: write tests reporting errors but that will have more involved work since file
});
}