Skip to content

Instantly share code, notes, and snippets.

@trescenzi
Created March 15, 2019 11:19
Show Gist options
  • Save trescenzi/b98666294e473ddddfe086a6cdb20799 to your computer and use it in GitHub Desktop.
Save trescenzi/b98666294e473ddddfe086a6cdb20799 to your computer and use it in GitHub Desktop.
Rough sketch of a directed graph router.
class GraphRouter {
constructor(state) {
this.vertices = {};
this.sortedVerticies = [];
this.visitedVerticies = [];
}
addNode(path, dependencies, resolve) {
const vertex = {
name: path.split('/').pop(),
path,
edges: dependencies,
resolve,
};
this.vertices[path] = vertex;
}
_visitForSort(vertex) {
if (this.visitedVerticies[vertex.path] === 2) return;
if (this.visitedVerticies[vertex.path] === 1) throw new Error(`CYCLE FOUND AT ${vertex}`);
this.visitedVerticies[vertex.path] = 1;
vertex.edges.length && vertex.edges.map((v) => this._visitForSort(this.vertices[v]));
this.visitedVerticies[vertex.path] = 2;
this.sortedVerticies.push(vertex);
}
sort() {
// Reverse topological sort
this.sortedVerticies = [];
this.visitedVerticies = [];
const vertices = Object.values(this.vertices);
while (vertices.length > 0) {
this._visitForSort(vertices.shift());
}
}
_sortIfNotSorted() {
if (Object.keys(this.vertices).length > this.sortedVerticies.length) {
this.sort();
}
}
get order() {
this._sortIfNotSorted();
return this.sortedVerticies;
}
next() {
this._sortIfNotSorted();
}
goTo(route) {
this._sortIfNotSorted();
const verticies = this.sortedVerticies;
let curr = verticies.shift();
while (curr.path !== route) {
console.log('Visiting', curr.path);
curr.resolve('some render root', {internet: true}, () => {});
curr = verticies.shift();
}
console.log('Visiting', curr.path);
curr.resolve('some render root', {internet: true}, () => {});
}
_findRouteIndex(route) {
this._sortIfNotSorted();
return this.sortedVerticies.findIndex(route);
}
}
const router = new GraphRouter();
const internetDeps = [];
const tvDeps = ['/tv-internet/internet'];
const phoneDeps = ['/tv-internet/tv'];
const tvInterenetDeps =
['/tv-internet/internet', '/tv-internet/tv', '/tv-internet/phone', '/sign-up'];
const doneDeps = ['/tv-internet', '/promotions', '/sign-up'];
const resolveNow = (_, __, resolve) => resolve(true);
router.addNode('/tv-internet/internet', internetDeps, (div, state, resolve) => {
if (state.internet) {
return resolve();
} else {
div.innerHTML = `<div> internet </div>`
}
});
router.addNode('/tv-internet/tv', tvDeps, resolveNow);
router.addNode('/tv-internet/phone', phoneDeps, resolveNow);
router.addNode('/tv-internet', tvInterenetDeps, resolveNow);
router.addNode('/promotions', ['/sign-up'], resolveNow);
router.addNode('/sign-up', [], resolveNow);
router.addNode('/done', doneDeps, resolveNow)
console.log(router.order.map((v) => v.path));
router.goTo('/promotions');
/*
[ '/tv-internet/internet',
'/tv-internet/tv',
'/tv-internet/phone',
'/sign-up',
'/tv-internet',
'/promotions',
'/done' ]
Visiting /tv-internet/internet
Visiting /tv-internet/tv
Visiting /tv-internet/phone
Visiting /sign-up
Visiting /tv-internet
Visiting /promotions
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment