es-grid-template
Version:
es-grid-template
71 lines • 2.16 kB
JavaScript
import { flatMap } from "./others";
/**
* Builds a tree structure from an array of objects based on `idProp` and `parentIdProp`.
* When A[parentIdProp] === B[idProp], object A will be moved to B's `children`.
* If an object's `parentIdProp` does not match any other object's `idProp`,
* it will be treated as a top-level node in the tree.
* @example
* const array = [
* { id: 'node-1', parent: 'root' },
* { id: 'node-2', parent: 'root' },
* { id: 'node-3', parent: 'node-2' },
* { id: 'node-4', parent: 'node-2' },
* { id: 'node-5', parent: 'node-4' },
* ]
* const tree = buildTree('id', 'parent', array)
* expect(tree).toEqual([
* { id: 'node-1', parent: 'root' },
* {
* id: 'node-2',
* parent: 'root',
* children: [
* { id: 'node-3', parent: 'node-2' },
* {
* id: 'node-4',
* parent: 'node-2',
* children: [{ id: 'node-5', parent: 'node-4' }],
* },
* ],
* },
* ])
*/
export default function buildTree(idProp, parentIdProp, items) {
const wrapperMap = new Map();
const ensure = id => {
if (wrapperMap.has(id)) {
return wrapperMap.get(id);
}
// @ts-ignore
const wrapper = {
id,
parent: null,
item: null,
children: []
};
wrapperMap.set(id, wrapper);
return wrapper;
};
for (const item of items) {
const parentWrapper = ensure(item[parentIdProp]);
const itemWrapper = ensure(item[idProp]);
itemWrapper.parent = parentWrapper;
parentWrapper.children.push(itemWrapper);
itemWrapper.item = item;
}
const topLevelWrappers = flatMap(Array.from(wrapperMap.values()).filter(wrapper => wrapper.parent == null), wrapper => wrapper.children);
return unwrapRecursively(topLevelWrappers);
function unwrapRecursively(wrapperArray) {
const result = [];
for (const wrapper of wrapperArray) {
if (wrapper.children.length === 0) {
result.push(wrapper.item);
} else {
result.push({
...wrapper.item,
children: unwrapRecursively(wrapper.children)
});
}
}
return result;
}
}