UNPKG

@barchart/common-js

Version:
313 lines (307 loc) 9.61 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var Tree_exports = {}; __export(Tree_exports, { default: () => Tree }); module.exports = __toCommonJS(Tree_exports); var is = __toESM(require("./../lang/is.js")); class Tree { /** * @param {*} value - The value of the node. * @param {Tree=} parent - The parent node. If not supplied, this will be the root node. */ constructor(value, parent) { this._value = value; this._parent = parent || null; this._children = []; } /** * Gets the root node. * * @public * @returns {Tree} */ getRoot() { if (this.getIsRoot()) { return this; } else { return this._parent.getRoot(); } } /** * Returns the parent node. If this is the root node, a null value is returned. * * @public * @returns {Tree|null} */ getParent() { return this._parent; } /** * Returns the collection of children nodes. * * @public * @returns {Array<Tree>} */ getChildren() { return this._children; } /** * Returns the value associated with the current node. * * @public * @returns {*} */ getValue() { return this._value; } /** * Returns true if this node has no children; otherwise false. * * @public * @returns {boolean} */ getIsLeaf() { return this._children.length === 0; } /** * Returns true if this node has children; otherwise false. * * @public * @returns {boolean} */ getIsInner() { return this._children.length !== 0; } /** * Returns true if this node has no parent; otherwise false. * * @public * @returns {boolean} */ getIsRoot() { return this._parent === null; } /** * Adds a child node to the current node and returns a reference * to the child node. * * @public * @param {*} value - The value of the child. * @returns {Tree} */ addChild(value) { const returnRef = new Tree(value, this); this._children.push(returnRef); return returnRef; } /** * Removes a child node. * * @public * @param {Tree} node - The child to remove. */ removeChild(node) { for (let i = this._children.length - 1; !(i < 0); i--) { const child = this._children[i]; if (child === node) { this._children.splice(i, 1); child._parent = null; child._children = []; break; } } } /** * Removes the current node from the parent tree. Use on a root node * has no effect. * * @public */ sever() { if (this.getIsRoot()) { return; } this.getParent().removeChild(this); } /** * Searches the children nodes for the first child node that matches the * predicate. * * @public * @param {nodePredicate} predicate - A predicate that tests each child node. The predicate takes two arguments -- the node's value, and the node itself. * @returns {Tree|null} */ findChild(predicate) { let returnRef = null; for (let i = 0; i < this._children.length; i++) { let child = this._children[i]; if (predicate(child.getValue(), child)) { returnRef = child; break; } } return returnRef; } /** * Searches the tree recursively, starting with the current node. * * @public * @param {nodePredicate} predicate - A predicate that tests each child node. The predicate takes two arguments -- the node's value, and the node itself. * @param {boolean=} parentFirst - If true, the tree will be searched from parent-to-child (breadth first). Otherwise, child-to-parent (depth first). * @param {boolean=} includeCurrentNode - True, if the current node should be checked against the predicate. * @returns {Tree|null} */ search(predicate, parentFirst, includeCurrentNode) { let returnRef = null; if (parentFirst && includeCurrentNode && predicate(this.getValue(), this)) { returnRef = this; } if (returnRef === null) { for (let i = 0; i < this._children.length; i++) { const child = this._children[i]; returnRef = child.search(predicate, parentFirst, true); if (returnRef !== null) { break; } } } if (returnRef === null && !parentFirst && includeCurrentNode && predicate(this.getValue(), this)) { returnRef = this; } return returnRef; } /** * Walks the children of the current node, running an action on each node. * * @public * @param {nodeAction} walkAction - A action to apply to each node. The action takes two arguments -- the node's value, and the node itself. * @param {boolean=} parentFirst - If true, the tree will be searched from parent-to-child (breadth first). Otherwise, child-to-parent (depth first). * @param {boolean=} includeCurrentNode - True if the current node should be applied to the action. */ walk(walkAction, parentFirst, includeCurrentNode) { const predicate = (value, node) => { walkAction(value, node); return false; }; this.search(predicate, parentFirst, includeCurrentNode); } /** * Returns the count of all descendant nodes by walking the tree. Consequently, this * function is not efficient. * * @public * @returns {number} */ count() { let count = 0; this.walk(() => count++, true, true); return count; } /** * Climbs the parents of the current node -- current node up to the root node, running an action on each node. * * @public * @param {nodeAction} climbAction - A action to apply to each node. The action takes two arguments -- the node's value, and the node itself. * @param {boolean=} includeCurrentNode - True if the current node should be applied to the action. */ climb(climbAction, includeCurrentNode) { if (includeCurrentNode) { climbAction(this.getValue(), this); } if (this._parent !== null) { this._parent.climb(climbAction, true); } } /** * Climbs the tree, evaluating each parent until a predicate is matched. Once matched, * the {@link Tree} node is returned. Otherwise, if the predicate cannot be matched, * a null value is returned. * * @public * @param {nodePredicate} predicate - A predicate that tests each child node. The predicate takes two arguments -- the node's value, and the node itself. * @param {boolean=} includeCurrentNode - If true, the predicate will be applied to the current node. * @returns {Tree|null} */ findParent(predicate, includeCurrentNode) { let returnRef; if (is.boolean(includeCurrentNode) && includeCurrentNode && predicate(this.getValue(), this)) { returnRef = this; } else if (this._parent !== null) { returnRef = this._parent.findParent(predicate, true); } else { returnRef = null; } return returnRef; } /** * Creates a representation of the tree using JavaScript objects and arrays. * * @public * @param {Function=} valueConverter - An optional function for converting the value of each node. * @param {boolean=} omitEmptyChildren - If true, empty children arrays will be excluded from output. * @returns {object} */ toJSObj(valueConverter, omitEmptyChildren) { let valueConverterToUse; if (is.fn(valueConverter)) { valueConverterToUse = valueConverter; } else { valueConverterToUse = (x) => x; } const converted = { value: valueConverterToUse(this._value) }; if (!(is.boolean(omitEmptyChildren) && omitEmptyChildren && this._children.length === 0)) { converted.children = this._children.map((child) => child.toJSObj(valueConverter, omitEmptyChildren)); } return converted; } /** * Returns a string representation. * * @public * @returns {string} */ toString() { return "[Tree]"; } } { const cjsExports = module.exports; const cjsDefaultExport = cjsExports && cjsExports.__esModule ? cjsExports.default : cjsExports; if (cjsDefaultExport && (typeof cjsDefaultExport === 'function' || typeof cjsDefaultExport === 'object')) { Object.keys(cjsExports).forEach((key) => { if (key !== 'default' && key !== '__esModule') { cjsDefaultExport[key] = cjsExports[key]; } }); } module.exports = cjsDefaultExport; }