@cloudcome/utils-core 1.19.1 → 1.20.0
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 +1 -1
- package/dist/array.cjs +181 -125
- package/dist/array.cjs.map +1 -1
- package/dist/array.mjs +181 -133
- package/dist/array.mjs.map +1 -1
- package/dist/async.cjs +181 -171
- package/dist/async.cjs.map +1 -1
- package/dist/async.mjs +181 -174
- package/dist/async.mjs.map +1 -1
- package/dist/base64.cjs +16 -12
- package/dist/base64.cjs.map +1 -1
- package/dist/base64.mjs +17 -14
- package/dist/base64.mjs.map +1 -1
- package/dist/cache.cjs +79 -67
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.d.ts +3 -3
- package/dist/cache.mjs +80 -71
- package/dist/cache.mjs.map +1 -1
- package/dist/color.cjs +478 -167
- package/dist/color.cjs.map +1 -1
- package/dist/color.d.ts +3 -3
- package/dist/color.mjs +480 -197
- package/dist/color.mjs.map +1 -1
- package/dist/crypto.cjs +474 -687
- package/dist/crypto.cjs.map +1 -1
- package/dist/crypto.mjs +476 -693
- package/dist/crypto.mjs.map +1 -1
- package/dist/date.cjs +972 -161
- package/dist/date.cjs.map +1 -1
- package/dist/date.d.ts +2 -2
- package/dist/date.mjs +962 -191
- package/dist/date.mjs.map +1 -1
- package/dist/dict.cjs +90 -52
- package/dist/dict.cjs.map +1 -1
- package/dist/dict.d.ts +1 -1
- package/dist/dict.mjs +91 -54
- package/dist/dict.mjs.map +1 -1
- package/dist/easing.cjs +105 -103
- package/dist/easing.cjs.map +1 -1
- package/dist/easing.mjs +106 -133
- package/dist/easing.mjs.map +1 -1
- package/dist/emitter.cjs +101 -96
- package/dist/emitter.cjs.map +1 -1
- package/dist/emitter.mjs +101 -97
- package/dist/emitter.mjs.map +1 -1
- package/dist/env.cjs +43 -9
- package/dist/env.cjs.map +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/env.mjs +43 -15
- package/dist/env.mjs.map +1 -1
- package/dist/error.cjs +26 -5
- package/dist/error.cjs.map +1 -1
- package/dist/error.mjs +26 -7
- package/dist/error.mjs.map +1 -1
- package/dist/exception.cjs +38 -20
- package/dist/exception.cjs.map +1 -1
- package/dist/exception.d.ts +5 -5
- package/dist/exception.mjs +38 -21
- package/dist/exception.mjs.map +1 -1
- package/dist/function.cjs +128 -68
- package/dist/function.cjs.map +1 -1
- package/dist/function.mjs +128 -72
- package/dist/function.mjs.map +1 -1
- package/dist/index.cjs +8 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +9 -5
- package/dist/index.mjs.map +1 -1
- package/dist/number.cjs +10 -14
- package/dist/number.mjs +2 -15
- package/dist/object/get-set.d.ts +27 -3
- package/dist/object/merge.d.ts +2 -2
- package/dist/object.cjs +369 -106
- package/dist/object.cjs.map +1 -1
- package/dist/object.mjs +366 -115
- package/dist/object.mjs.map +1 -1
- package/dist/path.cjs +144 -55
- package/dist/path.cjs.map +1 -1
- package/dist/path.mjs +144 -62
- package/dist/path.mjs.map +1 -1
- package/dist/promise.cjs +84 -43
- package/dist/promise.cjs.map +1 -1
- package/dist/promise.mjs +85 -50
- package/dist/promise.mjs.map +1 -1
- package/dist/qs.cjs +63 -39
- package/dist/qs.cjs.map +1 -1
- package/dist/qs.mjs +64 -42
- package/dist/qs.mjs.map +1 -1
- package/dist/regexp.cjs +118 -35
- package/dist/regexp.cjs.map +1 -1
- package/dist/regexp.mjs +119 -46
- package/dist/regexp.mjs.map +1 -1
- package/dist/string.cjs +12 -15
- package/dist/string.mjs +2 -16
- package/dist/string2.cjs +378 -142
- package/dist/string2.cjs.map +1 -1
- package/dist/string2.mjs +259 -143
- package/dist/string2.mjs.map +1 -1
- package/dist/time.cjs +136 -59
- package/dist/time.cjs.map +1 -1
- package/dist/time.mjs +136 -65
- package/dist/time.mjs.map +1 -1
- package/dist/timer.cjs +122 -112
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.mjs +123 -115
- package/dist/timer.mjs.map +1 -1
- package/dist/tree.cjs +207 -112
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.mjs +207 -116
- package/dist/tree.mjs.map +1 -1
- package/dist/try/curry.d.ts +1 -1
- package/dist/try.cjs +36 -37
- package/dist/try.cjs.map +1 -1
- package/dist/try.mjs +35 -37
- package/dist/try.mjs.map +1 -1
- package/dist/type.cjs +126 -24
- package/dist/type.cjs.map +1 -1
- package/dist/type.d.ts +2 -2
- package/dist/type.mjs +128 -45
- package/dist/type.mjs.map +1 -1
- package/dist/types.cjs +0 -2
- package/dist/types.d.ts +2 -2
- package/dist/types.mjs +0 -2
- package/dist/unique.cjs +41 -38
- package/dist/unique.cjs.map +1 -1
- package/dist/unique.mjs +42 -41
- package/dist/unique.mjs.map +1 -1
- package/dist/url.cjs +39 -30
- package/dist/url.cjs.map +1 -1
- package/dist/url.mjs +40 -33
- package/dist/url.mjs.map +1 -1
- package/dist/version.cjs +51 -33
- package/dist/version.cjs.map +1 -1
- package/dist/version.mjs +51 -35
- package/dist/version.mjs.map +1 -1
- package/package.json +104 -105
- package/dist/const.cjs +0 -14
- package/dist/const.cjs.map +0 -1
- package/dist/const.mjs +0 -15
- package/dist/const.mjs.map +0 -1
- package/dist/core.cjs +0 -362
- package/dist/core.cjs.map +0 -1
- package/dist/core.mjs +0 -363
- package/dist/core.mjs.map +0 -1
- package/dist/crypto/md5.d.mts +0 -1
- package/dist/crypto/sha1.d.mts +0 -1
- package/dist/crypto/sha256.d.mts +0 -1
- package/dist/crypto/sha512.d.mts +0 -1
- package/dist/each.cjs +0 -18
- package/dist/each.cjs.map +0 -1
- package/dist/each.mjs +0 -19
- package/dist/each.mjs.map +0 -1
- package/dist/merge.cjs +0 -87
- package/dist/merge.cjs.map +0 -1
- package/dist/merge.mjs +0 -88
- package/dist/merge.mjs.map +0 -1
- package/dist/number.cjs.map +0 -1
- package/dist/number.mjs.map +0 -1
- package/dist/string.cjs.map +0 -1
- package/dist/string.mjs.map +0 -1
- package/dist/types.cjs.map +0 -1
- package/dist/types.mjs.map +0 -1
package/dist/tree.mjs
CHANGED
|
@@ -1,125 +1,216 @@
|
|
|
1
|
+
import { isArray, isNullish, isUndefined } from "./type.mjs";
|
|
1
2
|
import { arrayEach } from "./array.mjs";
|
|
2
|
-
|
|
3
|
+
//#region src/tree.ts
|
|
4
|
+
/**
|
|
5
|
+
* 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。
|
|
6
|
+
*
|
|
7
|
+
* @param treeList - 要遍历的深度数组。
|
|
8
|
+
* @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。
|
|
9
|
+
* @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。
|
|
10
|
+
* @returns 无返回值。
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const treeList = [
|
|
15
|
+
* { value: 1, children: [{ value: 2 }, { value: 3 }] },
|
|
16
|
+
* { value: 4 }
|
|
17
|
+
* ];
|
|
18
|
+
*
|
|
19
|
+
* treeEach(treeList, (item) => {
|
|
20
|
+
* console.log(item.value);
|
|
21
|
+
* if (item.value === 2) return false; // 提前终止遍历
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
3
25
|
function treeEach(treeList, iterator, breadthFist = false) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
};
|
|
57
|
-
walk({
|
|
58
|
-
list: treeList,
|
|
59
|
-
level: 1,
|
|
60
|
-
parent: null,
|
|
61
|
-
path: []
|
|
62
|
-
});
|
|
26
|
+
const treeInfoList = [];
|
|
27
|
+
let returnFalse = false;
|
|
28
|
+
const iterate = (info) => {
|
|
29
|
+
if (iterator(info) === false) {
|
|
30
|
+
returnFalse = true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const next = (info, walk) => {
|
|
35
|
+
const { item, level } = info;
|
|
36
|
+
const { children } = item;
|
|
37
|
+
if (isArray(children)) returnFalse = walk({
|
|
38
|
+
...info,
|
|
39
|
+
parent: item,
|
|
40
|
+
list: children,
|
|
41
|
+
level: level + 1
|
|
42
|
+
}) === false;
|
|
43
|
+
};
|
|
44
|
+
const walk = (walker) => {
|
|
45
|
+
const { list, parent, path } = walker;
|
|
46
|
+
const path2 = [...path];
|
|
47
|
+
while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) path2.pop();
|
|
48
|
+
arrayEach(list, (item, index) => {
|
|
49
|
+
if (returnFalse) return false;
|
|
50
|
+
const info = {
|
|
51
|
+
...walker,
|
|
52
|
+
item,
|
|
53
|
+
index,
|
|
54
|
+
path: [...path2, item]
|
|
55
|
+
};
|
|
56
|
+
if (breadthFist) treeInfoList.push(info);
|
|
57
|
+
else {
|
|
58
|
+
iterate(info);
|
|
59
|
+
if (returnFalse) return false;
|
|
60
|
+
next(info, walk);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (breadthFist) while (!returnFalse) {
|
|
64
|
+
const info = treeInfoList.shift();
|
|
65
|
+
if (!info) break;
|
|
66
|
+
iterate(info);
|
|
67
|
+
if (returnFalse) break;
|
|
68
|
+
next(info, walk);
|
|
69
|
+
}
|
|
70
|
+
return !returnFalse;
|
|
71
|
+
};
|
|
72
|
+
walk({
|
|
73
|
+
list: treeList,
|
|
74
|
+
level: 1,
|
|
75
|
+
parent: null,
|
|
76
|
+
path: []
|
|
77
|
+
});
|
|
63
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* 在深度数组中查找满足条件的第一个节点信息。
|
|
81
|
+
*
|
|
82
|
+
* @param treeList - 要查找的深度数组。
|
|
83
|
+
* @param predicate - 判断节点是否满足条件的回调函数。
|
|
84
|
+
* @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。
|
|
85
|
+
* @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const treeList = [
|
|
90
|
+
* { value: 1, children: [{ value: 2 }, { value: 3 }] },
|
|
91
|
+
* { value: 4 }
|
|
92
|
+
* ];
|
|
93
|
+
*
|
|
94
|
+
* const found = treeFind(treeList, (info) => info.item.value === 3);
|
|
95
|
+
* console.log(found);
|
|
96
|
+
* // {
|
|
97
|
+
* // item: { value: 3 },
|
|
98
|
+
* // index: 1,
|
|
99
|
+
* // list: [{ value: 2 }, { value: 3 }],
|
|
100
|
+
* // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },
|
|
101
|
+
* // level: 2,
|
|
102
|
+
* // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]
|
|
103
|
+
* // }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
64
106
|
function treeFind(treeList, predicate, breadthFist = false) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
breadthFist
|
|
75
|
-
);
|
|
76
|
-
return found;
|
|
107
|
+
let found;
|
|
108
|
+
treeEach(treeList, (info) => {
|
|
109
|
+
if (predicate(info)) {
|
|
110
|
+
found = info;
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}, breadthFist);
|
|
114
|
+
return found;
|
|
77
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。
|
|
118
|
+
*
|
|
119
|
+
* @template I - 树节点的类型,必须继承自 `TreeItem`。
|
|
120
|
+
* @template T - 转换后的数据类型。
|
|
121
|
+
* @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。
|
|
122
|
+
* @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。
|
|
123
|
+
* @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。
|
|
124
|
+
* @returns {T[]} - 转换后的一维数组。
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const treeList = [
|
|
128
|
+
* { value: 1, children: [{ value: 2 }, { value: 3 }] },
|
|
129
|
+
* { value: 4 }
|
|
130
|
+
* ];
|
|
131
|
+
*
|
|
132
|
+
* const flattened = deepFlat(treeList, (info) => info.item.value);
|
|
133
|
+
* console.log(flattened); // [1, 2, 3, 4]
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
78
136
|
function deepFlat(deepList, flatten, breadthFist = false) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
},
|
|
85
|
-
breadthFist
|
|
86
|
-
);
|
|
87
|
-
return list2;
|
|
137
|
+
const list2 = [];
|
|
138
|
+
treeEach(deepList, (info) => {
|
|
139
|
+
list2.push(flatten(info));
|
|
140
|
+
}, breadthFist);
|
|
141
|
+
return list2;
|
|
88
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* 从扁平列表构建树形结构。
|
|
145
|
+
*
|
|
146
|
+
* @template I - 节点对象的类型,必须继承自 `AnyObject`。
|
|
147
|
+
* @param {I[]} list - 扁平化的节点列表。
|
|
148
|
+
* @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。
|
|
149
|
+
* @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。
|
|
150
|
+
* @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。
|
|
151
|
+
* @param {function} options.appendChild - 将子节点添加到父节点的函数。
|
|
152
|
+
* @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const list = [
|
|
157
|
+
* { id: 1, parentId: null, name: 'Root' },
|
|
158
|
+
* { id: 2, parentId: 1, name: 'Child 1' },
|
|
159
|
+
* { id: 3, parentId: 1, name: 'Child 2' }
|
|
160
|
+
* ];
|
|
161
|
+
*
|
|
162
|
+
* const tree = treeFrom(list, {
|
|
163
|
+
* getSelfKey: (item) => item.id,
|
|
164
|
+
* getParentKey: (item) => item.parentId,
|
|
165
|
+
* appendChild: (parent, info) => {
|
|
166
|
+
* if (!parent.children) parent.children = [];
|
|
167
|
+
* parent.children.push(info.item);
|
|
168
|
+
* }
|
|
169
|
+
* });
|
|
170
|
+
*
|
|
171
|
+
* console.log(tree);
|
|
172
|
+
* // {
|
|
173
|
+
* // id: 1,
|
|
174
|
+
* // parentId: null,
|
|
175
|
+
* // name: 'Root',
|
|
176
|
+
* // children: [
|
|
177
|
+
* // { id: 2, parentId: 1, name: 'Child 1' },
|
|
178
|
+
* // { id: 3, parentId: 1, name: 'Child 2' }
|
|
179
|
+
* // ]
|
|
180
|
+
* // }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
89
183
|
function treeFrom(list, options) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
184
|
+
const keyMap = /* @__PURE__ */ new Map();
|
|
185
|
+
const freeSet = /* @__PURE__ */ new Set();
|
|
186
|
+
const roots = [];
|
|
187
|
+
const assign = (info, isFirst = false) => {
|
|
188
|
+
const { parentKey, item } = info;
|
|
189
|
+
if (isNullish(parentKey)) roots.push(item);
|
|
190
|
+
else {
|
|
191
|
+
const parent = keyMap.get(parentKey);
|
|
192
|
+
if (isUndefined(parent)) {
|
|
193
|
+
if (isFirst) freeSet.add(info);
|
|
194
|
+
} else options.appendChild(parent, info);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
arrayEach(list, (item, index) => {
|
|
198
|
+
const selfKey = options.getSelfKey(item, index);
|
|
199
|
+
const parentKey = options.getParentKey(item, index);
|
|
200
|
+
if (isNullish(selfKey)) return;
|
|
201
|
+
const info = {
|
|
202
|
+
selfKey,
|
|
203
|
+
parentKey,
|
|
204
|
+
item,
|
|
205
|
+
index
|
|
206
|
+
};
|
|
207
|
+
keyMap.set(selfKey, info);
|
|
208
|
+
assign(info, true);
|
|
209
|
+
});
|
|
210
|
+
for (const info of freeSet.values()) assign(info);
|
|
211
|
+
return roots;
|
|
118
212
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
treeFrom
|
|
124
|
-
};
|
|
125
|
-
//# sourceMappingURL=tree.mjs.map
|
|
213
|
+
//#endregion
|
|
214
|
+
export { deepFlat, treeEach, treeFind, treeFrom };
|
|
215
|
+
|
|
216
|
+
//# sourceMappingURL=tree.mjs.map
|
package/dist/tree.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.mjs","sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (info: TreeInfo<I>) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (info: TreeInfo<I>) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (walker: TreeWalker<I>) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level, parent, path } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, level, parent, path } = walker;\n\n const path2 = [...path];\n while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(list: I[], options: TreeFromOptions<I>): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { selfKey, parentKey, item, index } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"names":["walk"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree.mjs","names":[],"sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (\n info: TreeInfo<I>,\n) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (\n info: TreeInfo<I>,\n) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (\n walker: TreeWalker<I>,\n) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, parent, path } = walker;\n\n const path2 = [...path];\n while (\n parent !== null &&\n path2.length > 0 &&\n path2[path2.length - 1] !== parent\n ) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(\n list: I[],\n options: TreeFromOptions<I>,\n): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { parentKey, item } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAgIA,SAAgB,SACd,UACA,UACA,cAAc,OACR;CACN,MAAM,eAA8B,EAAE;CACtC,IAAI,cAAc;CAElB,MAAM,WAAW,SAAsB;EACrC,IAAI,SAAS,KAAK,KAAK,OAAO;GAC5B,cAAc;GACd,OAAO;;;CAIX,MAAM,QAAQ,MAAmB,SAAsB;EACrD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,aAAa;EAErB,IAAI,QAAQ,SAAS,EACnB,cACE,KAAK;GACH,GAAG;GACH,QAAQ;GACR,MAAM;GACN,OAAO,QAAQ;GAChB,CAAC,KAAK;;CAIb,MAAM,QAAqB,WAAW;EACpC,MAAM,EAAE,MAAM,QAAQ,SAAS;EAE/B,MAAM,QAAQ,CAAC,GAAG,KAAK;EACvB,OACE,WAAW,QACX,MAAM,SAAS,KACf,MAAM,MAAM,SAAS,OAAO,QAE5B,MAAM,KAAK;EAGb,UAAU,OAAO,MAAM,UAAU;GAC/B,IAAI,aAAa,OAAO;GAExB,MAAM,OAAoB;IACxB,GAAG;IACH;IACA;IACA,MAAM,CAAC,GAAG,OAAO,KAAK;IACvB;GAGD,IAAI,aACF,aAAa,KAAK,KAAK;QAGpB;IACH,QAAQ,KAAK;IACb,IAAI,aAAa,OAAO;IACxB,KAAK,MAAM,KAAK;;IAElB;EAEF,IAAI,aACF,OAAO,CAAC,aAAa;GACnB,MAAM,OAAO,aAAa,OAAO;GACjC,IAAI,CAAC,MAAM;GAEX,QAAQ,KAAK;GACb,IAAI,aAAa;GAGjB,KAAK,MAAM,KAAK;;EAIpB,OAAO,CAAC;;CAGV,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM,EAAE;EACT,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BJ,SAAgB,SACd,UACA,WACA,cAAc,OACW;CACzB,IAAI;CAEJ,SACE,WACC,SAAS;EACR,IAAI,UAAU,KAAK,EAAE;GACnB,QAAQ;GACR,OAAO;;IAGX,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBT,SAAgB,SACd,UACA,SACA,cAAc,OACT;CACL,MAAM,QAAa,EAAE;CAErB,SACE,WACC,SAAS;EACR,MAAM,KAAK,QAAQ,KAAK,CAAC;IAE3B,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDT,SAAgB,SACd,MACA,SACyB;CACzB,MAAM,yBAAS,IAAI,KAA+B;CAClD,MAAM,0BAAU,IAAI,KAAsB;CAC1C,MAAM,QAAqB,EAAE;CAG7B,MAAM,UAAU,MAAuB,UAAU,UAAU;EACzD,MAAM,EAAE,WAAW,SAAS;EAG5B,IAAI,UAAU,UAAU,EACtB,MAAM,KAAK,KAAK;OAGb;GACH,MAAM,SAAS,OAAO,IAAI,UAAU;GAGpC,IAAI,YAAY,OAAO;QAEjB,SAAS,QAAQ,IAAI,KAAK;UAI9B,QAAQ,YAAY,QAAQ,KAAK;;;CAMvC,UAAU,OAAO,MAAM,UAAU;EAC/B,MAAM,UAAU,QAAQ,WAAW,MAAM,MAAM;EAC/C,MAAM,YAAY,QAAQ,aAAa,MAAM,MAAM;EAEnD,IAAI,UAAU,QAAQ,EAAE;EAExB,MAAM,OAAO;GAAE;GAAS;GAAW;GAAM;GAAO;EAChD,OAAO,IAAI,SAAS,KAAK;EAEzB,OAAO,MAAM,KAAK;GAClB;CAGF,KAAK,MAAM,QAAQ,QAAQ,QAAQ,EACjC,OAAO,KAAK;CAGd,OAAO"}
|
package/dist/try/curry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type Callback<T = void> = (err: null | undefined |
|
|
1
|
+
export type Callback<T = void> = (err: null | undefined | undefined | Error, res: T) => unknown;
|
|
2
2
|
export type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;
|
|
3
3
|
export type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;
|
|
4
4
|
export type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;
|
package/dist/try.cjs
CHANGED
|
@@ -1,51 +1,50 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const
|
|
4
|
-
const
|
|
2
|
+
const require_type = require("./type.cjs");
|
|
3
|
+
const require_error = require("./error.cjs");
|
|
4
|
+
//#region src/try/curry.ts
|
|
5
5
|
function callbackCurry(cf, ...args) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
return function callbackCurried(callback) {
|
|
7
|
+
cf.apply(this, [...args, callback]);
|
|
8
|
+
};
|
|
9
9
|
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/try/callback.ts
|
|
10
12
|
function tryCallback(cf, ...args) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
});
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
callbackCurry.apply(this, [cf, ...args])((err, res) => {
|
|
15
|
+
if (err) resolve([require_error.errorNormalize(err), void 0]);
|
|
16
|
+
else resolve([void 0, res]);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
20
19
|
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/try/function.ts
|
|
21
22
|
function trySync(syncFn) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
try {
|
|
24
|
+
return [void 0, syncFn()];
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return [require_error.errorNormalize(err), void 0];
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
function tryAsync(asyncFn) {
|
|
29
|
-
|
|
30
|
-
(res) => [void 0, res],
|
|
31
|
-
(err) => [error.errorNormalize(err), void 0]
|
|
32
|
-
);
|
|
30
|
+
return asyncFn().then((res) => [void 0, res], (err) => [require_error.errorNormalize(err), void 0]);
|
|
33
31
|
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/try/promise.ts
|
|
34
34
|
function tryPromise(promise) {
|
|
35
|
-
|
|
36
|
-
(res) => [void 0, res],
|
|
37
|
-
(err) => [error.errorNormalize(err), void 0]
|
|
38
|
-
);
|
|
35
|
+
return promise.then((res) => [void 0, res], (err) => [require_error.errorNormalize(err), void 0]);
|
|
39
36
|
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/try/main.ts
|
|
40
39
|
function tryFlatten(flattenAble) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return tryCallback(flattenAble);
|
|
40
|
+
if ("then" in flattenAble) return tryPromise(flattenAble);
|
|
41
|
+
if (flattenAble.length === 0) {
|
|
42
|
+
if (require_type.isAsyncFunction(flattenAble)) return tryAsync(flattenAble);
|
|
43
|
+
return trySync(flattenAble);
|
|
44
|
+
}
|
|
45
|
+
return tryCallback(flattenAble);
|
|
49
46
|
}
|
|
47
|
+
//#endregion
|
|
50
48
|
exports.tryFlatten = tryFlatten;
|
|
51
|
-
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=try.cjs.map
|
package/dist/try.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"try.cjs","sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"try.cjs","names":[],"sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["export type Callback<T = void> = (\n err: null | undefined | undefined | Error,\n res: T,\n) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (\n a: A,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (\n a: A,\n b: B,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (\n a: A,\n b: B,\n c: C,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(\n cf: CallbackFunction0<T>,\n): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(\n cf: CallbackFunction1<A, T>,\n a: A,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(\n cf: CallbackFunction2<A, B, T>,\n a: A,\n b: B,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(\n cf: unknown,\n ...args: unknown[]\n): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(\n cf: CallbackFunction0<T>,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(\n cf: CallbackFunction1<A, T>,\n a: A,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(\n cf: CallbackFunction2<A, B, T>,\n a: A,\n b: B,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(\n cf: unknown,\n ...args: unknown[]\n): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(\n asyncFn: AsyncFunction<T>,\n): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(\n promise: PromiseLike<T>,\n): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport {\n type AsyncFunction,\n type SyncFunction,\n tryAsync,\n trySync,\n} from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> =\n | SyncFunction<T>\n | AsyncFunction<T>\n | CallbackFunction0<T>\n | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(\n flattenAble: AsyncFunction<T>,\n): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(\n flattenAble: CallbackFunction0<T> | PromiseLike<T>,\n): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble))\n return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"mappings":";;;;AA0FA,SAAgB,cACd,IACA,GAAG,MACuB;CAC1B,OAAO,SAAS,gBAAgB,UAA6B;EAG3D,GAAG,MAAM,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC;;;;;ACzCvC,SAAgB,YACd,IACA,GAAG,MAC8B;CACjC,OAAO,IAAI,SAAS,YAAY;EAG9B,cAAc,MAAM,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE,KAAK,QAAQ;GACrD,IAAI,KACF,QAAQ,CAAC,cAAA,eAAe,IAAI,EAAE,KAAA,EAAU,CAAU;QAElD,QAAQ,CAAC,KAAA,GAAW,IAAI,CAAU;IAEpC;GACF;;;;ACjEJ,SAAgB,QAAW,QAA2C;CACpE,IAAI;EACF,OAAO,CAAC,KAAA,GAAW,QAAQ,CAAC;UACrB,KAAK;EACZ,OAAO,CAAC,cAAA,eAAe,IAAI,EAAE,KAAA,EAAU;;;AAM3C,SAAgB,SACd,SAC2B;CAC3B,OAAO,SAAS,CAAC,MACd,QAAQ,CAAC,KAAA,GAAW,IAAI,GACxB,QAAQ,CAAC,cAAA,eAAe,IAAI,EAAE,KAAA,EAAU,CAC1C;;;;AClBH,SAAgB,WACd,SAC+B;CAC/B,OAAO,QAAQ,MACZ,QAAQ,CAAC,KAAA,GAAW,IAAI,GACxB,QAAQ,CAAC,cAAA,eAAe,IAAI,EAAE,KAAA,EAAU,CAC1C;;;;ACkBH,SAAgB,WAAc,aAAsC;CAClE,IAAI,UAAU,aACZ,OAAO,WAAc,YAAY;CAInC,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,aAAA,gBAAgB,YAAY,EAC9B,OAAO,SAAY,YAAgC;EACrD,OAAO,QAAW,YAA+B;;CAGnD,OAAO,YAAe,YAAY"}
|
package/dist/try.mjs
CHANGED
|
@@ -1,51 +1,49 @@
|
|
|
1
1
|
import { isAsyncFunction } from "./type.mjs";
|
|
2
2
|
import { errorNormalize } from "./error.mjs";
|
|
3
|
+
//#region src/try/curry.ts
|
|
3
4
|
function callbackCurry(cf, ...args) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
return function callbackCurried(callback) {
|
|
6
|
+
cf.apply(this, [...args, callback]);
|
|
7
|
+
};
|
|
7
8
|
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/try/callback.ts
|
|
8
11
|
function tryCallback(cf, ...args) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
});
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
callbackCurry.apply(this, [cf, ...args])((err, res) => {
|
|
14
|
+
if (err) resolve([errorNormalize(err), void 0]);
|
|
15
|
+
else resolve([void 0, res]);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
18
|
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/try/function.ts
|
|
19
21
|
function trySync(syncFn) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
try {
|
|
23
|
+
return [void 0, syncFn()];
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return [errorNormalize(err), void 0];
|
|
26
|
+
}
|
|
25
27
|
}
|
|
26
28
|
function tryAsync(asyncFn) {
|
|
27
|
-
|
|
28
|
-
(res) => [void 0, res],
|
|
29
|
-
(err) => [errorNormalize(err), void 0]
|
|
30
|
-
);
|
|
29
|
+
return asyncFn().then((res) => [void 0, res], (err) => [errorNormalize(err), void 0]);
|
|
31
30
|
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/try/promise.ts
|
|
32
33
|
function tryPromise(promise) {
|
|
33
|
-
|
|
34
|
-
(res) => [void 0, res],
|
|
35
|
-
(err) => [errorNormalize(err), void 0]
|
|
36
|
-
);
|
|
34
|
+
return promise.then((res) => [void 0, res], (err) => [errorNormalize(err), void 0]);
|
|
37
35
|
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/try/main.ts
|
|
38
38
|
function tryFlatten(flattenAble) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
return tryCallback(flattenAble);
|
|
39
|
+
if ("then" in flattenAble) return tryPromise(flattenAble);
|
|
40
|
+
if (flattenAble.length === 0) {
|
|
41
|
+
if (isAsyncFunction(flattenAble)) return tryAsync(flattenAble);
|
|
42
|
+
return trySync(flattenAble);
|
|
43
|
+
}
|
|
44
|
+
return tryCallback(flattenAble);
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//# sourceMappingURL=try.mjs.map
|
|
46
|
+
//#endregion
|
|
47
|
+
export { tryFlatten };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=try.mjs.map
|