@lukeaus/plain-tree
Version:
A plain tree with a bunch of tree tools
1 lines • 25.3 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/utilsNodeTree.ts","../src/Tree.ts","../src/Node.ts","../src/create.ts"],"sourcesContent":["export const nodeData = (node: any): any => {\n return node && 'data' in node ? node.data : node;\n};\n\nexport const nodesData = (nodes: Array<any>): any => {\n return nodes.map(nodeData);\n};\n\nexport const hasChildren = (node: any): boolean => {\n return Boolean(node && node.children && node.children.length);\n};\n\nconst generateChars = (length: number): string => {\n const random11Chars = (): string =>\n Math.random()\n .toString(36)\n .substring(2, 15);\n let chars = '';\n while (chars.length < length) {\n chars += random11Chars();\n }\n return chars.slice(0, length);\n};\n\nexport const generateId = (): string => {\n return generateChars(36);\n};\n\nexport const firstArrayElement = (arr: any): any => {\n return Array.isArray(arr) && arr.length ? arr[0] : null;\n};\n\n/*\n * Return a new object without properties in disallowedKeys\n */\nexport const filterObject = (\n obj: object,\n { disallowedKeys = [] }: { disallowedKeys: Array<string> }\n): object => {\n const filteredObj = Object.keys(obj)\n .filter(key => !disallowedKeys.includes(key))\n .reduce((o, key) => {\n o[key] = obj[key];\n return o;\n }, {});\n return filteredObj;\n};\n","/*\n * Common Node and Tree utilities\n */\nimport { NodeOrNull, SerializedNode } from './types';\nimport { hasChildren } from './utils';\nimport Node from './Node';\n\nexport const nodeToJsonFormatter = (node: Node): SerializedNode => {\n const { parent, data, children, id } = node;\n const obj: SerializedNode = {\n data,\n children,\n id,\n parentId: null\n };\n parent && (obj.parentId = parent.id);\n obj.children = (node.children as Node[]).map(\n (child: Node): SerializedNode => nodeToJsonFormatter(child)\n );\n return obj;\n};\n\nexport const widthsByHeight = (node: NodeOrNull): Array<number> => {\n if (node === null) {\n return [1];\n } else {\n const counter = [1];\n let currentQueue = [node];\n let nextQueue: NodeOrNull[] = [];\n do {\n while (currentQueue.length) {\n const node = currentQueue.pop();\n hasChildren(node) && nextQueue.push(...node.children);\n }\n if (nextQueue.length) {\n counter[counter.length] = nextQueue.length;\n }\n [nextQueue, currentQueue] = [currentQueue, nextQueue];\n } while (currentQueue.length);\n return counter;\n }\n};\n\nexport const flattenByHeight = (\n node: NodeOrNull,\n fn: Function | null = null\n): any[][] => {\n let currentQueue = [node];\n let nextQueue: NodeOrNull[] = [];\n const result = [[fn(node)]];\n do {\n while (currentQueue.length) {\n const node = currentQueue.pop();\n hasChildren(node) && nextQueue.push(...node.children);\n }\n if (nextQueue.length) {\n // explicit argument passing to fn to placate TypeScript\n if (fn) {\n result[result.length] = nextQueue.map(node => fn(node));\n } else {\n result[result.length] = nextQueue;\n }\n }\n [nextQueue, currentQueue] = [currentQueue, nextQueue];\n } while (currentQueue.length);\n return result;\n};\n","import Node from './Node';\nimport { nodeData, hasChildren, firstArrayElement } from './utils';\nimport { widthsByHeight, flattenByHeight } from './utilsNodeTree';\nimport { NodeOrNull } from './types';\n\ntype TraverseReturn = void | boolean | Array<NodeOrNull>;\ntype TraverseOptions = {\n some?: boolean;\n every?: boolean;\n returnBoolean?: boolean;\n returnArray?: boolean;\n};\n\nclass Tree {\n constructor(public root: NodeOrNull = null) {\n this.root = root;\n }\n\n private _traverse(\n fn: Function,\n { some, every, returnBoolean, returnArray }: TraverseOptions = {},\n queueMethod: string\n ): TraverseReturn {\n const queue = [this.root];\n const results: Array<NodeOrNull> = [];\n let didBreak = false;\n let lastResult: undefined | boolean;\n while (queue.length) {\n const node = queue.shift();\n hasChildren(node) && queue[queueMethod](...node.children);\n if (some || every) {\n const result = fn(node);\n if (result && returnArray) {\n results.push(node);\n }\n if ((every && !result) || (some && result)) {\n didBreak = true;\n lastResult = result;\n break;\n }\n } else {\n fn(node);\n }\n }\n if (every) {\n if (returnBoolean) {\n return !didBreak;\n } else if (returnArray) {\n return results;\n }\n } else if (some) {\n if (returnBoolean) {\n return Boolean(lastResult);\n } else if (returnArray) {\n return results;\n }\n }\n }\n\n private _traverseBreathFirst(\n fn: Function,\n opts?: TraverseOptions\n ): TraverseReturn {\n return this._traverse(fn, opts, 'push');\n }\n\n private _traverseDepthFirst(\n fn: Function,\n opts?: TraverseOptions\n ): TraverseReturn {\n return this._traverse(fn, opts, 'unshift');\n }\n\n traverseBreathFirst(fn: Function): TraverseReturn {\n this._traverseBreathFirst(fn);\n }\n\n /*\n * Hit the bottom of the tree as fast as possible\n * Then go up and get parent's children, then go down again\n */\n traverseDepthFirst(fn: Function): TraverseReturn {\n this._traverseDepthFirst(fn);\n }\n\n /*\n * Return true if a single node is truthy for fn, else false\n * exit early on first truthy value\n */\n someBreathFirst(fn: Function): boolean {\n return Boolean(\n this._traverseBreathFirst(fn, {\n some: true,\n returnBoolean: true\n })\n );\n }\n\n /*\n * Return true if a single node is truthy for fn, else false\n * exit early on first truthy value\n */\n someDepthFirst(fn: Function): boolean {\n return Boolean(\n this._traverseDepthFirst(fn, {\n some: true,\n returnBoolean: true\n })\n );\n }\n\n /*\n * Return true if result of function for every node is truthy\n * exit early on first function falsey value\n */\n everyBreathFirst(fn: Function): boolean {\n return Boolean(\n this._traverseDepthFirst(fn, {\n every: true,\n returnBoolean: true\n })\n );\n }\n\n /*\n * Return true if result of function for every node is truthy\n * exit early on first function falsey value\n */\n everyDepthFirst(fn: Function): boolean {\n return Boolean(\n this._traverseDepthFirst(fn, { every: true, returnBoolean: true })\n );\n }\n\n findOneBreathFirst(fn: Function): NodeOrNull {\n const result = this._traverseBreathFirst(fn, {\n some: true,\n returnArray: true\n });\n return firstArrayElement(result);\n }\n\n findOneDepthFirst(fn: Function): NodeOrNull {\n const result = this._traverseDepthFirst(fn, {\n some: true,\n returnArray: true\n });\n return firstArrayElement(result);\n }\n\n findAllBreathFirst(fn: Function): Array<NodeOrNull> {\n const result = this._traverseBreathFirst(fn, {\n every: true,\n returnArray: true\n });\n return Array.isArray(result) ? result : [];\n }\n\n findAllDepthFirst(fn: Function): Array<NodeOrNull> {\n const result = this._traverseDepthFirst(fn, {\n every: true,\n returnArray: true\n });\n return Array.isArray(result) ? result : [];\n }\n\n flatMap(fn: Function | null = null): Array<any> {\n const acc: Array<any> = [];\n this._traverseBreathFirst((node: Node) => {\n (fn && acc.push(fn(node))) || acc.push(node);\n });\n return acc;\n }\n\n flattenData(): Array<any> {\n return this.flatMap(nodeData);\n }\n\n flattenByHeight(fn: Function | null = null): any[][] {\n return flattenByHeight(this.root, fn);\n }\n\n flattenDataByHeight(): any[][] {\n return this.flattenByHeight(nodeData);\n }\n\n /*\n * Get the width of each height of the tree from top to bottom\n */\n widthsByHeight(): Array<number> {\n return widthsByHeight(this.root);\n }\n\n /*\n * Root has height 0\n */\n nodesAtHeight(height: number): Array<NodeOrNull> {\n const counter = this.root ? [1] : [];\n let currentQueue = [this.root];\n if (counter.length === height) {\n return currentQueue;\n }\n let nextQueue: NodeOrNull[] = [];\n do {\n while (currentQueue.length) {\n const node = currentQueue.pop();\n hasChildren(node) && nextQueue.push(...node.children);\n }\n if (counter.length === height) {\n return nextQueue;\n break;\n } else {\n if (nextQueue.length) {\n counter[counter.length] = nextQueue.length;\n }\n [nextQueue, currentQueue] = [currentQueue, nextQueue];\n }\n } while (currentQueue.length);\n return [];\n }\n\n countNodes(): number {\n return this.widthsByHeight().reduce((acc, curr) => acc + curr, 0);\n }\n\n maxWidth(): number {\n return Math.max(...this.widthsByHeight());\n }\n\n height(): number {\n return this.root ? this.root.height() : 0;\n }\n\n toJson(): string {\n return this.root ? this.root.toJson() : '';\n }\n}\n\nexport default Tree;\n","import { generateId } from './utils';\nimport {\n nodeToJsonFormatter,\n widthsByHeight,\n flattenByHeight\n} from './utilsNodeTree';\nimport { NodeOrNull } from './types';\n\nclass Node {\n data: any;\n children: Node[] = [];\n id: string;\n parent: NodeOrNull;\n\n constructor(\n data: any,\n { id, parent }: { id?: string; parent?: NodeOrNull } = {}\n ) {\n this.id = id !== undefined ? id : generateId();\n this.parent = parent || null;\n this.data = data;\n this.children = [];\n }\n\n addChild(data: any, { id }: { id?: string } = {}): Node {\n const node = new Node(data, { id, parent: this });\n this.children.push(node);\n return node;\n }\n\n private _removeChildren(fn: Function): Array<Node> {\n const removedChildren: Array<Node> = [];\n this.children = this.children.filter(node => {\n if (fn(node)) {\n removedChildren.push(node);\n return false;\n }\n return true;\n });\n return removedChildren;\n }\n\n removeChildren(fn: Function): Array<Node> {\n return this._removeChildren(fn);\n }\n\n removeChildrenByData(data: any): Array<Node> {\n const fn: Function = (node: Node) => node.data === data;\n return this._removeChildren(fn);\n }\n\n removeChildrenById(id: string): Array<Node> {\n const fn: Function = (node: Node) => node.id === id;\n return this._removeChildren(fn);\n }\n\n isLeaf(): boolean {\n return this.parent !== null && !Boolean(this.children.length);\n }\n\n hasChildren(): boolean {\n return Boolean(this.children.length);\n }\n\n toJson(): string {\n const objectToSerialize = nodeToJsonFormatter(this);\n return JSON.stringify(objectToSerialize);\n }\n\n depth(): number {\n if (!this.parent) {\n return 0;\n } else {\n let depth = 0;\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let currentNode: Node = this;\n while (currentNode.parent) {\n depth += 1;\n currentNode = currentNode.parent;\n }\n return depth;\n }\n }\n\n widthsByHeight(): Array<number> {\n return widthsByHeight(this);\n }\n\n height(): number {\n return this.widthsByHeight().length - 1;\n }\n\n flattenByHeight(fn: Function | null = null): any[][] {\n return flattenByHeight(this, fn);\n }\n}\n\nexport default Node;\n","import {\n NodeOrNull,\n CreateOptions,\n CreateOptionsWithCustomChildrenKey,\n ObjectAnyProperties\n} from './types';\nimport Tree from './Tree';\nimport Node from './Node';\nimport { filterObject } from './utils';\n\nconst ID_KEY_DEFAULT = 'id';\nconst PARENT_ID_KEY_DEFAULT = 'parentId';\nconst CHILDREN_KEY_DEFAULT = 'children';\n\n/*\n * Create an array of objects representing a tree\n * Return array (as tree may have multiple roots).\n * Takes a flat array that looks like this:\n * [\n * {\n * id: 'sports',\n * name: 'Sports',\n * parentId: null\n * },\n * {\n * id: 'ball',\n * name: 'Ball',\n * parentId: 'sports'\n * },\n * {\n * id: 'non-ball',\n * name: 'Non Ball',\n * parentId: 'sports'\n * },\n * {\n * id: 'tennis',\n * name: 'Tennis',\n * parentId: 'ball'\n * }\n * ];\n * Returns a tree array that looks like this\n * [\n * {\n * \"id\": \"sports\",\n * \"name\": \"Sports\",\n * \"parentId\": null,\n * \"children\": [\n * {\n * \"id\": \"ball\",\n * \"name\": \"Ball\",\n * \"parentId\": \"sports\",\n * \"children\": [\n * {\n * \"id\": \"tennis\",\n * \"name\": \"Tennis\",\n * \"parentId\": \"ball\",\n * \"children\": []\n * }\n * ]\n * },\n * {\n * \"id\": \"non-ball\",\n * \"name\": \"Non Ball\",\n * \"parentId\": \"sports\",\n * \"children\": []\n * }\n * ]\n * }\n * ]\n */\nexport const createTreeArrayFromFlatArray = (\n data: Array<ObjectAnyProperties>,\n {\n idKey = ID_KEY_DEFAULT,\n parentIdKey = PARENT_ID_KEY_DEFAULT,\n childrenKey = CHILDREN_KEY_DEFAULT\n }: CreateOptionsWithCustomChildrenKey = {}\n): Array<ObjectAnyProperties> => {\n const treeArray: Array<ObjectAnyProperties> = [];\n const childrenOf = {};\n data.forEach((obj: any) => {\n const id = obj[idKey];\n const parentId = obj[parentIdKey];\n // obj may have children\n childrenOf[id] = childrenOf[id] || [];\n // init obj's children\n obj[childrenKey] = childrenOf[id];\n if (parentId) {\n // init obj's parent's children object\n childrenOf[parentId] = childrenOf[parentId] || [];\n // push obj into its parent's children object\n childrenOf[parentId].push(obj);\n } else {\n treeArray.push(obj);\n }\n });\n return treeArray;\n};\n\n/*\n * Take an object that looks like a node, and turn it into a node.\n * Take all properties from obj that aren't in disallowedKeys and set as\n * 'data' on the node.\n */\nexport const objectToNode = (\n obj: object,\n parent: NodeOrNull = null,\n {\n idKey = ID_KEY_DEFAULT,\n parentIdKey = PARENT_ID_KEY_DEFAULT,\n childrenKey = CHILDREN_KEY_DEFAULT\n }: CreateOptionsWithCustomChildrenKey = {}\n): Node => {\n const disallowedKeys = [idKey, parentIdKey, childrenKey];\n const data = filterObject(obj, { disallowedKeys });\n if (parent) {\n return parent.addChild(data, { id: obj[idKey] });\n } else {\n return new Node(data, { id: obj[idKey] });\n }\n};\n\n/*\n * Create a node for each element in an array, then recursively create child nodes\n */\nexport const createNodes = (\n data: Array<ObjectAnyProperties>,\n parentNode: NodeOrNull = null,\n opts: CreateOptionsWithCustomChildrenKey = {}\n): void => {\n if (!data.length) {\n return;\n }\n const { childrenKey = CHILDREN_KEY_DEFAULT } = opts;\n data.forEach(obj => {\n const node = objectToNode(obj, parentNode, opts);\n // create all the nodes for the children of this node, with this node as parent\n createNodes(obj[childrenKey], node, opts);\n });\n};\n\n/*\n * Tree array to supply (example):\n * [\n * {\n * \"id\": \"sports\",\n * \"name\": \"Sports\",\n * \"parentId\": null,\n * \"children\": [\n * {\n * \"id\": \"ball\",\n * \"name\": \"Ball\",\n * \"parentId\": \"sports\",\n * \"children\": [\n * {\n * \"id\": \"tennis\",\n * \"name\": \"Tennis\",\n * \"parentId\": \"ball\",\n * \"children\": []\n * }\n * ]\n * },\n * {\n * \"id\": \"non-ball\",\n * \"name\": \"Non Ball\",\n * \"parentId\": \"sports\",\n * \"children\": []\n * }\n * ]\n * }\n * ]\n * Return a Tree instance\n */\nexport const createTreeFromTreeArray = (\n data: Array<ObjectAnyProperties>,\n opts: CreateOptionsWithCustomChildrenKey = {}\n): Tree => {\n if (!data.length) {\n return new Tree();\n } else if (data.length > 1) {\n // TODO: add this feature\n throw new Error(\n 'Converting an array to tree only accepts an array with 0 or 1 node currently'\n );\n }\n const { childrenKey = CHILDREN_KEY_DEFAULT } = opts;\n const rootObj = data[0];\n const root = objectToNode(rootObj, null, opts);\n const tree = new Tree(root);\n createNodes(rootObj[childrenKey], root, opts);\n return tree;\n};\n\n/*\n * Map the supplied array of objects to what is required required for Node creation\n */\nconst mapFlatArray = (\n data: Array<ObjectAnyProperties>,\n { idKey, parentIdKey }: CreateOptions = {}\n): Array<ObjectAnyProperties> => {\n if (idKey || parentIdKey) {\n const disallowedKeys = [\n ...(idKey ? [idKey] : []),\n ...(parentIdKey ? [parentIdKey] : [])\n ];\n return data.map(obj => {\n const newObj = filterObject(obj, { disallowedKeys });\n idKey && (newObj[ID_KEY_DEFAULT] = obj[idKey]);\n parentIdKey && (newObj[PARENT_ID_KEY_DEFAULT] = obj[parentIdKey]);\n return newObj;\n });\n }\n return data;\n};\n\n/*\n * Flat array to supply example:\n * [\n * {\n * id: 'sports',\n * name: 'Sports',\n * parentId: null\n * },\n * {\n * id: 'ball',\n * name: 'Ball',\n * parentId: 'sports'\n * },\n * {\n * id: 'non-ball',\n * name: 'Non Ball',\n * parentId: 'sports'\n * },\n * {\n * id: 'tennis',\n * name: 'Tennis',\n * parentId: 'ball'\n * }\n * ];\n */\nexport const createTreeFromFlatArray = (\n data: Array<ObjectAnyProperties>,\n opts: CreateOptions = {}\n): any => {\n const mappedFlatArray = mapFlatArray(data, opts);\n const treeArray: Array<ObjectAnyProperties> = createTreeArrayFromFlatArray(\n mappedFlatArray\n );\n if (!treeArray.length) {\n return new Tree();\n } else if ((treeArray.length = 1)) {\n return createTreeFromTreeArray(treeArray);\n } else {\n // TODO: add functionality\n throw new Error(\n 'Converting an array to tree only accepts an array with 0 or 1 node currently'\n );\n }\n};\n"],"names":["nodeData","node","data","nodesData","nodes","map","hasChildren","Boolean","children","length","generateId","chars","Math","random","toString","substring","slice","generateChars","firstArrayElement","arr","Array","isArray","filterObject","obj","ref","Object","keys","filter","key","disallowedKeys","includes","reduce","o","nodeToJsonFormatter","parentId","parent","id","child","widthsByHeight","counter","currentQueue","nextQueue","pop","push","flattenByHeight","fn","result","Tree","constructor","root","_traverse","queueMethod","lastResult","queue","this","results","didBreak","shift","some","every","returnArray","returnBoolean","_traverseBreathFirst","opts","_traverseDepthFirst","traverseBreathFirst","traverseDepthFirst","someBreathFirst","someDepthFirst","everyBreathFirst","everyDepthFirst","findOneBreathFirst","findOneDepthFirst","findAllBreathFirst","findAllDepthFirst","flatMap","acc","flattenData","flattenDataByHeight","nodesAtHeight","height","countNodes","curr","maxWidth","max","toJson","Node","undefined","addChild","_removeChildren","removedChildren","removeChildren","removeChildrenByData","removeChildrenById","isLeaf","objectToSerialize","JSON","stringify","depth","currentNode","const","createTreeArrayFromFlatArray","treeArray","childrenOf","forEach","idKey","parentIdKey","childrenKey","objectToNode","createNodes","parentNode","createTreeFromTreeArray","Error","rootObj","tree","createTreeFromFlatArray","mappedFlatArray","newObj","mapFlatArray"],"mappings":"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"}