UNPKG

a-to-treejs

Version:

Convert array to tree fastly, and opposite.

562 lines (459 loc) 15.7 kB
import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray'; import _createForOfIteratorHelper from '@babel/runtime/helpers/esm/createForOfIteratorHelper'; import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties'; import kindOf from 'kind-of'; import isPlainObject from 'is-plain-obj'; /** whether v is among (null, undefined, '') */ function isNothing(v) { return v === null || v === undefined || v === ''; } /** The first-level element in result as the topest branch node */ function convert1$1(data, adapter) { var result = []; var nodeMap = new Map(); var _adapter$id = adapter.id, id = _adapter$id === void 0 ? 'id' : _adapter$id, _adapter$parent_id = adapter.parent_id, parent_id = _adapter$parent_id === void 0 ? 'parent_id' : _adapter$parent_id, _adapter$children_pro = adapter.children_prop, children_prop = _adapter$children_pro === void 0 ? 'children' : _adapter$children_pro, parent_prop = adapter.parent_prop, container_prop = adapter.container_prop; var createNode = function () { if (container_prop) { if (parent_prop) { return function (value) { var node = {}; node[parent_prop] = null; node[children_prop] = []; node[container_prop] = value; return node; }; } else { return function (value) { var node = {}; node[container_prop] = value; node[children_prop] = []; return node; }; } } else { if (parent_prop) { return function (value) { var node = value; node[children_prop] = []; node[parent_prop] = null; return node; }; } else { return function (value) { value[children_prop] = []; return value; }; } } }(); for (var i = 0, node, nodeId, nodePId, shouleHasParent, vnodeSelf, parent; i < data.length; i++) { node = createNode(data[i]); nodeId = data[i][id]; nodePId = data[i][parent_id]; vnodeSelf = nodeMap.get(nodeId); parent = nodeMap.get(nodePId); /** the node as the topest branch node. */ shouleHasParent = !isNothing(nodePId); if (!parent && shouleHasParent) { var vnode = createNode({}); nodeMap.set(nodePId, vnode); parent = vnode; } if (shouleHasParent && parent_prop) { node[parent_prop] = parent; } var realNode = vnodeSelf || node; if (vnodeSelf) { // merge node var c = vnodeSelf[children_prop]; Object.assign(vnodeSelf, node); vnodeSelf[children_prop] = c; } else { nodeMap.set(nodeId, node); } if (shouleHasParent) { parent[children_prop].push(realNode); } else { result.push(realNode); } } nodeMap.clear(); return result; } /** The first-level element in result as leaf node */ function convert2$1(data, adapter) { var nodeMap = new Map(); var isBranchMap = new Map(); var _adapter$id = adapter.id, id = _adapter$id === void 0 ? 'id' : _adapter$id, _adapter$parent_id = adapter.parent_id, parent_id = _adapter$parent_id === void 0 ? 'parent_id' : _adapter$parent_id, _adapter$parent_prop = adapter.parent_prop, parent_prop = _adapter$parent_prop === void 0 ? 'parent' : _adapter$parent_prop, children_prop = adapter.children_prop, container_prop = adapter.container_prop; var createNode = function () { if (container_prop) { if (children_prop) { return function (value) { var node = {}; node[parent_prop] = null; node[children_prop] = []; node[container_prop] = value; return node; }; } else { return function (value) { var node = {}; node[parent_prop] = null; node[container_prop] = value; return node; }; } } if (children_prop) { return function (value) { value[parent_prop] = null; value[children_prop] = []; return value; }; } else { return function (value) { value[parent_prop] = null; return value; }; } }(); for (var i = 0, node, nodeId, nodePId, vnodeSelf, parent, shouleHasParent; i < data.length; i++) { node = createNode(data[i]); nodeId = data[i][id]; nodePId = data[i][parent_id]; shouleHasParent = !isNothing(nodePId); isBranchMap.set(nodeId, false); shouleHasParent && isBranchMap.set(nodePId, true); parent = nodeMap.get(nodePId) || null; if (!parent && shouleHasParent) { var vnode = createNode({}); nodeMap.set(nodePId, vnode); parent = vnode; } node[parent_prop] = parent; vnodeSelf = nodeMap.get(nodeId); if (vnodeSelf) { var children = children_prop ? vnodeSelf[children_prop] : null; Object.assign(vnodeSelf, node); children && (vnodeSelf[children_prop] = children); children_prop && parent && parent[children_prop].push(vnodeSelf); } else { nodeMap.set(nodeId, node); children_prop && parent && parent[children_prop].push(node); } } var leafNodeIds = []; var _iterator = _createForOfIteratorHelper(isBranchMap.entries()), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var _step$value = _slicedToArray(_step.value, 2), _id = _step$value[0], flag = _step$value[1]; if (!flag && _id) leafNodeIds.push(_id); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var result = leafNodeIds.map(function (id) { return nodeMap.get(id); }); nodeMap.clear(); return result; } var _excluded$1 = ["strict"]; function arrayToTree$1(data) { var adapter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (kindOf(data) !== 'array') { return []; } var errors = validateAdapter$1(adapter); if (errors.length > 0) { var msg = "The 'adapter' is invalid, causes: \n ".concat(errors.join('\n')); throw new Error(msg); } var _adapter$strict = adapter.strict, strict = _adapter$strict === void 0 ? false : _adapter$strict, rest = _objectWithoutProperties(adapter, _excluded$1); if (strict) { var _catchErrors = catchErrors(data, { id: adapter.id, parent_id: adapter.parent_id }), detail = _catchErrors.detail, errorKinds = _catchErrors.errorKinds; if (detail.length > 0) { console.log('Inregular data causes: \n', detail); throw new Error('The data isn\'t regular, causes: ' + errorKinds.join(', ')); } } var _adapter$root = adapter.root, root = _adapter$root === void 0 ? 'branch' : _adapter$root; return root === 'branch' ? convert1$1(data, rest) : convert2$1(data, rest); } function validateAdapter$1(adapter) { var errors = []; if (!isPlainObject(adapter)) { errors.push("Expected 'adapter' as a plain object, instead of ".concat(kindOf(adapter), " ")); } var root = adapter.root, id = adapter.id, parent_id = adapter.parent_id, parent_prop = adapter.parent_prop, children_prop = adapter.children_prop, container_prop = adapter.container_prop; if (root && root !== 'branch' && root !== 'leaf') { errors.push("Expected 'adapter.root' must be 'branch' or 'leaf', instead of ".concat(root)); } if (id && parent_id && id === parent_id) { errors.push('The \'adapter.id\' equals with \'adapter.parent_id\'.'); } var k1 = kindOf(id); if (id && k1 !== 'string') { errors.push("Expected 'adapter.id' as a not empty string, instead of ".concat(id, ".")); } var k2 = kindOf(parent_id); if (parent_id && k2 !== 'string') { errors.push("Expected 'adapter.parent_id' as a not empty string, instead of ".concat(parent_id, ".")); } var k3 = kindOf(parent_prop); if (parent_prop && k3 !== 'string') { errors.push("Expected 'adapter.parent_prop' as a not empty string, instead of ".concat(parent_prop, ".")); } var k4 = kindOf(children_prop); if (children_prop && k4 !== 'string') { errors.push("Expected 'adapter.children_prop' as a not empty string, instead of ".concat(children_prop, ".")); } var k5 = kindOf(container_prop); if (container_prop && k5 !== 'string') { errors.push("Expected 'adapter.container_prop' as a not empty string, instead of ".concat(container_prop, ".")); } return errors; } function catchErrors(data) { var adapter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var DUPLICATED_ID_ERROR = 'duplicated id'; var UNKNOWN_PARENT_ID_ERROR = 'unknown parent_id'; var INFINITE_REF_ERROR = 'self.id equals oneself ancestor.id'; var nodeMap = new Map(); var errorLogMap = new Map(); var parentIdMap = new Map(); var _adapter$id = adapter.id, idKey = _adapter$id === void 0 ? 'id' : _adapter$id, _adapter$parent_id = adapter.parent_id, parentIdKey = _adapter$parent_id === void 0 ? 'parent_id' : _adapter$parent_id; var errorKindMap = new Map(); errorKindMap.set(DUPLICATED_ID_ERROR, false); errorKindMap.set(UNKNOWN_PARENT_ID_ERROR, false); errorKindMap.set(INFINITE_REF_ERROR, false); function addError(node, error) { errorKindMap.set(error, true); var id = node[idKey]; if (errorLogMap.has(id)) { errorLogMap.get(id).errors.push(error); } else { errorLogMap.set(id, { node: node, errors: [error] }); } } for (var i = 0, el, id, parent_id; i < data.length; i++) { el = data[i]; id = el[idKey]; parent_id = el[parentIdKey]; if (nodeMap.has(id)) { addError(el, DUPLICATED_ID_ERROR); } else { nodeMap.set(id, el); parentIdMap.set(id, parent_id); } } var _iterator = _createForOfIteratorHelper(parentIdMap.entries()), _step; try { var _loop = function _loop() { var _step$value = _slicedToArray(_step.value, 2), selfId = _step$value[0], parentId = _step$value[1]; if (!isNothing(parentId)) { var recur = function recur(ancestorId) { if (isNothing(ancestorId)) return; if (selfId === ancestorId) { addError(nodeMap.get(selfId), INFINITE_REF_ERROR); } else { recur(parentIdMap.get(ancestorId)); } }; if (!nodeMap.has(parentId)) { addError(nodeMap.get(selfId), UNKNOWN_PARENT_ID_ERROR); } recur(parentId); } }; for (_iterator.s(); !(_step = _iterator.n()).done;) { _loop(); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var errors = []; var _iterator2 = _createForOfIteratorHelper(errorLogMap.entries()), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var _step2$value = _slicedToArray(_step2.value, 2), error = _step2$value[1]; errors.push(error); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } var errorKinds = []; var _iterator3 = _createForOfIteratorHelper(errorKindMap.entries()), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _step3$value = _slicedToArray(_step3.value, 2), kind = _step3$value[0], flag = _step3$value[1]; if (flag) errorKinds.push(kind); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } nodeMap.clear(); errorLogMap.clear(); parentIdMap.clear(); errorKindMap.clear(); return { detail: errors, errorKinds: errorKinds }; } /** Flatten nodes, the first-element as the topest branch node. */ function convert1(data, adapter) { var parent_prop = adapter.parent_prop, _adapter$children_pro = adapter.children_prop, children_prop = _adapter$children_pro === void 0 ? 'children' : _adapter$children_pro, container_prop = adapter.container_prop; var result = []; function recur(nodes) { for (var i = 0, node, nodeValue, children; i < nodes.length; i++) { node = nodes[i]; nodeValue = container_prop ? node[container_prop] : node; children = node[children_prop] || []; if (!container_prop) { delete nodeValue[children_prop]; parent_prop && delete nodeValue[parent_prop]; } result.push(nodeValue); recur(children); } } recur(data); return result; } /** Flatten nodes, the first-element as leaf node. */ function convert2(data, adapter) { var _adapter$id = adapter.id, id = _adapter$id === void 0 ? 'id' : _adapter$id, _adapter$parent_prop = adapter.parent_prop, parent_prop = _adapter$parent_prop === void 0 ? 'parent' : _adapter$parent_prop, children_prop = adapter.children_prop, container_prop = adapter.container_prop; var result = []; var collected = new Map(); function recur(node) { var nodeValue = container_prop ? node[container_prop] : node; var nodeId = nodeValue[id]; if (collected.has(nodeId)) return; var parent = node[parent_prop]; if (!container_prop) { delete nodeValue[parent_prop]; children_prop && delete nodeValue[children_prop]; } collected.set(nodeId, 1); result.push(nodeValue); parent && recur(parent); } for (var i = 0; i < data.length; i++) { recur(data[i]); } collected.clear(); return result; } var _excluded = ["root"]; function treeToArray$1(data) { var adapter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (kindOf(data) !== 'array') { return []; } var errors = validateAdapter(adapter); if (errors.length > 0) { var msg = "The 'adapter' is invalid, causes: \n ".concat(errors.join('\n')); throw new Error(msg); } var _adapter$root = adapter.root, root = _adapter$root === void 0 ? 'branch' : _adapter$root, rest = _objectWithoutProperties(adapter, _excluded); return root === 'branch' ? convert1(data, rest) : convert2(data, rest); } function validateAdapter() { var adapter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var errors = []; if (!isPlainObject(adapter)) { errors.push("Expected 'adapter' as a plain object, instead of ".concat(kindOf(adapter), " ")); } var id = adapter.id, _adapter$root2 = adapter.root, root = _adapter$root2 === void 0 ? 'branch' : _adapter$root2, children_prop = adapter.children_prop, parent_prop = adapter.parent_prop, container_prop = adapter.container_prop; if (root && root !== 'branch' && root !== 'leaf') { errors.push("Expected 'adapter.root' must be 'branch' or 'leaf', instead of ".concat(root)); } var k1 = kindOf(id); if (!id || k1 !== 'string') { errors.push("Expected 'adapter.id' as a not empty string, instead of ".concat(id, ".")); } var k2 = kindOf(parent_prop); if (parent_prop && k2 !== 'string') { errors.push("Expected 'adapter.parent_prop' as a not empty string, instead of ".concat(parent_prop, ".")); } var k3 = kindOf(children_prop); if (children_prop && k3 !== 'string') { errors.push("Expected 'adapter.children_prop' as a not empty string, instead of ".concat(children_prop, ".")); } var k4 = kindOf(container_prop); if (container_prop && k4 !== 'string') { errors.push("Expected 'adapter.container_prop' as a not empty string, instead of ".concat(container_prop, ".")); } return errors; } var treeToArray = treeToArray$1; var arrayToTree = arrayToTree$1; export { arrayToTree as default, treeToArray };