tree-processor 0.8.0 → 0.8.1
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 +247 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,30 +1,104 @@
|
|
|
1
1
|
# tree-processor
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
一个轻量级的树结构数据处理工具库,使用 TypeScript 编写,支持 tree-shaking,每个格式打包体积约 **6-7 KB**(ESM: 6.39 KB,CJS: 6.64 KB,UMD: 6.68 KB)。
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
## 📋 目录
|
|
18
|
+
|
|
19
|
+
- [特性](#-特性)
|
|
20
|
+
- [使用场景](#-使用场景)
|
|
21
|
+
- [安装](#-安装)
|
|
22
|
+
- [快速开始](#-快速开始)
|
|
23
|
+
- [API 文档](#-api-文档)
|
|
24
|
+
- [遍历方法](#遍历方法)
|
|
25
|
+
- [查找方法](#查找方法)
|
|
26
|
+
- [修改方法](#修改方法)
|
|
27
|
+
- [判断方法](#判断方法)
|
|
28
|
+
- [工具方法](#工具方法)
|
|
29
|
+
- [自定义字段名](#自定义字段名)
|
|
30
|
+
- [测试](#测试)
|
|
31
|
+
- [开发](#开发)
|
|
32
|
+
- [技术栈](#技术栈)
|
|
33
|
+
- [贡献](#-贡献)
|
|
34
|
+
- [更新日志](#-更新日志)
|
|
35
|
+
- [许可证](#-许可证)
|
|
36
|
+
- [相关链接](#-相关链接)
|
|
6
37
|
|
|
7
38
|
## ✨ 特性
|
|
8
39
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
40
|
+
- **轻量级** - 每个格式打包体积仅 6-7 KB(ESM: 6.39 KB,CJS: 6.64 KB,UMD: 6.68 KB),对项目体积影响极小
|
|
41
|
+
- **支持 Tree-shaking** - 支持按需导入,只打包实际使用的代码,进一步减小打包体积
|
|
42
|
+
- **完整的 TypeScript 支持** - 提供完整的类型定义和智能提示,提升开发体验
|
|
43
|
+
- **灵活的自定义字段名** - 支持自定义 children 和 id 字段名,适配各种数据结构
|
|
44
|
+
- **零依赖** - 无任何外部依赖,开箱即用,无需担心依赖冲突
|
|
45
|
+
- **完善的测试覆盖** - 包含 272 个测试用例,覆盖基础功能、边界情况、异常处理、复杂场景等
|
|
46
|
+
- **丰富的 API** - 提供 30+ 个方法,包含类似数组的 API(map、filter、find、some、every、includes、at、indexOf 等),以及树结构特有的操作(获取父子节点、深度计算、数据验证等),涵盖遍历、查找、修改、判断等完整场景
|
|
47
|
+
|
|
48
|
+
**已支持的方法:** mapTree、forEachTree、filterTree、findTree、pushTree、unshiftTree、popTree、shiftTree、someTree、everyTree、includesTree、atTree、indexOfTree、atIndexOfTree、dedupTree、removeTree、getParentTree、getChildrenTree、getSiblingsTree、getNodeDepthMap、getNodeDepth、isLeafNode、isRootNode、isEmptyTreeData、isEmptySingleTreeData、isTreeData、isSingleTreeData、isValidTreeNode、isTreeNodeWithCircularCheck、isSafeTreeDepth。每个方法的最后一个参数可以自定义 children 和 id 的属性名。
|
|
49
|
+
|
|
50
|
+
### 💡 使用场景
|
|
51
|
+
|
|
52
|
+
- **导航系统** - 多级菜单、路由配置的展开、折叠、搜索、过滤
|
|
53
|
+
- **文件系统** - 文件目录的遍历、查找、移动、删除
|
|
54
|
+
- **权限系统** - 组织架构、角色权限的树形结构管理和验证
|
|
55
|
+
- **框架开发** - 组件树、路由树等树形结构的构建和管理
|
|
56
|
+
- **数据管理** - 分类管理、评论系统、树形选择器等数据操作
|
|
16
57
|
|
|
17
58
|
## 📦 安装
|
|
18
59
|
|
|
19
60
|
```bash
|
|
61
|
+
npm install tree-processor
|
|
62
|
+
# 或
|
|
20
63
|
yarn add tree-processor
|
|
21
64
|
# 或
|
|
22
|
-
|
|
65
|
+
pnpm add tree-processor
|
|
23
66
|
```
|
|
24
67
|
|
|
25
|
-
##
|
|
68
|
+
## 🚀 快速开始
|
|
26
69
|
|
|
27
|
-
|
|
70
|
+
```javascript
|
|
71
|
+
import { mapTree, findTree, filterTree } from 'tree-processor'
|
|
72
|
+
|
|
73
|
+
const treeData = [
|
|
74
|
+
{
|
|
75
|
+
id: 1,
|
|
76
|
+
name: 'node1',
|
|
77
|
+
children: [
|
|
78
|
+
{ id: 2, name: 'node2' },
|
|
79
|
+
{ id: 3, name: 'node3' },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
// 获取所有节点名称
|
|
85
|
+
const names = mapTree(treeData, (node) => node.name)
|
|
86
|
+
console.log(names) // ['node1', 'node2', 'node3']
|
|
87
|
+
|
|
88
|
+
// 查找节点
|
|
89
|
+
const node = findTree(treeData, (n) => n.id === 2)
|
|
90
|
+
console.log(node) // { id: 2, name: 'node2' }
|
|
91
|
+
|
|
92
|
+
// 过滤节点
|
|
93
|
+
const filtered = filterTree(treeData, (n) => n.id > 1)
|
|
94
|
+
console.log(filtered) // [{ id: 2, name: 'node2' }, { id: 3, name: 'node3' }]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 📖 API 文档
|
|
98
|
+
|
|
99
|
+
### 引入方式
|
|
100
|
+
|
|
101
|
+
#### 默认导入(推荐用于需要多个方法的场景)
|
|
28
102
|
|
|
29
103
|
#### 默认导入(推荐用于需要多个方法的场景)
|
|
30
104
|
|
|
@@ -59,7 +133,7 @@ const { mapTree, filterTree } = require('tree-processor')
|
|
|
59
133
|
- 只有在需要显式声明变量类型时才需要引入类型(如 `const treeData: TreeData = [...]`)
|
|
60
134
|
- 使用 `import type` 导入类型不会增加运行时体积(类型在编译时会被移除)
|
|
61
135
|
|
|
62
|
-
###
|
|
136
|
+
### 示例数据
|
|
63
137
|
|
|
64
138
|
以下示例数据将用于后续所有方法的演示:
|
|
65
139
|
|
|
@@ -87,7 +161,11 @@ const treeData = [
|
|
|
87
161
|
];
|
|
88
162
|
```
|
|
89
163
|
|
|
90
|
-
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 遍历方法
|
|
167
|
+
|
|
168
|
+
### mapTree
|
|
91
169
|
|
|
92
170
|
遍历树结构数据,对每个节点执行回调函数,返回映射后的数组。
|
|
93
171
|
|
|
@@ -108,7 +186,7 @@ const modifiedNodes = t.mapTree(treeData, (node) => ({
|
|
|
108
186
|
console.log(modifiedNodes) // 返回包含 label 字段的新数组
|
|
109
187
|
```
|
|
110
188
|
|
|
111
|
-
### forEachTree
|
|
189
|
+
### forEachTree
|
|
112
190
|
|
|
113
191
|
遍历树结构数据,对每个节点执行回调函数。与 mapTree 的区别是不返回值,性能更好,适合只需要遍历而不需要返回结果的场景。
|
|
114
192
|
|
|
@@ -132,7 +210,7 @@ t.forEachTree(treeData, () => {
|
|
|
132
210
|
console.log(nodeCount) // 节点总数
|
|
133
211
|
```
|
|
134
212
|
|
|
135
|
-
### filterTree
|
|
213
|
+
### filterTree
|
|
136
214
|
|
|
137
215
|
过滤树结构数据,返回满足条件的节点。
|
|
138
216
|
|
|
@@ -154,7 +232,11 @@ const leafNodes = t.filterTree(treeData, (node) => {
|
|
|
154
232
|
console.log(leafNodes) // 返回所有叶子节点
|
|
155
233
|
```
|
|
156
234
|
|
|
157
|
-
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 查找方法
|
|
238
|
+
|
|
239
|
+
### findTree
|
|
158
240
|
|
|
159
241
|
查找树结构数据中满足条件的第一个节点。如果未找到,返回 null。
|
|
160
242
|
|
|
@@ -172,85 +254,7 @@ const nodeNotFound = t.findTree(treeData, (node) => node.id === 999)
|
|
|
172
254
|
console.log(nodeNotFound) // null
|
|
173
255
|
```
|
|
174
256
|
|
|
175
|
-
###
|
|
176
|
-
|
|
177
|
-
在指定节点下添加子节点到末尾。返回 true 表示添加成功,false 表示未找到目标节点。
|
|
178
|
-
|
|
179
|
-
```javascript
|
|
180
|
-
// 在ID为1的节点下添加新子节点
|
|
181
|
-
const addSuccess = t.pushTree(treeData, 1, { id: 7, name: 'node7' })
|
|
182
|
-
console.log(addSuccess) // true
|
|
183
|
-
console.log(treeData) // 新节点已添加到 children 数组末尾
|
|
184
|
-
|
|
185
|
-
// 尝试在不存在的节点下添加
|
|
186
|
-
const addFailed = t.pushTree(treeData, 999, { id: 8, name: 'node8' })
|
|
187
|
-
console.log(addFailed) // false,未找到目标节点
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### unshiftTree(在指定节点下添加子节点到开头)
|
|
191
|
-
|
|
192
|
-
在指定节点下添加子节点到开头。返回 true 表示添加成功,false 表示未找到目标节点。
|
|
193
|
-
|
|
194
|
-
```javascript
|
|
195
|
-
// 在ID为1的节点下添加新子节点到开头
|
|
196
|
-
const unshiftSuccess = t.unshiftTree(treeData, 1, { id: 7, name: 'node7' })
|
|
197
|
-
console.log(unshiftSuccess) // true
|
|
198
|
-
console.log(treeData) // 新节点已添加到 children 数组开头
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### popTree(删除指定节点下的最后一个子节点)
|
|
202
|
-
|
|
203
|
-
删除指定节点下的最后一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 false。
|
|
204
|
-
|
|
205
|
-
```javascript
|
|
206
|
-
// 删除ID为1的节点下的最后一个子节点
|
|
207
|
-
const removedNode = t.popTree(treeData, 1)
|
|
208
|
-
console.log(removedNode) // 返回被删除的节点对象,或 false
|
|
209
|
-
|
|
210
|
-
// 尝试删除不存在的节点下的子节点
|
|
211
|
-
const popFailed = t.popTree(treeData, 999)
|
|
212
|
-
console.log(popFailed) // false
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### shiftTree(删除指定节点下的第一个子节点)
|
|
216
|
-
|
|
217
|
-
删除指定节点下的第一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 false。
|
|
218
|
-
|
|
219
|
-
```javascript
|
|
220
|
-
// 删除ID为1的节点下的第一个子节点
|
|
221
|
-
const shiftedNode = t.shiftTree(treeData, 1)
|
|
222
|
-
console.log(shiftedNode) // 返回被删除的节点对象,或 false
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### someTree(树结构数据的some方法)
|
|
226
|
-
|
|
227
|
-
检查树结构数据中是否存在满足条件的节点。只要有一个节点满足条件就返回 true。
|
|
228
|
-
|
|
229
|
-
```javascript
|
|
230
|
-
// 检查是否存在名称为 'node2' 的节点
|
|
231
|
-
const hasNode2 = t.someTree(treeData, node => node.name === 'node2')
|
|
232
|
-
console.log(hasNode2) // true
|
|
233
|
-
|
|
234
|
-
// 检查是否存在ID大于10的节点
|
|
235
|
-
const hasLargeId = t.someTree(treeData, node => node.id > 10)
|
|
236
|
-
console.log(hasLargeId) // false
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### everyTree(树结构数据的every方法)
|
|
240
|
-
|
|
241
|
-
检查树结构数据中是否所有节点都满足条件。只有所有节点都满足条件才返回 true。
|
|
242
|
-
|
|
243
|
-
```javascript
|
|
244
|
-
// 检查所有节点的ID是否都大于0
|
|
245
|
-
const allIdsPositive = t.everyTree(treeData, node => node.id > 0)
|
|
246
|
-
console.log(allIdsPositive) // true
|
|
247
|
-
|
|
248
|
-
// 检查所有节点是否都有 name 属性
|
|
249
|
-
const allHaveName = t.everyTree(treeData, node => node.name)
|
|
250
|
-
console.log(allHaveName) // 根据实际数据返回 true 或 false
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### includesTree(检查树中是否包含指定节点)
|
|
257
|
+
### includesTree
|
|
254
258
|
|
|
255
259
|
检查树结构数据中是否包含指定ID的节点。
|
|
256
260
|
|
|
@@ -261,7 +265,7 @@ const hasNode = t.includesTree(treeData, nodeId)
|
|
|
261
265
|
console.log(hasNode) // true 表示包含该节点,false 表示不包含
|
|
262
266
|
```
|
|
263
267
|
|
|
264
|
-
### atTree
|
|
268
|
+
### atTree
|
|
265
269
|
|
|
266
270
|
根据父节点ID和子节点索引获取节点。支持负数索引,和数组的 at 方法一样。未找到返回 null。
|
|
267
271
|
|
|
@@ -279,7 +283,7 @@ const nodeNotFound = t.atTree(treeData, 1, 10)
|
|
|
279
283
|
console.log(nodeNotFound) // null
|
|
280
284
|
```
|
|
281
285
|
|
|
282
|
-
### indexOfTree
|
|
286
|
+
### indexOfTree
|
|
283
287
|
|
|
284
288
|
返回一个数组,值为从根节点开始到 targetId 所在节点的索引路径。未找到返回 null。返回值可以传入 atIndexOfTree 的第二个参数进行取值。
|
|
285
289
|
|
|
@@ -298,7 +302,7 @@ const nodeByPath = t.atIndexOfTree(treeData, indexPath)
|
|
|
298
302
|
console.log(nodeByPath) // 获取到ID为4的节点
|
|
299
303
|
```
|
|
300
304
|
|
|
301
|
-
### atIndexOfTree
|
|
305
|
+
### atIndexOfTree
|
|
302
306
|
|
|
303
307
|
根据索引路径获取节点。路径无效或超出范围返回 null。
|
|
304
308
|
|
|
@@ -317,7 +321,73 @@ const invalidPath = t.atIndexOfTree(treeData, [999])
|
|
|
317
321
|
console.log(invalidPath) // null
|
|
318
322
|
```
|
|
319
323
|
|
|
320
|
-
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## 修改方法
|
|
327
|
+
|
|
328
|
+
### pushTree
|
|
329
|
+
|
|
330
|
+
在指定节点下添加子节点到末尾。返回 true 表示添加成功,false 表示未找到目标节点。
|
|
331
|
+
|
|
332
|
+
```javascript
|
|
333
|
+
// 在ID为1的节点下添加新子节点
|
|
334
|
+
const addSuccess = t.pushTree(treeData, 1, { id: 7, name: 'node7' })
|
|
335
|
+
console.log(addSuccess) // true
|
|
336
|
+
console.log(treeData) // 新节点已添加到 children 数组末尾
|
|
337
|
+
|
|
338
|
+
// 尝试在不存在的节点下添加
|
|
339
|
+
const addFailed = t.pushTree(treeData, 999, { id: 8, name: 'node8' })
|
|
340
|
+
console.log(addFailed) // false,未找到目标节点
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### unshiftTree
|
|
344
|
+
|
|
345
|
+
在指定节点下添加子节点到开头。返回 true 表示添加成功,false 表示未找到目标节点。
|
|
346
|
+
|
|
347
|
+
```javascript
|
|
348
|
+
// 在ID为1的节点下添加新子节点到开头
|
|
349
|
+
const unshiftSuccess = t.unshiftTree(treeData, 1, { id: 7, name: 'node7' })
|
|
350
|
+
console.log(unshiftSuccess) // true
|
|
351
|
+
console.log(treeData) // 新节点已添加到 children 数组开头
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### popTree
|
|
355
|
+
|
|
356
|
+
删除指定节点下的最后一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 false。
|
|
357
|
+
|
|
358
|
+
```javascript
|
|
359
|
+
// 删除ID为1的节点下的最后一个子节点
|
|
360
|
+
const removedNode = t.popTree(treeData, 1)
|
|
361
|
+
console.log(removedNode) // 返回被删除的节点对象,或 false
|
|
362
|
+
|
|
363
|
+
// 尝试删除不存在的节点下的子节点
|
|
364
|
+
const popFailed = t.popTree(treeData, 999)
|
|
365
|
+
console.log(popFailed) // false
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### shiftTree
|
|
369
|
+
|
|
370
|
+
删除指定节点下的第一个子节点。返回被删除的节点,如果节点不存在或没有子节点则返回 false。
|
|
371
|
+
|
|
372
|
+
```javascript
|
|
373
|
+
// 删除ID为1的节点下的第一个子节点
|
|
374
|
+
const shiftedNode = t.shiftTree(treeData, 1)
|
|
375
|
+
console.log(shiftedNode) // 返回被删除的节点对象,或 false
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### removeTree
|
|
379
|
+
|
|
380
|
+
删除树结构数据中指定ID的节点,包括根节点和子节点。
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
const nodeIdToRemove = 2
|
|
384
|
+
const removeSuccess = t.removeTree(treeData, nodeIdToRemove)
|
|
385
|
+
|
|
386
|
+
console.log(removeSuccess) // true 表示删除成功,false 表示未找到节点
|
|
387
|
+
console.log(treeData) // 删除后的树结构
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### dedupTree
|
|
321
391
|
|
|
322
392
|
树结构对象数组去重方法,根据指定的键去除重复节点。保留第一次出现的节点。
|
|
323
393
|
|
|
@@ -331,19 +401,39 @@ const uniqueByNameTree = t.dedupTree(treeData, 'name')
|
|
|
331
401
|
console.log(uniqueByNameTree) // 返回根据 name 去重后的数据
|
|
332
402
|
```
|
|
333
403
|
|
|
334
|
-
|
|
404
|
+
---
|
|
335
405
|
|
|
336
|
-
|
|
406
|
+
## 判断方法
|
|
407
|
+
|
|
408
|
+
### someTree
|
|
409
|
+
|
|
410
|
+
检查树结构数据中是否存在满足条件的节点。只要有一个节点满足条件就返回 true。
|
|
337
411
|
|
|
338
412
|
```javascript
|
|
339
|
-
|
|
340
|
-
const
|
|
413
|
+
// 检查是否存在名称为 'node2' 的节点
|
|
414
|
+
const hasNode2 = t.someTree(treeData, node => node.name === 'node2')
|
|
415
|
+
console.log(hasNode2) // true
|
|
341
416
|
|
|
342
|
-
|
|
343
|
-
|
|
417
|
+
// 检查是否存在ID大于10的节点
|
|
418
|
+
const hasLargeId = t.someTree(treeData, node => node.id > 10)
|
|
419
|
+
console.log(hasLargeId) // false
|
|
344
420
|
```
|
|
345
421
|
|
|
346
|
-
###
|
|
422
|
+
### everyTree
|
|
423
|
+
|
|
424
|
+
检查树结构数据中是否所有节点都满足条件。只有所有节点都满足条件才返回 true。
|
|
425
|
+
|
|
426
|
+
```javascript
|
|
427
|
+
// 检查所有节点的ID是否都大于0
|
|
428
|
+
const allIdsPositive = t.everyTree(treeData, node => node.id > 0)
|
|
429
|
+
console.log(allIdsPositive) // true
|
|
430
|
+
|
|
431
|
+
// 检查所有节点是否都有 name 属性
|
|
432
|
+
const allHaveName = t.everyTree(treeData, node => node.name)
|
|
433
|
+
console.log(allHaveName) // 根据实际数据返回 true 或 false
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### getParentTree
|
|
347
437
|
|
|
348
438
|
获取指定节点的父节点。如果节点是根节点或未找到,返回 null。
|
|
349
439
|
|
|
@@ -361,7 +451,7 @@ const parentNotFound = t.getParentTree(treeData, 999)
|
|
|
361
451
|
console.log(parentNotFound) // null
|
|
362
452
|
```
|
|
363
453
|
|
|
364
|
-
### getChildrenTree
|
|
454
|
+
### getChildrenTree
|
|
365
455
|
|
|
366
456
|
获取指定节点的所有直接子节点。如果未找到节点或没有子节点,返回空数组。
|
|
367
457
|
|
|
@@ -394,7 +484,7 @@ const customChildren = t.getChildrenTree(customTree, 1, fieldNames)
|
|
|
394
484
|
console.log(customChildren) // 返回子节点数组
|
|
395
485
|
```
|
|
396
486
|
|
|
397
|
-
### getSiblingsTree
|
|
487
|
+
### getSiblingsTree
|
|
398
488
|
|
|
399
489
|
获取指定节点的所有兄弟节点(包括自己)。如果未找到节点,返回空数组。根节点的兄弟节点是其他根节点。
|
|
400
490
|
|
|
@@ -432,7 +522,11 @@ const customSiblings = t.getSiblingsTree(customTree, 2, fieldNames)
|
|
|
432
522
|
console.log(customSiblings) // 返回兄弟节点数组(包括自己)
|
|
433
523
|
```
|
|
434
524
|
|
|
435
|
-
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 工具方法
|
|
528
|
+
|
|
529
|
+
### getNodeDepthMap
|
|
436
530
|
|
|
437
531
|
返回一个字典,键代表节点的 id,值代表该节点在数据的第几层。深度从1开始,根节点深度为1。
|
|
438
532
|
|
|
@@ -450,7 +544,7 @@ const emptyDepthMap = t.getNodeDepthMap([])
|
|
|
450
544
|
console.log(emptyDepthMap) // {}
|
|
451
545
|
```
|
|
452
546
|
|
|
453
|
-
### getNodeDepth
|
|
547
|
+
### getNodeDepth
|
|
454
548
|
|
|
455
549
|
获取指定节点的深度。深度从1开始,根节点深度为1。
|
|
456
550
|
|
|
@@ -490,7 +584,7 @@ console.log(depth) // 2
|
|
|
490
584
|
- `getNodeDepthMap` - 批量获取所有节点的深度(一次性计算所有节点)
|
|
491
585
|
- `getNodeDepth` - 只获取单个节点的深度(只计算目标节点,效率更高)
|
|
492
586
|
|
|
493
|
-
### isLeafNode
|
|
587
|
+
### isLeafNode
|
|
494
588
|
|
|
495
589
|
检查节点是否是叶子节点(没有子节点)。轻量级方法,只检查节点本身,不遍历树。
|
|
496
590
|
|
|
@@ -536,7 +630,7 @@ console.log(t.isLeafNode(customNode, fieldNames)) // true
|
|
|
536
630
|
- `isLeafNode` - 只检查单个节点,轻量级(O(1)),适合在遍历时使用
|
|
537
631
|
- `getChildrenTree` - 获取子节点数组,需要传入 tree 和 nodeId,需要查找节点(O(n))
|
|
538
632
|
|
|
539
|
-
### isRootNode
|
|
633
|
+
### isRootNode
|
|
540
634
|
|
|
541
635
|
检查节点是否是根节点(没有父节点)。根节点是树结构数据数组中的顶层节点。
|
|
542
636
|
|
|
@@ -590,7 +684,7 @@ console.log(t.isRootNode(treeData, 999)) // false
|
|
|
590
684
|
- `getParentTree` - 返回父节点对象,需要判断是否为 null
|
|
591
685
|
- `getNodeDepth` - 返回深度,需要判断是否等于 1
|
|
592
686
|
|
|
593
|
-
### isEmptyTreeData
|
|
687
|
+
### isEmptyTreeData
|
|
594
688
|
|
|
595
689
|
检查树结构数据(数组)是否为空。空数组、null、undefined 都视为空。此函数支持 fieldNames 参数以保持 API 一致性,但该参数不生效(因为只检查数组是否为空,不访问 children 或 id 字段)。
|
|
596
690
|
|
|
@@ -613,7 +707,7 @@ const isEmptyWithFieldNames = t.isEmptyTreeData(treeData, fieldNames)
|
|
|
613
707
|
console.log(isEmptyWithFieldNames) // false(结果与不传 fieldNames 相同)
|
|
614
708
|
```
|
|
615
709
|
|
|
616
|
-
### isEmptySingleTreeData
|
|
710
|
+
### isEmptySingleTreeData
|
|
617
711
|
|
|
618
712
|
检查单个树结构数据是否为空。如果数据不是有效的单个树结构数据、没有 children 字段,或者 children 是空数组,则视为空。如果有子节点(children 数组不为空),即使子节点本身是空的,树也不为空。
|
|
619
713
|
|
|
@@ -666,7 +760,7 @@ const isEmptyCustom = t.isEmptySingleTreeData(customTree, fieldNames)
|
|
|
666
760
|
console.log(isEmptyCustom) // true
|
|
667
761
|
```
|
|
668
762
|
|
|
669
|
-
### isTreeData
|
|
763
|
+
### isTreeData
|
|
670
764
|
|
|
671
765
|
判断数据是否是树结构数据(数组)。树结构数据必须是一个数组,数组中的每个元素都必须是有效的单个树结构数据。
|
|
672
766
|
|
|
@@ -715,7 +809,7 @@ const fieldNames = { children: 'subNodes', id: 'nodeId' };
|
|
|
715
809
|
console.log(t.isTreeData(customForest, fieldNames)) // true
|
|
716
810
|
```
|
|
717
811
|
|
|
718
|
-
### isSingleTreeData
|
|
812
|
+
### isSingleTreeData
|
|
719
813
|
|
|
720
814
|
判断数据是否是单个树结构数据(单个对象)。树结构数据必须是一个对象(不能是数组、null、undefined 或基本类型),如果存在 children 字段,必须是数组类型,并且会递归检查所有子节点。
|
|
721
815
|
|
|
@@ -757,7 +851,7 @@ const fieldNames = { children: 'subNodes', id: 'nodeId' };
|
|
|
757
851
|
console.log(t.isSingleTreeData(customTree, fieldNames)) // true
|
|
758
852
|
```
|
|
759
853
|
|
|
760
|
-
### isValidTreeNode
|
|
854
|
+
### isValidTreeNode
|
|
761
855
|
|
|
762
856
|
检查单个节点是否是有效的树节点结构(轻量级,不递归检查子节点)。只检查节点本身的结构,不检查子节点。
|
|
763
857
|
|
|
@@ -794,7 +888,7 @@ console.log(t.isValidTreeNode(customNode, fieldNames)) // true
|
|
|
794
888
|
- `isValidTreeNode` - 只检查单个节点的基本结构,不递归检查子节点(轻量级)
|
|
795
889
|
- `isSingleTreeData` - 递归检查整个树结构,确保所有子节点都是有效的树结构
|
|
796
890
|
|
|
797
|
-
### isTreeNodeWithCircularCheck
|
|
891
|
+
### isTreeNodeWithCircularCheck
|
|
798
892
|
|
|
799
893
|
检查节点是否是有效的树节点结构,并检测循环引用。使用 WeakSet 跟踪已访问的节点,如果发现循环引用则返回 false。
|
|
800
894
|
|
|
@@ -834,7 +928,7 @@ console.log(t.isTreeNodeWithCircularCheck(customNode, fieldNames)) // true
|
|
|
834
928
|
- 数据验证,防止无限递归
|
|
835
929
|
- 调试时检查数据结构是否正确
|
|
836
930
|
|
|
837
|
-
### isSafeTreeDepth
|
|
931
|
+
### isSafeTreeDepth
|
|
838
932
|
|
|
839
933
|
检查树结构数据的深度是否安全(防止递归爆栈)。如果树的深度超过 `maxDepth`,返回 false。
|
|
840
934
|
|
|
@@ -937,6 +1031,36 @@ npm run build
|
|
|
937
1031
|
- **Terser** - JavaScript 压缩工具
|
|
938
1032
|
- **TypeScript** - 类型支持
|
|
939
1033
|
|
|
940
|
-
##
|
|
1034
|
+
## 🤝 贡献
|
|
1035
|
+
|
|
1036
|
+
欢迎贡献!如果你有任何想法或发现问题,请:
|
|
1037
|
+
|
|
1038
|
+
1. Fork 本仓库
|
|
1039
|
+
2. 创建你的特性分支 (`git checkout -b feature/AmazingFeature`)
|
|
1040
|
+
3. 提交你的更改 (`git commit -m 'Add some AmazingFeature'`)
|
|
1041
|
+
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
|
1042
|
+
5. 开启一个 Pull Request
|
|
1043
|
+
|
|
1044
|
+
## 📝 更新日志
|
|
1045
|
+
|
|
1046
|
+
查看 [CHANGELOG.md](./CHANGELOG.md) 了解详细的版本更新记录。
|
|
1047
|
+
|
|
1048
|
+
## 📄 许可证
|
|
1049
|
+
|
|
1050
|
+
本项目采用 [MIT](./LICENSE) 许可证。
|
|
1051
|
+
|
|
1052
|
+
## 🔗 相关链接
|
|
1053
|
+
|
|
1054
|
+
- [GitHub 仓库](https://github.com/knott11/tree-processor)
|
|
1055
|
+
- [npm 包](https://www.npmjs.com/package/tree-processor)
|
|
1056
|
+
- [问题反馈](https://github.com/knott11/tree-processor/issues)
|
|
1057
|
+
|
|
1058
|
+
---
|
|
1059
|
+
|
|
1060
|
+
<div align="center">
|
|
1061
|
+
|
|
1062
|
+
如果这个项目对你有帮助,请给它一个 ⭐️
|
|
1063
|
+
|
|
1064
|
+
Made with ❤️ by [knott11](https://github.com/knott11)
|
|
941
1065
|
|
|
942
|
-
|
|
1066
|
+
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tree-processor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "A lightweight TypeScript library for processing tree-structured data with comprehensive methods (map, filter, find, push, pop, remove, getParent, includes, etc.), supporting tree-shaking and custom field names",
|
|
5
5
|
"main": "dist/tree-processor.cjs.js",
|
|
6
6
|
"module": "dist/tree-processor.esm.js",
|