@jbrowse/plugin-wiggle
Version:
JBrowse 2 wiggle adapters, tracks, etc.
116 lines (115 loc) • 3.89 kB
JavaScript
import { optional } from "./accessors.js";
import { Node, computeHeight } from "./hierarchy/index.js";
var preroot = { depth: -1 }, ambiguous = {}, imputed = {};
function defaultId(d) {
return d.id;
}
function defaultParentId(d) {
return d.parentId;
}
export default function () {
var id = defaultId, parentId = defaultParentId, path;
function stratify(data) {
var nodes = Array.from(data), currentId = id, currentParentId = parentId, n, d, i, root, parent, node, nodeId, nodeKey, nodeByKey = new Map;
if (path != null) {
const I = nodes.map((d, i) => normalize(path(d, i, data)));
const P = I.map(parentof);
const S = new Set(I).add("");
for (const i of P) {
if (!S.has(i)) {
S.add(i);
I.push(i);
P.push(parentof(i));
nodes.push(imputed);
}
}
currentId = (_, i) => I[i];
currentParentId = (_, i) => P[i];
}
for (i = 0, n = nodes.length; i < n; ++i) {
d = nodes[i], node = nodes[i] = new Node(d);
if ((nodeId = currentId(d, i, data)) != null && (nodeId += "")) {
nodeKey = node.id = nodeId;
nodeByKey.set(nodeKey, nodeByKey.has(nodeKey) ? ambiguous : node);
}
if ((nodeId = currentParentId(d, i, data)) != null && (nodeId += "")) {
node.parent = nodeId;
}
}
for (i = 0; i < n; ++i) {
node = nodes[i];
if (nodeId = node.parent) {
parent = nodeByKey.get(nodeId);
if (!parent)
throw new Error("missing: " + nodeId);
if (parent === ambiguous)
throw new Error("ambiguous: " + nodeId);
if (parent.children)
parent.children.push(node);
else
parent.children = [node];
node.parent = parent;
}
else {
if (root)
throw new Error("multiple roots");
root = node;
}
}
if (!root)
throw new Error("no root");
if (path != null) {
while (root.data === imputed && root.children.length === 1) {
root = root.children[0], --n;
}
for (let i = nodes.length - 1; i >= 0; --i) {
node = nodes[i];
if (node.data !== imputed)
break;
node.data = null;
}
}
root.parent = preroot;
root.eachBefore(function (node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
root.parent = null;
if (n > 0)
throw new Error("cycle");
return root;
}
stratify.id = function (x) {
return arguments.length ? (id = optional(x), stratify) : id;
};
stratify.parentId = function (x) {
return arguments.length ? (parentId = optional(x), stratify) : parentId;
};
stratify.path = function (x) {
return arguments.length ? (path = optional(x), stratify) : path;
};
return stratify;
}
function normalize(path) {
path = `${path}`;
let i = path.length;
if (slash(path, i - 1) && !slash(path, i - 2))
path = path.slice(0, -1);
return path[0] === "/" ? path : `/${path}`;
}
function parentof(path) {
let i = path.length;
if (i < 2)
return "";
while (--i > 1)
if (slash(path, i))
break;
return path.slice(0, i);
}
function slash(path, i) {
if (path[i] === "/") {
let k = 0;
while (i > 0 && path[--i] === "\\")
++k;
if ((k & 1) === 0)
return true;
}
return false;
}