@zid-utils/tree-utils 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +458 -0
- package/dist/index.js +276 -244
- package/package.json +6 -3
package/README.md
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# @zid-utils/tree-utils
|
|
2
|
+
|
|
3
|
+
> 树形数据结构处理工具库 (Tree data structure utility library)
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @zid-utils/tree-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 核心方法(来自 tree-lodash)
|
|
12
|
+
|
|
13
|
+
本包使用 [tree-lodash](https://github.com/zhangshichun/tree-lodash) 作为核心实现,提供强大的树操作功能。
|
|
14
|
+
|
|
15
|
+
### foreach - 遍历
|
|
16
|
+
|
|
17
|
+
遍历树或森林的所有节点。
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { foreach } from '@zid-utils/tree-utils';
|
|
21
|
+
|
|
22
|
+
const tree = {
|
|
23
|
+
key: '1',
|
|
24
|
+
title: 'Root',
|
|
25
|
+
children: [
|
|
26
|
+
{ key: '1-1', title: 'Child 1' },
|
|
27
|
+
{ key: '1-2', title: 'Child 2' }
|
|
28
|
+
]
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
foreach(tree, (node, meta) => {
|
|
32
|
+
console.log(`${' '.repeat(meta.depth)}${node.title}`);
|
|
33
|
+
}, { strategy: 'pre' });
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### map - 映射
|
|
37
|
+
|
|
38
|
+
遍历并映射每个节点,返回新的树结构。
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { map } from '@zid-utils/tree-utils';
|
|
42
|
+
|
|
43
|
+
const newTree = map(tree, (node) => ({
|
|
44
|
+
...node,
|
|
45
|
+
title: `Mapped: ${node.title}`
|
|
46
|
+
}));
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### filter - 过滤
|
|
50
|
+
|
|
51
|
+
过滤树节点,保留符合条件的节点。
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { filter } from '@zid-utils/tree-utils';
|
|
55
|
+
|
|
56
|
+
const filteredTree = filter(tree, (node) => node.key.startsWith('1-'));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### find - 查找
|
|
60
|
+
|
|
61
|
+
查找第一个匹配的节点。
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { find } from '@zid-utils/tree-utils';
|
|
65
|
+
|
|
66
|
+
const node = find(tree, (node) => node.key === '1-1');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### some - 存在检查
|
|
70
|
+
|
|
71
|
+
检查是否存在匹配的节点。
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { some } from '@zid-utils/tree-utils';
|
|
75
|
+
|
|
76
|
+
const exists = some(tree, (node) => node.key === '1-1');
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### toArray - 扁平化
|
|
80
|
+
|
|
81
|
+
将树结构扁平化为数组。
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { toArray } from '@zid-utils/tree-utils';
|
|
85
|
+
|
|
86
|
+
const nodes = toArray(tree);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### fromArray - 构建树
|
|
90
|
+
|
|
91
|
+
从扁平数组构建树结构。
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { fromArray } from '@zid-utils/tree-utils';
|
|
95
|
+
|
|
96
|
+
const array = [
|
|
97
|
+
{ id: 1, pid: null, title: 'Root' },
|
|
98
|
+
{ id: 2, pid: 1, title: 'Child' }
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const tree = fromArray(array, {
|
|
102
|
+
parentKey: 'pid',
|
|
103
|
+
itemKey: 'id',
|
|
104
|
+
childrenKey: 'children'
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 扩展方法
|
|
109
|
+
|
|
110
|
+
### 节点查询
|
|
111
|
+
|
|
112
|
+
#### getLeafNodes
|
|
113
|
+
|
|
114
|
+
获取所有叶子节点。
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { getLeafNodes } from '@zid-utils/tree-utils';
|
|
118
|
+
|
|
119
|
+
const leafNodes = getLeafNodes(tree, 'isLeaf');
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### findNodeByKey
|
|
123
|
+
|
|
124
|
+
根据 key 查找节点。
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { findNodeByKey } from '@zid-utils/tree-utils';
|
|
128
|
+
|
|
129
|
+
const node = findNodeByKey(tree, '1-1');
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### findNodeById
|
|
133
|
+
|
|
134
|
+
根据 id 查找节点。
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { findNodeById } from '@zid-utils/tree-utils';
|
|
138
|
+
|
|
139
|
+
const node = findNodeById(tree, 'node-id');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### findNodeByMatcher
|
|
143
|
+
|
|
144
|
+
根据匹配器查找节点。
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { findNodeByMatcher } from '@zid-utils/tree-utils';
|
|
148
|
+
|
|
149
|
+
const node = findNodeByMatcher(tree, (n) => n.title === 'Target');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### nodeExistsInTree
|
|
153
|
+
|
|
154
|
+
检查节点是否存在于树中。
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { nodeExistsInTree } from '@zid-utils/tree-utils';
|
|
158
|
+
|
|
159
|
+
const exists = nodeExistsInTree(tree, 'node-title');
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### findParentOf
|
|
163
|
+
|
|
164
|
+
查找节点的父节点。
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { findParentOf } from '@zid-utils/tree-utils';
|
|
168
|
+
|
|
169
|
+
const parent = findParentOf(tree, 'child-key');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### getNodePath
|
|
173
|
+
|
|
174
|
+
获取节点路径。
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { getNodePath, type PathNode } from '@zid-utils/tree-utils';
|
|
178
|
+
|
|
179
|
+
const path = getNodePath(tree, '1-2', 'key', 'children');
|
|
180
|
+
// 返回 PathNode[] 包含路径信息
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### getNodeDepth
|
|
184
|
+
|
|
185
|
+
获取节点深度。
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { getNodeDepth } from '@zid-utils/tree-utils';
|
|
189
|
+
|
|
190
|
+
const depth = getNodeDepth(tree, '1-2-1');
|
|
191
|
+
// 返回节点所在层级(根节点为0)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### getNodeBreadcrumb
|
|
195
|
+
|
|
196
|
+
获取面包屑路径(所有祖先节点)。
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { getNodeBreadcrumb } from '@zid-utils/tree-utils';
|
|
200
|
+
|
|
201
|
+
const breadcrumb = getNodeBreadcrumb(tree, '1-2-1');
|
|
202
|
+
// 返回从根到目标的所有节点
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### getTreeStats
|
|
206
|
+
|
|
207
|
+
获取树统计信息。
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { getTreeStats } from '@zid-utils/tree-utils';
|
|
211
|
+
|
|
212
|
+
const stats = getTreeStats(tree);
|
|
213
|
+
// { totalNodes: 10, maxDepth: 3, leafCount: 5 }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 节点操作
|
|
217
|
+
|
|
218
|
+
#### updateKeys
|
|
219
|
+
|
|
220
|
+
更新节点的 key。
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { updateKeys } from '@zid-utils/tree-utils';
|
|
224
|
+
|
|
225
|
+
updateKeys(sourceNode, targetNode);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### updateNodeTitleByKey
|
|
229
|
+
|
|
230
|
+
根据 key 更新节点标题。
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import { updateNodeTitleByKey } from '@zid-utils/tree-utils';
|
|
234
|
+
|
|
235
|
+
updateNodeTitleByKey(tree, '1-1', 'New Title');
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### updateNodeByMatcher
|
|
239
|
+
|
|
240
|
+
根据匹配器更新节点。
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { updateNodeByMatcher } from '@zid-utils/tree-utils';
|
|
244
|
+
|
|
245
|
+
const newTree = updateNodeByMatcher(
|
|
246
|
+
tree,
|
|
247
|
+
(node) => node.key === 'target',
|
|
248
|
+
(node) => ({ ...node, title: 'Updated' })
|
|
249
|
+
);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### moveNodeInTree
|
|
253
|
+
|
|
254
|
+
在树中移动节点。
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { moveNodeInTree } from '@zid-utils/tree-utils';
|
|
258
|
+
|
|
259
|
+
moveNodeInTree(tree, 'source-key', 'target-key');
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### cloneNode
|
|
263
|
+
|
|
264
|
+
克隆节点。
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { cloneNode } from '@zid-utils/tree-utils';
|
|
268
|
+
|
|
269
|
+
cloneNode(sourceNode, targetNode);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### copyNode
|
|
273
|
+
|
|
274
|
+
复制节点(带副本标识)。
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { copyNode } from '@zid-utils/tree-utils';
|
|
278
|
+
|
|
279
|
+
const newTree = copyNode(tree, 'source-key', 'target-key');
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### deleteNode
|
|
283
|
+
|
|
284
|
+
删除节点。
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
import { deleteNode } from '@zid-utils/tree-utils';
|
|
288
|
+
|
|
289
|
+
const newTree = deleteNode(tree, 'key-to-delete');
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
#### addLeafProperties
|
|
293
|
+
|
|
294
|
+
为节点添加叶子属性。
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { addLeafProperties } from '@zid-utils/tree-utils';
|
|
298
|
+
|
|
299
|
+
const newTree = addLeafProperties(tree);
|
|
300
|
+
// 自动设置 isLeaf 和 disabled 属性
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 树转换
|
|
304
|
+
|
|
305
|
+
#### transformTreeKeys
|
|
306
|
+
|
|
307
|
+
转换树节点的键。
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import { transformTreeKeys } from '@zid-utils/tree-utils';
|
|
311
|
+
|
|
312
|
+
const newTree = transformTreeKeys(tree, {
|
|
313
|
+
title: 'label',
|
|
314
|
+
key: 'id'
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### transformTreeNodes
|
|
319
|
+
|
|
320
|
+
转换树节点数据。
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { transformTreeNodes } from '@zid-utils/tree-utils';
|
|
324
|
+
|
|
325
|
+
const newTree = transformTreeNodes(tree, (node) => ({
|
|
326
|
+
...node,
|
|
327
|
+
isActive: true
|
|
328
|
+
}));
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### searchInTree
|
|
332
|
+
|
|
333
|
+
在树中搜索节点。
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { searchInTree } from '@zid-utils/tree-utils';
|
|
337
|
+
|
|
338
|
+
const results = searchInTree(tree, 'search-term');
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 工具函数
|
|
342
|
+
|
|
343
|
+
#### findFirstLeaf
|
|
344
|
+
|
|
345
|
+
查找第一个叶子节点。
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { findFirstLeaf } from '@zid-utils/tree-utils';
|
|
349
|
+
|
|
350
|
+
const leaf = findFirstLeaf(tree);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### traverseTreeValues
|
|
354
|
+
|
|
355
|
+
遍历树中特定键的值。
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { traverseTreeValues } from '@zid-utils/tree-utils';
|
|
359
|
+
|
|
360
|
+
const values = traverseTreeValues(tree, 'title');
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
#### filterCheckedLeafKeys
|
|
364
|
+
|
|
365
|
+
过滤选中的叶子节点 key。
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import { filterCheckedLeafKeys } from '@zid-utils/tree-utils';
|
|
369
|
+
|
|
370
|
+
const keys = filterCheckedLeafKeys(tree);
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### collectLeafValuesByKey
|
|
374
|
+
|
|
375
|
+
收集叶子节点的值。
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
import { collectLeafValuesByKey } from '@zid-utils/tree-utils';
|
|
379
|
+
|
|
380
|
+
const values = collectLeafValuesByKey(tree, 'parent-value');
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### convertGroupsToTreeData
|
|
384
|
+
|
|
385
|
+
将分组数据转换为树形结构。
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { convertGroupsToTreeData, type TreeGroup } from '@zid-utils/tree-utils';
|
|
389
|
+
|
|
390
|
+
const tree = convertGroupsToTreeData(items, 'category');
|
|
391
|
+
// 返回 TreeGroup[] 类型
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## 类型定义
|
|
395
|
+
|
|
396
|
+
### TreeNode
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
interface TreeNode {
|
|
400
|
+
key?: string | number;
|
|
401
|
+
title?: string | number;
|
|
402
|
+
children?: TreeNode[];
|
|
403
|
+
isLeaf?: boolean;
|
|
404
|
+
disabled?: boolean;
|
|
405
|
+
selectable?: boolean;
|
|
406
|
+
checked?: boolean;
|
|
407
|
+
[key: string]: any;
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### PathNode
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
interface PathNode<T> {
|
|
415
|
+
node: T; // 节点数据
|
|
416
|
+
depth: number; // 深度(根节点为0)
|
|
417
|
+
index: number; // 在兄弟节点中的索引
|
|
418
|
+
parent: PathNode<T> | null; // 父节点
|
|
419
|
+
path: string; // 路径字符串,如 'root/child/grandchild'
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### TreeGroup
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
interface TreeGroup {
|
|
427
|
+
label: string;
|
|
428
|
+
value: string | number;
|
|
429
|
+
children?: any[];
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## 遍历策略
|
|
434
|
+
|
|
435
|
+
所有核心方法都支持三种遍历策略:
|
|
436
|
+
|
|
437
|
+
- `pre` - 前序遍历(默认)
|
|
438
|
+
- `post` - 后序遍历
|
|
439
|
+
- `breadth` - 广度优先遍历
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import { foreach } from '@zid-utils/tree-utils';
|
|
443
|
+
|
|
444
|
+
foreach(tree, callback, { strategy: 'breadth' });
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## 相关库推荐
|
|
448
|
+
|
|
449
|
+
### 文件系统场景
|
|
450
|
+
- [@httpx/treeu](https://github.com/belgattitude/httpx/tree/main/packages/treeu) - 轻量级 DFS 搜索和路径映射,适合深层嵌套树的性能优化
|
|
451
|
+
|
|
452
|
+
### 其他选择
|
|
453
|
+
- [tree-model](https://github.com/joaonuno/tree-model) - 模型驱动的树操作
|
|
454
|
+
- [js-tree](https://github.com/guigrpa/js-tree) - React 集成友好的树组件
|
|
455
|
+
|
|
456
|
+
## License
|
|
457
|
+
|
|
458
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
1
|
+
// src/traverse/foreach.ts
|
|
2
|
+
import { default as default2 } from "tree-lodash";
|
|
3
|
+
|
|
4
|
+
// src/traverse/toArray.ts
|
|
5
|
+
import { default as default3 } from "tree-lodash";
|
|
6
|
+
|
|
7
|
+
// src/query/find.ts
|
|
8
|
+
import { default as default4 } from "tree-lodash";
|
|
9
|
+
|
|
10
|
+
// src/query/some.ts
|
|
11
|
+
import { default as default5 } from "tree-lodash";
|
|
12
|
+
|
|
13
|
+
// src/query/getLeafNodes.ts
|
|
6
14
|
var getLeafNodes = (treeData, isLeafKey = "isLeaf") => {
|
|
7
15
|
function collectLeafNodes(nodes) {
|
|
8
16
|
const leafNodes = [];
|
|
@@ -17,24 +25,8 @@ var getLeafNodes = (treeData, isLeafKey = "isLeaf") => {
|
|
|
17
25
|
}
|
|
18
26
|
return collectLeafNodes(treeData);
|
|
19
27
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (children && children.length > 0) {
|
|
23
|
-
return children.filter(callback).map((child) => {
|
|
24
|
-
return {
|
|
25
|
-
...child,
|
|
26
|
-
children: filterChildren(child.children)
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
return [];
|
|
31
|
-
};
|
|
32
|
-
const rootNodes = isOnlyFilterChildren ? nodes : nodes.filter(callback);
|
|
33
|
-
return rootNodes.map((node) => ({
|
|
34
|
-
...node,
|
|
35
|
-
children: filterChildren(node.children)
|
|
36
|
-
}));
|
|
37
|
-
};
|
|
28
|
+
|
|
29
|
+
// src/query/findNodeByKey.ts
|
|
38
30
|
var findNodeByKey = (treeData, key) => {
|
|
39
31
|
for (let i = 0; i < treeData.length; i++) {
|
|
40
32
|
const node = treeData[i];
|
|
@@ -50,28 +42,127 @@ var findNodeByKey = (treeData, key) => {
|
|
|
50
42
|
}
|
|
51
43
|
return null;
|
|
52
44
|
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (node.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
45
|
+
|
|
46
|
+
// src/query/findNodeById.ts
|
|
47
|
+
var findNodeById = (nodes, id) => {
|
|
48
|
+
for (const node of nodes) {
|
|
49
|
+
if (node.id === id) return node;
|
|
50
|
+
if (node.children && node.children.length) {
|
|
51
|
+
const found = findNodeById(node.children, id);
|
|
52
|
+
if (found) return found;
|
|
62
53
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/query/findNodeByMatcher.ts
|
|
59
|
+
var findNodeByMatcher = (nodes, matcher, childrenKey = "children") => {
|
|
60
|
+
for (const node of nodes) {
|
|
61
|
+
if (matcher(node)) {
|
|
62
|
+
return node;
|
|
63
|
+
}
|
|
64
|
+
if (node[childrenKey]) {
|
|
65
|
+
const found = findNodeByMatcher(node[childrenKey], matcher, childrenKey);
|
|
66
|
+
if (found) {
|
|
67
|
+
return found;
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
return null;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/query/nodeExistsInTree.ts
|
|
75
|
+
var nodeExistsInTree = (nodes, searchValue) => {
|
|
76
|
+
return nodes.some((node) => {
|
|
77
|
+
if (node.value === searchValue || node.title === searchValue) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (node.children && Array.isArray(node.children)) {
|
|
81
|
+
return nodeExistsInTree(node.children, searchValue);
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// src/query/findParentOf.ts
|
|
88
|
+
var findParentOf = (nodes, targetKey) => {
|
|
89
|
+
for (const node of nodes) {
|
|
90
|
+
if (node.children?.some((child) => child.key === targetKey)) {
|
|
91
|
+
return node;
|
|
92
|
+
}
|
|
93
|
+
if (node.children) {
|
|
94
|
+
const found = findParentOf(node.children, targetKey);
|
|
95
|
+
if (found) return found;
|
|
96
|
+
}
|
|
72
97
|
}
|
|
73
|
-
return
|
|
98
|
+
return null;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/query/getNodePath.ts
|
|
102
|
+
var getNodePath = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
103
|
+
const findPath = (nodes, target, currentPath) => {
|
|
104
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
105
|
+
const node = nodes[i];
|
|
106
|
+
const newPathNode = {
|
|
107
|
+
node,
|
|
108
|
+
depth: currentPath.length,
|
|
109
|
+
index: i,
|
|
110
|
+
parent: currentPath.length > 0 ? currentPath[currentPath.length - 1] : null,
|
|
111
|
+
path: currentPath.length === 0 ? String(node[keyField]) : `${currentPath[currentPath.length - 1].path}/${String(node[keyField])}`
|
|
112
|
+
};
|
|
113
|
+
if (node[keyField] === target) {
|
|
114
|
+
return [...currentPath, newPathNode];
|
|
115
|
+
}
|
|
116
|
+
const children = node[childrenKey];
|
|
117
|
+
if (children && Array.isArray(children) && children.length > 0) {
|
|
118
|
+
const result = findPath(children, target, [
|
|
119
|
+
...currentPath,
|
|
120
|
+
newPathNode
|
|
121
|
+
]);
|
|
122
|
+
if (result) {
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
};
|
|
129
|
+
return findPath(treeData, targetKey, []);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/query/getNodeDepth.ts
|
|
133
|
+
var getNodeDepth = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
134
|
+
const path = getNodePath(treeData, targetKey, keyField, childrenKey);
|
|
135
|
+
return path ? path.length - 1 : -1;
|
|
74
136
|
};
|
|
137
|
+
|
|
138
|
+
// src/query/getNodeBreadcrumb.ts
|
|
139
|
+
var getNodeBreadcrumb = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
140
|
+
const path = getNodePath(treeData, targetKey, keyField, childrenKey);
|
|
141
|
+
return path ? path.map((p) => p.node) : [];
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// src/query/getTreeStats.ts
|
|
145
|
+
var getTreeStats = (treeData, childrenKey = "children") => {
|
|
146
|
+
let totalNodes = 0;
|
|
147
|
+
let maxDepth = 0;
|
|
148
|
+
let leafCount = 0;
|
|
149
|
+
const traverse = (nodes, depth) => {
|
|
150
|
+
for (const node of nodes) {
|
|
151
|
+
totalNodes++;
|
|
152
|
+
maxDepth = Math.max(maxDepth, depth);
|
|
153
|
+
const children = node[childrenKey];
|
|
154
|
+
if (children && Array.isArray(children) && children.length > 0) {
|
|
155
|
+
traverse(children, depth + 1);
|
|
156
|
+
} else {
|
|
157
|
+
leafCount++;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
traverse(treeData, 0);
|
|
162
|
+
return { totalNodes, maxDepth, leafCount };
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// src/modify/updateKeys.ts
|
|
75
166
|
var updateKeys = (sourceNode, targetNode) => {
|
|
76
167
|
sourceNode.key = `${targetNode.key}-${targetNode.children?.length}`;
|
|
77
168
|
if (sourceNode.children) {
|
|
@@ -80,6 +171,49 @@ var updateKeys = (sourceNode, targetNode) => {
|
|
|
80
171
|
});
|
|
81
172
|
}
|
|
82
173
|
};
|
|
174
|
+
|
|
175
|
+
// src/modify/updateNodeTitleByKey.ts
|
|
176
|
+
var updateNodeTitleByKey = (tree, targetKey, newTitle) => {
|
|
177
|
+
for (const node of tree) {
|
|
178
|
+
if (node.key === targetKey) {
|
|
179
|
+
node.title = newTitle;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (node.children) {
|
|
183
|
+
updateNodeTitleByKey(node.children, targetKey, newTitle);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/modify/updateNodeByMatcher.ts
|
|
189
|
+
var updateNodeByMatcher = (nodes, matcher, updater, childrenKey = "children") => {
|
|
190
|
+
return nodes.map((node) => {
|
|
191
|
+
if (matcher(node)) {
|
|
192
|
+
return updater(node);
|
|
193
|
+
}
|
|
194
|
+
if (node[childrenKey] && node[childrenKey].length > 0) {
|
|
195
|
+
const newChildren = updateNodeByMatcher(
|
|
196
|
+
node[childrenKey],
|
|
197
|
+
matcher,
|
|
198
|
+
updater,
|
|
199
|
+
childrenKey
|
|
200
|
+
);
|
|
201
|
+
if (newChildren !== node[childrenKey]) {
|
|
202
|
+
return {
|
|
203
|
+
...node,
|
|
204
|
+
[childrenKey]: newChildren
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return node;
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// src/modify/moveNodeInTree.ts
|
|
213
|
+
var defaultLogger = {
|
|
214
|
+
warn: (msg) => console.warn("[tree-utils]", msg),
|
|
215
|
+
error: (msg) => console.error("[tree-utils]", msg)
|
|
216
|
+
};
|
|
83
217
|
var moveNodeInTree = (treeData, sourceKey, targetKey, logger = defaultLogger) => {
|
|
84
218
|
function findNode(nodes, key) {
|
|
85
219
|
if (!nodes) return null;
|
|
@@ -133,6 +267,8 @@ var moveNodeInTree = (treeData, sourceKey, targetKey, logger = defaultLogger) =>
|
|
|
133
267
|
targetNode.children = targetNode.children || [];
|
|
134
268
|
targetNode.children.push(sourceNode);
|
|
135
269
|
};
|
|
270
|
+
|
|
271
|
+
// src/modify/cloneNode.ts
|
|
136
272
|
var cloneNode = (sourceNode, targetNode) => {
|
|
137
273
|
const clonedNode = { ...sourceNode };
|
|
138
274
|
if (targetNode.children) {
|
|
@@ -141,6 +277,8 @@ var cloneNode = (sourceNode, targetNode) => {
|
|
|
141
277
|
targetNode.children = [clonedNode];
|
|
142
278
|
}
|
|
143
279
|
};
|
|
280
|
+
|
|
281
|
+
// src/modify/copyNode.ts
|
|
144
282
|
var copyNode = (treeData, key, targetKey) => {
|
|
145
283
|
const sourceNode = structuredClone(findNodeByKey(treeData, key));
|
|
146
284
|
const targetNode = findNodeByKey(treeData, targetKey);
|
|
@@ -152,17 +290,8 @@ var copyNode = (treeData, key, targetKey) => {
|
|
|
152
290
|
}
|
|
153
291
|
return treeData;
|
|
154
292
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (node.key === targetKey) {
|
|
158
|
-
node.title = newTitle;
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (node.children) {
|
|
162
|
-
updateNodeTitleByKey(node.children, targetKey, newTitle);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
293
|
+
|
|
294
|
+
// src/modify/deleteNode.ts
|
|
166
295
|
var deleteNode = (treeData, key) => {
|
|
167
296
|
const delNode = (data) => {
|
|
168
297
|
return data.filter((node) => {
|
|
@@ -177,19 +306,8 @@ var deleteNode = (treeData, key) => {
|
|
|
177
306
|
};
|
|
178
307
|
return delNode([...treeData]);
|
|
179
308
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const flatten = (node) => {
|
|
183
|
-
if (filter(node)) {
|
|
184
|
-
result.push(node);
|
|
185
|
-
}
|
|
186
|
-
if (node.children) {
|
|
187
|
-
node.children.forEach(flatten);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
tree.forEach(flatten);
|
|
191
|
-
return result;
|
|
192
|
-
};
|
|
309
|
+
|
|
310
|
+
// src/modify/addLeafProperties.ts
|
|
193
311
|
var addLeafProperties = (treeData) => {
|
|
194
312
|
return treeData.map((node) => {
|
|
195
313
|
const isLeaf = !node.children || node.children.length === 0;
|
|
@@ -201,66 +319,19 @@ var addLeafProperties = (treeData) => {
|
|
|
201
319
|
};
|
|
202
320
|
});
|
|
203
321
|
};
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const result = [];
|
|
216
|
-
const traverse = (nodes) => {
|
|
217
|
-
if (!nodes || nodes.length === 0) return;
|
|
218
|
-
for (const node of nodes) {
|
|
219
|
-
if (node.checked === false) continue;
|
|
220
|
-
if (node.children && node.children.length > 0) {
|
|
221
|
-
traverse(node.children);
|
|
222
|
-
} else if (node.checked === true) {
|
|
223
|
-
result.push(node.key);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
traverse(treeData);
|
|
228
|
-
return result;
|
|
229
|
-
};
|
|
230
|
-
var nodeExistsInTree = (nodes, searchValue) => {
|
|
231
|
-
return nodes.some((node) => {
|
|
232
|
-
if (node.value === searchValue || node.title === searchValue) {
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
if (node.children && Array.isArray(node.children)) {
|
|
236
|
-
return nodeExistsInTree(node.children, searchValue);
|
|
237
|
-
}
|
|
238
|
-
return false;
|
|
239
|
-
});
|
|
240
|
-
};
|
|
241
|
-
var collectLeafValuesByKey = (nodes, targetValue, isLeafKey = "isLeaf") => {
|
|
242
|
-
for (const node of nodes) {
|
|
243
|
-
if (node.value === targetValue) {
|
|
244
|
-
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
|
245
|
-
const leafNodes = getLeafNodes([node], isLeafKey);
|
|
246
|
-
return leafNodes.map((leaf) => leaf.value);
|
|
247
|
-
}
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
if (node.children && Array.isArray(node.children)) {
|
|
251
|
-
const result = collectLeafValuesByKey(
|
|
252
|
-
node.children,
|
|
253
|
-
targetValue,
|
|
254
|
-
isLeafKey
|
|
255
|
-
);
|
|
256
|
-
if (result !== null) {
|
|
257
|
-
return result;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return null;
|
|
322
|
+
|
|
323
|
+
// src/transform/map.ts
|
|
324
|
+
import { default as default6 } from "tree-lodash";
|
|
325
|
+
|
|
326
|
+
// src/transform/filter.ts
|
|
327
|
+
import { default as default7 } from "tree-lodash";
|
|
328
|
+
|
|
329
|
+
// src/transform/transformTreeKeys.ts
|
|
330
|
+
var defaultLogger2 = {
|
|
331
|
+
warn: (msg) => console.warn("[tree-utils]", msg),
|
|
332
|
+
error: (msg) => console.error("[tree-utils]", msg)
|
|
262
333
|
};
|
|
263
|
-
var transformTreeKeys = (treeData, keyMapping, childrenKey = "children", logger =
|
|
334
|
+
var transformTreeKeys = (treeData, keyMapping, childrenKey = "children", logger = defaultLogger2) => {
|
|
264
335
|
if (!Array.isArray(treeData)) {
|
|
265
336
|
logger.warn?.("transformTreeKeys: treeData must be an array");
|
|
266
337
|
return [];
|
|
@@ -288,7 +359,13 @@ var transformTreeKeys = (treeData, keyMapping, childrenKey = "children", logger
|
|
|
288
359
|
};
|
|
289
360
|
return treeData.map(transformNode);
|
|
290
361
|
};
|
|
291
|
-
|
|
362
|
+
|
|
363
|
+
// src/transform/transformTreeNodes.ts
|
|
364
|
+
var defaultLogger3 = {
|
|
365
|
+
warn: (msg) => console.warn("[tree-utils]", msg),
|
|
366
|
+
error: (msg) => console.error("[tree-utils]", msg)
|
|
367
|
+
};
|
|
368
|
+
var transformTreeNodes = (treeData, transformer, childrenKey = "children", logger = defaultLogger3) => {
|
|
292
369
|
if (!Array.isArray(treeData)) {
|
|
293
370
|
logger.warn?.("transformTreeNodes: treeData must be an array");
|
|
294
371
|
return [];
|
|
@@ -313,126 +390,35 @@ var transformTreeNodes = (treeData, transformer, childrenKey = "children", logge
|
|
|
313
390
|
};
|
|
314
391
|
return treeData.map(transformNode);
|
|
315
392
|
};
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
393
|
+
|
|
394
|
+
// src/transform/searchInTree.ts
|
|
395
|
+
var searchInTree = (tree, searchValue) => {
|
|
396
|
+
function searchRecursive(node, searchText, result2) {
|
|
397
|
+
const title = node.title?.toString().toLowerCase() || "";
|
|
398
|
+
const text = searchText.toLowerCase();
|
|
399
|
+
const arr = text.split("");
|
|
400
|
+
if (node.isLeaf && arr.every((item) => title.includes(item))) {
|
|
401
|
+
if (!result2.some((item) => item.key === node.key)) {
|
|
402
|
+
result2.push(node);
|
|
403
|
+
}
|
|
320
404
|
}
|
|
321
405
|
if (node.children) {
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
return null;
|
|
327
|
-
};
|
|
328
|
-
var findNodeByMatcher = (nodes, matcher, childrenKey = "children") => {
|
|
329
|
-
for (const node of nodes) {
|
|
330
|
-
if (matcher(node)) {
|
|
331
|
-
return node;
|
|
332
|
-
}
|
|
333
|
-
if (node[childrenKey]) {
|
|
334
|
-
const found = findNodeByMatcher(node[childrenKey], matcher, childrenKey);
|
|
335
|
-
if (found) {
|
|
336
|
-
return found;
|
|
406
|
+
for (const child of node.children) {
|
|
407
|
+
searchRecursive(child, text, result2);
|
|
337
408
|
}
|
|
338
409
|
}
|
|
339
410
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return updater(node);
|
|
346
|
-
}
|
|
347
|
-
if (node[childrenKey] && node[childrenKey].length > 0) {
|
|
348
|
-
const newChildren = updateNodeByMatcher(
|
|
349
|
-
node[childrenKey],
|
|
350
|
-
matcher,
|
|
351
|
-
updater,
|
|
352
|
-
childrenKey
|
|
353
|
-
);
|
|
354
|
-
if (newChildren !== node[childrenKey]) {
|
|
355
|
-
return {
|
|
356
|
-
...node,
|
|
357
|
-
[childrenKey]: newChildren
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return node;
|
|
362
|
-
});
|
|
363
|
-
};
|
|
364
|
-
var getNodePath = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
365
|
-
const findPath = (nodes, target, currentPath) => {
|
|
366
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
367
|
-
const node = nodes[i];
|
|
368
|
-
const newPathNode = {
|
|
369
|
-
node,
|
|
370
|
-
depth: currentPath.length,
|
|
371
|
-
index: i,
|
|
372
|
-
parent: currentPath.length > 0 ? currentPath[currentPath.length - 1] : null,
|
|
373
|
-
path: currentPath.length === 0 ? String(node[keyField]) : `${currentPath[currentPath.length - 1].path}/${String(node[keyField])}`
|
|
374
|
-
};
|
|
375
|
-
if (node[keyField] === target) {
|
|
376
|
-
return [...currentPath, newPathNode];
|
|
377
|
-
}
|
|
378
|
-
const children = node[childrenKey];
|
|
379
|
-
if (children && Array.isArray(children) && children.length > 0) {
|
|
380
|
-
const result = findPath(children, target, [
|
|
381
|
-
...currentPath,
|
|
382
|
-
newPathNode
|
|
383
|
-
]);
|
|
384
|
-
if (result) {
|
|
385
|
-
return result;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return null;
|
|
390
|
-
};
|
|
391
|
-
return findPath(treeData, targetKey, []);
|
|
392
|
-
};
|
|
393
|
-
var getNodeDepth = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
394
|
-
const path = getNodePath(treeData, targetKey, keyField, childrenKey);
|
|
395
|
-
return path ? path.length - 1 : -1;
|
|
396
|
-
};
|
|
397
|
-
var getNodeBreadcrumb = (treeData, targetKey, keyField = "key", childrenKey = "children") => {
|
|
398
|
-
const path = getNodePath(treeData, targetKey, keyField, childrenKey);
|
|
399
|
-
return path ? path.map((p) => p.node) : [];
|
|
400
|
-
};
|
|
401
|
-
var getTreeStats = (treeData, childrenKey = "children") => {
|
|
402
|
-
let totalNodes = 0;
|
|
403
|
-
let maxDepth = 0;
|
|
404
|
-
let leafCount = 0;
|
|
405
|
-
const traverse = (nodes, depth) => {
|
|
406
|
-
for (const node of nodes) {
|
|
407
|
-
totalNodes++;
|
|
408
|
-
maxDepth = Math.max(maxDepth, depth);
|
|
409
|
-
const children = node[childrenKey];
|
|
410
|
-
if (children && Array.isArray(children) && children.length > 0) {
|
|
411
|
-
traverse(children, depth + 1);
|
|
412
|
-
} else {
|
|
413
|
-
leafCount++;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
traverse(treeData, 0);
|
|
418
|
-
return { totalNodes, maxDepth, leafCount };
|
|
419
|
-
};
|
|
420
|
-
var mapTree = (treeData, mapper, childrenKey = "children") => {
|
|
421
|
-
const traverse = (nodes, parent) => {
|
|
422
|
-
return nodes.map((node) => {
|
|
423
|
-
const mappedNode = mapper(node, parent);
|
|
424
|
-
const children = node[childrenKey];
|
|
425
|
-
if (children && Array.isArray(children) && children.length > 0) {
|
|
426
|
-
return {
|
|
427
|
-
...mappedNode,
|
|
428
|
-
[childrenKey]: traverse(children, node)
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
return mappedNode;
|
|
432
|
-
});
|
|
433
|
-
};
|
|
434
|
-
return traverse(treeData);
|
|
411
|
+
const result = [];
|
|
412
|
+
for (const rootNode of tree) {
|
|
413
|
+
searchRecursive(rootNode, searchValue.toLowerCase(), result);
|
|
414
|
+
}
|
|
415
|
+
return result;
|
|
435
416
|
};
|
|
417
|
+
|
|
418
|
+
// src/build/fromArray.ts
|
|
419
|
+
import { default as default8 } from "tree-lodash";
|
|
420
|
+
|
|
421
|
+
// src/utils/findFirstLeaf.ts
|
|
436
422
|
var findFirstLeaf = (treeData, childrenKey = "children") => {
|
|
437
423
|
for (const node of treeData) {
|
|
438
424
|
const children = node[childrenKey];
|
|
@@ -444,6 +430,8 @@ var findFirstLeaf = (treeData, childrenKey = "children") => {
|
|
|
444
430
|
}
|
|
445
431
|
return null;
|
|
446
432
|
};
|
|
433
|
+
|
|
434
|
+
// src/utils/traverseTreeValues.ts
|
|
447
435
|
var traverseTreeValues = (treeData, key, childrenKey = "children") => {
|
|
448
436
|
const result = [];
|
|
449
437
|
const traverse = (nodes) => {
|
|
@@ -460,6 +448,50 @@ var traverseTreeValues = (treeData, key, childrenKey = "children") => {
|
|
|
460
448
|
traverse(treeData);
|
|
461
449
|
return result;
|
|
462
450
|
};
|
|
451
|
+
|
|
452
|
+
// src/utils/filterCheckedLeafKeys.ts
|
|
453
|
+
var filterCheckedLeafKeys = (treeData) => {
|
|
454
|
+
const result = [];
|
|
455
|
+
const traverse = (nodes) => {
|
|
456
|
+
if (!nodes || nodes.length === 0) return;
|
|
457
|
+
for (const node of nodes) {
|
|
458
|
+
if (node.checked === false) continue;
|
|
459
|
+
if (node.children && node.children.length > 0) {
|
|
460
|
+
traverse(node.children);
|
|
461
|
+
} else if (node.checked === true) {
|
|
462
|
+
result.push(node.key);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
traverse(treeData);
|
|
467
|
+
return result;
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// src/utils/collectLeafValuesByKey.ts
|
|
471
|
+
var collectLeafValuesByKey = (nodes, targetValue, isLeafKey = "isLeaf") => {
|
|
472
|
+
for (const node of nodes) {
|
|
473
|
+
if (node.value === targetValue) {
|
|
474
|
+
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
|
475
|
+
const leafNodes = getLeafNodes([node], isLeafKey);
|
|
476
|
+
return leafNodes.map((leaf) => leaf.value);
|
|
477
|
+
}
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
if (node.children && Array.isArray(node.children)) {
|
|
481
|
+
const result = collectLeafValuesByKey(
|
|
482
|
+
node.children,
|
|
483
|
+
targetValue,
|
|
484
|
+
isLeafKey
|
|
485
|
+
);
|
|
486
|
+
if (result !== null) {
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return null;
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
// src/utils/convertGroupsToTreeData.ts
|
|
463
495
|
var convertGroupsToTreeData = (groups, groupKey = "group", _childrenKey = "children") => {
|
|
464
496
|
const groupMap = /* @__PURE__ */ new Map();
|
|
465
497
|
for (const item of groups) {
|
|
@@ -482,27 +514,27 @@ export {
|
|
|
482
514
|
convertGroupsToTreeData,
|
|
483
515
|
copyNode,
|
|
484
516
|
deleteNode,
|
|
517
|
+
default7 as filter,
|
|
485
518
|
filterCheckedLeafKeys,
|
|
486
|
-
|
|
519
|
+
default4 as find,
|
|
487
520
|
findFirstLeaf,
|
|
488
|
-
findNodeById as findNode,
|
|
489
|
-
collectLeafValuesByKey as findNodeAndCollectLeafValues,
|
|
490
521
|
findNodeById,
|
|
491
522
|
findNodeByKey,
|
|
492
523
|
findNodeByMatcher,
|
|
493
|
-
nodeExistsInTree as findNodeInTree,
|
|
494
524
|
findParentOf,
|
|
495
|
-
|
|
496
|
-
|
|
525
|
+
default2 as foreach,
|
|
526
|
+
default8 as fromArray,
|
|
497
527
|
getLeafNodes,
|
|
498
528
|
getNodeBreadcrumb,
|
|
499
529
|
getNodeDepth,
|
|
500
530
|
getNodePath,
|
|
501
531
|
getTreeStats,
|
|
502
|
-
|
|
532
|
+
default6 as map,
|
|
503
533
|
moveNodeInTree,
|
|
504
534
|
nodeExistsInTree,
|
|
505
535
|
searchInTree,
|
|
536
|
+
default5 as some,
|
|
537
|
+
default3 as toArray,
|
|
506
538
|
transformTreeKeys,
|
|
507
539
|
transformTreeNodes,
|
|
508
540
|
traverseTreeValues,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zid-utils/tree-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Tree data structure utility functions",
|
|
5
5
|
"repository": "github:huangzida/utils-packages",
|
|
6
6
|
"type": "module",
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
],
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"tsup": "^8.0.2",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
22
|
+
"typescript": "^5.4.5",
|
|
23
|
+
"vitest": "^2.0.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"tree-lodash": "^0.4.0"
|
|
24
27
|
},
|
|
25
28
|
"scripts": {
|
|
26
29
|
"build": "tsup src/index.ts --format esm --out-dir dist --clean",
|