UNPKG

array-to-tree

Version:

Convert a plain array of nodes (with pointers to parent nodes) to a tree

110 lines (93 loc) 2.56 kB
'use strict'; var property = require('nested-property'); var keyBy = require('lodash.keyby'); function createTree(array, rootNodes, customID, childrenProperty) { var tree = []; for (var rootNode in rootNodes) { var node = rootNodes[rootNode]; var childNode = array[node[customID]]; if (!node && !rootNodes.hasOwnProperty(rootNode)) { continue; } if (childNode) { node[childrenProperty] = createTree( array, childNode, customID, childrenProperty ); } tree.push(node); } return tree; } function groupByParents(array, options) { var arrayByID = keyBy(array, options.customID); return array.reduce(function(prev, item) { var parentID = property.get(item, options.parentProperty); if (!parentID || !arrayByID.hasOwnProperty(parentID)) { parentID = options.rootID; } if (parentID && prev.hasOwnProperty(parentID)) { prev[parentID].push(item); return prev; } prev[parentID] = [item]; return prev; }, {}); } function isObject(o) { return Object.prototype.toString.call(o) === '[object Object]'; } function deepClone(data) { if (Array.isArray(data)) { return data.map(deepClone); } else if (isObject(data)) { return Object.keys(data).reduce(function(o, k) { o[k] = deepClone(data[k]); return o; }, {}); } else { return data; } } /** * arrayToTree * Convert a plain array of nodes (with pointers to parent nodes) to a nested * data structure * * @name arrayToTree * @function * * @param {Array} data An array of data * @param {Object} options An object containing the following fields: * * - `parentProperty` (String): A name of a property where a link to * a parent node could be found. Default: 'parent_id' * - `customID` (String): An unique node identifier. Default: 'id' * - `childrenProperty` (String): A name of a property where children nodes * are going to be stored. Default: 'children'. * * @return {Array} Result of transformation */ module.exports = function arrayToTree(data, options) { options = Object.assign( { parentProperty: 'parent_id', childrenProperty: 'children', customID: 'id', rootID: '0' }, options ); if (!Array.isArray(data)) { throw new TypeError('Expected an array but got an invalid argument'); } var grouped = groupByParents(deepClone(data), options); return createTree( grouped, grouped[options.rootID], options.customID, options.childrenProperty ); };