66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
import { TaskDefinition } from "../services/WorkflowTemplateService";
|
|
|
|
export const getAllDescendants = (
|
|
guid: string,
|
|
tasks: TaskDefinition[],
|
|
): Set<string> => {
|
|
const descendants = new Set<string>();
|
|
|
|
const visit = (current: string) => {
|
|
for (const t of tasks) {
|
|
const preds = (t.config.predecessors as string[]) ?? [];
|
|
|
|
// If t depends on current, it's a child
|
|
if (
|
|
preds.includes(current) &&
|
|
!descendants.has(t.config.guid as string)
|
|
) {
|
|
const childGuid = t.config.guid as string;
|
|
descendants.add(childGuid);
|
|
visit(childGuid); // recursively find grandchildren
|
|
}
|
|
}
|
|
};
|
|
|
|
visit(guid);
|
|
return descendants;
|
|
};
|
|
|
|
export const sortTasksTopologically = (
|
|
tasks: TaskDefinition[],
|
|
): TaskDefinition[] => {
|
|
// Build adjacency list: task -> its predecessors
|
|
const preds = new Map<string, string[]>();
|
|
const byId = new Map<string, TaskDefinition>();
|
|
|
|
tasks.forEach((t) => {
|
|
const guid = t.config.guid as string;
|
|
byId.set(guid, t);
|
|
preds.set(guid, (t.config.predecessors as string[]) ?? []);
|
|
});
|
|
|
|
const result: TaskDefinition[] = [];
|
|
const visited = new Set<string>();
|
|
const temp = new Set<string>(); // for cycle detection (should never trigger now)
|
|
|
|
const visit = (guid: string) => {
|
|
if (visited.has(guid)) return;
|
|
if (temp.has(guid)) throw new Error("Cycle detected unexpectedly");
|
|
|
|
temp.add(guid);
|
|
|
|
for (const p of preds.get(guid) ?? []) {
|
|
visit(p);
|
|
}
|
|
|
|
temp.delete(guid);
|
|
visited.add(guid);
|
|
result.push(byId.get(guid)!);
|
|
};
|
|
|
|
// Visit all tasks
|
|
tasks.forEach((t) => visit(t.config.guid as string));
|
|
|
|
return result;
|
|
};
|