@xarc/run
Version:
concurrent or serial run npm scripts, javascript tasks, and more
79 lines (67 loc) • 2.15 kB
JavaScript
;
const each = require("lodash.foreach");
const assert = require("assert");
class NSOrder {
constructor() {
this._namespaces = [];
this._overrides = {};
}
//
// make name order before overrides (string or array of string)
//
// the ordering is kept by an integer
// each new namespace is reset with a init value (default 1)
// then the max of values of its overrides is looked up
// if its value is not > max, then it's set to max + 1
// process repeated until all override max are smaller
//
// finally sort namespace by order value
//
add(name, overrides, priority = 1) {
let overrideMap = this._overrides[name];
if (!overrideMap) {
overrideMap = this._overrides[name] = { initValue: priority, others: [] };
this._namespaces.push(name);
}
if (!overrides) {
overrides = [];
} else if (!Array.isArray(overrides)) {
overrides = [overrides];
}
overrideMap.others = overrideMap.others.concat(overrides);
// do a first level circular check
each(this._overrides, (ov, ns) => {
if (ns !== name && overrideMap.others.indexOf(ns) >= 0 && ov.others.indexOf(name) >= 0) {
throw new Error(`circular namespace override between '${name}' and '${ns}'`);
}
});
// reset all values
each(this._overrides, v => (v.value = v.initValue));
// assign value base on override map
let done;
let n = 0;
do {
done = true;
each(this._overrides, ov => {
if (ov.others.length === 0) return;
const max = ov.others.reduce(
(max, oname) =>
Math.max((this._overrides[oname] && this._overrides[oname].value) || 0, max),
1
);
if (ov.value <= max) {
done = false;
ov.value = 1 + max;
}
});
n++;
assert(
n < 10,
"calculating namespace order looped too many times, there may be circular overrides"
);
} while (!done);
this._namespaces.sort((a, b) => this._overrides[b].value - this._overrides[a].value);
return this._namespaces;
}
}
module.exports = NSOrder;