UNPKG

a-to-treejs

Version:

Convert array to tree fastly, and opposite.

858 lines (701 loc) 23.5 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ATT = {})); })(this, (function (exports) { 'use strict'; function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = it.call(o); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } var toString = Object.prototype.toString; var kindOf = function kindOf(val) { if (val === void 0) return 'undefined'; if (val === null) return 'null'; var type = typeof val; if (type === 'boolean') return 'boolean'; if (type === 'string') return 'string'; if (type === 'number') return 'number'; if (type === 'symbol') return 'symbol'; if (type === 'function') { return isGeneratorFn(val) ? 'generatorfunction' : 'function'; } if (isArray(val)) return 'array'; if (isBuffer(val)) return 'buffer'; if (isArguments(val)) return 'arguments'; if (isDate(val)) return 'date'; if (isError(val)) return 'error'; if (isRegexp(val)) return 'regexp'; switch (ctorName(val)) { case 'Symbol': return 'symbol'; case 'Promise': return 'promise'; // Set, Map, WeakSet, WeakMap case 'WeakMap': return 'weakmap'; case 'WeakSet': return 'weakset'; case 'Map': return 'map'; case 'Set': return 'set'; // 8-bit typed arrays case 'Int8Array': return 'int8array'; case 'Uint8Array': return 'uint8array'; case 'Uint8ClampedArray': return 'uint8clampedarray'; // 16-bit typed arrays case 'Int16Array': return 'int16array'; case 'Uint16Array': return 'uint16array'; // 32-bit typed arrays case 'Int32Array': return 'int32array'; case 'Uint32Array': return 'uint32array'; case 'Float32Array': return 'float32array'; case 'Float64Array': return 'float64array'; } if (isGeneratorObj(val)) { return 'generator'; } // Non-plain objects type = toString.call(val); switch (type) { case '[object Object]': return 'object'; // iterators case '[object Map Iterator]': return 'mapiterator'; case '[object Set Iterator]': return 'setiterator'; case '[object String Iterator]': return 'stringiterator'; case '[object Array Iterator]': return 'arrayiterator'; } // other return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; function ctorName(val) { return typeof val.constructor === 'function' ? val.constructor.name : null; } function isArray(val) { if (Array.isArray) return Array.isArray(val); return val instanceof Array; } function isError(val) { return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); } function isDate(val) { if (val instanceof Date) return true; return typeof val.toDateString === 'function' && typeof val.getDate === 'function' && typeof val.setDate === 'function'; } function isRegexp(val) { if (val instanceof RegExp) return true; return typeof val.flags === 'string' && typeof val.ignoreCase === 'boolean' && typeof val.multiline === 'boolean' && typeof val.global === 'boolean'; } function isGeneratorFn(name, val) { return ctorName(name) === 'GeneratorFunction'; } function isGeneratorObj(val) { return typeof val.throw === 'function' && typeof val.return === 'function' && typeof val.next === 'function'; } function isArguments(val) { try { if (typeof val.length === 'number' && typeof val.callee === 'function') { return true; } } catch (err) { if (err.message.indexOf('callee') !== -1) { return true; } } return false; } /** * If you need to support Safari 5-7 (8-10 yr-old browser), * take a look at https://github.com/feross/is-buffer */ function isBuffer(val) { if (val.constructor && typeof val.constructor.isBuffer === 'function') { return val.constructor.isBuffer(val); } return false; } function isPlainObject(value) { if (typeof value !== 'object' || value === null) { return false; } const prototype = Object.getPrototypeOf(value); return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); } /** 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; exports["default"] = arrayToTree; exports.treeToArray = treeToArray; Object.defineProperty(exports, '__esModule', { value: true }); }));