You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

simple-tree-utils

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

simple-tree-utils - npm Package Compare versions

Comparing version

to
3.1.0

8

CHANGELOG.md

@@ -5,4 +5,12 @@ ### Changelog

#### [3.1.0](https://github.com/Raiper34/simple-tree-utils/compare/3.0.1...3.1.0)
- feat(deleteby): add deleteBy method to delete nodes by given callback [`c62afc9`](https://github.com/Raiper34/simple-tree-utils/commit/c62afc9059b2f7c6a81ef488ede2c419f43a948c)
- feat(computepaths): add computePaths method to compute paths for all nodes [`e30e6a8`](https://github.com/Raiper34/simple-tree-utils/commit/e30e6a8713471a0fc9976f6e5b16248fec767198)
- feat(foreach): add forEach moethod to iterate over each nodes [`1352f44`](https://github.com/Raiper34/simple-tree-utils/commit/1352f44a409d7726ea2e68a3983b188f555bf912)
#### [3.0.1](https://github.com/Raiper34/simple-tree-utils/compare/3.0.0...3.0.1)
> 11 April 2025
- fix(tree2list): ability to parse tree with nodes that does not contain children property [`30e8f49`](https://github.com/Raiper34/simple-tree-utils/commit/30e8f4957a9ef10cb63d367b3121299d4f491b8f)

@@ -9,0 +17,0 @@

31

dist/simple-tree-utils.d.ts

@@ -79,2 +79,8 @@ /**

/**
* Method to iterate over all nodes
* @param tree - tree structure to iterate over
* @param fn - callback function to perform
*/
forEach(tree: any[], fn: (item: any) => any): void;
/**
* Method to find all nodes in tree structure by given callback function

@@ -94,5 +100,17 @@ * @param tree - tree structure to search in

* @param id - identifier of node to delete
* @returns deleted node, if nothing deleted then returns null
*/
delete(tree: any[], id: any): any;
/**
* Method to delete node in tree by given callback function (mutable operation!)
* @param tree - tree structure for node deleting
* @param fn - callback function to remove all nodes
* @returns deleted nodes
* @example
* ```ts
* utils.deleteBy(tree, item => item.id === myId);
* ```
*/
deleteBy(tree: any[] | undefined, fn: (item: any) => boolean): any[];
/**
* Method to add new node to tree, node will be added as last child (mutable operation!)

@@ -106,3 +124,3 @@ * @param tree - tree structure for node adding

/**
* Method to add new node to tree, node will be added as last child (mutable operation!)
* Method to add new node to tree, node will be added as first child (mutable operation!)
* @param tree - tree structure for node adding

@@ -298,2 +316,13 @@ * @param parentId - identifier of parent node, null if new node should be on root level

/**
* Method to compute paths for nodes (mutable operation)
* path property will be added into each node
* e.g. {path: "parent/child"...}
* @param tree - tree structure
* @param pathComputationProperty - property to use for path computation
* @param delimiter - to delimit path
* @param pathProperty - property where path will be stored
* @param originPath - path of top level nodes
*/
computePaths(tree: any[], pathComputationProperty: string, delimiter?: string, pathProperty?: string, originPath?: string): void;
/**
* Helper method to deep clone object

@@ -300,0 +329,0 @@ * @param obj - object to be cloned

2

dist/simple-tree-utils.iife.js

@@ -1,1 +0,1 @@

var simpleTreeUtils=function(l){"use strict";const u="id",g="parentId",P="children";class o{constructor(e){this.idProp=(e==null?void 0:e.idProp)||u,this.parentIdProp=(e==null?void 0:e.parentIdProp)||g,this.childrenProp=(e==null?void 0:e.childrenProp)||P}list2Tree(e,t=null){return e.filter(r=>r[this.parentIdProp]===t).map(r=>({...r,[this.childrenProp]:this.list2Tree(e,r[this.idProp])}))}tree2List(e){return this._tree2List(o.deepCopy(e))}_tree2List(e,t=null){return o.deepCopy(e).reduce((r,i)=>{const{[this.childrenProp]:s,...n}=i;return[...r,{...n,[this.parentIdProp]:t},...s!=null&&s.length?this._tree2List(s,n[this.idProp]):[]]},[])}get(e,t){return this.find(e,r=>r[this.idProp]===t)}find(e,t){const r=e.find(i=>t(i));return r||e.reduce((i,s)=>i||this.find(s[this.childrenProp]||[],t),null)}filter(e,t){const r=e.filter(i=>t(i));return e.reduce((i,s)=>[...i,...s[this.childrenProp].length?this.filter(s[this.childrenProp],t):[]],r)}delete(e,t){const r=e.findIndex(i=>i[this.idProp]==t);return r!=-1?e.splice(r,1)[0]:e.reduce((i,s)=>i||this.delete(s[this.childrenProp],t),null)}add(e,t,r,...i){this._add("push",e,t,r,...i)}addUnshift(e,t,r,...i){this._add("unshift",e,t,r,...i)}_add(e,t,r,i,...s){if(r==null){t[e](i,...s);return}const n=t.findIndex(h=>h[this.idProp]==r);if(n!=-1){t[n][this.childrenProp][e]({[this.childrenProp]:[],...i},...s.map(h=>({[this.childrenProp]:[],...h})));return}t.forEach(h=>this.add(h[this.childrenProp],r,i,...s))}edit(e,t,r){const i=e.findIndex(s=>s[this.idProp]==t);if(i!=-1){e[i]={[this.idProp]:e[i][this.idProp],[this.childrenProp]:[],...r};return}e.forEach(s=>this.edit(s[this.childrenProp],t,r))}getDescendants(e,t){const r=this.get(e,t);return r?this._getDescendants(r):[]}_getDescendants(e){return[...e[this.childrenProp],...e[this.childrenProp].reduce((t,r)=>[...t,...this._getDescendants(r)],[])]}getAncestors(e,t){const r=[];let i=this.getParent(e,t);for(;i;)r.push(i),i=this.getParent(e,i[this.idProp]);return r.reverse()}getPathNodes(e,t){return this.getAncestors(e,t)}getParent(e,t){return this._getParent(e,t)}_getParent(e,t,r=null){return e.find(s=>s[this.idProp]===t)?r:e.reduce((s,n)=>s||this._getParent(n[this.childrenProp]||[],t,n),null)}getChildren(e,t){var r;return((r=this.get(e,t))==null?void 0:r[this.childrenProp])||[]}getNeighbours(e,t){return[this.getParent(e,t),...this.getChildren(e,t)].filter(r=>r)}getSiblings(e,t){var r;return(((r=this.getParent(e,t))==null?void 0:r[this.childrenProp])||[]).filter(i=>i[this.idProp]!==t)}getLeafs(e,t){return this.filter(this.getSubTree(e,t),r=>!r[this.childrenProp].length)}getSubTree(e,t){return this.getChildren(e,t)}getSize(e,t){return this.tree2List(this.getSubTree(e,t)).length+1}getBreath(e,t){return this.getLeafs(e,t).length}getDepth(e,t){return this.getPathNodes(e,t).length}getLevel(e,t){return this.getDepth(e,t)+1}getDegree(e,t){return this.getChildren(e,t).length}getTreeDegree(e){return e.reduce((t,r)=>Math.max(t,r[this.childrenProp].length,this.getTreeDegree(r[this.childrenProp])),0)}getNodesAtLevel(e,t){return this._getNodesAtLevel(e,t)}_getNodesAtLevel(e,t,r=0){return e.reduce((i,s)=>[...i,...t===r?[s]:[],...r<t?this._getNodesAtLevel(s[this.childrenProp],t,r+1):[]],[])}getWidth(e,t){return this.getNodesAtLevel(e,t).length}getHeight(e,t){return this.getHeightNode(this.getSubTree(e,t))}getHeightNode(e,t=0){return e.reduce((r,i)=>Math.max(r,this.getHeightNode(i[this.childrenProp],t+1)),t)}getDistance(e,t,r){const i=[...this.getPathNodes(e,t),this.get(e,t)],s=[...this.getPathNodes(e,r),this.get(e,r)],n=[...i].reverse().find(d=>s.includes(d));if(!n)return-1;const h=i.findIndex(d=>d.id===n.id),p=s.findIndex(d=>d.id===n.id);return i.length-h-1+(s.length-p-1)}static deepCopy(e){return JSON.parse(JSON.stringify(e))}}return l.TreeUtils=o,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}),l}({});
var simpleTreeUtils=function(l){"use strict";const u="id",P="parentId",g="children";class o{constructor(e){this.idProp=(e==null?void 0:e.idProp)||u,this.parentIdProp=(e==null?void 0:e.parentIdProp)||P,this.childrenProp=(e==null?void 0:e.childrenProp)||g}list2Tree(e,t=null){return e.filter(r=>r[this.parentIdProp]===t).map(r=>({...r,[this.childrenProp]:this.list2Tree(e,r[this.idProp])}))}tree2List(e){return this._tree2List(o.deepCopy(e))}_tree2List(e,t=null){return o.deepCopy(e).reduce((r,s)=>{const{[this.childrenProp]:i,...h}=s;return[...r,{...h,[this.parentIdProp]:t},...i!=null&&i.length?this._tree2List(i,h[this.idProp]):[]]},[])}get(e,t){return this.find(e,r=>r[this.idProp]===t)}find(e,t){const r=e.find(s=>t(s));return r||e.reduce((s,i)=>s||this.find(i[this.childrenProp]||[],t),null)}forEach(e,t){e==null||e.forEach(r=>{t(r),this.forEach(r[this.childrenProp],t)})}filter(e,t){const r=e.filter(s=>t(s));return e.reduce((s,i)=>[...s,...i[this.childrenProp].length?this.filter(i[this.childrenProp],t):[]],r)}delete(e,t){return this.deleteBy(e,r=>r[this.idProp]===t)[0]||null}deleteBy(e=[],t){const s=e.filter(i=>t(i)).map((i,h)=>h).reverse().reduce((i,h)=>[...i,...e.splice(h,1)],[]);return e.reduce((i,h)=>[...i,...this.deleteBy(h[this.childrenProp],t)],s)}add(e,t,r,...s){this._add("push",e,t,r,...s)}addUnshift(e,t,r,...s){this._add("unshift",e,t,r,...s)}_add(e,t,r,s,...i){if(r==null){t[e](s,...i);return}const h=t.findIndex(n=>n[this.idProp]==r);if(h!=-1){t[h][this.childrenProp][e]({[this.childrenProp]:[],...s},...i.map(n=>({[this.childrenProp]:[],...n})));return}t.forEach(n=>this.add(n[this.childrenProp],r,s,...i))}edit(e,t,r){const s=e.findIndex(i=>i[this.idProp]==t);if(s!=-1){e[s]={[this.idProp]:e[s][this.idProp],[this.childrenProp]:[],...r};return}e.forEach(i=>this.edit(i[this.childrenProp],t,r))}getDescendants(e,t){const r=this.get(e,t);return r?this._getDescendants(r):[]}_getDescendants(e){return[...e[this.childrenProp],...e[this.childrenProp].reduce((t,r)=>[...t,...this._getDescendants(r)],[])]}getAncestors(e,t){const r=[];let s=this.getParent(e,t);for(;s;)r.push(s),s=this.getParent(e,s[this.idProp]);return r.reverse()}getPathNodes(e,t){return this.getAncestors(e,t)}getParent(e,t){return this._getParent(e,t)}_getParent(e,t,r=null){return e.find(i=>i[this.idProp]===t)?r:e.reduce((i,h)=>i||this._getParent(h[this.childrenProp]||[],t,h),null)}getChildren(e,t){var r;return((r=this.get(e,t))==null?void 0:r[this.childrenProp])||[]}getNeighbours(e,t){return[this.getParent(e,t),...this.getChildren(e,t)].filter(r=>r)}getSiblings(e,t){var r;return(((r=this.getParent(e,t))==null?void 0:r[this.childrenProp])||[]).filter(s=>s[this.idProp]!==t)}getLeafs(e,t){return this.filter(this.getSubTree(e,t),r=>!r[this.childrenProp].length)}getSubTree(e,t){return this.getChildren(e,t)}getSize(e,t){return this.tree2List(this.getSubTree(e,t)).length+1}getBreath(e,t){return this.getLeafs(e,t).length}getDepth(e,t){return this.getPathNodes(e,t).length}getLevel(e,t){return this.getDepth(e,t)+1}getDegree(e,t){return this.getChildren(e,t).length}getTreeDegree(e){return e.reduce((t,r)=>Math.max(t,r[this.childrenProp].length,this.getTreeDegree(r[this.childrenProp])),0)}getNodesAtLevel(e,t){return this._getNodesAtLevel(e,t)}_getNodesAtLevel(e,t,r=0){return e.reduce((s,i)=>[...s,...t===r?[i]:[],...r<t?this._getNodesAtLevel(i[this.childrenProp],t,r+1):[]],[])}getWidth(e,t){return this.getNodesAtLevel(e,t).length}getHeight(e,t){return this.getHeightNode(this.getSubTree(e,t))}getHeightNode(e,t=0){return e.reduce((r,s)=>Math.max(r,this.getHeightNode(s[this.childrenProp],t+1)),t)}getDistance(e,t,r){const s=[...this.getPathNodes(e,t),this.get(e,t)],i=[...this.getPathNodes(e,r),this.get(e,r)],h=[...s].reverse().find(d=>i.includes(d));if(!h)return-1;const n=s.findIndex(d=>d.id===h.id),c=i.findIndex(d=>d.id===h.id);return s.length-n-1+(i.length-c-1)}computePaths(e,t,r="/",s="path",i="/"){e==null||e.forEach(h=>{h[s]=i,this.computePaths(h[this.childrenProp],t,r,s,`${h.path}${h[t]}${r}`)})}static deepCopy(e){return JSON.parse(JSON.stringify(e))}}return l.TreeUtils=o,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}),l}({});

@@ -1,2 +0,2 @@

const g = "id", p = "parentId", P = "children";
const p = "id", P = "parentId", u = "children";
class o {

@@ -8,3 +8,3 @@ /**

constructor(e) {
this.idProp = (e == null ? void 0 : e.idProp) || g, this.parentIdProp = (e == null ? void 0 : e.parentIdProp) || p, this.childrenProp = (e == null ? void 0 : e.childrenProp) || P;
this.idProp = (e == null ? void 0 : e.idProp) || p, this.parentIdProp = (e == null ? void 0 : e.parentIdProp) || P, this.childrenProp = (e == null ? void 0 : e.childrenProp) || u;
}

@@ -39,8 +39,8 @@ /**

_tree2List(e, t = null) {
return o.deepCopy(e).reduce((r, i) => {
const { [this.childrenProp]: s, ...n } = i;
return o.deepCopy(e).reduce((r, s) => {
const { [this.childrenProp]: i, ...h } = s;
return [
...r,
{ ...n, [this.parentIdProp]: t },
...s != null && s.length ? this._tree2List(s, n[this.idProp]) : []
{ ...h, [this.parentIdProp]: t },
...i != null && i.length ? this._tree2List(i, h[this.idProp]) : []
];

@@ -69,5 +69,5 @@ }, []);

find(e, t) {
const r = e.find((i) => t(i));
const r = e.find((s) => t(s));
return r || e.reduce(
(i, s) => i || this.find(s[this.childrenProp] || [], t),
(s, i) => s || this.find(i[this.childrenProp] || [], t),
null

@@ -77,2 +77,12 @@ );

/**
* Method to iterate over all nodes
* @param tree - tree structure to iterate over
* @param fn - callback function to perform
*/
forEach(e, t) {
e == null || e.forEach((r) => {
t(r), this.forEach(r[this.childrenProp], t);
});
}
/**
* Method to find all nodes in tree structure by given callback function

@@ -88,4 +98,4 @@ * @param tree - tree structure to search in

filter(e, t) {
const r = e.filter((i) => t(i));
return e.reduce((i, s) => [...i, ...s[this.childrenProp].length ? this.filter(s[this.childrenProp], t) : []], r);
const r = e.filter((s) => t(s));
return e.reduce((s, i) => [...s, ...i[this.childrenProp].length ? this.filter(i[this.childrenProp], t) : []], r);
}

@@ -96,8 +106,22 @@ /**

* @param id - identifier of node to delete
* @returns deleted node, if nothing deleted then returns null
*/
delete(e, t) {
const r = e.findIndex((i) => i[this.idProp] == t);
return r != -1 ? e.splice(r, 1)[0] : e.reduce((i, s) => i || this.delete(s[this.childrenProp], t), null);
return this.deleteBy(e, (r) => r[this.idProp] === t)[0] || null;
}
/**
* Method to delete node in tree by given callback function (mutable operation!)
* @param tree - tree structure for node deleting
* @param fn - callback function to remove all nodes
* @returns deleted nodes
* @example
* ```ts
* utils.deleteBy(tree, item => item.id === myId);
* ```
*/
deleteBy(e = [], t) {
const s = e.filter((i) => t(i)).map((i, h) => h).reverse().reduce((i, h) => [...i, ...e.splice(h, 1)], []);
return e.reduce((i, h) => [...i, ...this.deleteBy(h[this.childrenProp], t)], s);
}
/**
* Method to add new node to tree, node will be added as last child (mutable operation!)

@@ -109,7 +133,7 @@ * @param tree - tree structure for node adding

*/
add(e, t, r, ...i) {
this._add("push", e, t, r, ...i);
add(e, t, r, ...s) {
this._add("push", e, t, r, ...s);
}
/**
* Method to add new node to tree, node will be added as last child (mutable operation!)
* Method to add new node to tree, node will be added as first child (mutable operation!)
* @param tree - tree structure for node adding

@@ -120,4 +144,4 @@ * @param parentId - identifier of parent node, null if new node should be on root level

*/
addUnshift(e, t, r, ...i) {
this._add("unshift", e, t, r, ...i);
addUnshift(e, t, r, ...s) {
this._add("unshift", e, t, r, ...s);
}

@@ -132,16 +156,16 @@ /**

*/
_add(e, t, r, i, ...s) {
_add(e, t, r, s, ...i) {
if (r == null) {
t[e](i, ...s);
t[e](s, ...i);
return;
}
const n = t.findIndex((h) => h[this.idProp] == r);
if (n != -1) {
t[n][this.childrenProp][e](
{ [this.childrenProp]: [], ...i },
...s.map((h) => ({ [this.childrenProp]: [], ...h }))
const h = t.findIndex((n) => n[this.idProp] == r);
if (h != -1) {
t[h][this.childrenProp][e](
{ [this.childrenProp]: [], ...s },
...i.map((n) => ({ [this.childrenProp]: [], ...n }))
);
return;
}
t.forEach((h) => this.add(h[this.childrenProp], r, i, ...s));
t.forEach((n) => this.add(n[this.childrenProp], r, s, ...i));
}

@@ -155,8 +179,8 @@ /**

edit(e, t, r) {
const i = e.findIndex((s) => s[this.idProp] == t);
if (i != -1) {
e[i] = { [this.idProp]: e[i][this.idProp], [this.childrenProp]: [], ...r };
const s = e.findIndex((i) => i[this.idProp] == t);
if (s != -1) {
e[s] = { [this.idProp]: e[s][this.idProp], [this.childrenProp]: [], ...r };
return;
}
e.forEach((s) => this.edit(s[this.childrenProp], t, r));
e.forEach((i) => this.edit(i[this.childrenProp], t, r));
}

@@ -193,5 +217,5 @@ /**

const r = [];
let i = this.getParent(e, t);
for (; i; )
r.push(i), i = this.getParent(e, i[this.idProp]);
let s = this.getParent(e, t);
for (; s; )
r.push(s), s = this.getParent(e, s[this.idProp]);
return r.reverse();

@@ -226,4 +250,4 @@ }

_getParent(e, t, r = null) {
return e.find((s) => s[this.idProp] === t) ? r : e.reduce(
(s, n) => s || this._getParent(n[this.childrenProp] || [], t, n),
return e.find((i) => i[this.idProp] === t) ? r : e.reduce(
(i, h) => i || this._getParent(h[this.childrenProp] || [], t, h),
null

@@ -259,3 +283,3 @@ );

var r;
return (((r = this.getParent(e, t)) == null ? void 0 : r[this.childrenProp]) || []).filter((i) => i[this.idProp] !== t);
return (((r = this.getParent(e, t)) == null ? void 0 : r[this.childrenProp]) || []).filter((s) => s[this.idProp] !== t);
}

@@ -352,6 +376,6 @@ /**

_getNodesAtLevel(e, t, r = 0) {
return e.reduce((i, s) => [
...i,
...t === r ? [s] : [],
...r < t ? this._getNodesAtLevel(s[this.childrenProp], t, r + 1) : []
return e.reduce((s, i) => [
...s,
...t === r ? [i] : [],
...r < t ? this._getNodesAtLevel(i[this.childrenProp], t, r + 1) : []
], []);

@@ -385,3 +409,3 @@ }

getHeightNode(e, t = 0) {
return e.reduce((r, i) => Math.max(r, this.getHeightNode(i[this.childrenProp], t + 1)), t);
return e.reduce((r, s) => Math.max(r, this.getHeightNode(s[this.childrenProp], t + 1)), t);
}

@@ -396,9 +420,24 @@ /**

getDistance(e, t, r) {
const i = [...this.getPathNodes(e, t), this.get(e, t)], s = [...this.getPathNodes(e, r), this.get(e, r)], n = [...i].reverse().find((d) => s.includes(d));
if (!n)
const s = [...this.getPathNodes(e, t), this.get(e, t)], i = [...this.getPathNodes(e, r), this.get(e, r)], h = [...s].reverse().find((d) => i.includes(d));
if (!h)
return -1;
const h = i.findIndex((d) => d.id === n.id), l = s.findIndex((d) => d.id === n.id);
return i.length - h - 1 + (s.length - l - 1);
const n = s.findIndex((d) => d.id === h.id), l = i.findIndex((d) => d.id === h.id);
return s.length - n - 1 + (i.length - l - 1);
}
/**
* Method to compute paths for nodes (mutable operation)
* path property will be added into each node
* e.g. {path: "parent/child"...}
* @param tree - tree structure
* @param pathComputationProperty - property to use for path computation
* @param delimiter - to delimit path
* @param pathProperty - property where path will be stored
* @param originPath - path of top level nodes
*/
computePaths(e, t, r = "/", s = "path", i = "/") {
e == null || e.forEach((h) => {
h[s] = i, this.computePaths(h[this.childrenProp], t, r, s, `${h.path}${h[t]}${r}`);
});
}
/**
* Helper method to deep clone object

@@ -405,0 +444,0 @@ * @param obj - object to be cloned

{
"name": "simple-tree-utils",
"version": "3.0.1",
"version": "3.1.0",
"description": "Simple Tree Utils is the library to convert and manipulate with tree-like structures.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -38,3 +38,3 @@ [![npm version](https://badge.fury.io/js/simple-tree-utils.svg)](https://badge.fury.io/js/simple-tree-utils)

```html
<script src="https://cdn.jsdelivr.net/npm/simple-tree-utils@3.0.1/dist/simple-tree-utils.iife.js"></script>
<script src="https://cdn.jsdelivr.net/npm/simple-tree-utils@3.1.0/dist/simple-tree-utils.iife.js"></script>
```

@@ -102,3 +102,3 @@

```html
<script src="https://cdn.jsdelivr.net/npm/simple-tree-utils@3.0.1/dist/simple-tree-utils.iife.js"></script>
<script src="https://cdn.jsdelivr.net/npm/simple-tree-utils@3.1.0/dist/simple-tree-utils.iife.js"></script>
<script>

@@ -105,0 +105,0 @@ const utils = new simpleTreeUtils.TreeUtils();

@@ -135,2 +135,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

/**
* Method to iterate over all nodes
* @param tree - tree structure to iterate over
* @param fn - callback function to perform
*/
forEach(tree: any[], fn: (item: any) => any): void {
tree?.forEach(item => {
fn(item);
this.forEach(item[this.childrenProp], fn);
});
}
/**
* Method to find all nodes in tree structure by given callback function

@@ -156,12 +168,28 @@ * @param tree - tree structure to search in

* @param id - identifier of node to delete
* @returns deleted node, if nothing deleted then returns null
*/
delete(tree: any[], id: any): any {
const index = tree.findIndex(item => item[this.idProp] == id);
if (index != -1) {
return tree.splice(index, 1)[0];
}
return tree.reduce((acc, curr) => acc || this.delete(curr[this.childrenProp], id), null);
return this.deleteBy(tree, item => item[this.idProp] === id)[0] || null;
}
/**
* Method to delete node in tree by given callback function (mutable operation!)
* @param tree - tree structure for node deleting
* @param fn - callback function to remove all nodes
* @returns deleted nodes
* @example
* ```ts
* utils.deleteBy(tree, item => item.id === myId);
* ```
*/
deleteBy(tree: any[] = [], fn: (item: any) => boolean): any[] {
const indexesToRemove = tree
.filter(item => fn(item))
.map((_item, index) => index)
.reverse();
const removedItems = indexesToRemove.reduce<any>((acc, curr) => ([...acc, ...tree.splice(curr, 1)]), []);
return tree.reduce((acc, curr) => [...acc, ...this.deleteBy(curr[this.childrenProp], fn)], removedItems)
}
/**
* Method to add new node to tree, node will be added as last child (mutable operation!)

@@ -178,3 +206,3 @@ * @param tree - tree structure for node adding

/**
* Method to add new node to tree, node will be added as last child (mutable operation!)
* Method to add new node to tree, node will be added as first child (mutable operation!)
* @param tree - tree structure for node adding

@@ -493,2 +521,19 @@ * @param parentId - identifier of parent node, null if new node should be on root level

/**
* Method to compute paths for nodes (mutable operation)
* path property will be added into each node
* e.g. {path: "parent/child"...}
* @param tree - tree structure
* @param pathComputationProperty - property to use for path computation
* @param delimiter - to delimit path
* @param pathProperty - property where path will be stored
* @param originPath - path of top level nodes
*/
computePaths(tree: any[], pathComputationProperty: string, delimiter = '/', pathProperty = 'path', originPath = '/'): void {
tree?.forEach(item => {
item[pathProperty] = originPath;
this.computePaths(item[this.childrenProp], pathComputationProperty, delimiter, pathProperty, `${item.path}${item[pathComputationProperty]}${delimiter}`);
});
}
/**
* Helper method to deep clone object

@@ -495,0 +540,0 @@ * @param obj - object to be cloned

@@ -110,3 +110,3 @@ import {beforeEach, describe, expect, it} from 'vitest'

it('should delete node by given customId', () => {
treeUtils.delete(mock, 6);
const deleted = treeUtils.delete(mock, 6);
const out = [

@@ -126,6 +126,86 @@ {

},
]
];
expect(deleted).toEqual({customId: 6, parentCustomId: 3, name: 'Node 6', customChildren: []});
expect(mock).toEqual(out);
});
it('should delete node returns null when not found', () => {
const deleted = treeUtils.delete(mock, 100);
expect(deleted).toEqual(null);
});
it('should delete node when there is no children property', () => {
const input = [{customId: 1, parentCustomId: null, name: 'Node 1', customChildren: [
{customId: 3, parentCustomId: 1, name: 'Node 3', customChildren: [
{customId: 6, parentCustomId: 3, name: 'Node 6'}]},
{customId: 4, parentCustomId: 1, name: 'Node 4'}]},
];
const deleted = treeUtils.deleteBy(input, item => item.customId === 6);
expect(deleted).toEqual([{customId: 6, parentCustomId: 3, name: 'Node 6'}]);
});
it('should delete node by given callback', () => {
const deleted = treeUtils.deleteBy(mock, item => item.customId === 5 || item.customId === 6);
const out = [
{
customId: 1, parentCustomId: null, name: 'Node 1', customChildren: [
{
customId: 3, parentCustomId: 1, name: 'Node 3', customChildren: []
},
{customId: 4, parentCustomId: 1, name: 'Node 4', customChildren: []},
]
},
{customId: 2, parentCustomId: null, name: 'Node 2', customChildren: []},
];
expect(deleted).toEqual([
{customId: 6, parentCustomId: 3, name: 'Node 6', customChildren: []},
{customId: 5, parentCustomId: 2, name: 'Node 5', customChildren: []},
]);
expect(mock).toEqual(out);
});
it('should iterate over each node', () => {
treeUtils.forEach(mock, item => item.name = `I${item.name}`);
const out = [
{
customId: 1, parentCustomId: null, name: 'INode 1', customChildren: [
{
customId: 3, parentCustomId: 1, name: 'INode 3', customChildren: [
{customId: 6, parentCustomId: 3, name: 'INode 6', customChildren: []},
]
},
{customId: 4, parentCustomId: 1, name: 'INode 4', customChildren: []},
]
},
{
customId: 2, parentCustomId: null, name: 'INode 2', customChildren: [
{customId: 5, parentCustomId: 2, name: 'INode 5', customChildren: []},
]
},
];
expect(mock).toEqual(out);
});
it('should compute paths for nodes', () => {
treeUtils.computePaths(mock, 'name');
const out = [
{
customId: 1, parentCustomId: null, name: 'Node 1', path: '/', customChildren: [
{
customId: 3, parentCustomId: 1, name: 'Node 3', path: '/Node 1/', customChildren: [
{customId: 6, parentCustomId: 3, name: 'Node 6', path: '/Node 1/Node 3/', customChildren: []},
]
},
{customId: 4, parentCustomId: 1, name: 'Node 4', path: '/Node 1/', customChildren: []},
]
},
{
customId: 2, parentCustomId: null, name: 'Node 2', path: '/', customChildren: [
{customId: 5, parentCustomId: 2, name: 'Node 5', path: '/Node 2/', customChildren: []},
]
},
];
expect(mock).toEqual(out);
});
it('should add node to tree as first child of given node', () => {

@@ -132,0 +212,0 @@ treeUtils.addUnshift(mock, 1, {customId: 7, parentCustomId: 4, name: 'Node 7', customChildren: []});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet