/** * Graph respects explicit dependencies * and implicit by resources (via positions) */ export const makeGraphFromTasks = (tasks: Array): Graph => { // task and blockedBy const graph: Graph = new Map(); const resourcesTasks = new Map>(); // Create graphs for (const t of tasks) { // resource and its tasks const tasksOfResource = resourcesTasks.get(t.resourceId) ?? []; tasksOfResource.push(t); resourcesTasks.set(t.resourceId, tasksOfResource); graph.set(t.id, new Set(t.blockedBy ?? [])); } // Now add deps for (const tasksOfResource of resourcesTasks.values()) { // first sort by position so links of tasks starts with higher position // then topological sort to reduce cyclic deps tasksOfResource.sort((a, b) => a.position - b.position); // is toposort needed? const sortedTasks = toposort(graph, tasksOfResource); // add to graph such edges so current node has prev as dependency (blocked by prev) let prevTask: Task | void; for (const task of sortedTasks) { if ( prevTask && prevTask.id !== task.id && // has no incoming edge as well (otherwise it will be cyclic dep) !graph.get(prevTask.id)?.has(task.id) ) { graph.get(task.id)?.add(prevTask.id); } prevTask = task; } } return graph; };