@pawover/kit 0.0.0-alpha.9 → 0.0.0-beta.2
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/dist/enums.d.ts +25 -0
- package/dist/enums.d.ts.map +1 -0
- package/dist/enums.js +25 -0
- package/dist/enums.js.map +1 -0
- package/dist/hooks-alova.d.ts +23 -0
- package/dist/hooks-alova.d.ts.map +1 -0
- package/dist/hooks-alova.js +39 -0
- package/dist/hooks-alova.js.map +1 -0
- package/dist/hooks-react.d.ts +89 -0
- package/dist/hooks-react.d.ts.map +1 -0
- package/dist/hooks-react.js +340 -0
- package/dist/hooks-react.js.map +1 -0
- package/dist/index.d.ts +2445 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1430 -1
- package/dist/index.js.map +1 -0
- package/dist/patches-fetchEventSource.d.ts +806 -0
- package/dist/patches-fetchEventSource.d.ts.map +1 -0
- package/dist/patches-fetchEventSource.js +315 -0
- package/dist/patches-fetchEventSource.js.map +1 -0
- package/dist/vite.d.ts +13 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +23 -0
- package/dist/vite.js.map +1 -0
- package/dist/zod.d.ts +105 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +138 -0
- package/dist/zod.js.map +1 -0
- package/metadata.json +160 -0
- package/package.json +51 -35
- package/dist/enums/index.js +0 -20
- package/dist/hooks/react/index.js +0 -5
- package/dist/hooks/react/useCreation.js +0 -19
- package/dist/hooks/react/useLatest.js +0 -13
- package/dist/hooks/react/useMount.js +0 -29
- package/dist/hooks/react/useResponsive.js +0 -59
- package/dist/hooks/react/useUnmount.js +0 -18
- package/dist/types/enums/index.d.ts +0 -20
- package/dist/types/hooks/react/index.d.ts +0 -5
- package/dist/types/hooks/react/useCreation.d.ts +0 -10
- package/dist/types/hooks/react/useLatest.d.ts +0 -8
- package/dist/types/hooks/react/useMount.d.ts +0 -11
- package/dist/types/hooks/react/useResponsive.d.ts +0 -16
- package/dist/types/hooks/react/useUnmount.d.ts +0 -7
- package/dist/types/index.d.ts +0 -1
- package/dist/types/utils/array.d.ts +0 -76
- package/dist/types/utils/clone.d.ts +0 -13
- package/dist/types/utils/index.d.ts +0 -7
- package/dist/types/utils/object.d.ts +0 -54
- package/dist/types/utils/string.d.ts +0 -15
- package/dist/types/utils/to.d.ts +0 -5
- package/dist/types/utils/tree/index.d.ts +0 -6
- package/dist/types/utils/tree/rowsToTree.d.ts +0 -10
- package/dist/types/utils/tree/treeFilter.d.ts +0 -6
- package/dist/types/utils/tree/treeFind.d.ts +0 -8
- package/dist/types/utils/tree/treeForEach.d.ts +0 -5
- package/dist/types/utils/tree/treeMap.d.ts +0 -6
- package/dist/types/utils/tree/treeToRows.d.ts +0 -9
- package/dist/types/utils/tree/types.d.ts +0 -24
- package/dist/types/utils/typeof.d.ts +0 -37
- package/dist/types/zod/index.d.ts +0 -3
- package/dist/types/zod/primitive.d.ts +0 -32
- package/dist/types/zod/validator/input.d.ts +0 -27
- package/dist/types/zod/validator/societal.d.ts +0 -39
- package/dist/utils/array.js +0 -196
- package/dist/utils/clone.js +0 -75
- package/dist/utils/index.js +0 -7
- package/dist/utils/object.js +0 -149
- package/dist/utils/string.js +0 -73
- package/dist/utils/to.js +0 -16
- package/dist/utils/tree/index.js +0 -6
- package/dist/utils/tree/rowsToTree.js +0 -35
- package/dist/utils/tree/treeFilter.js +0 -92
- package/dist/utils/tree/treeFind.js +0 -82
- package/dist/utils/tree/treeForEach.js +0 -60
- package/dist/utils/tree/treeMap.js +0 -79
- package/dist/utils/tree/treeToRows.js +0 -13
- package/dist/utils/tree/types.js +0 -10
- package/dist/utils/typeof.js +0 -149
- package/dist/zod/index.js +0 -3
- package/dist/zod/primitive.js +0 -32
- package/dist/zod/validator/input.js +0 -39
- package/dist/zod/validator/societal.js +0 -57
package/dist/index.js
CHANGED
|
@@ -1 +1,1430 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/utils/typeof/types.ts
|
|
2
|
+
const PROTOTYPE_TAGS = {
|
|
3
|
+
abortSignal: "[object AbortSignal]",
|
|
4
|
+
array: "[object Array]",
|
|
5
|
+
asyncFunction: "[object AsyncFunction]",
|
|
6
|
+
asyncGeneratorFunction: "[object AsyncGeneratorFunction]",
|
|
7
|
+
bigInt: "[object BigInt]",
|
|
8
|
+
blob: "[object Blob]",
|
|
9
|
+
boolean: "[object Boolean]",
|
|
10
|
+
date: "[object Date]",
|
|
11
|
+
error: "[object Error]",
|
|
12
|
+
file: "[object File]",
|
|
13
|
+
function: "[object Function]",
|
|
14
|
+
generatorFunction: "[object GeneratorFunction]",
|
|
15
|
+
map: "[object Map]",
|
|
16
|
+
null: "[object Null]",
|
|
17
|
+
number: "[object Number]",
|
|
18
|
+
object: "[object Object]",
|
|
19
|
+
promise: "[object Promise]",
|
|
20
|
+
readableStream: "[object ReadableStream]",
|
|
21
|
+
regExp: "[object RegExp]",
|
|
22
|
+
set: "[object Set]",
|
|
23
|
+
string: "[object String]",
|
|
24
|
+
symbol: "[object Symbol]",
|
|
25
|
+
undefined: "[object Undefined]",
|
|
26
|
+
URLSearchParams: "[object URLSearchParams]",
|
|
27
|
+
weakMap: "[object WeakMap]",
|
|
28
|
+
weakSet: "[object WeakSet]",
|
|
29
|
+
webSocket: "[object WebSocket]",
|
|
30
|
+
window: "[object Window]"
|
|
31
|
+
};
|
|
32
|
+
const TYPED_ARRAY_TAGS = new Set([
|
|
33
|
+
"[object Int8Array]",
|
|
34
|
+
"[object Uint8Array]",
|
|
35
|
+
"[object Uint8ClampedArray]",
|
|
36
|
+
"[object Int16Array]",
|
|
37
|
+
"[object Uint16Array]",
|
|
38
|
+
"[object Int32Array]",
|
|
39
|
+
"[object Uint32Array]",
|
|
40
|
+
"[object Float32Array]",
|
|
41
|
+
"[object Float64Array]",
|
|
42
|
+
"[object BigInt64Array]",
|
|
43
|
+
"[object BigUint64Array]"
|
|
44
|
+
]);
|
|
45
|
+
function resolvePrototypeString(value) {
|
|
46
|
+
return Object.prototype.toString.call(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils/typeof/isAbortSignal.ts
|
|
51
|
+
function isAbortSignal(value) {
|
|
52
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.abortSignal;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/utils/typeof/isArray.ts
|
|
57
|
+
function isArray(value) {
|
|
58
|
+
return Array.isArray(value);
|
|
59
|
+
}
|
|
60
|
+
function isTypedArray(value) {
|
|
61
|
+
return typeof value === "object" && value !== null && TYPED_ARRAY_TAGS.has(resolvePrototypeString(value));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/utils/typeof/isBigInt.ts
|
|
66
|
+
function isBigInt(value) {
|
|
67
|
+
return typeof value === "bigint";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/utils/typeof/isBlob.ts
|
|
72
|
+
function isBlob(value) {
|
|
73
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.blob;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/utils/typeof/isBoolean.ts
|
|
78
|
+
function isBoolean(value) {
|
|
79
|
+
return typeof value === "boolean";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/utils/typeof/isClass.ts
|
|
84
|
+
function isConstructable(fn) {
|
|
85
|
+
try {
|
|
86
|
+
Reflect.construct(fn, []);
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function isClass(value) {
|
|
93
|
+
return isFunction(value) && !isAsyncFunction(value) && Function.prototype.toString.call(value).startsWith("class ") && isConstructable(value) && value.prototype !== void 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/utils/typeof/isObject.ts
|
|
98
|
+
/**
|
|
99
|
+
* 判断是否为对象类型
|
|
100
|
+
* - 可选是否检查原型为 `Object.prototype`,防止原型链污染
|
|
101
|
+
*
|
|
102
|
+
* @param value 待检查值
|
|
103
|
+
* @param prototypeCheck 是否进行原型检查,默认 `true`
|
|
104
|
+
*/
|
|
105
|
+
function isObject(value, prototypeCheck = true) {
|
|
106
|
+
const check = resolvePrototypeString(value) === PROTOTYPE_TAGS.object;
|
|
107
|
+
return prototypeCheck ? check && Object.getPrototypeOf(value) === Object.prototype : check;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/utils/typeof/isDate.ts
|
|
112
|
+
function isDate(value) {
|
|
113
|
+
if (!isObject(value)) return false;
|
|
114
|
+
try {
|
|
115
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.date && typeof value["getTime"] === "function";
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/utils/typeof/isEqual.ts
|
|
123
|
+
/**
|
|
124
|
+
* 检查给定的值是否相等
|
|
125
|
+
* @reference https://github.com/radashi-org/radashi/blob/main/src/typed/isEqual.ts
|
|
126
|
+
*
|
|
127
|
+
* @param {T} x
|
|
128
|
+
* @param {T} y
|
|
129
|
+
*/
|
|
130
|
+
function isEqual(x, y) {
|
|
131
|
+
if (Object.is(x, y)) return true;
|
|
132
|
+
if (isDate(x) && isDate(y)) return x.getTime() === y.getTime();
|
|
133
|
+
if (isRegExp(x) && isRegExp(y)) return x.toString() === y.toString();
|
|
134
|
+
if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) return false;
|
|
135
|
+
const keysX = Reflect.ownKeys(x);
|
|
136
|
+
const keysY = Reflect.ownKeys(y);
|
|
137
|
+
if (keysX.length !== keysY.length) return false;
|
|
138
|
+
for (const key of keysX) {
|
|
139
|
+
if (!Reflect.has(y, key)) return false;
|
|
140
|
+
if (!isEqual(x[key], y[key])) return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/utils/typeof/isError.ts
|
|
147
|
+
function isError(value) {
|
|
148
|
+
return value instanceof Error || resolvePrototypeString(value) === PROTOTYPE_TAGS.error;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/utils/typeof/isFalsy.ts
|
|
153
|
+
function isFalsy(value) {
|
|
154
|
+
if (isNaN(value) || isNull(value) || isUndefined(value)) return true;
|
|
155
|
+
return value === false || value === 0 || value === 0n || value === "";
|
|
156
|
+
}
|
|
157
|
+
function isFalsyLike(value) {
|
|
158
|
+
if (isFalsy(value)) return true;
|
|
159
|
+
return typeof value === "string" && (value === "null" || value === "undefined" || value === "NaN" || value === "false" || value === "0" || value === "0n");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/utils/typeof/isFile.ts
|
|
164
|
+
function isFile(value) {
|
|
165
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.file;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/utils/typeof/isFunction.ts
|
|
170
|
+
function isFunction(value) {
|
|
171
|
+
return typeof value === "function";
|
|
172
|
+
}
|
|
173
|
+
function isAsyncFunction(value) {
|
|
174
|
+
return isFunction(value) && resolvePrototypeString(value) === PROTOTYPE_TAGS.asyncFunction;
|
|
175
|
+
}
|
|
176
|
+
function isGeneratorFunction(value) {
|
|
177
|
+
return isFunction(value) && resolvePrototypeString(value) === PROTOTYPE_TAGS.generatorFunction;
|
|
178
|
+
}
|
|
179
|
+
function isAsyncGeneratorFunction(value) {
|
|
180
|
+
return isFunction(value) && resolvePrototypeString(value) === PROTOTYPE_TAGS.asyncGeneratorFunction;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/utils/typeof/isIterable.ts
|
|
185
|
+
function isIterable(value) {
|
|
186
|
+
return isObject(value) && Symbol.iterator in value;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/utils/typeof/isMap.ts
|
|
191
|
+
function isMap(value) {
|
|
192
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.map;
|
|
193
|
+
}
|
|
194
|
+
function isWeakMap(value) {
|
|
195
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.weakMap;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region src/utils/typeof/isNull.ts
|
|
200
|
+
function isNull(value) {
|
|
201
|
+
return value === null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/utils/typeof/isNumber.ts
|
|
206
|
+
/**
|
|
207
|
+
* 检查 value 是否为 number 类型
|
|
208
|
+
*
|
|
209
|
+
* @param value 待检查值
|
|
210
|
+
* @param checkNaN 是否排除 `NaN`,默认为 `true`
|
|
211
|
+
*/
|
|
212
|
+
function isNumber(value, checkNaN = true) {
|
|
213
|
+
return typeof value === "number" && (!checkNaN || !isNaN(value));
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* 检查 value 是否为 NaN
|
|
217
|
+
*
|
|
218
|
+
* @param value 待检查值
|
|
219
|
+
*/
|
|
220
|
+
function isNaN(value) {
|
|
221
|
+
return Number.isNaN(value);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 检查 value 是否为整数
|
|
225
|
+
*
|
|
226
|
+
* @param value 待检查值
|
|
227
|
+
* @param safeCheck 是否附加安全数检查
|
|
228
|
+
*/
|
|
229
|
+
function isInteger(value, safeCheck = true) {
|
|
230
|
+
const check = Number.isInteger(value);
|
|
231
|
+
return safeCheck ? check && Number.isSafeInteger(value) : check;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* 检查 value 是否为正整数
|
|
235
|
+
* - 此函数中 `0` 不被视为正整数
|
|
236
|
+
*
|
|
237
|
+
* @param value 待检查值
|
|
238
|
+
* @param safeCheck 是否附加安全数检查
|
|
239
|
+
*/
|
|
240
|
+
function isPositiveInteger(value, safeCheck = true) {
|
|
241
|
+
return isInteger(value, safeCheck) && value > 0;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 检查 value 是否为负整数
|
|
245
|
+
* - 此函数中 `0` 不被视为负整数
|
|
246
|
+
*
|
|
247
|
+
* @param value 待检查值
|
|
248
|
+
* @param safeCheck 是否附加安全数检查
|
|
249
|
+
*/
|
|
250
|
+
function isNegativeInteger(value, safeCheck = true) {
|
|
251
|
+
return isInteger(value, safeCheck) && value < 0;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 检查 value 是否为 Infinity
|
|
255
|
+
* - 排除 `NaN`
|
|
256
|
+
*
|
|
257
|
+
* @param value 待检查值
|
|
258
|
+
*/
|
|
259
|
+
function isInfinity(value) {
|
|
260
|
+
return isNumber(value) && (Number.POSITIVE_INFINITY === value || Number.NEGATIVE_INFINITY === value);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* 检查 value 是否类似 Infinity
|
|
264
|
+
* - 排除 `NaN`
|
|
265
|
+
*
|
|
266
|
+
* @param value 待检查值
|
|
267
|
+
*/
|
|
268
|
+
function isInfinityLike(value) {
|
|
269
|
+
const check = isInfinity(value);
|
|
270
|
+
if (check) return check;
|
|
271
|
+
if (typeof value === "string") {
|
|
272
|
+
const v = value.trim().toLowerCase();
|
|
273
|
+
return v === "infinity" || v === "-infinity" || v === "+infinity";
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/utils/typeof/isPromise.ts
|
|
280
|
+
function isPromise(value) {
|
|
281
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.promise;
|
|
282
|
+
}
|
|
283
|
+
function isPromiseLike(value) {
|
|
284
|
+
return isPromise(value) || isObject(value) && isFunction(value["then"]);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/utils/typeof/isReadableStream.ts
|
|
289
|
+
/**
|
|
290
|
+
* Checks if a value is a WHATWG ReadableStream instance.
|
|
291
|
+
*
|
|
292
|
+
* - Uses `Object.prototype.toString` where supported (modern browsers, Node.js ≥18).
|
|
293
|
+
* - Falls back to duck-typing in older environments.
|
|
294
|
+
* - Resistant to basic forgery, but not 100% secure in all polyfill scenarios.
|
|
295
|
+
*
|
|
296
|
+
* ⚠️ Note: In older Node.js (<18) or with non-compliant polyfills, this may return false positives or negatives.
|
|
297
|
+
*/
|
|
298
|
+
function isReadableStream(value) {
|
|
299
|
+
if (resolvePrototypeString(value) === PROTOTYPE_TAGS.readableStream) return true;
|
|
300
|
+
return isObject(value) && isFunction(value["getReader"]) && isFunction(value["pipeThrough"]);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/utils/typeof/isRegExp.ts
|
|
305
|
+
function isRegExp(value) {
|
|
306
|
+
if (!isObject(value)) return false;
|
|
307
|
+
try {
|
|
308
|
+
const regex = value;
|
|
309
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.regExp && isString(regex.source) && isString(regex.flags) && isBoolean(regex.global) && isFunction(regex.test);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/utils/typeof/isSet.ts
|
|
317
|
+
function isSet(value) {
|
|
318
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.set;
|
|
319
|
+
}
|
|
320
|
+
function isWeakSet(value) {
|
|
321
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.weakSet;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/utils/typeof/isString.ts
|
|
326
|
+
/**
|
|
327
|
+
* 检查 value 是否为 string 类型
|
|
328
|
+
*
|
|
329
|
+
* @param value 待检查值
|
|
330
|
+
* @param checkEmpty 是否排除空字符串
|
|
331
|
+
*/
|
|
332
|
+
function isString(value, checkEmpty = false) {
|
|
333
|
+
return typeof value === "string" && (!checkEmpty || !!value.length);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
//#endregion
|
|
337
|
+
//#region src/utils/typeof/isSymbol.ts
|
|
338
|
+
function isSymbol(value) {
|
|
339
|
+
return typeof value === "symbol";
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/utils/typeof/isUndefined.ts
|
|
344
|
+
function isUndefined(value) {
|
|
345
|
+
return typeof value === "undefined";
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/utils/typeof/isURLSearchParams.ts
|
|
350
|
+
function isURLSearchParams(value) {
|
|
351
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.URLSearchParams;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/utils/typeof/isWebSocket.ts
|
|
356
|
+
function isWebSocket(value) {
|
|
357
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.webSocket;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/utils/typeof/isWindow.ts
|
|
362
|
+
function isWindow(value) {
|
|
363
|
+
return resolvePrototypeString(value) === PROTOTYPE_TAGS.window;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
//#endregion
|
|
367
|
+
//#region src/utils/array/arrayCast.ts
|
|
368
|
+
/**
|
|
369
|
+
* 构造数组
|
|
370
|
+
* @param candidate 待构造项
|
|
371
|
+
* @param checkEmpty 是否检查 `undefined` 和 `null`
|
|
372
|
+
*/
|
|
373
|
+
function arrayCast(candidate, checkEmpty = true) {
|
|
374
|
+
if (checkEmpty && (isUndefined(candidate) || isNull(candidate))) return [];
|
|
375
|
+
return isArray(candidate) ? [...candidate] : [candidate];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region src/utils/array/arrayCompete.ts
|
|
380
|
+
/**
|
|
381
|
+
* 数组竞争
|
|
382
|
+
* - 返回在匹配函数的比较条件中获胜的最终项目,适用于更复杂的最小值/最大值计算
|
|
383
|
+
*
|
|
384
|
+
* @param initialList 数组
|
|
385
|
+
* @param match 匹配函数
|
|
386
|
+
*/
|
|
387
|
+
function arrayCompete(initialList, match) {
|
|
388
|
+
if (!isArray(initialList) || initialList.length === 0 || !isFunction(match)) return null;
|
|
389
|
+
return initialList.reduce(match);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/utils/array/arrayCounting.ts
|
|
394
|
+
/**
|
|
395
|
+
* 统计数组的项目出现次数
|
|
396
|
+
* - 通过给定的标识符匹配函数,返回一个对象,其中键是回调函数返回的 key 值,每个值是一个整数,表示该 key 出现的次数
|
|
397
|
+
*
|
|
398
|
+
* @param initialList 初始数组
|
|
399
|
+
* @param match 匹配函数
|
|
400
|
+
*/
|
|
401
|
+
function arrayCounting(initialList, match) {
|
|
402
|
+
if (!isArray(initialList) || !isFunction(match)) return {};
|
|
403
|
+
return initialList.reduce((prev, curr) => {
|
|
404
|
+
const id = match(curr).toString();
|
|
405
|
+
prev[id] = (prev[id] ?? 0) + 1;
|
|
406
|
+
return prev;
|
|
407
|
+
}, {});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
//#endregion
|
|
411
|
+
//#region src/utils/array/arrayDifference.ts
|
|
412
|
+
/**
|
|
413
|
+
* 求数组差集
|
|
414
|
+
*
|
|
415
|
+
* @param initialList 初始数组
|
|
416
|
+
* @param diffList 对比数组
|
|
417
|
+
* @param match 匹配函数
|
|
418
|
+
*/
|
|
419
|
+
function arrayDifference(initialList, diffList, match) {
|
|
420
|
+
if (!isArray(initialList) && !isArray(diffList)) return [];
|
|
421
|
+
if (!isArray(initialList) || !initialList.length) return [...diffList];
|
|
422
|
+
if (!isArray(diffList) || !diffList.length) return [...initialList];
|
|
423
|
+
if (!isFunction(match)) {
|
|
424
|
+
const arraySet = new Set(diffList);
|
|
425
|
+
return Array.from(new Set(initialList.filter((item) => !arraySet.has(item))));
|
|
426
|
+
}
|
|
427
|
+
const map = /* @__PURE__ */ new Map();
|
|
428
|
+
diffList.forEach((item) => {
|
|
429
|
+
map.set(match(item), true);
|
|
430
|
+
});
|
|
431
|
+
return initialList.filter((a) => !map.get(match(a)));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/utils/array/arrayFirst.ts
|
|
436
|
+
function arrayFirst(initialList, saveValue) {
|
|
437
|
+
if (!isArray(initialList) || initialList.length === 0) return saveValue;
|
|
438
|
+
return initialList[0];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/utils/array/arrayFork.ts
|
|
443
|
+
/**
|
|
444
|
+
* 数组分组过滤
|
|
445
|
+
* - 给定一个数组和一个条件,返回一个由两个数组组成的元组,其中第一个数组包含所有满足条件的项,第二个数组包含所有不满足条件的项
|
|
446
|
+
*
|
|
447
|
+
* @param initialList 初始数组
|
|
448
|
+
* @param match 条件匹配函数
|
|
449
|
+
*/
|
|
450
|
+
function arrayFork(initialList, match) {
|
|
451
|
+
const forked = [[], []];
|
|
452
|
+
if (isArray(initialList)) for (const item of initialList) forked[match(item) ? 0 : 1].push(item);
|
|
453
|
+
return forked;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/utils/array/arrayIntersection.ts
|
|
458
|
+
/**
|
|
459
|
+
* 求数组交集
|
|
460
|
+
*
|
|
461
|
+
* @param initialList 初始数组
|
|
462
|
+
* @param diffList 对比数组
|
|
463
|
+
* @param match 匹配函数
|
|
464
|
+
*/
|
|
465
|
+
function arrayIntersection(initialList, diffList, match) {
|
|
466
|
+
if (!isArray(initialList) && !isArray(diffList)) return [];
|
|
467
|
+
if (!isArray(initialList) || !initialList.length) return [...diffList];
|
|
468
|
+
if (!isArray(diffList) || !diffList.length) return [...initialList];
|
|
469
|
+
if (!isFunction(match)) {
|
|
470
|
+
const arraySet = new Set(diffList);
|
|
471
|
+
return Array.from(new Set(initialList.filter((item) => arraySet.has(item))));
|
|
472
|
+
}
|
|
473
|
+
const map = /* @__PURE__ */ new Map();
|
|
474
|
+
diffList.forEach((item) => {
|
|
475
|
+
map.set(match(item), true);
|
|
476
|
+
});
|
|
477
|
+
return initialList.filter((a) => map.get(match(a)));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region src/utils/array/arrayLast.ts
|
|
482
|
+
function arrayLast(initialList, saveValue) {
|
|
483
|
+
if (!isArray(initialList) || initialList.length === 0) return saveValue;
|
|
484
|
+
return initialList[initialList.length - 1];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/utils/array/arrayMerge.ts
|
|
489
|
+
/**
|
|
490
|
+
* 数组合并
|
|
491
|
+
* - 通过给定的标识符匹配函数,用第二个数组中的匹配项替换第一个数组中匹配项的所有内容
|
|
492
|
+
*
|
|
493
|
+
* @param initialList 初始数组
|
|
494
|
+
* @param mergeList 待合并数组
|
|
495
|
+
* @param match 匹配函数
|
|
496
|
+
*/
|
|
497
|
+
function arrayMerge(initialList, mergeList, match) {
|
|
498
|
+
if (!isArray(initialList)) return [];
|
|
499
|
+
if (!isArray(mergeList)) return [...initialList];
|
|
500
|
+
if (!isFunction(match)) return Array.from(new Set([...initialList, ...mergeList]));
|
|
501
|
+
const keys = /* @__PURE__ */ new Map();
|
|
502
|
+
for (const item of mergeList) keys.set(match(item), item);
|
|
503
|
+
return initialList.map((prevItem) => {
|
|
504
|
+
const key = match(prevItem);
|
|
505
|
+
return keys.has(key) ? keys.get(key) : prevItem;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/utils/array/arrayPick.ts
|
|
511
|
+
/**
|
|
512
|
+
* 数组选择
|
|
513
|
+
* - 一次性应用 `filter` 和 `map` 操作
|
|
514
|
+
*
|
|
515
|
+
* @param initialList 初始数组
|
|
516
|
+
* @param filter filter 函数
|
|
517
|
+
* @param mapper map 函数
|
|
518
|
+
*/
|
|
519
|
+
function arrayPick(initialList, filter, mapper) {
|
|
520
|
+
if (!isArray(initialList)) return [];
|
|
521
|
+
if (!isFunction(filter)) return [...initialList];
|
|
522
|
+
const hasMapper = isFunction(mapper);
|
|
523
|
+
return initialList.reduce((prev, curr, index) => {
|
|
524
|
+
if (!filter(curr, index)) return prev;
|
|
525
|
+
if (hasMapper) prev.push(mapper(curr, index));
|
|
526
|
+
else prev.push(curr);
|
|
527
|
+
return prev;
|
|
528
|
+
}, []);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region src/utils/array/arrayReplace.ts
|
|
533
|
+
/**
|
|
534
|
+
* 数组项替换
|
|
535
|
+
* - 在给定的数组中,替换符合匹配函数结果的项目。只替换第一个匹配项。始终返回原始数组的副本。
|
|
536
|
+
*
|
|
537
|
+
* @param initialList 初始数组
|
|
538
|
+
* @param newItem 替换项
|
|
539
|
+
* @param match 匹配函数
|
|
540
|
+
*/
|
|
541
|
+
function arrayReplace(initialList, newItem, match) {
|
|
542
|
+
if (!initialList) return [];
|
|
543
|
+
if (newItem === void 0 || !isFunction(match)) return [...initialList];
|
|
544
|
+
for (let i = 0; i < initialList.length; i++) {
|
|
545
|
+
const item = initialList[i];
|
|
546
|
+
if (item !== void 0 && match(item, i)) return [
|
|
547
|
+
...initialList.slice(0, i),
|
|
548
|
+
newItem,
|
|
549
|
+
...initialList.slice(i + 1, initialList.length)
|
|
550
|
+
];
|
|
551
|
+
}
|
|
552
|
+
return [...initialList];
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/utils/array/arraySplit.ts
|
|
557
|
+
/**
|
|
558
|
+
* 数组切分
|
|
559
|
+
* - 将数组以指定的长度切分后,组合在高维数组中
|
|
560
|
+
*
|
|
561
|
+
* @param initialList 初始数组
|
|
562
|
+
* @param size 分割尺寸,默认 `10`
|
|
563
|
+
*/
|
|
564
|
+
function arraySplit(initialList, size = 10) {
|
|
565
|
+
if (!isArray(initialList)) return [];
|
|
566
|
+
const count = Math.ceil(initialList.length / size);
|
|
567
|
+
return Array.from({ length: count }).fill(null).map((_c, i) => {
|
|
568
|
+
return initialList.slice(i * size, i * size + size);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region src/utils/function/to.ts
|
|
574
|
+
/**
|
|
575
|
+
* @param promise
|
|
576
|
+
* @param errorExt 可以传递给err对象的其他信息
|
|
577
|
+
*/
|
|
578
|
+
function to(promise, errorExt) {
|
|
579
|
+
return promise.then((data) => [null, data]).catch((err) => {
|
|
580
|
+
if (errorExt) return [{
|
|
581
|
+
...err,
|
|
582
|
+
...errorExt
|
|
583
|
+
}, void 0];
|
|
584
|
+
return [err ? err : /* @__PURE__ */ new Error("defaultError"), void 0];
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
//#endregion
|
|
589
|
+
//#region src/utils/string/stringToNumber.ts
|
|
590
|
+
const R1$1 = /[^0-9.-]/g;
|
|
591
|
+
/**
|
|
592
|
+
* 从字符串中提取数字字符串
|
|
593
|
+
*
|
|
594
|
+
* @param input 待处理字符串
|
|
595
|
+
*/
|
|
596
|
+
function stringToNumber(input) {
|
|
597
|
+
if (!isString(input, true)) return "";
|
|
598
|
+
const cleaned = input.replace(R1$1, "");
|
|
599
|
+
let isDecimal = false;
|
|
600
|
+
let signCount = 0;
|
|
601
|
+
let firstIndex = -1;
|
|
602
|
+
const stringList = cleaned.split("").map((s, i) => {
|
|
603
|
+
if (s === ".") {
|
|
604
|
+
if (isDecimal) return "";
|
|
605
|
+
isDecimal = true;
|
|
606
|
+
return ".";
|
|
607
|
+
}
|
|
608
|
+
if (s === "-") {
|
|
609
|
+
firstIndex === -1 && signCount++;
|
|
610
|
+
return "";
|
|
611
|
+
}
|
|
612
|
+
firstIndex === -1 && (firstIndex = i);
|
|
613
|
+
return s;
|
|
614
|
+
});
|
|
615
|
+
const sign = signCount % 2 === 1 ? "-" : "";
|
|
616
|
+
if (firstIndex === -1) return sign + "0";
|
|
617
|
+
let result = stringList.join("");
|
|
618
|
+
if (result.startsWith(".")) result = "0" + result;
|
|
619
|
+
if (result.endsWith(".")) result = result.slice(0, -1);
|
|
620
|
+
return sign + result;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region src/utils/math/toMathBignumber.ts
|
|
625
|
+
/**
|
|
626
|
+
* 将任意类型的值转换为 `math.bignumber`
|
|
627
|
+
*
|
|
628
|
+
* @param mathJsInstance mathJs 实例
|
|
629
|
+
* @param value 任意类型的值
|
|
630
|
+
* @param saveValue 安全值
|
|
631
|
+
*/
|
|
632
|
+
function toMathBignumber(mathJsInstance, value, saveValue) {
|
|
633
|
+
const errorValue = saveValue ?? mathJsInstance.bignumber(0);
|
|
634
|
+
if (isFalsyLike(value) || isInfinityLike(value)) return errorValue;
|
|
635
|
+
try {
|
|
636
|
+
return mathJsInstance.bignumber(stringToNumber(`${value}`));
|
|
637
|
+
} catch (error) {
|
|
638
|
+
return errorValue;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
//#endregion
|
|
643
|
+
//#region src/utils/math/toMathDecimal.ts
|
|
644
|
+
function toMathDecimal(mathJsInstance, value, precision, isFormat = true) {
|
|
645
|
+
const bigNumber = toMathBignumber(mathJsInstance, value);
|
|
646
|
+
return isFormat ? mathJsInstance.format(bigNumber, {
|
|
647
|
+
notation: "fixed",
|
|
648
|
+
precision
|
|
649
|
+
}) : bigNumber;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region src/utils/math/toMathEvaluate.ts
|
|
654
|
+
/**
|
|
655
|
+
* 数学表达式求值
|
|
656
|
+
*
|
|
657
|
+
* @param mathJsInstance mathJs 实例
|
|
658
|
+
* @param expr 表达式
|
|
659
|
+
* @param scope 键值映射
|
|
660
|
+
*/
|
|
661
|
+
function toMathEvaluate(mathJsInstance, expr, scope) {
|
|
662
|
+
const evaluateValue = `${mathJsInstance.evaluate(expr, scope || {})}`;
|
|
663
|
+
return mathJsInstance.format(toMathBignumber(mathJsInstance, evaluateValue), { notation: "fixed" });
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
//#endregion
|
|
667
|
+
//#region src/utils/object/cloneDeep.ts
|
|
668
|
+
const DefaultCloningStrategy = {
|
|
669
|
+
cloneMap(input, track, clone) {
|
|
670
|
+
const output = track(/* @__PURE__ */ new Map());
|
|
671
|
+
for (const [key, value] of input) output.set(key, clone(value));
|
|
672
|
+
return output;
|
|
673
|
+
},
|
|
674
|
+
cloneSet(input, track, clone) {
|
|
675
|
+
const output = track(/* @__PURE__ */ new Set());
|
|
676
|
+
for (const value of input) output.add(clone(value));
|
|
677
|
+
return output;
|
|
678
|
+
},
|
|
679
|
+
cloneArray(input, track, clone) {
|
|
680
|
+
const output = track(new Array(input.length));
|
|
681
|
+
input.forEach((value, index) => {
|
|
682
|
+
output[index] = clone(value);
|
|
683
|
+
});
|
|
684
|
+
return output;
|
|
685
|
+
},
|
|
686
|
+
cloneObject(input, track, clone) {
|
|
687
|
+
const output = track(Object.create(Object.getPrototypeOf(input)));
|
|
688
|
+
for (const key of Reflect.ownKeys(input)) {
|
|
689
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
690
|
+
if ("value" in descriptor) descriptor.value = clone(descriptor.value);
|
|
691
|
+
Object.defineProperty(output, key, descriptor);
|
|
692
|
+
}
|
|
693
|
+
return output;
|
|
694
|
+
},
|
|
695
|
+
cloneOther(input, track) {
|
|
696
|
+
return track(input);
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
/**
|
|
700
|
+
* cloneDeep
|
|
701
|
+
* @reference https://github.com/radashi-org/radashi/blob/main/src/object/cloneDeep.ts
|
|
702
|
+
*/
|
|
703
|
+
function cloneDeep(root, customStrategy) {
|
|
704
|
+
const strategy = {
|
|
705
|
+
...DefaultCloningStrategy,
|
|
706
|
+
...customStrategy
|
|
707
|
+
};
|
|
708
|
+
const tracked = /* @__PURE__ */ new Map();
|
|
709
|
+
const track = (parent, newParent) => {
|
|
710
|
+
tracked.set(parent, newParent);
|
|
711
|
+
return newParent;
|
|
712
|
+
};
|
|
713
|
+
const clone = (value) => {
|
|
714
|
+
return value && typeof value === "object" ? tracked.get(value) ?? cloneDeep$1(value, strategy) : value;
|
|
715
|
+
};
|
|
716
|
+
const cloneDeep$1 = (parent, strategy$1) => {
|
|
717
|
+
const newParent = (isObject(parent) ? strategy$1.cloneObject : isArray(parent) ? strategy$1.cloneArray : isMap(parent) ? strategy$1.cloneMap : isSet(parent) ? strategy$1.cloneSet : strategy$1.cloneOther)(parent, track.bind(null, parent), clone);
|
|
718
|
+
if (!newParent) return cloneDeep$1(parent, DefaultCloningStrategy);
|
|
719
|
+
tracked.set(parent, newParent);
|
|
720
|
+
return newParent;
|
|
721
|
+
};
|
|
722
|
+
return cloneDeep$1(root, strategy);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region src/utils/object/objectKeys.ts
|
|
727
|
+
/**
|
|
728
|
+
* 返回对象的可枚举属性和方法的名称
|
|
729
|
+
* - `Object.keys` 始终返回 `string[]` 类型,此函数可以返回具体类型
|
|
730
|
+
*
|
|
731
|
+
* @param obj 对象
|
|
732
|
+
*/
|
|
733
|
+
function objectKeys(obj) {
|
|
734
|
+
return Object.keys(obj);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region src/utils/object/enumTypeCheck.ts
|
|
739
|
+
function enumTypeCheck(enumeration) {
|
|
740
|
+
if (!isObject(enumeration)) throw Error(`function enumKeys expected parameter is a enum, but got ${typeof enumeration}`);
|
|
741
|
+
if (!objectKeys(enumeration).length) throw Error("Enum requires at least one member");
|
|
742
|
+
return enumeration;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/utils/object/objectEntries.ts
|
|
747
|
+
/**
|
|
748
|
+
* 返回对象的可枚举属性的键/值数组
|
|
749
|
+
*
|
|
750
|
+
* @param obj 对象
|
|
751
|
+
*/
|
|
752
|
+
function objectEntries(obj) {
|
|
753
|
+
return Object.entries(obj);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
//#endregion
|
|
757
|
+
//#region src/utils/object/objectValues.ts
|
|
758
|
+
/**
|
|
759
|
+
* 返回对象的可枚举属性的值数组
|
|
760
|
+
*
|
|
761
|
+
* @param obj 对象
|
|
762
|
+
*/
|
|
763
|
+
function objectValues(obj) {
|
|
764
|
+
return Object.values(obj);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
//#endregion
|
|
768
|
+
//#region src/utils/object/enumEntries.ts
|
|
769
|
+
/**
|
|
770
|
+
* 返回枚举的属性的键/值数组
|
|
771
|
+
*
|
|
772
|
+
* @param enumeration 枚举
|
|
773
|
+
*/
|
|
774
|
+
function enumEntries(enumeration) {
|
|
775
|
+
const e = enumTypeCheck(enumeration);
|
|
776
|
+
const keys = objectKeys(e);
|
|
777
|
+
const values = objectValues(e);
|
|
778
|
+
const entries = objectEntries(e);
|
|
779
|
+
if (keys.every((k) => values.some((v) => `${v}` === k))) return entries.splice(keys.length / 2, keys.length / 2);
|
|
780
|
+
return entries;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
//#endregion
|
|
784
|
+
//#region src/utils/object/enumKeys.ts
|
|
785
|
+
/**
|
|
786
|
+
* 获取枚举所有属性的键
|
|
787
|
+
*
|
|
788
|
+
* @param enumeration 枚举
|
|
789
|
+
*/
|
|
790
|
+
function enumKeys(enumeration) {
|
|
791
|
+
const e = enumTypeCheck(enumeration);
|
|
792
|
+
const keys = objectKeys(e);
|
|
793
|
+
const values = objectValues(e);
|
|
794
|
+
if (keys.every((k) => values.some((v) => `${v}` === k))) return keys.splice(keys.length / 2, keys.length / 2);
|
|
795
|
+
return keys;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/utils/object/enumValues.ts
|
|
800
|
+
/**
|
|
801
|
+
* 获取枚举所有属性的值
|
|
802
|
+
*
|
|
803
|
+
* @param enumeration 枚举
|
|
804
|
+
*/
|
|
805
|
+
function enumValues(enumeration) {
|
|
806
|
+
const e = enumTypeCheck(enumeration);
|
|
807
|
+
const keys = objectKeys(e);
|
|
808
|
+
const values = objectValues(e);
|
|
809
|
+
if (keys.every((k) => values.some((v) => `${v}` === k))) return values.splice(keys.length / 2, keys.length / 2);
|
|
810
|
+
return values;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
//#endregion
|
|
814
|
+
//#region src/utils/object/mapEntries.ts
|
|
815
|
+
function mapEntries(obj, toEntry) {
|
|
816
|
+
const defaultResult = {};
|
|
817
|
+
if (!obj) return defaultResult;
|
|
818
|
+
return objectEntries(obj).reduce((acc, [key, value]) => {
|
|
819
|
+
const [newKey, newValue] = toEntry(key, value);
|
|
820
|
+
acc[newKey] = newValue;
|
|
821
|
+
return acc;
|
|
822
|
+
}, defaultResult);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
//#endregion
|
|
826
|
+
//#region src/utils/object/objectAssign.ts
|
|
827
|
+
/**
|
|
828
|
+
* 递归地将第二个对象合并到第一个对象的副本中
|
|
829
|
+
* - 只有普通对象才会递归合并
|
|
830
|
+
*
|
|
831
|
+
* @param initial 初始对象
|
|
832
|
+
* @param override 待合并对象
|
|
833
|
+
*/
|
|
834
|
+
function objectAssign(initial, override) {
|
|
835
|
+
if (!isObject(initial) || !isObject(override)) return initial ?? override ?? {};
|
|
836
|
+
const proto = Object.getPrototypeOf(initial);
|
|
837
|
+
const assigned = proto ? { ...initial } : Object.assign(Object.create(proto), initial);
|
|
838
|
+
for (const key of Object.keys(override)) assigned[key] = isObject(initial[key]) && isObject(override[key]) ? objectAssign(initial[key], override[key]) : override[key];
|
|
839
|
+
return assigned;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
//#endregion
|
|
843
|
+
//#region src/utils/object/objectCrush.ts
|
|
844
|
+
function objectCrush(value) {
|
|
845
|
+
if (!value) return {};
|
|
846
|
+
function crushReducer(crushed, value$1, path) {
|
|
847
|
+
if (isObject(value$1) || isArray(value$1)) for (const [prop, propValue] of Object.entries(value$1)) crushReducer(crushed, propValue, path ? `${path}.${prop}` : prop);
|
|
848
|
+
else crushed[path] = value$1;
|
|
849
|
+
return crushed;
|
|
850
|
+
}
|
|
851
|
+
return crushReducer({}, value, "");
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region src/utils/object/objectPick.ts
|
|
856
|
+
function objectPick(obj, keys) {
|
|
857
|
+
const result = {};
|
|
858
|
+
if (!isObject(obj)) return result;
|
|
859
|
+
if (!isArray(keys)) return obj;
|
|
860
|
+
return keys.reduce((acc, curr) => {
|
|
861
|
+
if (curr in obj) acc[curr] = obj[curr];
|
|
862
|
+
return acc;
|
|
863
|
+
}, result);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
//#endregion
|
|
867
|
+
//#region src/utils/object/objectSwitch.ts
|
|
868
|
+
/**
|
|
869
|
+
* 对象反转
|
|
870
|
+
* - 返回交换了对象的可枚举属性的值/键对象
|
|
871
|
+
*
|
|
872
|
+
* @param obj 对象
|
|
873
|
+
*/
|
|
874
|
+
function objectSwitch(obj) {
|
|
875
|
+
const result = {};
|
|
876
|
+
if (!isObject(obj)) return result;
|
|
877
|
+
for (const [k, v] of objectEntries(obj)) result[v] = k;
|
|
878
|
+
return result;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
//#endregion
|
|
882
|
+
//#region src/utils/string/stringInitialCase.ts
|
|
883
|
+
const R1 = /\S+/g;
|
|
884
|
+
const R2 = /[^a-zA-Z\u00C0-\u017F]/;
|
|
885
|
+
/**
|
|
886
|
+
* 字符串首字母大小写
|
|
887
|
+
* - 包含非西欧字母字符时,不处理
|
|
888
|
+
* - 纯字母且全大写时,不处理
|
|
889
|
+
* - 纯字母且非全大写时,首字母小写,其余保留
|
|
890
|
+
* - 纯字母且非全大写时,首字母大写,其余保留
|
|
891
|
+
*
|
|
892
|
+
* @param input 待处理字符串
|
|
893
|
+
* @param caseType 大小写类型
|
|
894
|
+
*/
|
|
895
|
+
function stringInitialCase(input, caseType) {
|
|
896
|
+
if (!isString(input, true)) return "";
|
|
897
|
+
return input.replace(R1, (word) => {
|
|
898
|
+
if (R2.test(word)) return word;
|
|
899
|
+
if (word === word.toLocaleUpperCase()) return word;
|
|
900
|
+
if (caseType === "lower" && word[0]) return word[0].toLocaleLowerCase() + word.slice(1);
|
|
901
|
+
if (caseType === "upper" && word[0]) return word[0].toLocaleUpperCase() + word.slice(1);
|
|
902
|
+
return word;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
//#endregion
|
|
907
|
+
//#region src/utils/string/stringReplace.ts
|
|
908
|
+
/**
|
|
909
|
+
* 字符串替换
|
|
910
|
+
* - 替换第一个匹配项
|
|
911
|
+
*
|
|
912
|
+
* @param input 待处理字符串
|
|
913
|
+
* @param search 匹配项
|
|
914
|
+
* @param replacement 替换项
|
|
915
|
+
*/
|
|
916
|
+
function stringReplace(input, search, replacement) {
|
|
917
|
+
if (!isString(input, true)) return "";
|
|
918
|
+
return input.replace(search, replacement);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
//#endregion
|
|
922
|
+
//#region src/utils/string/stringTemplate.ts
|
|
923
|
+
/**
|
|
924
|
+
* 字符串模板替换
|
|
925
|
+
*
|
|
926
|
+
* @param input 待处理字符串
|
|
927
|
+
* @param template 模板对象
|
|
928
|
+
* @param regex 模板匹配正则
|
|
929
|
+
*/
|
|
930
|
+
function stringTemplate(input, template, regex = /\{\{(.+?)\}\}/g) {
|
|
931
|
+
if (!isString(input, true)) return "";
|
|
932
|
+
let result = "";
|
|
933
|
+
let from = 0;
|
|
934
|
+
let match;
|
|
935
|
+
while (match = regex.exec(input)) {
|
|
936
|
+
result += input.slice(from, match.index) + template[match[1]];
|
|
937
|
+
from = regex.lastIndex;
|
|
938
|
+
}
|
|
939
|
+
return result + input.slice(from);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
//#endregion
|
|
943
|
+
//#region src/utils/string/stringToJson.ts
|
|
944
|
+
/**
|
|
945
|
+
* 处理 JSON 字符串
|
|
946
|
+
*
|
|
947
|
+
* @param input 待处理字符串
|
|
948
|
+
* @param safeValue 安全值
|
|
949
|
+
*/
|
|
950
|
+
function stringToJson(input, safeValue) {
|
|
951
|
+
if (!isString(input, true)) return safeValue;
|
|
952
|
+
try {
|
|
953
|
+
return JSON.parse(input);
|
|
954
|
+
} catch (error) {
|
|
955
|
+
return safeValue;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
//#endregion
|
|
960
|
+
//#region src/utils/string/stringToPosix.ts
|
|
961
|
+
/**
|
|
962
|
+
* 将路径转换为 POSIX 风格
|
|
963
|
+
*
|
|
964
|
+
* @param input 待处理字符串
|
|
965
|
+
*/
|
|
966
|
+
function stringToPosix(input) {
|
|
967
|
+
if (!isString(input, true)) return "";
|
|
968
|
+
let normalized = input.replace(/^[A-Za-z]:[\\/]?/, "").replace(/^[\\/]+/, "");
|
|
969
|
+
normalized = normalized.replace(/\\/g, "/");
|
|
970
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
971
|
+
if (normalized.startsWith("/")) normalized = normalized.substring(1);
|
|
972
|
+
return normalized;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
//#endregion
|
|
976
|
+
//#region src/utils/string/stringToValues.ts
|
|
977
|
+
function stringToValues(input, valueType = "number", splitSymbol = ",") {
|
|
978
|
+
if (!isString(input, true)) return [];
|
|
979
|
+
try {
|
|
980
|
+
const values = input.split(splitSymbol);
|
|
981
|
+
if (valueType === "number") return values.map((d) => Number(d));
|
|
982
|
+
return values;
|
|
983
|
+
} catch (error) {
|
|
984
|
+
return [];
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/utils/string/stringTrim.ts
|
|
990
|
+
/**
|
|
991
|
+
* 从字符串中裁切掉所有的前缀和后缀字符
|
|
992
|
+
*
|
|
993
|
+
* @param input 待处理字符串
|
|
994
|
+
* @param charsToTrim 裁切字符,默认为 `" "`
|
|
995
|
+
*/
|
|
996
|
+
function stringTrim(input, charsToTrim = " ") {
|
|
997
|
+
if (!isString(input, true)) return "";
|
|
998
|
+
const toTrim = charsToTrim.replace(/[\W]{1}/g, "\\$&");
|
|
999
|
+
const regex = new RegExp(`^[${toTrim}]+|[${toTrim}]+$`, "g");
|
|
1000
|
+
return input.replace(regex, "");
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region src/utils/string/stringTruncate.ts
|
|
1005
|
+
/**
|
|
1006
|
+
* 截取字符串
|
|
1007
|
+
* - 支持中英文混排,不会在汉字中间截断
|
|
1008
|
+
*
|
|
1009
|
+
* @param input 待处理字符串
|
|
1010
|
+
* @param maxLength 最大长度
|
|
1011
|
+
* @param ellipsis 省略符,默认为 `...`
|
|
1012
|
+
*/
|
|
1013
|
+
function stringTruncate(input, maxLength, ellipsis = "...") {
|
|
1014
|
+
if (!isString(input, true)) return "";
|
|
1015
|
+
if (!isPositiveInteger(maxLength)) return input;
|
|
1016
|
+
if (input.length <= maxLength) return input;
|
|
1017
|
+
const truncated = input.slice(0, maxLength - ellipsis.length);
|
|
1018
|
+
return truncated.length > 0 ? truncated + ellipsis : "";
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
//#endregion
|
|
1022
|
+
//#region src/utils/tree/types.ts
|
|
1023
|
+
function getFinalChildrenKey(tree, meta, options) {
|
|
1024
|
+
if (isFunction(options.getChildrenKey)) {
|
|
1025
|
+
const dynamicChildrenKey = options.getChildrenKey(tree, meta);
|
|
1026
|
+
if (dynamicChildrenKey && dynamicChildrenKey !== null) return dynamicChildrenKey;
|
|
1027
|
+
}
|
|
1028
|
+
return options.childrenKey;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
//#endregion
|
|
1032
|
+
//#region src/utils/tree/treeFilter.ts
|
|
1033
|
+
function preImpl$3(row, callback, options) {
|
|
1034
|
+
if (!callback(row, options)) return;
|
|
1035
|
+
const finalChildrenKey = getFinalChildrenKey(row, options, options);
|
|
1036
|
+
const children = row[finalChildrenKey];
|
|
1037
|
+
let newChildren;
|
|
1038
|
+
if (isArray(children)) {
|
|
1039
|
+
const nextLevelOptions = {
|
|
1040
|
+
...options,
|
|
1041
|
+
parents: [...options.parents, row],
|
|
1042
|
+
depth: options.depth + 1
|
|
1043
|
+
};
|
|
1044
|
+
newChildren = children.map((c) => preImpl$3(c, callback, nextLevelOptions)).filter((c) => !!c);
|
|
1045
|
+
}
|
|
1046
|
+
return {
|
|
1047
|
+
...row,
|
|
1048
|
+
[finalChildrenKey]: newChildren
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function postImpl$3(row, callback, options) {
|
|
1052
|
+
const finalChildrenKey = getFinalChildrenKey(row, options, options);
|
|
1053
|
+
const children = row[finalChildrenKey];
|
|
1054
|
+
let newChildren;
|
|
1055
|
+
if (isArray(children)) {
|
|
1056
|
+
const nextLevelOptions = {
|
|
1057
|
+
...options,
|
|
1058
|
+
parents: [...options.parents, row],
|
|
1059
|
+
depth: options.depth + 1
|
|
1060
|
+
};
|
|
1061
|
+
newChildren = children.map((c) => preImpl$3(c, callback, nextLevelOptions)).filter((c) => !!c);
|
|
1062
|
+
}
|
|
1063
|
+
if (!callback(row, options)) return;
|
|
1064
|
+
return {
|
|
1065
|
+
...row,
|
|
1066
|
+
[finalChildrenKey]: newChildren
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
function breadthImpl$3(row, callback, options) {
|
|
1070
|
+
const queue = [{
|
|
1071
|
+
queueRow: row,
|
|
1072
|
+
queueOptions: options
|
|
1073
|
+
}];
|
|
1074
|
+
const resultCache = /* @__PURE__ */ new WeakMap();
|
|
1075
|
+
const newNodeCache = /* @__PURE__ */ new WeakMap();
|
|
1076
|
+
const childrenKeyCache = /* @__PURE__ */ new WeakMap();
|
|
1077
|
+
let result;
|
|
1078
|
+
const runQueue = () => {
|
|
1079
|
+
if (queue.length === 0) return result;
|
|
1080
|
+
const { queueRow, queueOptions } = queue.shift();
|
|
1081
|
+
const finalChildrenKey = getFinalChildrenKey(queueRow, queueOptions, queueOptions);
|
|
1082
|
+
const children = queueRow[finalChildrenKey];
|
|
1083
|
+
if (isArray(children)) {
|
|
1084
|
+
const nextLevelOptions = {
|
|
1085
|
+
...queueOptions,
|
|
1086
|
+
parents: [...queueOptions.parents, queueRow],
|
|
1087
|
+
depth: queueOptions.depth + 1
|
|
1088
|
+
};
|
|
1089
|
+
const subQueueItems = children.map((queueRow$1) => ({
|
|
1090
|
+
queueRow: queueRow$1,
|
|
1091
|
+
queueOptions: nextLevelOptions
|
|
1092
|
+
}));
|
|
1093
|
+
queue.push(...subQueueItems);
|
|
1094
|
+
}
|
|
1095
|
+
const parent = arrayLast(queueOptions.parents);
|
|
1096
|
+
const isTopNode = queueOptions.depth === 0;
|
|
1097
|
+
const parentResult = parent && resultCache.get(parent);
|
|
1098
|
+
if (!isTopNode && !parentResult) return runQueue();
|
|
1099
|
+
const callbackResult = callback(queueRow, queueOptions);
|
|
1100
|
+
if (isTopNode && !callbackResult) return;
|
|
1101
|
+
const newNode = {
|
|
1102
|
+
...queueRow,
|
|
1103
|
+
[finalChildrenKey]: void 0
|
|
1104
|
+
};
|
|
1105
|
+
if (isTopNode) result = newNode;
|
|
1106
|
+
resultCache.set(queueRow, callbackResult);
|
|
1107
|
+
newNodeCache.set(queueRow, newNode);
|
|
1108
|
+
childrenKeyCache.set(queueRow, finalChildrenKey);
|
|
1109
|
+
if (callbackResult && parent) {
|
|
1110
|
+
const parentNewNode = newNodeCache.get(parent);
|
|
1111
|
+
const parentChildrenKey = childrenKeyCache.get(parent);
|
|
1112
|
+
if (parentNewNode && parentChildrenKey) {
|
|
1113
|
+
if (!parentNewNode[parentChildrenKey]) parentNewNode[parentChildrenKey] = [];
|
|
1114
|
+
parentNewNode[parentChildrenKey].push(newNode);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return runQueue();
|
|
1118
|
+
};
|
|
1119
|
+
return runQueue();
|
|
1120
|
+
}
|
|
1121
|
+
const strategies$3 = {
|
|
1122
|
+
pre: preImpl$3,
|
|
1123
|
+
post: postImpl$3,
|
|
1124
|
+
breadth: breadthImpl$3
|
|
1125
|
+
};
|
|
1126
|
+
function treeFilter(tree, callback, options = {}) {
|
|
1127
|
+
const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
|
|
1128
|
+
const traversalMethod = strategies$3[strategy];
|
|
1129
|
+
const innerOptions = {
|
|
1130
|
+
childrenKey,
|
|
1131
|
+
depth: 0,
|
|
1132
|
+
parents: [],
|
|
1133
|
+
getChildrenKey
|
|
1134
|
+
};
|
|
1135
|
+
return isArray(tree) ? tree.map((row) => traversalMethod(row, callback, innerOptions)).filter((t) => !!t) : traversalMethod(tree, callback, innerOptions) || [];
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
//#endregion
|
|
1139
|
+
//#region src/utils/tree/treeFind.ts
|
|
1140
|
+
const strategies$2 = {
|
|
1141
|
+
pre: preImpl$2,
|
|
1142
|
+
post: postImpl$2,
|
|
1143
|
+
breadth: breadthImpl$2
|
|
1144
|
+
};
|
|
1145
|
+
function preImpl$2(row, callback, options) {
|
|
1146
|
+
if (callback(row, options)) return row;
|
|
1147
|
+
const children = row[getFinalChildrenKey(row, options, options)];
|
|
1148
|
+
if (isArray(children)) for (const child of children) {
|
|
1149
|
+
const result = preImpl$2(child, callback, {
|
|
1150
|
+
...options,
|
|
1151
|
+
parents: [...options.parents, row],
|
|
1152
|
+
depth: options.depth + 1
|
|
1153
|
+
});
|
|
1154
|
+
if (result) return result;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
function postImpl$2(row, callback, options) {
|
|
1158
|
+
const children = row[getFinalChildrenKey(row, options, options)];
|
|
1159
|
+
if (isArray(children)) for (const child of children) {
|
|
1160
|
+
const result = postImpl$2(child, callback, {
|
|
1161
|
+
...options,
|
|
1162
|
+
parents: [...options.parents, row],
|
|
1163
|
+
depth: options.depth + 1
|
|
1164
|
+
});
|
|
1165
|
+
if (result) return result;
|
|
1166
|
+
}
|
|
1167
|
+
if (callback(row, options)) return row;
|
|
1168
|
+
}
|
|
1169
|
+
function breadthImpl$2(row, callback, options) {
|
|
1170
|
+
const queue = [{
|
|
1171
|
+
queueRow: row,
|
|
1172
|
+
queueOptions: options
|
|
1173
|
+
}];
|
|
1174
|
+
const runQueue = () => {
|
|
1175
|
+
if (queue.length === 0) return;
|
|
1176
|
+
const { queueRow, queueOptions } = queue.shift();
|
|
1177
|
+
const children = queueRow[getFinalChildrenKey(queueRow, queueOptions, queueOptions)];
|
|
1178
|
+
if (isArray(children)) {
|
|
1179
|
+
const nextLevelOptions = {
|
|
1180
|
+
...queueOptions,
|
|
1181
|
+
parents: [...queueOptions.parents, queueRow],
|
|
1182
|
+
depth: queueOptions.depth + 1
|
|
1183
|
+
};
|
|
1184
|
+
const subQueueItems = children.map((queueRow$1) => ({
|
|
1185
|
+
queueRow: queueRow$1,
|
|
1186
|
+
queueOptions: nextLevelOptions
|
|
1187
|
+
}));
|
|
1188
|
+
queue.push(...subQueueItems);
|
|
1189
|
+
}
|
|
1190
|
+
if (callback(queueRow, queueOptions)) return queueRow;
|
|
1191
|
+
return runQueue();
|
|
1192
|
+
};
|
|
1193
|
+
return runQueue();
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* 查找树节点,找到第一个返回非空值的节点
|
|
1197
|
+
*/
|
|
1198
|
+
function treeFind(tree, callback, options = {}) {
|
|
1199
|
+
const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
|
|
1200
|
+
const traversalMethod = strategies$2[strategy];
|
|
1201
|
+
const innerOptions = {
|
|
1202
|
+
childrenKey,
|
|
1203
|
+
depth: 0,
|
|
1204
|
+
parents: [],
|
|
1205
|
+
getChildrenKey
|
|
1206
|
+
};
|
|
1207
|
+
if (isArray(tree)) {
|
|
1208
|
+
for (const row of tree) {
|
|
1209
|
+
const result = traversalMethod(row, callback, innerOptions);
|
|
1210
|
+
if (result) return result;
|
|
1211
|
+
}
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
return traversalMethod(tree, callback, innerOptions);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
//#endregion
|
|
1218
|
+
//#region src/utils/tree/treeForEach.ts
|
|
1219
|
+
const strategies$1 = {
|
|
1220
|
+
pre: preImpl$1,
|
|
1221
|
+
post: postImpl$1,
|
|
1222
|
+
breadth: breadthImpl$1
|
|
1223
|
+
};
|
|
1224
|
+
function preImpl$1(row, callback, options) {
|
|
1225
|
+
callback(row, options);
|
|
1226
|
+
const children = row[getFinalChildrenKey(row, options, options)];
|
|
1227
|
+
if (isArray(children)) {
|
|
1228
|
+
const nextLevelOptions = {
|
|
1229
|
+
...options,
|
|
1230
|
+
parents: [...options.parents, row],
|
|
1231
|
+
depth: options.depth + 1
|
|
1232
|
+
};
|
|
1233
|
+
for (const child of children) preImpl$1(child, callback, nextLevelOptions);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
function postImpl$1(row, callback, options) {
|
|
1237
|
+
const children = row[getFinalChildrenKey(row, options, options)];
|
|
1238
|
+
if (isArray(children)) {
|
|
1239
|
+
const nextLevelOptions = {
|
|
1240
|
+
...options,
|
|
1241
|
+
parents: [...options.parents, row],
|
|
1242
|
+
depth: options.depth + 1
|
|
1243
|
+
};
|
|
1244
|
+
for (const child of children) postImpl$1(child, callback, nextLevelOptions);
|
|
1245
|
+
}
|
|
1246
|
+
callback(row, options);
|
|
1247
|
+
}
|
|
1248
|
+
function breadthImpl$1(row, callback, options) {
|
|
1249
|
+
const queue = [{
|
|
1250
|
+
queueRow: row,
|
|
1251
|
+
queueOptions: options
|
|
1252
|
+
}];
|
|
1253
|
+
const runQueue = () => {
|
|
1254
|
+
if (queue.length === 0) return;
|
|
1255
|
+
const { queueRow, queueOptions } = queue.shift();
|
|
1256
|
+
const children = queueRow[getFinalChildrenKey(queueRow, queueOptions, queueOptions)];
|
|
1257
|
+
if (isArray(children)) {
|
|
1258
|
+
const nextLevelOptions = {
|
|
1259
|
+
...queueOptions,
|
|
1260
|
+
parents: [...queueOptions.parents, queueRow],
|
|
1261
|
+
depth: queueOptions.depth + 1
|
|
1262
|
+
};
|
|
1263
|
+
const subQueueItems = children.map((queueRow$1) => ({
|
|
1264
|
+
queueRow: queueRow$1,
|
|
1265
|
+
queueOptions: nextLevelOptions
|
|
1266
|
+
}));
|
|
1267
|
+
queue.push(...subQueueItems);
|
|
1268
|
+
}
|
|
1269
|
+
callback(queueRow, queueOptions);
|
|
1270
|
+
runQueue();
|
|
1271
|
+
};
|
|
1272
|
+
runQueue();
|
|
1273
|
+
}
|
|
1274
|
+
function treeForEach(tree, callback, options = {}) {
|
|
1275
|
+
const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
|
|
1276
|
+
const traversalMethod = strategies$1[strategy];
|
|
1277
|
+
const innerOptions = {
|
|
1278
|
+
childrenKey,
|
|
1279
|
+
depth: 0,
|
|
1280
|
+
parents: [],
|
|
1281
|
+
getChildrenKey
|
|
1282
|
+
};
|
|
1283
|
+
if (isArray(tree)) for (const row of tree) traversalMethod(row, callback, innerOptions);
|
|
1284
|
+
else traversalMethod(tree, callback, innerOptions);
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region src/utils/tree/treeMap.ts
|
|
1289
|
+
const strategies = {
|
|
1290
|
+
pre: preImpl,
|
|
1291
|
+
post: postImpl,
|
|
1292
|
+
breadth: breadthImpl
|
|
1293
|
+
};
|
|
1294
|
+
function preImpl(row, callback, options) {
|
|
1295
|
+
const finalChildrenKey = getFinalChildrenKey(row, options, options);
|
|
1296
|
+
const result = callback(row, options);
|
|
1297
|
+
const children = row[finalChildrenKey];
|
|
1298
|
+
let newChildren;
|
|
1299
|
+
if (isArray(children)) {
|
|
1300
|
+
const nextLevelOptions = {
|
|
1301
|
+
...options,
|
|
1302
|
+
parents: [...options.parents, row],
|
|
1303
|
+
depth: options.depth + 1
|
|
1304
|
+
};
|
|
1305
|
+
newChildren = children.map((c) => preImpl(c, callback, nextLevelOptions));
|
|
1306
|
+
}
|
|
1307
|
+
return {
|
|
1308
|
+
...result,
|
|
1309
|
+
[finalChildrenKey]: newChildren
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
function postImpl(row, callback, options) {
|
|
1313
|
+
const finalChildrenKey = getFinalChildrenKey(row, options, options);
|
|
1314
|
+
const children = row[finalChildrenKey];
|
|
1315
|
+
let newChildren;
|
|
1316
|
+
if (isArray(children)) {
|
|
1317
|
+
const nextLevelOptions = {
|
|
1318
|
+
...options,
|
|
1319
|
+
parents: [...options.parents, row],
|
|
1320
|
+
depth: options.depth + 1
|
|
1321
|
+
};
|
|
1322
|
+
newChildren = children.map((c) => postImpl(c, callback, nextLevelOptions));
|
|
1323
|
+
}
|
|
1324
|
+
return {
|
|
1325
|
+
...callback(row, options),
|
|
1326
|
+
[finalChildrenKey]: newChildren
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
function breadthImpl(row, callback, options) {
|
|
1330
|
+
const queue = [{
|
|
1331
|
+
queueRow: row,
|
|
1332
|
+
queueOptions: options
|
|
1333
|
+
}];
|
|
1334
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
1335
|
+
const childrenKeyCache = /* @__PURE__ */ new WeakMap();
|
|
1336
|
+
let result;
|
|
1337
|
+
const runQueue = () => {
|
|
1338
|
+
if (queue.length === 0) return result;
|
|
1339
|
+
const { queueRow, queueOptions } = queue.shift();
|
|
1340
|
+
const finalChildrenKey = getFinalChildrenKey(queueRow, queueOptions, queueOptions);
|
|
1341
|
+
const children = queueRow[finalChildrenKey];
|
|
1342
|
+
if (isArray(children)) {
|
|
1343
|
+
const nextLevelOptions = {
|
|
1344
|
+
...queueOptions,
|
|
1345
|
+
parents: [...queueOptions.parents, queueRow],
|
|
1346
|
+
depth: queueOptions.depth + 1
|
|
1347
|
+
};
|
|
1348
|
+
const subQueueItems = children.map((queueRow$1) => ({
|
|
1349
|
+
queueRow: queueRow$1,
|
|
1350
|
+
queueOptions: nextLevelOptions
|
|
1351
|
+
}));
|
|
1352
|
+
queue.push(...subQueueItems);
|
|
1353
|
+
}
|
|
1354
|
+
const res = callback(queueRow, queueOptions);
|
|
1355
|
+
cache.set(queueRow, res);
|
|
1356
|
+
childrenKeyCache.set(queueRow, finalChildrenKey);
|
|
1357
|
+
const parent = arrayLast(queueOptions.parents);
|
|
1358
|
+
if (parent) {
|
|
1359
|
+
const newParent = cache.get(parent);
|
|
1360
|
+
const parentChildrenKey = childrenKeyCache.get(parent);
|
|
1361
|
+
if (newParent && parentChildrenKey) if (newParent[parentChildrenKey]) newParent[parentChildrenKey].push(res);
|
|
1362
|
+
else newParent[parentChildrenKey] = [res];
|
|
1363
|
+
}
|
|
1364
|
+
if (queueOptions.depth === 0) result = res;
|
|
1365
|
+
return runQueue();
|
|
1366
|
+
};
|
|
1367
|
+
return runQueue();
|
|
1368
|
+
}
|
|
1369
|
+
function treeMap(tree, callback, options = {}) {
|
|
1370
|
+
const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
|
|
1371
|
+
const traversalMethod = strategies[strategy];
|
|
1372
|
+
const innerOptions = {
|
|
1373
|
+
childrenKey,
|
|
1374
|
+
depth: 0,
|
|
1375
|
+
parents: [],
|
|
1376
|
+
getChildrenKey
|
|
1377
|
+
};
|
|
1378
|
+
return isArray(tree) ? tree.map((row) => traversalMethod(row, callback, innerOptions)) : traversalMethod(tree, callback, innerOptions);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
//#endregion
|
|
1382
|
+
//#region src/utils/tree/rowsToTree.ts
|
|
1383
|
+
/**
|
|
1384
|
+
* 行结构 转 树结构
|
|
1385
|
+
*/
|
|
1386
|
+
function rowsToTree(rows, options) {
|
|
1387
|
+
const { parentIdKey = "parentId", rowKey = "id", childrenKey = "children" } = options || {};
|
|
1388
|
+
const result = [];
|
|
1389
|
+
const map = /* @__PURE__ */ new Map();
|
|
1390
|
+
for (const row of rows) {
|
|
1391
|
+
const id = row[rowKey];
|
|
1392
|
+
if (!map.get(id)) map.set(id, row);
|
|
1393
|
+
}
|
|
1394
|
+
for (const row of rows) {
|
|
1395
|
+
const parentId = row[parentIdKey];
|
|
1396
|
+
const parent = map.get(parentId);
|
|
1397
|
+
if (!parent || !parentId) {
|
|
1398
|
+
result.push(row);
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
const siblings = parent[childrenKey];
|
|
1402
|
+
if (isNull(siblings) || isUndefined(siblings)) parent[childrenKey] = [row];
|
|
1403
|
+
else if (Array.isArray(siblings)) siblings.push(row);
|
|
1404
|
+
else {
|
|
1405
|
+
const message = `The key "${childrenKey.toString()}" in parent item is not an array.`;
|
|
1406
|
+
throw new Error(message);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
return result;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
//#endregion
|
|
1413
|
+
//#region src/utils/tree/treeToRows.ts
|
|
1414
|
+
/**
|
|
1415
|
+
* 树结构 转 行结构
|
|
1416
|
+
*/
|
|
1417
|
+
function treeToRows(tree, options = {}) {
|
|
1418
|
+
const { childrenKey = "children" } = options;
|
|
1419
|
+
const result = [];
|
|
1420
|
+
if (!tree) return result;
|
|
1421
|
+
treeForEach(tree, (t) => result.push({
|
|
1422
|
+
...t,
|
|
1423
|
+
[childrenKey]: void 0
|
|
1424
|
+
}), options);
|
|
1425
|
+
return result;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
//#endregion
|
|
1429
|
+
export { arrayCast, arrayCompete, arrayCounting, arrayDifference, arrayFirst, arrayFork, arrayIntersection, arrayLast, arrayMerge, arrayPick, arrayReplace, arraySplit, cloneDeep, enumEntries, enumKeys, enumTypeCheck, enumValues, isAbortSignal, isArray, isAsyncFunction, isAsyncGeneratorFunction, isBigInt, isBlob, isBoolean, isClass, isDate, isEqual, isError, isFalsy, isFalsyLike, isFile, isFunction, isGeneratorFunction, isInfinity, isInfinityLike, isInteger, isIterable, isMap, isNaN, isNegativeInteger, isNull, isNumber, isObject, isPositiveInteger, isPromise, isPromiseLike, isReadableStream, isRegExp, isSet, isString, isSymbol, isTypedArray, isURLSearchParams, isUndefined, isWeakMap, isWeakSet, isWebSocket, isWindow, mapEntries, objectAssign, objectCrush, objectEntries, objectKeys, objectPick, objectSwitch, objectValues, rowsToTree, stringInitialCase, stringReplace, stringTemplate, stringToJson, stringToNumber, stringToPosix, stringToValues, stringTrim, stringTruncate, to, toMathBignumber, toMathDecimal, toMathEvaluate, treeFilter, treeFind, treeForEach, treeMap, treeToRows };
|
|
1430
|
+
//# sourceMappingURL=index.js.map
|