a-to-treejs
Version:
Convert array to tree fastly, and opposite.
858 lines (701 loc) • 23.5 kB
JavaScript
(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 });
}));