import {required} from "./accessors.js"; import {Node, computeHeight} from "./hierarchy/index.js"; var keyPrefix = "$", // Protect against keys like “__proto__”. preroot = {depth: -1}, ambiguous = {}; function defaultId(d) { return d.id; } function defaultParentId(d) { return d.parentId; } export default function() { var id = defaultId, parentId = defaultParentId; function stratify(data) { var d, i, n = data.length, root, parent, node, nodes = new Array(n), nodeId, nodeKey, nodeByKey = {}; for (i = 0; i < n; ++i) { d = data[i], node = nodes[i] = new Node(d); if ((nodeId = id(d, i, data)) != null && (nodeId += "")) { nodeKey = keyPrefix + (node.id = nodeId); nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node; } } for (i = 0; i < n; ++i) { node = nodes[i], nodeId = parentId(data[i], i, data); if (nodeId == null || !(nodeId += "")) { if (root) throw new Error("multiple roots"); root = node; } else { parent = nodeByKey[keyPrefix + 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; } } if (!root) throw new Error("no root"); 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 = required(x), stratify) : id; }; stratify.parentId = function(x) { return arguments.length ? (parentId = required(x), stratify) : parentId; }; return stratify; }