Skip to content

Commit 42479ca

Browse files
committed
Maintain project references more clearly
- no need to maintain map from referencing projects to references - When queueing for downstream projects, always handle build order
1 parent c8cdb81 commit 42479ca

File tree

2 files changed

+33
-61
lines changed

2 files changed

+33
-61
lines changed

src/compiler/tsbuild.ts

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ namespace ts {
1111
message(diag: DiagnosticMessage, ...args: string[]): void;
1212
}
1313

14-
type Mapper = ReturnType<typeof createDependencyMapper>;
1514
interface DependencyGraph {
1615
buildQueue: ResolvedConfigFileName[];
17-
dependencyMap: Mapper;
16+
referencingProjectsMap: ConfigFileMap<ConfigFileMap<true>>;
1817
}
1918

2019
export interface BuildOptions {
@@ -220,40 +219,18 @@ namespace ts {
220219
}
221220
}
222221

223-
function createDependencyMapper(toPath: ToResolvedConfigFilePath) {
224-
const childToParents = createFileMap<ResolvedConfigFileName[]>(toPath);
225-
const parentToChildren = createFileMap<ResolvedConfigFileName[]>(toPath);
226-
227-
function addReference(childConfigFileName: ResolvedConfigFileName, parentConfigFileName: ResolvedConfigFileName): void {
228-
addEntry(childToParents, childConfigFileName, parentConfigFileName);
229-
addEntry(parentToChildren, parentConfigFileName, childConfigFileName);
230-
}
231-
232-
function getReferencesTo(parentConfigFileName: ResolvedConfigFileName): ResolvedConfigFileName[] {
233-
return parentToChildren.getValue(parentConfigFileName) || [];
234-
}
235-
236-
function getReferencesOf(childConfigFileName: ResolvedConfigFileName): ResolvedConfigFileName[] {
237-
return childToParents.getValue(childConfigFileName) || [];
238-
}
239-
240-
function addEntry(mapToAddTo: typeof childToParents | typeof parentToChildren, key: ResolvedConfigFileName, element: ResolvedConfigFileName) {
241-
key = normalizePath(key) as ResolvedConfigFileName;
242-
element = normalizePath(element) as ResolvedConfigFileName;
243-
let arr = mapToAddTo.getValue(key);
244-
if (arr === undefined) {
245-
mapToAddTo.setValue(key, arr = []);
246-
}
247-
if (arr.indexOf(element) < 0) {
248-
arr.push(element);
249-
}
222+
function getOrCreateValueFromConfigFileMap<T>(configFileMap: ConfigFileMap<T>, resolved: ResolvedConfigFileName, createT: () => T): T {
223+
const existingValue = configFileMap.getValue(resolved);
224+
let newValue: T | undefined;
225+
if (!existingValue) {
226+
newValue = createT();
227+
configFileMap.setValue(resolved, newValue);
250228
}
229+
return existingValue || newValue!;
230+
}
251231

252-
return {
253-
addReference,
254-
getReferencesTo,
255-
getReferencesOf,
256-
};
232+
function getOrCreateValueMapFromConfigFileMap<T>(configFileMap: ConfigFileMap<Map<T>>, resolved: ResolvedConfigFileName): Map<T> {
233+
return getOrCreateValueFromConfigFileMap<Map<T>>(configFileMap, resolved, createMap);
257234
}
258235

259236
function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine) {
@@ -529,19 +506,9 @@ namespace ts {
529506
}
530507
}
531508

532-
function getOrCreateExistingWatches<T>(resolved: ResolvedConfigFileName, allWatches: ConfigFileMap<Map<T>>) {
533-
const existingWatches = allWatches.getValue(resolved);
534-
let newWatches: Map<T> | undefined;
535-
if (!existingWatches) {
536-
newWatches = createMap();
537-
allWatches.setValue(resolved, newWatches);
538-
}
539-
return existingWatches || newWatches!;
540-
}
541-
542509
function watchWildCardDirectories(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) {
543510
updateWatchingWildcardDirectories(
544-
getOrCreateExistingWatches(resolved, allWatchedWildcardDirectories),
511+
getOrCreateValueMapFromConfigFileMap(allWatchedWildcardDirectories, resolved),
545512
createMapFromTemplate(parsed.configFileSpecs!.wildcardDirectories),
546513
(dir, flags) => {
547514
return hostWithWatch.watchDirectory(dir, fileOrDirectory => {
@@ -564,7 +531,7 @@ namespace ts {
564531

565532
function watchInputFiles(resolved: ResolvedConfigFileName, parsed: ParsedCommandLine) {
566533
mutateMap(
567-
getOrCreateExistingWatches(resolved, allWatchedInputFiles),
534+
getOrCreateValueMapFromConfigFileMap(allWatchedInputFiles, resolved),
568535
arrayToMap(parsed.fileNames, toPath),
569536
{
570537
createNewValue: (_key, input) => hostWithWatch.watchFile(input, () => {
@@ -818,7 +785,7 @@ namespace ts {
818785

819786
if (addProjToQueue(resolved, reloadLevel)) {
820787
// TODO: instead of adding the dependent project to queue right away postpone this
821-
queueBuildForDownstreamReferences(resolved, getGlobalDependencyGraph());
788+
queueBuildForDownstreamReferences(resolved);
822789
}
823790
}
824791

@@ -857,12 +824,15 @@ namespace ts {
857824
}
858825

859826
// Mark all downstream projects of this one needing to be built "later"
860-
function queueBuildForDownstreamReferences(root: ResolvedConfigFileName, dependencyGraph: DependencyGraph) {
861-
const deps = dependencyGraph.dependencyMap.getReferencesTo(root);
862-
for (const ref of deps) {
827+
function queueBuildForDownstreamReferences(root: ResolvedConfigFileName) {
828+
const dependencyGraph = getGlobalDependencyGraph();
829+
const referencingProjects = dependencyGraph.referencingProjectsMap.getValue(root);
830+
if (!referencingProjects) return;
831+
// Always use build order to queue projects
832+
for (const project of dependencyGraph.buildQueue) {
863833
// Can skip circular references
864-
if (addProjToQueue(ref)) {
865-
queueBuildForDownstreamReferences(ref, dependencyGraph);
834+
if (referencingProjects.hasKey(project) && addProjToQueue(project)) {
835+
queueBuildForDownstreamReferences(project);
866836
}
867837
}
868838
}
@@ -944,14 +914,14 @@ namespace ts {
944914
const permanentMarks = createFileMap<true>(toPath);
945915
const circularityReportStack: string[] = [];
946916
const buildOrder: ResolvedConfigFileName[] = [];
947-
const graph = createDependencyMapper(toPath);
917+
const referencingProjectsMap = createFileMap<ConfigFileMap<true>>(toPath);
948918
for (const root of roots) {
949919
visit(root);
950920
}
951921

952922
return {
953923
buildQueue: buildOrder,
954-
dependencyMap: graph,
924+
referencingProjectsMap
955925
};
956926

957927
function visit(projPath: ResolvedConfigFileName, inCircularContext = false) {
@@ -972,7 +942,9 @@ namespace ts {
972942
for (const ref of parsed.projectReferences) {
973943
const resolvedRefPath = resolveProjectName(ref.path);
974944
visit(resolvedRefPath, inCircularContext || ref.circular);
975-
graph.addReference(projPath, resolvedRefPath);
945+
// Get projects referencing resolvedRefPath and add projPath to it
946+
const referencingProjects = getOrCreateValueFromConfigFileMap(referencingProjectsMap, resolvedRefPath, () => createFileMap(toPath));
947+
referencingProjects.setValue(projPath, true);
976948
}
977949
}
978950

src/testRunner/unittests/tsbuildWatchMode.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,16 @@ namespace ts.tscWatch {
137137
...getOutputFileNames(SubProject.core, "index"),
138138
...(additionalFiles ? getOutputFileNames(SubProject.core, newFileWithoutExtension) : emptyArray)
139139
]);
140-
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
141-
const changedTests = getOutputFileStamps(host, additionalFiles);
142-
verifyChangedFiles(changedTests, changedCore, [
143-
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
144-
]);
145140
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
146141
const changedLogic = getOutputFileStamps(host, additionalFiles);
147-
verifyChangedFiles(changedLogic, changedTests, [
142+
verifyChangedFiles(changedLogic, changedCore, [
148143
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
149144
]);
145+
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
146+
const changedTests = getOutputFileStamps(host, additionalFiles);
147+
verifyChangedFiles(changedTests, changedLogic, [
148+
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
149+
]);
150150
host.checkTimeoutQueueLength(0);
151151
checkOutputErrorsIncremental(host, emptyArray);
152152
verifyWatches();

0 commit comments

Comments
 (0)