JSFiddle - React, Tailwind, and code Playground
JavaScript
class Job {
serialize(){
return this.n;
}
normalize(){ return this; }
};
class JobList extends Job {};
class ParallelJobList extends JobList {
constructor(jobs){
super();
this.list = new Set(jobs);
}
add(job){
this.list.add(job);
}
serialize(i=0){
let s = '{\n';
for(const x of this.list)
s += ' '.repeat(i) + ' ' + x.serialize(i+1) + '\n';
s += ' '.repeat(i) + '}';
return s;
}
normalize(){
let n = new ParallelJobList([...this.list].map(x=>x.normalize()));
if(n.list.size == 1)
return [...n.list][0];
return n;
}
};
class SequentialJobList extends JobList {
constructor(jobs){
super();
this.list = [...(jobs??[])];
}
add(job){
this.list.push(job);
}
serialize(i=0){
let s = '(\n';
for(const x of this.list)
s += ' '.repeat(i) + ' ' + x.serialize(i+1) + '\n';
s += ' '.repeat(i) + ')';
return s;
}
normalize(){
let n = new SequentialJobList(this.list.map(x=>x.normalize()));
if(n.list.length == 1)
return n.list[0];
return n;
}
};
const depends = Symbol('depends');
const dependants = Symbol('dependants');
const a = new Job(); a.n='a';
const b = new Job(); b.n='b';
const c = new Job(); c.n='c';
const d = new Job(); d.n='d';
const e = new Job(); e.n='e';
const f = new Job(); f.n='f';
const g = new Job(); g.n='g';
const h = new Job(); h.n='h';
const i = new Job(); i.n='i';
const jobs = [a,b,c,d,e,f,g,h,i];
for(let [x,y] of [
[a,d],
[b,d],
[d,e],
[d,f],
[b,f],
[g,e],
[h,i]
]){
(y[depends]??=new Set()).add(x);
(x[dependants]??=new Set()).add(y);
}
const top_nodes = new Set();
for(const a of jobs)
if(!a[depends])
top_nodes.add(a);
const component = Symbol('component');
function flood_fill(group, node){
if(node[component])
return;
node[component] = group;
for(const dnode of [...(node[dependants]??[]), ...(node[depends]??[])])
flood_fill(group, dnode);
}
{
let...