@pawover/kit 0.4.2 → 0.6.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/package.json +166 -29
- package/packages/eslint-rules/dist/core.antfu.cjs +78 -0
- package/packages/eslint-rules/dist/core.antfu.d.cts +1 -0
- package/packages/eslint-rules/dist/core.antfu.d.ts +74 -0
- package/packages/eslint-rules/dist/core.antfu.js +79 -0
- package/packages/eslint-rules/dist/core.imports.cjs +59 -0
- package/packages/eslint-rules/dist/core.imports.d.cts +1 -0
- package/packages/eslint-rules/dist/core.imports.d.ts +61 -0
- package/packages/eslint-rules/dist/core.imports.js +59 -0
- package/packages/eslint-rules/dist/core.importsSort.cjs +7 -0
- package/packages/eslint-rules/dist/core.importsSort.d.cts +1 -0
- package/packages/eslint-rules/dist/core.importsSort.d.ts +7 -0
- package/packages/eslint-rules/dist/core.importsSort.js +7 -0
- package/packages/eslint-rules/dist/core.javascript.cjs +1208 -0
- package/packages/eslint-rules/dist/core.javascript.d.cts +1 -0
- package/packages/eslint-rules/dist/core.javascript.d.ts +1216 -0
- package/packages/eslint-rules/dist/core.javascript.js +1208 -0
- package/packages/eslint-rules/dist/core.react.cjs +551 -0
- package/packages/eslint-rules/dist/core.react.d.cts +1 -0
- package/packages/eslint-rules/dist/core.react.d.ts +551 -0
- package/packages/eslint-rules/dist/core.react.js +551 -0
- package/packages/eslint-rules/dist/core.reactHooks.cjs +107 -0
- package/packages/eslint-rules/dist/core.reactHooks.d.cts +1 -0
- package/packages/eslint-rules/dist/core.reactHooks.d.ts +107 -0
- package/packages/eslint-rules/dist/core.reactHooks.js +107 -0
- package/packages/eslint-rules/dist/core.stylistic.cjs +608 -0
- package/packages/eslint-rules/dist/core.stylistic.d.cts +1 -0
- package/packages/eslint-rules/dist/core.stylistic.d.ts +595 -0
- package/packages/eslint-rules/dist/core.stylistic.js +608 -0
- package/packages/eslint-rules/dist/core.typescript.cjs +905 -0
- package/packages/eslint-rules/dist/core.typescript.d.cts +1 -0
- package/packages/eslint-rules/dist/core.typescript.d.ts +917 -0
- package/packages/eslint-rules/dist/core.typescript.js +906 -0
- package/packages/eslint-rules/dist/core.vue.cjs +312 -0
- package/packages/eslint-rules/dist/core.vue.d.cts +1 -0
- package/packages/eslint-rules/dist/core.vue.d.ts +293 -0
- package/packages/eslint-rules/dist/core.vue.js +313 -0
- package/packages/eslint-rules/dist/index.cjs +126 -0
- package/packages/eslint-rules/dist/index.d.cts +1 -0
- package/packages/eslint-rules/dist/index.d.ts +113 -0
- package/packages/eslint-rules/dist/index.js +126 -0
- package/packages/eslint-rules/dist/preset-Bk6lxNP0.cjs +107 -0
- package/packages/eslint-rules/dist/preset-CQJST7pW.js +102 -0
- package/packages/hooks/dist/alova.cjs +53 -0
- package/packages/hooks/dist/alova.d.cts +1 -0
- package/packages/hooks/dist/index.cjs +0 -0
- package/packages/hooks/dist/index.d.cts +1 -0
- package/packages/hooks/dist/react.cjs +169 -0
- package/packages/hooks/dist/react.d.cts +1 -0
- package/packages/hooks/dist/react.d.ts +2 -60
- package/packages/hooks/dist/react.js +2 -2441
- package/packages/types/dist/index.cjs +0 -0
- package/packages/types/dist/index.d.cts +1 -0
- package/packages/types/dist/index.d.ts +271 -0
- package/packages/types/dist/index.js +0 -0
- package/packages/types/dist/react.cjs +0 -0
- package/packages/types/dist/react.d.cts +1 -0
- package/packages/types/dist/react.d.ts +64 -0
- package/packages/types/dist/react.js +0 -0
- package/packages/utils/dist/index.cjs +2300 -0
- package/packages/utils/dist/index.d.cts +1 -0
- package/packages/utils/dist/index.d.ts +156 -2721
- package/packages/utils/dist/index.js +122 -35
- package/packages/utils/dist/math-BznvO4qI.cjs +1029 -0
- package/packages/utils/dist/{math-B5PyWuKn.js → math-DRbCtLQH.js} +31 -27
- package/packages/utils/dist/math.cjs +3 -0
- package/packages/utils/dist/math.d.cts +1 -0
- package/packages/utils/dist/math.d.ts +3 -0
- package/packages/utils/dist/math.js +1 -1
- package/packages/utils/dist/vite.cjs +44 -0
- package/packages/utils/dist/vite.d.cts +1 -0
- package/packages/utils/dist/vite.js +12 -8
- package/packages/zod/dist/index.cjs +91 -0
- package/packages/zod/dist/index.d.cts +1 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { ArrayUtil, EnvUtil, ObjectUtil, StringUtil, TypeUtil } from "@pawover/kit-utils";
|
|
3
|
+
import { clone, isEqual } from "es-toolkit";
|
|
2
4
|
//#region src/react/useLatest.ts
|
|
3
5
|
/**
|
|
4
6
|
* 返回当前最新值的 Hook
|
|
@@ -11,2030 +13,6 @@ function useLatest(value) {
|
|
|
11
13
|
return ref;
|
|
12
14
|
}
|
|
13
15
|
//#endregion
|
|
14
|
-
//#region ../utils/dist/math-B5PyWuKn.js
|
|
15
|
-
/**
|
|
16
|
-
* 类型工具类
|
|
17
|
-
*/
|
|
18
|
-
var TypeUtil = class {
|
|
19
|
-
static PROTOTYPE_TAGS = {
|
|
20
|
-
STRING: "[object String]",
|
|
21
|
-
NUMBER: "[object Number]",
|
|
22
|
-
BOOLEAN: "[object Boolean]",
|
|
23
|
-
BIGINT: "[object BigInt]",
|
|
24
|
-
SYMBOL: "[object Symbol]",
|
|
25
|
-
UNDEFINED: "[object Undefined]",
|
|
26
|
-
NULL: "[object Null]",
|
|
27
|
-
OBJECT: "[object Object]",
|
|
28
|
-
FUNCTION: "[object Function]",
|
|
29
|
-
GENERATOR_FUNCTION: "[object GeneratorFunction]",
|
|
30
|
-
ASYNC_FUNCTION: "[object AsyncFunction]",
|
|
31
|
-
ASYNC_GENERATOR_FUNCTION: "[object AsyncGeneratorFunction]",
|
|
32
|
-
PROMISE: "[object Promise]",
|
|
33
|
-
MAP: "[object Map]",
|
|
34
|
-
SET: "[object Set]",
|
|
35
|
-
WEAK_MAP: "[object WeakMap]",
|
|
36
|
-
WEAK_SET: "[object WeakSet]",
|
|
37
|
-
BLOB: "[object Blob]",
|
|
38
|
-
FILE: "[object File]",
|
|
39
|
-
READABLE_STREAM: "[object ReadableStream]",
|
|
40
|
-
GLOBAL: "[object global]",
|
|
41
|
-
WINDOW: "[object Window]",
|
|
42
|
-
IFRAME: "[object HTMLIFrameElement]",
|
|
43
|
-
DATE: "[object Date]",
|
|
44
|
-
ERROR: "[object Error]",
|
|
45
|
-
REG_EXP: "[object RegExp]",
|
|
46
|
-
WEB_SOCKET: "[object WebSocket]",
|
|
47
|
-
URL_SEARCH_PARAMS: "[object URLSearchParams]",
|
|
48
|
-
ABORT_SIGNAL: "[object AbortSignal]"
|
|
49
|
-
};
|
|
50
|
-
static TYPED_ARRAY_TAGS = /* @__PURE__ */ new Set([
|
|
51
|
-
"[object Int8Array]",
|
|
52
|
-
"[object Uint8Array]",
|
|
53
|
-
"[object Uint8ClampedArray]",
|
|
54
|
-
"[object Int16Array]",
|
|
55
|
-
"[object Uint16Array]",
|
|
56
|
-
"[object Int32Array]",
|
|
57
|
-
"[object Uint32Array]",
|
|
58
|
-
"[object Float32Array]",
|
|
59
|
-
"[object Float64Array]",
|
|
60
|
-
"[object BigInt64Array]",
|
|
61
|
-
"[object BigUint64Array]"
|
|
62
|
-
]);
|
|
63
|
-
/**
|
|
64
|
-
* 获取值的 [[Prototype]] 标签
|
|
65
|
-
*
|
|
66
|
-
* @param value - 任意 JavaScript 值
|
|
67
|
-
* @returns 标准化的类型标签字符串
|
|
68
|
-
*/
|
|
69
|
-
static getPrototypeString(value) {
|
|
70
|
-
return Object.prototype.toString.call(value);
|
|
71
|
-
}
|
|
72
|
-
static isConstructable(fn) {
|
|
73
|
-
try {
|
|
74
|
-
Reflect.construct(fn, []);
|
|
75
|
-
return true;
|
|
76
|
-
} catch {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* 检查 value 是否为 string 类型
|
|
82
|
-
* - 当 `checkEmpty` 为 `true` 时,会先 trim 再判断是否为空
|
|
83
|
-
*
|
|
84
|
-
* @param value 待检查值
|
|
85
|
-
* @param checkEmpty 是否检查空字符串(含空白字符串),默认为 `false`
|
|
86
|
-
* @returns 是否为字符串
|
|
87
|
-
* @example
|
|
88
|
-
* ```ts
|
|
89
|
-
* TypeUtil.isString("abc"); // true
|
|
90
|
-
* TypeUtil.isString(""); // true
|
|
91
|
-
* TypeUtil.isString("", true); // false
|
|
92
|
-
* TypeUtil.isString(" ", true); // false
|
|
93
|
-
* TypeUtil.isString(" a ", true); // true
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
static isString(value, checkEmpty = false) {
|
|
97
|
-
return typeof value === "string" && (!checkEmpty || value.trim().length > 0);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* 检查 value 是否为 number 类型
|
|
101
|
-
* - 默认会调用 `TypeUtil.isNaN`(内部基于 `Number.isNaN`)过滤掉 `NaN`
|
|
102
|
-
*
|
|
103
|
-
* @param value 待检查值
|
|
104
|
-
* @param checkNaN 是否检查 `NaN`,默认为 `true`
|
|
105
|
-
* @returns 是否为 number
|
|
106
|
-
* @example
|
|
107
|
-
* ```ts
|
|
108
|
-
* TypeUtil.isNumber(1); // true
|
|
109
|
-
* TypeUtil.isNumber(NaN); // false (default)
|
|
110
|
-
* TypeUtil.isNumber(NaN, false); // true
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
static isNumber(value, checkNaN = true) {
|
|
114
|
-
return typeof value === "number" && (!checkNaN || !this.isNaN(value));
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* 检查 value 是否为 NaN
|
|
118
|
-
* - 禁止使用全局 `isNaN`,其会先进行隐式数字转换,可能导致误判(例如 `isNaN("foo") === true`)
|
|
119
|
-
* - 使用 `Number.isNaN` 仅在值本身就是 `NaN` 时返回 `true`,语义更严格且更安全
|
|
120
|
-
*
|
|
121
|
-
* @param value 待检查值
|
|
122
|
-
* @returns 是否为 NaN
|
|
123
|
-
* @example
|
|
124
|
-
* ```ts
|
|
125
|
-
* TypeUtil.isNaN(NaN); // true
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
128
|
-
static isNaN(value) {
|
|
129
|
-
return Number.isNaN(value);
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* 检查 value 是否为整数
|
|
133
|
-
*
|
|
134
|
-
* @param value 待检查值
|
|
135
|
-
* @param checkSafe 是否附加安全整数检查
|
|
136
|
-
* @returns 是否为整数
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* TypeUtil.isInteger(1); // true
|
|
140
|
-
* TypeUtil.isInteger(1.1); // false
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
static isInteger(value, checkSafe = true) {
|
|
144
|
-
const check = Number.isInteger(value);
|
|
145
|
-
return checkSafe ? check && Number.isSafeInteger(value) : check;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* 检查 value 是否为正整数
|
|
149
|
-
* - 此函数中 `0` 不被视为正整数
|
|
150
|
-
*
|
|
151
|
-
* @param value 待检查值
|
|
152
|
-
* @param checkSafe 是否附加安全整数检查
|
|
153
|
-
* @example
|
|
154
|
-
* ```ts
|
|
155
|
-
* TypeUtil.isPositiveInteger(1); // true
|
|
156
|
-
* TypeUtil.isPositiveInteger(0); // false
|
|
157
|
-
* ```
|
|
158
|
-
*/
|
|
159
|
-
static isPositiveInteger(value, checkSafe = true) {
|
|
160
|
-
return this.isInteger(value, checkSafe) && value > 0;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* 检查 value 是否为负整数
|
|
164
|
-
* - 此函数中 `0` 不被视为负整数
|
|
165
|
-
*
|
|
166
|
-
* @param value 待检查值
|
|
167
|
-
* @param checkSafe 是否附加安全整数检查
|
|
168
|
-
* @example
|
|
169
|
-
* ```ts
|
|
170
|
-
* TypeUtil.isNegativeInteger(-1); // true
|
|
171
|
-
* TypeUtil.isNegativeInteger(0); // false
|
|
172
|
-
* ```
|
|
173
|
-
*/
|
|
174
|
-
static isNegativeInteger(value, checkSafe = true) {
|
|
175
|
-
return this.isInteger(value, checkSafe) && value < 0;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* 检查 value 是否为 Infinity
|
|
179
|
-
* - 排除 `NaN`
|
|
180
|
-
*
|
|
181
|
-
* @param value 待检查值
|
|
182
|
-
* @example
|
|
183
|
-
* ```ts
|
|
184
|
-
* TypeUtil.isInfinity(Infinity); // true
|
|
185
|
-
* TypeUtil.isInfinity(1); // false
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
static isInfinity(value) {
|
|
189
|
-
return this.isNumber(value) && (Number.POSITIVE_INFINITY === value || Number.NEGATIVE_INFINITY === value);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* 检查 value 是否类似 Infinity
|
|
193
|
-
* - 排除 `NaN`
|
|
194
|
-
*
|
|
195
|
-
* @param value 待检查值
|
|
196
|
-
* @example
|
|
197
|
-
* ```ts
|
|
198
|
-
* TypeUtil.isInfinityLike("Infinity"); // true
|
|
199
|
-
* TypeUtil.isInfinityLike("123"); // false
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
static isInfinityLike(value) {
|
|
203
|
-
const check = this.isInfinity(value);
|
|
204
|
-
if (check) return check;
|
|
205
|
-
if (typeof value === "string") return [
|
|
206
|
-
"infinity",
|
|
207
|
-
"-infinity",
|
|
208
|
-
"+infinity",
|
|
209
|
-
"Infinity",
|
|
210
|
-
"-Infinity",
|
|
211
|
-
"+Infinity"
|
|
212
|
-
].includes(value.trim());
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* 检查 value 是否为 Boolean
|
|
217
|
-
* @param value 待检查值
|
|
218
|
-
* @returns 是否为 Boolean
|
|
219
|
-
* @example
|
|
220
|
-
* ```ts
|
|
221
|
-
* TypeUtil.isBoolean(false); // true
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
static isBoolean(value) {
|
|
225
|
-
return typeof value === "boolean";
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* 检查 value 是否为 BigInt
|
|
229
|
-
* @param value 待检查值
|
|
230
|
-
* @returns 是否为 BigInt
|
|
231
|
-
* @example
|
|
232
|
-
* ```ts
|
|
233
|
-
* TypeUtil.isBigInt(1n); // true
|
|
234
|
-
* ```
|
|
235
|
-
*/
|
|
236
|
-
static isBigInt(value) {
|
|
237
|
-
return typeof value === "bigint";
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* 检查 value 是否为 Symbol
|
|
241
|
-
* @param value 待检查值
|
|
242
|
-
* @returns 是否为 Symbol
|
|
243
|
-
* @example
|
|
244
|
-
* ```ts
|
|
245
|
-
* TypeUtil.isSymbol(Symbol("a")); // true
|
|
246
|
-
* ```
|
|
247
|
-
*/
|
|
248
|
-
static isSymbol(value) {
|
|
249
|
-
return typeof value === "symbol";
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* 检查 value 是否为 undefined
|
|
253
|
-
* @param value 待检查值
|
|
254
|
-
* @returns 是否为 undefined
|
|
255
|
-
* @example
|
|
256
|
-
* ```ts
|
|
257
|
-
* TypeUtil.isUndefined(undefined); // true
|
|
258
|
-
* ```
|
|
259
|
-
*/
|
|
260
|
-
static isUndefined(value) {
|
|
261
|
-
return typeof value === "undefined";
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* 检查 value 是否为 null
|
|
265
|
-
* @param value 待检查值
|
|
266
|
-
* @returns 是否为 null
|
|
267
|
-
* @example
|
|
268
|
-
* ```ts
|
|
269
|
-
* TypeUtil.isNull(null); // true
|
|
270
|
-
* ```
|
|
271
|
-
*/
|
|
272
|
-
static isNull(value) {
|
|
273
|
-
return value === null;
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* 检查 value 是否为 null 或 undefined
|
|
277
|
-
* @param value 待检查值
|
|
278
|
-
* @returns 是否为 Nullish
|
|
279
|
-
* @example
|
|
280
|
-
* ```ts
|
|
281
|
-
* TypeUtil.isNullish(null); // true
|
|
282
|
-
* TypeUtil.isNullish(undefined); // true
|
|
283
|
-
* ```
|
|
284
|
-
*/
|
|
285
|
-
static isNullish(value) {
|
|
286
|
-
return this.isNull(value) || this.isUndefined(value);
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* 检查 value 是否为 Function
|
|
290
|
-
* @param value 待检查值
|
|
291
|
-
* @returns 是否为 Function
|
|
292
|
-
* @example
|
|
293
|
-
* ```ts
|
|
294
|
-
* TypeUtil.isFunction(() => {}); // true
|
|
295
|
-
* ```
|
|
296
|
-
*/
|
|
297
|
-
static isFunction(value) {
|
|
298
|
-
return typeof value === "function";
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* 检查 value 是否为 AsyncFunction
|
|
302
|
-
* @param value 待检查值
|
|
303
|
-
* @returns 是否为 AsyncFunction
|
|
304
|
-
* @example
|
|
305
|
-
* ```ts
|
|
306
|
-
* TypeUtil.isAsyncFunction(async () => {}); // true
|
|
307
|
-
* ```
|
|
308
|
-
*/
|
|
309
|
-
static isAsyncFunction(value) {
|
|
310
|
-
return this.isFunction(value) && this.getPrototypeString(value) === this.PROTOTYPE_TAGS.ASYNC_FUNCTION;
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* 检查 value 是否为 GeneratorFunction
|
|
314
|
-
* @param value 待检查值
|
|
315
|
-
* @returns 是否为 GeneratorFunction
|
|
316
|
-
* @example
|
|
317
|
-
* ```ts
|
|
318
|
-
* TypeUtil.isGeneratorFunction(function * a () {}); // true
|
|
319
|
-
* ```
|
|
320
|
-
*/
|
|
321
|
-
static isGeneratorFunction(value) {
|
|
322
|
-
return this.isFunction(value) && this.getPrototypeString(value) === this.PROTOTYPE_TAGS.GENERATOR_FUNCTION;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* 检查 value 是否为 AsyncGeneratorFunction
|
|
326
|
-
* @param value 待检查值
|
|
327
|
-
* @returns 是否为 AsyncGeneratorFunction
|
|
328
|
-
* @example
|
|
329
|
-
* ```ts
|
|
330
|
-
* TypeUtil.isAsyncGeneratorFunction(async function * a () {}); // true
|
|
331
|
-
* ```
|
|
332
|
-
*/
|
|
333
|
-
static isAsyncGeneratorFunction(value) {
|
|
334
|
-
return this.isFunction(value) && this.getPrototypeString(value) === this.PROTOTYPE_TAGS.ASYNC_GENERATOR_FUNCTION;
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* 检查 value 是否为 Promise
|
|
338
|
-
* @param value 待检查值
|
|
339
|
-
* @returns 是否为 Promise
|
|
340
|
-
* @example
|
|
341
|
-
* ```ts
|
|
342
|
-
* TypeUtil.isPromise(Promise.resolve(1)); // true
|
|
343
|
-
* ```
|
|
344
|
-
*/
|
|
345
|
-
static isPromise(value) {
|
|
346
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.PROMISE;
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* 检查 value 是否为 PromiseLike
|
|
350
|
-
* - 可识别拥有 then 方法的非 Promise 对象
|
|
351
|
-
* @param value 待检查值
|
|
352
|
-
* @returns 是否为 PromiseLike
|
|
353
|
-
* @example
|
|
354
|
-
* ```ts
|
|
355
|
-
* TypeUtil.isPromiseLike({ then: () => {} }); // true
|
|
356
|
-
* ```
|
|
357
|
-
*/
|
|
358
|
-
static isPromiseLike(value) {
|
|
359
|
-
return this.isPromise(value) || this.isPlainObject(value, false) && this.isFunction(value["then"]);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* 判断是否为普通对象类型
|
|
363
|
-
* - 可选是否检查原型为 `Object.prototype`,防止原型链污染
|
|
364
|
-
*
|
|
365
|
-
* @param value 待检查值
|
|
366
|
-
* @param prototypeCheck 是否进行原型检查,默认 `true`
|
|
367
|
-
* @returns 是否为 Plain Object (当 prototypeCheck=true) 或 object
|
|
368
|
-
* @example
|
|
369
|
-
* ```ts
|
|
370
|
-
* TypeUtil.isPlainObject({}); // true
|
|
371
|
-
* TypeUtil.isPlainObject([]); // false
|
|
372
|
-
* TypeUtil.isPlainObject(new Date()); // false
|
|
373
|
-
* TypeUtil.isPlainObject(new (class {})()); // false
|
|
374
|
-
* TypeUtil.isPlainObject(new (class {})(), false); // true
|
|
375
|
-
* TypeUtil.isPlainObject(Object.create(null)) // false
|
|
376
|
-
* TypeUtil.isPlainObject(Object.create(null), false) // true
|
|
377
|
-
* ```
|
|
378
|
-
*/
|
|
379
|
-
static isPlainObject(value, prototypeCheck = true) {
|
|
380
|
-
const check = this.getPrototypeString(value) === this.PROTOTYPE_TAGS.OBJECT;
|
|
381
|
-
return prototypeCheck ? check && Object.getPrototypeOf(value) === Object.prototype : check;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* 判断是否为广义对象类型
|
|
385
|
-
*
|
|
386
|
-
* @param value 待检查值
|
|
387
|
-
* @returns 是否为对象
|
|
388
|
-
* @example
|
|
389
|
-
* ```ts
|
|
390
|
-
* TypeUtil.isObject({}); // true
|
|
391
|
-
* TypeUtil.isObject([]); // true
|
|
392
|
-
* TypeUtil.isObject(new Date()); // true
|
|
393
|
-
* TypeUtil.isObject(null); // false
|
|
394
|
-
* TypeUtil.isObject("string"); // false
|
|
395
|
-
* ```
|
|
396
|
-
*/
|
|
397
|
-
static isObject(value) {
|
|
398
|
-
return typeof value === "object" && value !== null;
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* 判断一个对象是否为有效的枚举
|
|
402
|
-
* - 枚举成员不能为空
|
|
403
|
-
* - 枚举成员的键不能具有数值名
|
|
404
|
-
* - 枚举成员的值必须类型一致且为 `string` 或 `number` 类型
|
|
405
|
-
* - 枚举成员的值不能重复
|
|
406
|
-
* - 枚举成员的值必须全部为双向映射或非双向映射
|
|
407
|
-
*
|
|
408
|
-
* @param enumeration 待检查值
|
|
409
|
-
* @returns [是否为有效的枚举, 是否为双向枚举]
|
|
410
|
-
* @example
|
|
411
|
-
* ```ts
|
|
412
|
-
* enum A { X, Y }
|
|
413
|
-
* TypeUtil.isEnumeration(A); // [true, true]
|
|
414
|
-
* ```
|
|
415
|
-
*/
|
|
416
|
-
static isEnumeration(enumeration) {
|
|
417
|
-
if (typeof enumeration !== "object" || enumeration === null) return [false, false];
|
|
418
|
-
const keys = Object.keys(enumeration);
|
|
419
|
-
if (keys.length === 0) return [false, false];
|
|
420
|
-
const originalKeys = [];
|
|
421
|
-
const numericKeys = [];
|
|
422
|
-
for (const key of keys) if (/^\d+$/.test(key)) numericKeys.push(key);
|
|
423
|
-
else originalKeys.push(key);
|
|
424
|
-
if (originalKeys.length === 0) return [false, false];
|
|
425
|
-
let valueType = null;
|
|
426
|
-
const values = [];
|
|
427
|
-
for (const key of originalKeys) {
|
|
428
|
-
const value = enumeration[key];
|
|
429
|
-
const type = typeof value;
|
|
430
|
-
if (type !== "string" && type !== "number") return [false, false];
|
|
431
|
-
if (valueType === null) valueType = type;
|
|
432
|
-
else if (type !== valueType) return [false, false];
|
|
433
|
-
values.push(value);
|
|
434
|
-
}
|
|
435
|
-
if (new Set(values).size !== values.length) return [false, false];
|
|
436
|
-
let isBidirectional = false;
|
|
437
|
-
if (numericKeys.length > 0) {
|
|
438
|
-
if (numericKeys.length !== originalKeys.length) return [false, false];
|
|
439
|
-
const reverseMappedNames = /* @__PURE__ */ new Set();
|
|
440
|
-
for (const numKey of numericKeys) {
|
|
441
|
-
const reverseValue = enumeration[numKey];
|
|
442
|
-
if (typeof reverseValue !== "string") return [false, false];
|
|
443
|
-
if (!originalKeys.includes(reverseValue)) return [false, false];
|
|
444
|
-
reverseMappedNames.add(reverseValue);
|
|
445
|
-
}
|
|
446
|
-
if (reverseMappedNames.size !== originalKeys.length) return [false, false];
|
|
447
|
-
isBidirectional = true;
|
|
448
|
-
}
|
|
449
|
-
return [true, isBidirectional];
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* 检查 value 是否为 Class
|
|
453
|
-
*
|
|
454
|
-
* @param value 待检查值
|
|
455
|
-
* @returns 是否为 Class
|
|
456
|
-
* @example
|
|
457
|
-
* ```ts
|
|
458
|
-
* class A {}
|
|
459
|
-
* TypeUtil.isClass(A); // true
|
|
460
|
-
* TypeUtil.isClass(() => {}); // false
|
|
461
|
-
* ```
|
|
462
|
-
*/
|
|
463
|
-
static isClass(value) {
|
|
464
|
-
return this.isFunction(value) && !this.isAsyncFunction(value) && Function.prototype.toString.call(value).startsWith("class ") && this.isConstructable(value) && value.prototype !== void 0;
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* 检查 value 是否为数组
|
|
468
|
-
*
|
|
469
|
-
* @param value 待检查值
|
|
470
|
-
* @returns 是否为数组
|
|
471
|
-
* @example
|
|
472
|
-
* ```ts
|
|
473
|
-
* TypeUtil.isArray([]); // true
|
|
474
|
-
* ```
|
|
475
|
-
*/
|
|
476
|
-
static isArray(value) {
|
|
477
|
-
return Array.isArray(value);
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* 检查 value 是否为 TypedArray
|
|
481
|
-
*
|
|
482
|
-
* @param value 待检查值
|
|
483
|
-
* @returns 是否为 TypedArray
|
|
484
|
-
* @example
|
|
485
|
-
* ```ts
|
|
486
|
-
* TypeUtil.isTypedArray(new Int8Array()); // true
|
|
487
|
-
* ```
|
|
488
|
-
*/
|
|
489
|
-
static isTypedArray(value) {
|
|
490
|
-
return typeof value === "object" && value !== null && this.TYPED_ARRAY_TAGS.has(this.getPrototypeString(value));
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* 检查 value 是否为 Map
|
|
494
|
-
* @param value 待检查值
|
|
495
|
-
* @returns 是否为 Map
|
|
496
|
-
* @example
|
|
497
|
-
* ```ts
|
|
498
|
-
* TypeUtil.isMap(new Map()); // true
|
|
499
|
-
* ```
|
|
500
|
-
*/
|
|
501
|
-
static isMap(value) {
|
|
502
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.MAP;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* 检查 value 是否为 WeakMap
|
|
506
|
-
* @param value 待检查值
|
|
507
|
-
* @returns 是否为 WeakMap
|
|
508
|
-
* @example
|
|
509
|
-
* ```ts
|
|
510
|
-
* TypeUtil.isWeakMap(new WeakMap()); // true
|
|
511
|
-
* ```
|
|
512
|
-
*/
|
|
513
|
-
static isWeakMap(value) {
|
|
514
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.WEAK_MAP;
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* 检查 value 是否为 Set
|
|
518
|
-
* @param value 待检查值
|
|
519
|
-
* @returns 是否为 Set
|
|
520
|
-
* @example
|
|
521
|
-
* ```ts
|
|
522
|
-
* TypeUtil.isSet(new Set()); // true
|
|
523
|
-
* ```
|
|
524
|
-
*/
|
|
525
|
-
static isSet(value) {
|
|
526
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.SET;
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* 检查 value 是否为 WeakSet
|
|
530
|
-
* @param value 待检查值
|
|
531
|
-
* @returns 是否为 WeakSet
|
|
532
|
-
* @example
|
|
533
|
-
* ```ts
|
|
534
|
-
* TypeUtil.isWeakSet(new WeakSet()); // true
|
|
535
|
-
* ```
|
|
536
|
-
*/
|
|
537
|
-
static isWeakSet(value) {
|
|
538
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.WEAK_SET;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* 检查 value 是否为 Blob
|
|
542
|
-
* @param value 待检查值
|
|
543
|
-
* @returns 是否为 Blob
|
|
544
|
-
* @example
|
|
545
|
-
* ```ts
|
|
546
|
-
* TypeUtil.isBlob(new Blob(["a"])); // true
|
|
547
|
-
* ```
|
|
548
|
-
*/
|
|
549
|
-
static isBlob(value) {
|
|
550
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.BLOB;
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* 检查 value 是否为 File
|
|
554
|
-
* @param value 待检查值
|
|
555
|
-
* @returns 是否为 File
|
|
556
|
-
* @example
|
|
557
|
-
* ```ts
|
|
558
|
-
* TypeUtil.isFile(new File(["a"], "a.txt")); // true
|
|
559
|
-
* ```
|
|
560
|
-
*/
|
|
561
|
-
static isFile(value) {
|
|
562
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.FILE;
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* 检查 value 是否为 ReadableStream
|
|
566
|
-
* - Uses `Object.prototype.toString` where supported (modern browsers, Node.js ≥18).
|
|
567
|
-
* - Falls back to duck-typing in older environments.
|
|
568
|
-
* - Resistant to basic forgery, but not 100% secure in all polyfill scenarios.
|
|
569
|
-
* - ⚠️ Note: In older Node.js (<18) or with non-compliant polyfills, this may return false positives or negatives.
|
|
570
|
-
*
|
|
571
|
-
* @param value 待检查值
|
|
572
|
-
* @returns 是否为 ReadableStream
|
|
573
|
-
* @example
|
|
574
|
-
* ```ts
|
|
575
|
-
* TypeUtil.isReadableStream(new ReadableStream()); // true
|
|
576
|
-
* ```
|
|
577
|
-
*/
|
|
578
|
-
static isReadableStream(value) {
|
|
579
|
-
if (this.getPrototypeString(value) === this.PROTOTYPE_TAGS.READABLE_STREAM) return true;
|
|
580
|
-
return this.isPlainObject(value) && this.isFunction(value["getReader"]) && this.isFunction(value["pipeThrough"]);
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* 检查 value 是否为 Window
|
|
584
|
-
* @param value 待检查值
|
|
585
|
-
* @returns 是否为 Window
|
|
586
|
-
* @example
|
|
587
|
-
* ```ts
|
|
588
|
-
* TypeUtil.isWindow(window); // true
|
|
589
|
-
* ```
|
|
590
|
-
*/
|
|
591
|
-
static isWindow(value) {
|
|
592
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.WINDOW;
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* 检查 value 是否为 HTMLIFrameElement
|
|
596
|
-
* @param value 待检查值
|
|
597
|
-
* @returns 是否为 HTMLIFrameElement
|
|
598
|
-
* @example
|
|
599
|
-
* ```ts
|
|
600
|
-
* TypeUtil.isIframe(document.createElement("iframe")); // true
|
|
601
|
-
* ```
|
|
602
|
-
*/
|
|
603
|
-
static isIframe(value) {
|
|
604
|
-
if (typeof window === "undefined") return false;
|
|
605
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.IFRAME;
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* 检查 value 是否为 Date 对象
|
|
609
|
-
*
|
|
610
|
-
* @param value 待检查值
|
|
611
|
-
* @param invalidCheck 是否要求日期有效(非 Invalid Date)。默认 true
|
|
612
|
-
* - true: 仅当是有效 Date 对象时返回 true(排除 new Date('invalid'))
|
|
613
|
-
* - false: 只要 [[Prototype]] 是 Date 即返回 true(包含 Invalid Date)
|
|
614
|
-
* @returns 是否为 Date 对象,根据 invalidCheck 返回不同语义的 Date 判定
|
|
615
|
-
*
|
|
616
|
-
* @example
|
|
617
|
-
* ```ts
|
|
618
|
-
* TypeUtil.isDate(new Date()); // true
|
|
619
|
-
* TypeUtil.isDate(new Date('invalid')); // false
|
|
620
|
-
* TypeUtil.isDate(new Date('invalid'), false); // true
|
|
621
|
-
* TypeUtil.isDate(null); // false
|
|
622
|
-
* TypeUtil.isDate({}); // false
|
|
623
|
-
* ```
|
|
624
|
-
*/
|
|
625
|
-
static isDate(value, invalidCheck = true) {
|
|
626
|
-
if (!value || typeof value !== "object") return false;
|
|
627
|
-
if (this.getPrototypeString(value) !== this.PROTOTYPE_TAGS.DATE) return false;
|
|
628
|
-
if (!invalidCheck) return true;
|
|
629
|
-
try {
|
|
630
|
-
const time = value.getTime();
|
|
631
|
-
return typeof time === "number" && !Number.isNaN(time);
|
|
632
|
-
} catch {
|
|
633
|
-
return false;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* 检查 value 是否为 Error 对象
|
|
638
|
-
* @param value 待检查值
|
|
639
|
-
* @returns 是否为 Error
|
|
640
|
-
* @example
|
|
641
|
-
* ```ts
|
|
642
|
-
* TypeUtil.isError(new Error("x")); // true
|
|
643
|
-
* ```
|
|
644
|
-
*/
|
|
645
|
-
static isError(value) {
|
|
646
|
-
return value instanceof Error || this.getPrototypeString(value) === this.PROTOTYPE_TAGS.ERROR;
|
|
647
|
-
}
|
|
648
|
-
/**
|
|
649
|
-
* 检查 value 是否为 RegExp
|
|
650
|
-
* @param value 待检查值
|
|
651
|
-
* @returns 是否为 RegExp
|
|
652
|
-
* @example
|
|
653
|
-
* ```ts
|
|
654
|
-
* TypeUtil.isRegExp(/a/); // true
|
|
655
|
-
* ```
|
|
656
|
-
*/
|
|
657
|
-
static isRegExp(value) {
|
|
658
|
-
if (typeof value !== "object" || value === null) return false;
|
|
659
|
-
try {
|
|
660
|
-
const regex = value;
|
|
661
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.REG_EXP && this.isString(regex.source) && this.isString(regex.flags) && this.isBoolean(regex.global) && this.isFunction(regex.test);
|
|
662
|
-
} catch (error) {
|
|
663
|
-
return false;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* 检查 value 是否为 WebSocket
|
|
668
|
-
* @param value 待检查值
|
|
669
|
-
* @returns 是否为 WebSocket
|
|
670
|
-
* @example
|
|
671
|
-
* ```ts
|
|
672
|
-
* TypeUtil.isWebSocket(new WebSocket("wss://echo.websocket.events")); // true
|
|
673
|
-
* ```
|
|
674
|
-
*/
|
|
675
|
-
static isWebSocket(value) {
|
|
676
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.WEB_SOCKET;
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* 检查 value 是否为 URLSearchParams
|
|
680
|
-
* @param value 待检查值
|
|
681
|
-
* @returns 是否为 URLSearchParams
|
|
682
|
-
* @example
|
|
683
|
-
* ```ts
|
|
684
|
-
* TypeUtil.isURLSearchParams(new URLSearchParams("a=1")); // true
|
|
685
|
-
* ```
|
|
686
|
-
*/
|
|
687
|
-
static isURLSearchParams(value) {
|
|
688
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.URL_SEARCH_PARAMS;
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* 检查 value 是否为 AbortSignal
|
|
692
|
-
* @param value 待检查值
|
|
693
|
-
* @returns 是否为 AbortSignal
|
|
694
|
-
* @example
|
|
695
|
-
* ```ts
|
|
696
|
-
* TypeUtil.isAbortSignal(new AbortController().signal); // true
|
|
697
|
-
* ```
|
|
698
|
-
*/
|
|
699
|
-
static isAbortSignal(value) {
|
|
700
|
-
return this.getPrototypeString(value) === this.PROTOTYPE_TAGS.ABORT_SIGNAL;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* 检查 value 是否为可迭代对象 (Iterable)
|
|
704
|
-
* @param value 待检查值
|
|
705
|
-
* @returns 是否为 Iterable
|
|
706
|
-
* @example
|
|
707
|
-
* ```ts
|
|
708
|
-
* TypeUtil.isIterable([1, 2]); // true
|
|
709
|
-
* ```
|
|
710
|
-
*/
|
|
711
|
-
static isIterable(value) {
|
|
712
|
-
return !!value && typeof value[Symbol.iterator] === "function";
|
|
713
|
-
}
|
|
714
|
-
/**
|
|
715
|
-
* 检查 value 是否为 Falsy 值 (false, 0, "", null, undefined, NaN)
|
|
716
|
-
* @param value 待检查值
|
|
717
|
-
* @returns 是否为 Falsy
|
|
718
|
-
* @example
|
|
719
|
-
* ```ts
|
|
720
|
-
* TypeUtil.isFalsy(0); // true
|
|
721
|
-
* ```
|
|
722
|
-
*/
|
|
723
|
-
static isFalsy(value) {
|
|
724
|
-
if (this.isNaN(value) || this.isNull(value) || this.isUndefined(value)) return true;
|
|
725
|
-
return value === false || value === 0 || value === 0n || value === "";
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* 检查 value 是否为 FalsyLike 值
|
|
729
|
-
* - 包含字符串形式的 `"null"`、`"undefined"`、`"false"`、`"0"` 等
|
|
730
|
-
*
|
|
731
|
-
* @param value 待检查值
|
|
732
|
-
* @returns 是否为 FalsyLike
|
|
733
|
-
* @example
|
|
734
|
-
* ```ts
|
|
735
|
-
* TypeUtil.isFalsyLike("false"); // true
|
|
736
|
-
* TypeUtil.isFalsyLike("hello"); // false
|
|
737
|
-
* ```
|
|
738
|
-
*/
|
|
739
|
-
static isFalsyLike(value) {
|
|
740
|
-
if (this.isFalsy(value)) return true;
|
|
741
|
-
return typeof value === "string" && (value === "null" || value === "undefined" || value === "NaN" || value === "false" || value === "0" || value === "-0" || value === "0n");
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
/**
|
|
745
|
-
* 字符串工具类
|
|
746
|
-
*/
|
|
747
|
-
var StringUtil = class {
|
|
748
|
-
static cast(candidate, checkEmpty = true, trim = true) {
|
|
749
|
-
if (checkEmpty) {
|
|
750
|
-
if (candidate === null || candidate === void 0) return "";
|
|
751
|
-
if (typeof candidate === "string" && candidate.trim().length === 0) return "";
|
|
752
|
-
}
|
|
753
|
-
const result = String(candidate);
|
|
754
|
-
return trim ? result.trim() : result;
|
|
755
|
-
}
|
|
756
|
-
/**
|
|
757
|
-
* 从字符串中提取数字字符串
|
|
758
|
-
* - 移除非数字字符,保留符号和小数点
|
|
759
|
-
*
|
|
760
|
-
* @param input 待处理字符串
|
|
761
|
-
* @returns 提取出的数字字符串
|
|
762
|
-
* @example
|
|
763
|
-
* ```ts
|
|
764
|
-
* StringUtil.toNumber("$1,234.56"); // "1234.56"
|
|
765
|
-
* StringUtil.toNumber("abc-123"); // "-123"
|
|
766
|
-
* ```
|
|
767
|
-
*/
|
|
768
|
-
static toNumber(input) {
|
|
769
|
-
if (!TypeUtil.isString(input, true)) return "0";
|
|
770
|
-
const cleaned = input.replace(/[^0-9.-]/g, "");
|
|
771
|
-
if (!cleaned) return "0";
|
|
772
|
-
let isDecimal = false;
|
|
773
|
-
let signCount = 0;
|
|
774
|
-
let firstIndex = -1;
|
|
775
|
-
const stringList = cleaned.split("").map((s, i) => {
|
|
776
|
-
if (s === ".") {
|
|
777
|
-
if (isDecimal) return "";
|
|
778
|
-
isDecimal = true;
|
|
779
|
-
return ".";
|
|
780
|
-
}
|
|
781
|
-
if (s === "-") {
|
|
782
|
-
firstIndex === -1 && signCount++;
|
|
783
|
-
return "";
|
|
784
|
-
}
|
|
785
|
-
firstIndex === -1 && (firstIndex = i);
|
|
786
|
-
return s;
|
|
787
|
-
});
|
|
788
|
-
const sign = signCount % 2 === 1 ? "-" : "";
|
|
789
|
-
if (firstIndex === -1) return sign + "0";
|
|
790
|
-
let result = stringList.join("");
|
|
791
|
-
if (result.startsWith(".")) result = "0" + result;
|
|
792
|
-
if (result.endsWith(".")) result = result.slice(0, -1);
|
|
793
|
-
return sign + result;
|
|
794
|
-
}
|
|
795
|
-
static toLowerCase(input) {
|
|
796
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
797
|
-
return input.toLowerCase();
|
|
798
|
-
}
|
|
799
|
-
static toUpperCase(input) {
|
|
800
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
801
|
-
return input.toUpperCase();
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* 字符串首字母大小写
|
|
805
|
-
* - 包含非西欧字母字符时,不处理
|
|
806
|
-
* - 纯字母且全大写时,不处理
|
|
807
|
-
* - 纯字母且非全大写时,首字母小写,其余保留
|
|
808
|
-
* - 纯字母且非全大写时,首字母大写,其余保留
|
|
809
|
-
*
|
|
810
|
-
* @param input 待处理字符串
|
|
811
|
-
* @param caseType 大小写类型
|
|
812
|
-
* @returns 处理后的字符串
|
|
813
|
-
* @example
|
|
814
|
-
* ```ts
|
|
815
|
-
* StringUtil.toInitialCase("Hello", "lower"); // "hello"
|
|
816
|
-
* StringUtil.toInitialCase("hello", "upper"); // "Hello"
|
|
817
|
-
* ```
|
|
818
|
-
*/
|
|
819
|
-
static toInitialCase(input, caseType) {
|
|
820
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
821
|
-
return input.replace(/\S+/g, (word) => {
|
|
822
|
-
if (/[^a-zA-Z\u00C0-\u017F]/.test(word)) return word;
|
|
823
|
-
if (word === word.toLocaleUpperCase()) return word;
|
|
824
|
-
if (caseType === "lower" && word[0]) return word[0].toLocaleLowerCase() + word.slice(1);
|
|
825
|
-
if (caseType === "upper" && word[0]) return word[0].toLocaleUpperCase() + word.slice(1);
|
|
826
|
-
return word;
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* 将路径转换为 POSIX 风格
|
|
831
|
-
* - 统一使用正斜杠 (/)
|
|
832
|
-
* - 可选移除 Windows 盘符 (如 C:)
|
|
833
|
-
* - 可选移除开头的斜杠
|
|
834
|
-
* - 规范化连续斜杠为单个斜杠
|
|
835
|
-
*
|
|
836
|
-
* @param input 待处理字符串
|
|
837
|
-
* @param removeLeadingSlash 是否移除开头斜杠,默认为 `false`。如果移除了盘符,路径通常会以 / 开头,此参数可控制是否保留该 /
|
|
838
|
-
* @returns 转换后的路径,如果输入无效则返回空字符串
|
|
839
|
-
*
|
|
840
|
-
* @example
|
|
841
|
-
* ```ts
|
|
842
|
-
* StringUtil.toPosix("C:\\Windows\\System32"); // 默认: "/Windows/System32" (移除了 C: 并标准化)
|
|
843
|
-
*
|
|
844
|
-
* StringUtil.toPosix("C:\\Windows\\System32", true); // 移除开头斜杠: "Windows/System32"
|
|
845
|
-
*
|
|
846
|
-
* StringUtil.toPosix("\\\\server\\share\\file.txt"); // UNC 路径: "/server/share/file.txt"
|
|
847
|
-
*
|
|
848
|
-
* StringUtil.toPosix("folder\\subfolder\\file.txt"); // 相对路径: "folder/subfolder/file.txt"
|
|
849
|
-
* ```
|
|
850
|
-
*/
|
|
851
|
-
static toPosix(input, removeLeadingSlash = false) {
|
|
852
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
853
|
-
let normalized = input.replace(/^[A-Za-z]:([\\/])?/, (_, separator) => {
|
|
854
|
-
return separator ? "/" : "";
|
|
855
|
-
});
|
|
856
|
-
normalized = normalized.replaceAll("\\", "/");
|
|
857
|
-
normalized = normalized.replaceAll(/\/+/g, "/");
|
|
858
|
-
if (removeLeadingSlash && normalized.startsWith("/")) normalized = normalized.substring(1);
|
|
859
|
-
return normalized;
|
|
860
|
-
}
|
|
861
|
-
static toJson(input, fallback) {
|
|
862
|
-
if (!TypeUtil.isString(input, true)) return fallback;
|
|
863
|
-
try {
|
|
864
|
-
return JSON.parse(input);
|
|
865
|
-
} catch (error) {
|
|
866
|
-
return fallback;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
static toValues(input, valueType = "number", splitSymbol = ",") {
|
|
870
|
-
if (!TypeUtil.isString(input, true)) return [];
|
|
871
|
-
try {
|
|
872
|
-
const values = input.split(splitSymbol);
|
|
873
|
-
if (valueType === "number") return values.map((d) => Number(d));
|
|
874
|
-
return values;
|
|
875
|
-
} catch (error) {
|
|
876
|
-
return [];
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
|
-
* 从字符串中裁切掉所有的前缀和后缀字符
|
|
881
|
-
*
|
|
882
|
-
* @param input 待处理字符串
|
|
883
|
-
* @param charsToTrim 裁切字符,默认为 `" "`
|
|
884
|
-
* @returns 裁切后的字符串
|
|
885
|
-
* @example
|
|
886
|
-
* ```ts
|
|
887
|
-
* StringUtil.trim(" hello "); // "hello"
|
|
888
|
-
* StringUtil.trim("__hello__", "_"); // "hello"
|
|
889
|
-
* ```
|
|
890
|
-
*/
|
|
891
|
-
static trim(input, charsToTrim = " ") {
|
|
892
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
893
|
-
const toTrim = charsToTrim.replace(/[\W]{1}/g, "\\$&");
|
|
894
|
-
const regex = new RegExp(`^[${toTrim}]+|[${toTrim}]+$`, "g");
|
|
895
|
-
return input.replace(regex, "");
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* 截取字符串
|
|
899
|
-
* - 支持自定义省略符,不会截断在汉字中间(因为JS字符串本身按字符处理)
|
|
900
|
-
*
|
|
901
|
-
* @param input 待处理字符串
|
|
902
|
-
* @param maxLength 最大长度 (包含省略符)
|
|
903
|
-
* @param ellipsis 省略符,默认为 `...`
|
|
904
|
-
* @returns 截取后的字符串
|
|
905
|
-
* @example
|
|
906
|
-
* ```ts
|
|
907
|
-
* StringUtil.truncate("hello world", 8); // "hello..."
|
|
908
|
-
* ```
|
|
909
|
-
*/
|
|
910
|
-
static truncate(input, maxLength, ellipsis = "...") {
|
|
911
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
912
|
-
const codePoints = Array.from(input);
|
|
913
|
-
if (!TypeUtil.isInteger(maxLength) || maxLength < 0) return input;
|
|
914
|
-
if (codePoints.length <= maxLength) return input;
|
|
915
|
-
const availableLength = maxLength - ellipsis.length;
|
|
916
|
-
if (availableLength <= 0) return "";
|
|
917
|
-
return codePoints.slice(0, availableLength).join("") + ellipsis;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* 字符串模板替换
|
|
921
|
-
* - 使用对象的属性值替换字符串中的 {{key}} 模板
|
|
922
|
-
*
|
|
923
|
-
* @param input 待处理字符串
|
|
924
|
-
* @param template 模板对象
|
|
925
|
-
* @param regex 模板匹配正则 (默认: `\{\{(.+?)\}\}`)
|
|
926
|
-
* @returns 替换后的字符串
|
|
927
|
-
* @example
|
|
928
|
-
* ```ts
|
|
929
|
-
* StringUtil.template("Hello {{name}}", { name: "World" }); // "Hello World"
|
|
930
|
-
* ```
|
|
931
|
-
*/
|
|
932
|
-
static template(input, template, regex = /\{\{(.+?)\}\}/g) {
|
|
933
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
934
|
-
regex.lastIndex = 0;
|
|
935
|
-
let result = "";
|
|
936
|
-
let from = 0;
|
|
937
|
-
let match;
|
|
938
|
-
while (match = regex.exec(input)) {
|
|
939
|
-
const replacement = template[match[1]];
|
|
940
|
-
const valueToInsert = replacement === null || replacement === void 0 ? match[0] : replacement;
|
|
941
|
-
result += input.slice(from, match.index) + valueToInsert;
|
|
942
|
-
from = regex.lastIndex;
|
|
943
|
-
}
|
|
944
|
-
return result + input.slice(from);
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* 字符串替换
|
|
948
|
-
* - 替换第一个匹配项
|
|
949
|
-
*
|
|
950
|
-
* @param input 待处理字符串
|
|
951
|
-
* @param search 匹配项
|
|
952
|
-
* @param replacement 替换项
|
|
953
|
-
* @returns 替换后的字符串
|
|
954
|
-
* @example
|
|
955
|
-
* ```ts
|
|
956
|
-
* StringUtil.replace("hello world", "world", "context"); // "hello context"
|
|
957
|
-
* ```
|
|
958
|
-
*/
|
|
959
|
-
static replace(input, search, replacement) {
|
|
960
|
-
if (!TypeUtil.isString(input, true)) return "";
|
|
961
|
-
return input.replace(search, replacement);
|
|
962
|
-
}
|
|
963
|
-
};
|
|
964
|
-
//#endregion
|
|
965
|
-
//#region ../utils/dist/index.js
|
|
966
|
-
/**
|
|
967
|
-
* 数组工具类
|
|
968
|
-
*/
|
|
969
|
-
var ArrayUtil = class {
|
|
970
|
-
static cast(candidate, checkEmpty = true) {
|
|
971
|
-
if (checkEmpty && (TypeUtil.isUndefined(candidate) || TypeUtil.isNull(candidate))) return [];
|
|
972
|
-
return TypeUtil.isArray(candidate) ? [...candidate] : [candidate];
|
|
973
|
-
}
|
|
974
|
-
static first(initialList, fallback) {
|
|
975
|
-
if (!TypeUtil.isArray(initialList) || initialList.length === 0) return fallback;
|
|
976
|
-
return initialList[0];
|
|
977
|
-
}
|
|
978
|
-
static last(initialList, fallback) {
|
|
979
|
-
if (!TypeUtil.isArray(initialList) || initialList.length === 0) return fallback;
|
|
980
|
-
return initialList[initialList.length - 1];
|
|
981
|
-
}
|
|
982
|
-
/**
|
|
983
|
-
* 数组竞选
|
|
984
|
-
* - 返回在匹配函数的比较条件中获胜的最终项目,适用于更复杂的最小值/最大值计算
|
|
985
|
-
*
|
|
986
|
-
* @param initialList 数组
|
|
987
|
-
* @param match 匹配函数
|
|
988
|
-
* @returns 获胜的元素,如果数组为空或参数无效则返回 `null`
|
|
989
|
-
* @example
|
|
990
|
-
* ```ts
|
|
991
|
-
* const list = [1, 10, 5];
|
|
992
|
-
* ArrayUtil.compete(list, (a, b) => (a > b ? a : b)); // 10
|
|
993
|
-
* ArrayUtil.compete(list, (a, b) => (a < b ? a : b)); // 1
|
|
994
|
-
* ```
|
|
995
|
-
*/
|
|
996
|
-
static compete(initialList, match) {
|
|
997
|
-
if (!TypeUtil.isArray(initialList) || initialList.length === 0 || !TypeUtil.isFunction(match)) return null;
|
|
998
|
-
return initialList.reduce(match);
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* 统计数组的项目出现次数
|
|
1002
|
-
* - 通过给定的标识符匹配函数,返回一个对象,其中键是回调函数返回的 key 值,每个值是一个整数,表示该 key 出现的次数
|
|
1003
|
-
*
|
|
1004
|
-
* @param initialList 初始数组
|
|
1005
|
-
* @param match 匹配函数
|
|
1006
|
-
* @returns 统计对象
|
|
1007
|
-
* @example
|
|
1008
|
-
* ```ts
|
|
1009
|
-
* const list = ["a", "b", "a", "c"];
|
|
1010
|
-
* ArrayUtil.count(list, (x) => x); // { a: 2, b: 1, c: 1 }
|
|
1011
|
-
*
|
|
1012
|
-
* const users = [{ id: 1, group: "A" }, { id: 2, group: "B" }, { id: 3, group: "A" }];
|
|
1013
|
-
* ArrayUtil.count(users, (u) => u.group); // { A: 2, B: 1 }
|
|
1014
|
-
* ```
|
|
1015
|
-
*/
|
|
1016
|
-
static count(initialList, match) {
|
|
1017
|
-
if (!TypeUtil.isArray(initialList) || !TypeUtil.isFunction(match)) return {};
|
|
1018
|
-
return initialList.reduce((prev, curr, index) => {
|
|
1019
|
-
const id = match(curr, index).toString();
|
|
1020
|
-
prev[id] = (prev[id] ?? 0) + 1;
|
|
1021
|
-
return prev;
|
|
1022
|
-
}, {});
|
|
1023
|
-
}
|
|
1024
|
-
/**
|
|
1025
|
-
* 获取数组差集
|
|
1026
|
-
* - 返回在 `initialList` 中存在,但在 `diffList` 中不存在的元素
|
|
1027
|
-
*
|
|
1028
|
-
* @param initialList 初始数组
|
|
1029
|
-
* @param diffList 对比数组
|
|
1030
|
-
* @param match 匹配函数
|
|
1031
|
-
* @returns 差集数组
|
|
1032
|
-
* @example
|
|
1033
|
-
* ```ts
|
|
1034
|
-
* ArrayUtil.difference([1, 2, 3], [2, 3, 4]); // [1]
|
|
1035
|
-
* ArrayUtil.difference([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // [{ id: 1 }]
|
|
1036
|
-
* ```
|
|
1037
|
-
*/
|
|
1038
|
-
static difference(initialList, diffList, match) {
|
|
1039
|
-
if (!TypeUtil.isArray(initialList) && !TypeUtil.isArray(diffList)) return [];
|
|
1040
|
-
if (!TypeUtil.isArray(initialList) || !initialList.length) return [];
|
|
1041
|
-
if (!TypeUtil.isArray(diffList) || !diffList.length) return [...initialList];
|
|
1042
|
-
if (!TypeUtil.isFunction(match)) {
|
|
1043
|
-
const arraySet = new Set(diffList);
|
|
1044
|
-
return Array.from(new Set(initialList.filter((item) => !arraySet.has(item))));
|
|
1045
|
-
}
|
|
1046
|
-
const map = /* @__PURE__ */ new Map();
|
|
1047
|
-
diffList.forEach((item, index) => {
|
|
1048
|
-
map.set(match(item, index), true);
|
|
1049
|
-
});
|
|
1050
|
-
return initialList.filter((item, index) => !map.get(match(item, index)));
|
|
1051
|
-
}
|
|
1052
|
-
static intersection(initialList, diffList, match) {
|
|
1053
|
-
if (!TypeUtil.isArray(initialList) || !TypeUtil.isArray(diffList)) return [];
|
|
1054
|
-
if (!initialList.length || !diffList.length) return [];
|
|
1055
|
-
if (!TypeUtil.isFunction(match)) {
|
|
1056
|
-
const diffSet = new Set(diffList);
|
|
1057
|
-
return initialList.filter((item) => diffSet.has(item));
|
|
1058
|
-
}
|
|
1059
|
-
const diffKeys = new Set(diffList.map((item, index) => match(item, index)));
|
|
1060
|
-
return initialList.filter((item, index) => diffKeys.has(match(item, index)));
|
|
1061
|
-
}
|
|
1062
|
-
static merge(initialList, mergeList, match) {
|
|
1063
|
-
if (!TypeUtil.isArray(initialList)) return [];
|
|
1064
|
-
if (!TypeUtil.isArray(mergeList)) return [...initialList];
|
|
1065
|
-
if (!TypeUtil.isFunction(match)) return Array.from(/* @__PURE__ */ new Set([...initialList, ...mergeList]));
|
|
1066
|
-
const keys = /* @__PURE__ */ new Map();
|
|
1067
|
-
mergeList.forEach((item, index) => {
|
|
1068
|
-
keys.set(match(item, index), item);
|
|
1069
|
-
});
|
|
1070
|
-
return initialList.map((prevItem, index) => {
|
|
1071
|
-
const key = match(prevItem, index);
|
|
1072
|
-
return keys.has(key) ? keys.get(key) : prevItem;
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
static pick(initialList, filter, mapper) {
|
|
1076
|
-
if (!TypeUtil.isArray(initialList)) return [];
|
|
1077
|
-
if (!TypeUtil.isFunction(filter)) return [...initialList];
|
|
1078
|
-
const hasMapper = TypeUtil.isFunction(mapper);
|
|
1079
|
-
return initialList.reduce((prev, curr, index) => {
|
|
1080
|
-
if (!filter(curr, index)) return prev;
|
|
1081
|
-
if (hasMapper) prev.push(mapper(curr, index));
|
|
1082
|
-
else prev.push(curr);
|
|
1083
|
-
return prev;
|
|
1084
|
-
}, []);
|
|
1085
|
-
}
|
|
1086
|
-
static replace(initialList, newItem, match) {
|
|
1087
|
-
if (!TypeUtil.isArray(initialList) || !initialList.length) return [];
|
|
1088
|
-
if (!TypeUtil.isFunction(match)) return [...initialList];
|
|
1089
|
-
for (let i = 0; i < initialList.length; i++) {
|
|
1090
|
-
const item = initialList[i];
|
|
1091
|
-
if (match(item, i)) return [
|
|
1092
|
-
...initialList.slice(0, i),
|
|
1093
|
-
newItem,
|
|
1094
|
-
...initialList.slice(i + 1, initialList.length)
|
|
1095
|
-
];
|
|
1096
|
-
}
|
|
1097
|
-
return [...initialList];
|
|
1098
|
-
}
|
|
1099
|
-
/**
|
|
1100
|
-
* 数组项替换并移动
|
|
1101
|
-
* - 在给定的数组中,替换并移动符合匹配函数结果的项目
|
|
1102
|
-
* - 只替换和移动第一个匹配项
|
|
1103
|
-
* - 未匹配时,根据 `position` 在指定位置插入 `newItem`
|
|
1104
|
-
*
|
|
1105
|
-
* @param initialList 初始数组
|
|
1106
|
-
* @param newItem 替换项
|
|
1107
|
-
* @param match 匹配函数
|
|
1108
|
-
* @param position 移动位置,可选 `start` | `end` | 索引位置, 默认为 `end`
|
|
1109
|
-
* @returns
|
|
1110
|
-
* @example
|
|
1111
|
-
* ```ts
|
|
1112
|
-
* ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, 0); // [5, 1, 3, 4]
|
|
1113
|
-
* ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, 2); // [1, 3, 5, 4]
|
|
1114
|
-
* ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, "start"); // [5, 1, 3, 4]
|
|
1115
|
-
* ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2); // [1, 3, 4, 5]
|
|
1116
|
-
* ```
|
|
1117
|
-
*/
|
|
1118
|
-
static replaceMove(initialList, newItem, match, position) {
|
|
1119
|
-
if (!TypeUtil.isArray(initialList)) return [];
|
|
1120
|
-
if (!initialList.length) return [newItem];
|
|
1121
|
-
if (!TypeUtil.isFunction(match)) return [...initialList];
|
|
1122
|
-
const result = [...initialList];
|
|
1123
|
-
const matchIndex = initialList.findIndex(match);
|
|
1124
|
-
if (matchIndex !== -1) result.splice(matchIndex, 1);
|
|
1125
|
-
if (position === "start") result.unshift(newItem);
|
|
1126
|
-
else if (position === 0 || TypeUtil.isPositiveInteger(position, false)) result.splice(Math.min(position, result.length), 0, newItem);
|
|
1127
|
-
else result.push(newItem);
|
|
1128
|
-
return result;
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* 数组切分
|
|
1132
|
-
* - 将数组以指定的长度切分后,组合在高维数组中
|
|
1133
|
-
*
|
|
1134
|
-
* @param initialList 初始数组
|
|
1135
|
-
* @param size 分割尺寸,默认 `10`
|
|
1136
|
-
* @returns 切分后的二维数组
|
|
1137
|
-
* @example
|
|
1138
|
-
* ```ts
|
|
1139
|
-
* ArrayUtil.split([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
|
|
1140
|
-
* ```
|
|
1141
|
-
*/
|
|
1142
|
-
static split(initialList, size = 10) {
|
|
1143
|
-
if (!TypeUtil.isArray(initialList)) return [];
|
|
1144
|
-
if (!TypeUtil.isPositiveInteger(size, false)) return [];
|
|
1145
|
-
const count = Math.ceil(initialList.length / size);
|
|
1146
|
-
return Array.from({ length: count }).fill(null).map((_c, i) => {
|
|
1147
|
-
return initialList.slice(i * size, i * size + size);
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
/**
|
|
1151
|
-
* 数组分组过滤
|
|
1152
|
-
* - 给定一个数组和一个条件,返回一个由两个数组组成的元组,其中第一个数组包含所有满足条件的项,第二个数组包含所有不满足条件的项
|
|
1153
|
-
*
|
|
1154
|
-
* @param initialList 初始数组
|
|
1155
|
-
* @param match 条件匹配函数
|
|
1156
|
-
* @returns [满足条件的项[], 不满足条件的项[]]
|
|
1157
|
-
* @example
|
|
1158
|
-
* ```ts
|
|
1159
|
-
* ArrayUtil.fork([1, 2, 3, 4], (n) => n % 2 === 0); // [[2, 4], [1, 3]]
|
|
1160
|
-
* ```
|
|
1161
|
-
*/
|
|
1162
|
-
static fork(initialList, match) {
|
|
1163
|
-
const forked = [[], []];
|
|
1164
|
-
if (TypeUtil.isArray(initialList)) initialList.forEach((item, index) => {
|
|
1165
|
-
forked[match(item, index) ? 0 : 1].push(item);
|
|
1166
|
-
});
|
|
1167
|
-
return forked;
|
|
1168
|
-
}
|
|
1169
|
-
/**
|
|
1170
|
-
* 数组解压
|
|
1171
|
-
* - `ArrayUtil.zip` 的反向操作
|
|
1172
|
-
*
|
|
1173
|
-
* @param arrayList 压缩后的数组
|
|
1174
|
-
* @returns 解压后的二维数组
|
|
1175
|
-
* @example
|
|
1176
|
-
* ```ts
|
|
1177
|
-
* ArrayUtil.unzip([[1, "a"], [2, "b"]]); // [[1, 2], ["a", "b"]]
|
|
1178
|
-
* ```
|
|
1179
|
-
*/
|
|
1180
|
-
static unzip(arrayList) {
|
|
1181
|
-
if (!TypeUtil.isArray(arrayList) || !arrayList.length) return [];
|
|
1182
|
-
const out = new Array(arrayList.reduce((max, arr) => Math.max(max, arr.length), 0));
|
|
1183
|
-
let index = 0;
|
|
1184
|
-
const get = (array) => array[index];
|
|
1185
|
-
for (; index < out.length; index++) out[index] = Array.from(arrayList, get);
|
|
1186
|
-
return out;
|
|
1187
|
-
}
|
|
1188
|
-
static zip(...arrays) {
|
|
1189
|
-
return this.unzip(arrays);
|
|
1190
|
-
}
|
|
1191
|
-
static zipToObject(keys, values) {
|
|
1192
|
-
const result = {};
|
|
1193
|
-
if (!TypeUtil.isArray(keys) || !keys.length) return result;
|
|
1194
|
-
const getValue = TypeUtil.isFunction(values) ? values : TypeUtil.isArray(values) ? (_k, i) => values[i] : (_k, _i) => values;
|
|
1195
|
-
return keys.reduce((acc, key, idx) => {
|
|
1196
|
-
acc[key] = getValue(key, idx);
|
|
1197
|
-
return acc;
|
|
1198
|
-
}, result);
|
|
1199
|
-
}
|
|
1200
|
-
};
|
|
1201
|
-
(class {
|
|
1202
|
-
/**
|
|
1203
|
-
* 每秒的毫秒数
|
|
1204
|
-
* @example
|
|
1205
|
-
* ```ts
|
|
1206
|
-
* DateTimeUtil.MILLISECONDS_PER_SECOND; // 1000
|
|
1207
|
-
* ```
|
|
1208
|
-
*/
|
|
1209
|
-
static MILLISECONDS_PER_SECOND = 1e3;
|
|
1210
|
-
/**
|
|
1211
|
-
* 每分钟的秒数
|
|
1212
|
-
* @example
|
|
1213
|
-
* ```ts
|
|
1214
|
-
* DateTimeUtil.SECOND_PER_MINUTE; // 60
|
|
1215
|
-
* ```
|
|
1216
|
-
*/
|
|
1217
|
-
static SECOND_PER_MINUTE = 60;
|
|
1218
|
-
/**
|
|
1219
|
-
* 每小时的分钟数
|
|
1220
|
-
* @example
|
|
1221
|
-
* ```ts
|
|
1222
|
-
* DateTimeUtil.MINUTE_PER_HOUR; // 60
|
|
1223
|
-
* ```
|
|
1224
|
-
*/
|
|
1225
|
-
static MINUTE_PER_HOUR = 60;
|
|
1226
|
-
/**
|
|
1227
|
-
* 每小时的秒数
|
|
1228
|
-
* @example
|
|
1229
|
-
* ```ts
|
|
1230
|
-
* DateTimeUtil.SECOND_PER_HOUR; // 3600
|
|
1231
|
-
* ```
|
|
1232
|
-
*/
|
|
1233
|
-
static SECOND_PER_HOUR = this.SECOND_PER_MINUTE ** 2;
|
|
1234
|
-
/**
|
|
1235
|
-
* 每天小时数
|
|
1236
|
-
* @example
|
|
1237
|
-
* ```ts
|
|
1238
|
-
* DateTimeUtil.HOUR_PER_DAY; // 24
|
|
1239
|
-
* ```
|
|
1240
|
-
*/
|
|
1241
|
-
static HOUR_PER_DAY = 24;
|
|
1242
|
-
/**
|
|
1243
|
-
* 每天秒数
|
|
1244
|
-
* @example
|
|
1245
|
-
* ```ts
|
|
1246
|
-
* DateTimeUtil.SECOND_PER_DAY; // 86400
|
|
1247
|
-
* ```
|
|
1248
|
-
*/
|
|
1249
|
-
static SECOND_PER_DAY = this.SECOND_PER_HOUR * this.HOUR_PER_DAY;
|
|
1250
|
-
/**
|
|
1251
|
-
* 每周天数
|
|
1252
|
-
* @example
|
|
1253
|
-
* ```ts
|
|
1254
|
-
* DateTimeUtil.DAY_PER_WEEK; // 7
|
|
1255
|
-
* ```
|
|
1256
|
-
*/
|
|
1257
|
-
static DAY_PER_WEEK = 7;
|
|
1258
|
-
/**
|
|
1259
|
-
* 每月天数
|
|
1260
|
-
* @example
|
|
1261
|
-
* ```ts
|
|
1262
|
-
* DateTimeUtil.DAY_PER_MONTH; // 30
|
|
1263
|
-
* ```
|
|
1264
|
-
*/
|
|
1265
|
-
static DAY_PER_MONTH = 30;
|
|
1266
|
-
/**
|
|
1267
|
-
* 每年天数
|
|
1268
|
-
* @example
|
|
1269
|
-
* ```ts
|
|
1270
|
-
* DateTimeUtil.DAY_PER_YEAR; // 365
|
|
1271
|
-
* ```
|
|
1272
|
-
*/
|
|
1273
|
-
static DAY_PER_YEAR = 365;
|
|
1274
|
-
/**
|
|
1275
|
-
* 每年月数
|
|
1276
|
-
* @example
|
|
1277
|
-
* ```ts
|
|
1278
|
-
* DateTimeUtil.MONTH_PER_YEAR; // 12
|
|
1279
|
-
* ```
|
|
1280
|
-
*/
|
|
1281
|
-
static MONTH_PER_YEAR = 12;
|
|
1282
|
-
/**
|
|
1283
|
-
* 每年平均周
|
|
1284
|
-
* @example
|
|
1285
|
-
* ```ts
|
|
1286
|
-
* DateTimeUtil.WEEK_PER_YEAR; // 52
|
|
1287
|
-
* ```
|
|
1288
|
-
*/
|
|
1289
|
-
static WEEK_PER_YEAR = 52;
|
|
1290
|
-
/**
|
|
1291
|
-
* 每月平均周
|
|
1292
|
-
* @example
|
|
1293
|
-
* ```ts
|
|
1294
|
-
* DateTimeUtil.WEEK_PER_MONTH; // 4
|
|
1295
|
-
* ```
|
|
1296
|
-
*/
|
|
1297
|
-
static WEEK_PER_MONTH = 4;
|
|
1298
|
-
/**
|
|
1299
|
-
* 常用时间格式模板集合
|
|
1300
|
-
*
|
|
1301
|
-
* @example
|
|
1302
|
-
* ```ts
|
|
1303
|
-
* DateTimeUtil.FORMAT.ISO_DATE; // "yyyy-MM-dd"
|
|
1304
|
-
* DateTimeUtil.FORMAT.CN_DATE_TIME; // "yyyy年MM月dd日 HH时mm分ss秒"
|
|
1305
|
-
* ```
|
|
1306
|
-
*/
|
|
1307
|
-
static FORMAT = {
|
|
1308
|
-
ISO_DATE: "yyyy-MM-dd",
|
|
1309
|
-
ISO_TIME: "HH:mm:ss",
|
|
1310
|
-
ISO_DATE_TIME: "yyyy-MM-dd HH:mm:ss",
|
|
1311
|
-
ISO_DATE_TIME_MS: "yyyy-MM-dd HH:mm:ss.SSS",
|
|
1312
|
-
ISO_DATETIME_TZ: "yyyy-MM-dd'T'HH:mm:ssXXX",
|
|
1313
|
-
ISO_DATETIME_TZ_MS: "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
|
|
1314
|
-
US_DATE: "MM/dd/yyyy",
|
|
1315
|
-
US_DATE_TIME: "MM/dd/yyyy HH:mm:ss",
|
|
1316
|
-
US_DATE_SHORT_YEAR: "MM/dd/yy",
|
|
1317
|
-
EU_DATE: "dd/MM/yyyy",
|
|
1318
|
-
EU_DATE_TIME: "dd/MM/yyyy HH:mm:ss",
|
|
1319
|
-
CN_DATE: "yyyy年MM月dd日",
|
|
1320
|
-
CN_DATE_TIME: "yyyy年MM月dd日 HH时mm分ss秒",
|
|
1321
|
-
CN_DATE_WEEKDAY: "yyyy年MM月dd日 EEE",
|
|
1322
|
-
CN_WEEKDAY_FULL: "EEEE",
|
|
1323
|
-
SHORT_DATE: "yy-MM-dd",
|
|
1324
|
-
SHORT_DATE_SLASH: "yy/MM/dd",
|
|
1325
|
-
MONTH_DAY: "MM-dd",
|
|
1326
|
-
MONTH_DAY_CN: "MM月dd日",
|
|
1327
|
-
DATE_WITH_WEEKDAY_SHORT: "yyyy-MM-dd (EEE)",
|
|
1328
|
-
DATE_WITH_WEEKDAY_FULL: "yyyy-MM-dd (EEEE)",
|
|
1329
|
-
TIME_24: "HH:mm:ss",
|
|
1330
|
-
TIME_24_NO_SEC: "HH:mm",
|
|
1331
|
-
TIME_12: "hh:mm:ss a",
|
|
1332
|
-
TIME_12_NO_SEC: "hh:mm a",
|
|
1333
|
-
TIMESTAMP: "yyyyMMddHHmmss",
|
|
1334
|
-
TIMESTAMP_MS: "yyyyMMddHHmmssSSS",
|
|
1335
|
-
RFC2822: "EEE, dd MMM yyyy HH:mm:ss xxx",
|
|
1336
|
-
READABLE_DATE: "MMM dd, yyyy",
|
|
1337
|
-
READABLE_DATE_TIME: "MMM dd, yyyy HH:mm",
|
|
1338
|
-
COMPACT_DATETIME: "yyyyMMdd_HHmmss"
|
|
1339
|
-
};
|
|
1340
|
-
/**
|
|
1341
|
-
* 获取当前时区信息
|
|
1342
|
-
*
|
|
1343
|
-
* @returns 时区信息对象 (UTC偏移和时区名称)
|
|
1344
|
-
* @example
|
|
1345
|
-
* ```ts
|
|
1346
|
-
* DateTimeUtil.getTimeZone(); // { UTC: "UTC+8", timeZone: "Asia/Shanghai" }
|
|
1347
|
-
* ```
|
|
1348
|
-
*/
|
|
1349
|
-
static getTimeZone() {
|
|
1350
|
-
const hour = 0 - (/* @__PURE__ */ new Date()).getTimezoneOffset() / this.MINUTE_PER_HOUR;
|
|
1351
|
-
return {
|
|
1352
|
-
UTC: "UTC" + (hour >= 0 ? "+" + hour : hour),
|
|
1353
|
-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
});
|
|
1357
|
-
/**
|
|
1358
|
-
* 环境检查工具类
|
|
1359
|
-
*/
|
|
1360
|
-
var EnvUtil = class {
|
|
1361
|
-
static _isBrowser = typeof window !== "undefined" && TypeUtil.isFunction(window?.document?.createElement);
|
|
1362
|
-
static _isWebWorker = typeof window === "undefined" && typeof self !== "undefined" && "importScripts" in self;
|
|
1363
|
-
static _isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
1364
|
-
/**
|
|
1365
|
-
* 检测是否处于浏览器环境
|
|
1366
|
-
*
|
|
1367
|
-
* @returns 是否为浏览器环境
|
|
1368
|
-
* @example
|
|
1369
|
-
* ```ts
|
|
1370
|
-
* EnvUtil.isBrowser(); // true: 浏览器, false: Node.js
|
|
1371
|
-
* ```
|
|
1372
|
-
*/
|
|
1373
|
-
static isBrowser() {
|
|
1374
|
-
return this._isBrowser;
|
|
1375
|
-
}
|
|
1376
|
-
/**
|
|
1377
|
-
* 检测是否处于 Web Worker 环境
|
|
1378
|
-
*
|
|
1379
|
-
* @returns 是否为 Web Worker 环境
|
|
1380
|
-
* @example
|
|
1381
|
-
* ```ts
|
|
1382
|
-
* EnvUtil.isWebWorker(); // true: Worker, false: 主线程/Node.js
|
|
1383
|
-
* ```
|
|
1384
|
-
*/
|
|
1385
|
-
static isWebWorker() {
|
|
1386
|
-
return this._isWebWorker;
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* 检测是否处于 React Native 环境
|
|
1390
|
-
*
|
|
1391
|
-
* @returns 是否为 React Native 环境
|
|
1392
|
-
* @example
|
|
1393
|
-
* ```ts
|
|
1394
|
-
* EnvUtil.isReactNative(); // true: React Native, false: Web/Node.js
|
|
1395
|
-
* ```
|
|
1396
|
-
*/
|
|
1397
|
-
static isReactNative() {
|
|
1398
|
-
return this._isReactNative;
|
|
1399
|
-
}
|
|
1400
|
-
/**
|
|
1401
|
-
* 检查是否在 iframe 环境中
|
|
1402
|
-
*
|
|
1403
|
-
* @returns 是否在 iframe 中
|
|
1404
|
-
* @example
|
|
1405
|
-
* ```ts
|
|
1406
|
-
* EnvUtil.isIframe(); // true: 当前页面在 iframe 中
|
|
1407
|
-
* ```
|
|
1408
|
-
*/
|
|
1409
|
-
static isIframe() {
|
|
1410
|
-
if (typeof window === "undefined") return false;
|
|
1411
|
-
try {
|
|
1412
|
-
return window.top !== window.self;
|
|
1413
|
-
} catch (error) {
|
|
1414
|
-
if (error.name === "SecurityError") return true;
|
|
1415
|
-
return false;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
/**
|
|
1419
|
-
* 检测当前设备是否为桌面设备
|
|
1420
|
-
*
|
|
1421
|
-
* @param minWidth - 桌面设备最小宽度(默认 1200px)
|
|
1422
|
-
* @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
|
|
1423
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1424
|
-
* @returns 是否为桌面设备
|
|
1425
|
-
* @example
|
|
1426
|
-
* ```ts
|
|
1427
|
-
* // 假设 window.innerWidth = 1920
|
|
1428
|
-
* EnvUtil.isDesktop(); // true
|
|
1429
|
-
*
|
|
1430
|
-
* // 自定义阈值
|
|
1431
|
-
* EnvUtil.isDesktop(1440, 13); // 更严格的桌面检测
|
|
1432
|
-
* ```
|
|
1433
|
-
*/
|
|
1434
|
-
static isDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
|
|
1435
|
-
if (typeof window === "undefined" || !TypeUtil.isPositiveInteger(minWidth) || !TypeUtil.isPositiveInteger(minScreenSize)) return false;
|
|
1436
|
-
if (window.innerWidth < minWidth) return false;
|
|
1437
|
-
try {
|
|
1438
|
-
const widthPx = window.screen.width;
|
|
1439
|
-
const heightPx = window.screen.height;
|
|
1440
|
-
const DPI = dpi * (window.devicePixelRatio || 1);
|
|
1441
|
-
const widthInch = widthPx / DPI;
|
|
1442
|
-
const heightInch = heightPx / DPI;
|
|
1443
|
-
return Math.sqrt(widthInch ** 2 + heightInch ** 2) >= minScreenSize;
|
|
1444
|
-
} catch {
|
|
1445
|
-
return true;
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* 检测当前设备是否为 Windows 桌面设备
|
|
1450
|
-
*
|
|
1451
|
-
* @param minWidth - 桌面设备最小宽度(默认 1200px)
|
|
1452
|
-
* @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
|
|
1453
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1454
|
-
* @returns 是否为 Windows 桌面设备
|
|
1455
|
-
* @example
|
|
1456
|
-
* ```ts
|
|
1457
|
-
* // UA contains Windows
|
|
1458
|
-
* EnvUtil.isWindowsDesktop(); // true
|
|
1459
|
-
* ```
|
|
1460
|
-
*/
|
|
1461
|
-
static isWindowsDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
|
|
1462
|
-
if (typeof navigator === "undefined" || !navigator.userAgent) return false;
|
|
1463
|
-
return /Windows/i.test(navigator.userAgent) && this.isDesktop(minWidth, minScreenSize, dpi);
|
|
1464
|
-
}
|
|
1465
|
-
/**
|
|
1466
|
-
* 检测当前设备是否为 macOS 桌面设备
|
|
1467
|
-
*
|
|
1468
|
-
* @param minWidth - 桌面设备最小宽度(默认 1200px)
|
|
1469
|
-
* @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
|
|
1470
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1471
|
-
* @returns 是否为 macOS 桌面设备
|
|
1472
|
-
* @example
|
|
1473
|
-
* ```ts
|
|
1474
|
-
* // UA contains Macintosh
|
|
1475
|
-
* EnvUtil.isMacOSDesktop(); // true
|
|
1476
|
-
* ```
|
|
1477
|
-
*/
|
|
1478
|
-
static isMacOSDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
|
|
1479
|
-
if (typeof navigator === "undefined" || !navigator.userAgent) return false;
|
|
1480
|
-
return /Macintosh/i.test(navigator.userAgent) && this.isDesktop(minWidth, minScreenSize, dpi);
|
|
1481
|
-
}
|
|
1482
|
-
/**
|
|
1483
|
-
* 检测当前设备是否为移动设备
|
|
1484
|
-
*
|
|
1485
|
-
* @param maxWidth - 移动设备最大宽度(默认 768px)
|
|
1486
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1487
|
-
* @returns 是否为移动设备
|
|
1488
|
-
* @example
|
|
1489
|
-
* ```ts
|
|
1490
|
-
* // 假设 window.innerWidth = 500
|
|
1491
|
-
* EnvUtil.isMobile(); // true
|
|
1492
|
-
* ```
|
|
1493
|
-
*/
|
|
1494
|
-
static isMobile(maxWidth = 768, dpi = 160) {
|
|
1495
|
-
if (typeof window === "undefined" || !TypeUtil.isPositiveInteger(maxWidth)) return false;
|
|
1496
|
-
if (window.innerWidth >= maxWidth) return false;
|
|
1497
|
-
try {
|
|
1498
|
-
const widthPx = window.screen.width;
|
|
1499
|
-
const heightPx = window.screen.height;
|
|
1500
|
-
const DPI = dpi * (window.devicePixelRatio || 1);
|
|
1501
|
-
const widthInch = widthPx / DPI;
|
|
1502
|
-
const heightInch = heightPx / DPI;
|
|
1503
|
-
return Math.sqrt(widthInch ** 2 + heightInch ** 2) < 7;
|
|
1504
|
-
} catch {
|
|
1505
|
-
return true;
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
/**
|
|
1509
|
-
* 检测当前设备是否为IOS移动设备
|
|
1510
|
-
*
|
|
1511
|
-
* @param maxWidth - 移动设备最大宽度(默认 768px)
|
|
1512
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1513
|
-
* @returns 是否为 iOS 移动设备 (iPhone/iPod)
|
|
1514
|
-
* @example
|
|
1515
|
-
* ```ts
|
|
1516
|
-
* // UA contains iPhone
|
|
1517
|
-
* EnvUtil.isIOSMobile(); // true
|
|
1518
|
-
* ```
|
|
1519
|
-
*/
|
|
1520
|
-
static isIOSMobile(maxWidth = 768, dpi = 160) {
|
|
1521
|
-
if (typeof navigator === "undefined" || !navigator.userAgent) return false;
|
|
1522
|
-
return /iPhone|iPad|iPod/i.test(navigator.userAgent) && this.isMobile(maxWidth, dpi);
|
|
1523
|
-
}
|
|
1524
|
-
/**
|
|
1525
|
-
* 检测当前设备是否为平板
|
|
1526
|
-
*
|
|
1527
|
-
* @param minWidth - 平板最小宽度(默认 768px)
|
|
1528
|
-
* @param maxWidth - 平板最大宽度(默认 1200px)
|
|
1529
|
-
* @param dpi - 标准 DPI 基准(默认 160)
|
|
1530
|
-
* @returns 是否为平板设备
|
|
1531
|
-
* @example
|
|
1532
|
-
* ```ts
|
|
1533
|
-
* // 假设 window.innerWidth = 1000
|
|
1534
|
-
* EnvUtil.isTablet(); // true
|
|
1535
|
-
* ```
|
|
1536
|
-
*/
|
|
1537
|
-
static isTablet(minWidth = 768, maxWidth = 1200, dpi = 160) {
|
|
1538
|
-
if (typeof window === "undefined" || !TypeUtil.isPositiveInteger(minWidth) || !TypeUtil.isPositiveInteger(maxWidth)) return false;
|
|
1539
|
-
const width = window.innerWidth;
|
|
1540
|
-
const isWithinWidthRange = width >= minWidth && width <= maxWidth;
|
|
1541
|
-
try {
|
|
1542
|
-
const widthPx = window.screen.width;
|
|
1543
|
-
const heightPx = window.screen.height;
|
|
1544
|
-
const DPI = dpi * (window.devicePixelRatio || 1);
|
|
1545
|
-
const widthInch = widthPx / DPI;
|
|
1546
|
-
const heightInch = heightPx / DPI;
|
|
1547
|
-
const screenInches = Math.sqrt(widthInch ** 2 + heightInch ** 2);
|
|
1548
|
-
return isWithinWidthRange || screenInches >= 7;
|
|
1549
|
-
} catch {
|
|
1550
|
-
return isWithinWidthRange;
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
};
|
|
1554
|
-
/**
|
|
1555
|
-
* MIME 工具类
|
|
1556
|
-
*/
|
|
1557
|
-
var MimeUtil = class {
|
|
1558
|
-
/**
|
|
1559
|
-
* 文件类型 MIME 常量
|
|
1560
|
-
* - 每个类型对应具体的文件扩展名
|
|
1561
|
-
*/
|
|
1562
|
-
static FILE_MIME = {
|
|
1563
|
-
/** 普通文本文件(.txt) */
|
|
1564
|
-
TEXT: "text/plain",
|
|
1565
|
-
/** 超文本标记语言文档(.html/.htm) */
|
|
1566
|
-
HTML: "text/html",
|
|
1567
|
-
/** 层叠样式表文件(.css) */
|
|
1568
|
-
CSS: "text/css",
|
|
1569
|
-
/** 逗号分隔值文件/表格数据(.csv) */
|
|
1570
|
-
CSV: "text/csv",
|
|
1571
|
-
/** 制表符分隔值文件(.tsv) */
|
|
1572
|
-
TSV: "text/tab-separated-values",
|
|
1573
|
-
/** XML 文档(.xml) */
|
|
1574
|
-
XML: "application/xml",
|
|
1575
|
-
/** XML 文档/兼容值 */
|
|
1576
|
-
XML_LEGACY: "text/xml",
|
|
1577
|
-
/** XHTML 文档(.xhtml/.xht) */
|
|
1578
|
-
XHTML: "application/xhtml+xml",
|
|
1579
|
-
/** JavaScript 文件(.js) */
|
|
1580
|
-
JS: "text/javascript",
|
|
1581
|
-
/** TypeScript 文件(.ts) */
|
|
1582
|
-
TS: "text/typescript",
|
|
1583
|
-
/** Python 文件(.py) */
|
|
1584
|
-
PY: "text/x-python",
|
|
1585
|
-
/** Shell 脚本 (.sh) */
|
|
1586
|
-
SH: "text/x-sh",
|
|
1587
|
-
/** C 语言源文件(.c) */
|
|
1588
|
-
C: "text/x-c",
|
|
1589
|
-
/** C++ 源文件(.cpp/.cc/.cxx) */
|
|
1590
|
-
CPP: "text/x-c++",
|
|
1591
|
-
/** C# 源文件(.cs) */
|
|
1592
|
-
CSHARP: "text/x-csharp",
|
|
1593
|
-
/** Java 源文件(.java) */
|
|
1594
|
-
JAVA: "text/x-java",
|
|
1595
|
-
/** Go 源文件(.go) */
|
|
1596
|
-
GO: "text/x-go",
|
|
1597
|
-
/** Rust 源文件(.rs) */
|
|
1598
|
-
RUST: "text/x-rust",
|
|
1599
|
-
/** PHP 文件(.php) */
|
|
1600
|
-
PHP: "text/x-php",
|
|
1601
|
-
/** Ruby 文件(.rb) */
|
|
1602
|
-
RUBY: "text/x-ruby",
|
|
1603
|
-
/** Swift 源文件(.swift) */
|
|
1604
|
-
SWIFT: "text/x-swift",
|
|
1605
|
-
/** YAML 文档(.yaml/.yml) */
|
|
1606
|
-
YAML: "application/yaml",
|
|
1607
|
-
/** YAML 文档/兼容值 */
|
|
1608
|
-
YAML_LEGACY: "text/vnd.yaml",
|
|
1609
|
-
/** TOML 文档(.toml) */
|
|
1610
|
-
TOML: "application/toml",
|
|
1611
|
-
/** TOML 文档/兼容值 */
|
|
1612
|
-
TOML_LEGACY: "text/x-toml",
|
|
1613
|
-
/** SQL 脚本(.sql) */
|
|
1614
|
-
SQL: "application/sql",
|
|
1615
|
-
/** SQL 脚本/兼容值 */
|
|
1616
|
-
SQL_LEGACY: "text/x-sql",
|
|
1617
|
-
/** Markdown 格式文档(.md/.markdown) */
|
|
1618
|
-
MARKDOWN: "text/markdown",
|
|
1619
|
-
/** 富文本格式文档(.rtf) */
|
|
1620
|
-
RTF: "application/rtf",
|
|
1621
|
-
/** iCalendar 日历格式(.ics) */
|
|
1622
|
-
CALENDAR: "text/calendar",
|
|
1623
|
-
/** JPEG 图像(.jpg/.jpeg) */
|
|
1624
|
-
JPEG: "image/jpeg",
|
|
1625
|
-
/** JPG 图像(JPEG 别名,.jpg) */
|
|
1626
|
-
JPG: "image/jpeg",
|
|
1627
|
-
/** PNG 图像/无损压缩,支持透明(.png) */
|
|
1628
|
-
PNG: "image/png",
|
|
1629
|
-
/** GIF 图像/支持动画(.gif) */
|
|
1630
|
-
GIF: "image/gif",
|
|
1631
|
-
/** Windows 位图(.bmp) */
|
|
1632
|
-
BMP: "image/bmp",
|
|
1633
|
-
/** SVG 向量图形(.svg) */
|
|
1634
|
-
SVG: "image/svg+xml",
|
|
1635
|
-
/** APNG 动态图像(.apng) */
|
|
1636
|
-
APNG: "image/apng",
|
|
1637
|
-
/** AVIF 图像/高效压缩(.avif) */
|
|
1638
|
-
AVIF: "image/avif",
|
|
1639
|
-
/** 图标文件格式(.ico) */
|
|
1640
|
-
ICO: "image/vnd.microsoft.icon",
|
|
1641
|
-
/** 图标文件格式/兼容值(.ico) */
|
|
1642
|
-
ICO_LEGACY: "image/x-icon",
|
|
1643
|
-
/** WebP 图像/高效压缩(.webp) */
|
|
1644
|
-
WEBP: "image/webp",
|
|
1645
|
-
/** TIFF 图像(.tif/.tiff) */
|
|
1646
|
-
TIFF: "image/tiff",
|
|
1647
|
-
/** HEIC 图像/高效编码(.heic) */
|
|
1648
|
-
HEIC: "image/heic",
|
|
1649
|
-
/** HEIF 图像/高效编码(.heif) */
|
|
1650
|
-
HEIF: "image/heif",
|
|
1651
|
-
/** Adobe Photoshop 文件(.psd) */
|
|
1652
|
-
PSD: "image/vnd.adobe.photoshop",
|
|
1653
|
-
/** MP3 音频(.mp3) */
|
|
1654
|
-
MP3: "audio/mpeg",
|
|
1655
|
-
/** AAC 音频(.aac) */
|
|
1656
|
-
AAC: "audio/aac",
|
|
1657
|
-
/** MIDI 音乐文件(.mid/.midi) */
|
|
1658
|
-
MIDI: "audio/midi",
|
|
1659
|
-
/** OGG 音频(.oga) */
|
|
1660
|
-
OGG_AUDIO: "audio/ogg",
|
|
1661
|
-
/** Opus 音频(.opus) */
|
|
1662
|
-
OPUS: "audio/opus",
|
|
1663
|
-
/** FLAC 无损音频(.flac) */
|
|
1664
|
-
FLAC: "audio/flac",
|
|
1665
|
-
/** WAV 音频(.wav) */
|
|
1666
|
-
WAV: "audio/wav",
|
|
1667
|
-
/** WebM 音频(.weba) */
|
|
1668
|
-
WEBM_AUDIO: "audio/webm",
|
|
1669
|
-
/** RealAudio 音频(.ra/.ram) */
|
|
1670
|
-
REAL_AUDIO: "audio/x-pn-realaudio",
|
|
1671
|
-
/** MP4 视频(.mp4) */
|
|
1672
|
-
MP4: "video/mp4",
|
|
1673
|
-
/** MPEG 视频(.mpeg/.mpg) */
|
|
1674
|
-
MPEG: "video/mpeg",
|
|
1675
|
-
/** OGG 视频(.ogv) */
|
|
1676
|
-
OGG_VIDEO: "video/ogg",
|
|
1677
|
-
/** AVI 视频(.avi) */
|
|
1678
|
-
AVI: "video/x-msvideo",
|
|
1679
|
-
/** 3GPP 视频(.3gp) */
|
|
1680
|
-
THREE_GPP: "video/3gpp",
|
|
1681
|
-
/** 3GPP2 视频(.3g2) */
|
|
1682
|
-
THREE_GPP2: "video/3gpp2",
|
|
1683
|
-
/** WebM 视频(.webm) */
|
|
1684
|
-
WEBM: "video/webm",
|
|
1685
|
-
/** Matroska 视频(.mkv) */
|
|
1686
|
-
MKV: "video/x-matroska",
|
|
1687
|
-
/** Matroska 音频(.mka) */
|
|
1688
|
-
MKA: "audio/x-matroska",
|
|
1689
|
-
/** QuickTime 视频(.mov) */
|
|
1690
|
-
QUICKTIME: "video/quicktime",
|
|
1691
|
-
/** PDF 文档(.pdf) */
|
|
1692
|
-
PDF: "application/pdf",
|
|
1693
|
-
/** Word 97-2003 文档(.doc) */
|
|
1694
|
-
DOC: "application/msword",
|
|
1695
|
-
/** Word 2007+ 文档(.docx) */
|
|
1696
|
-
DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
1697
|
-
/** Excel 2007+ 工作簿(.xlsx) */
|
|
1698
|
-
XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1699
|
-
/** 启用宏的Excel工作簿(.xlsm) */
|
|
1700
|
-
XLSM: "application/vnd.ms-excel.sheet.macroEnabled.12",
|
|
1701
|
-
/** Excel模板文件(.xltx) */
|
|
1702
|
-
XLTX: "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
|
1703
|
-
/** PowerPoint 2007+ 演示文稿(.pptx) */
|
|
1704
|
-
PPTX: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
1705
|
-
/** PowerPoint 97-2003 演示文稿(.ppt) */
|
|
1706
|
-
PPT: "application/vnd.ms-powerpoint",
|
|
1707
|
-
/** OpenDocument 文本文档(.odt) */
|
|
1708
|
-
ODT: "application/vnd.oasis.opendocument.text",
|
|
1709
|
-
/** OpenDocument 表格文档(.ods) */
|
|
1710
|
-
ODS: "application/vnd.oasis.opendocument.spreadsheet",
|
|
1711
|
-
/** OpenDocument 演示文稿(.odp) */
|
|
1712
|
-
ODP: "application/vnd.oasis.opendocument.presentation",
|
|
1713
|
-
/** EPUB 电子书(.epub) */
|
|
1714
|
-
EPUB: "application/epub+zip",
|
|
1715
|
-
/** Kindle 电子书(.azw) */
|
|
1716
|
-
AZW: "application/vnd.amazon.ebook",
|
|
1717
|
-
/** ZIP 压缩文件(.zip) */
|
|
1718
|
-
ZIP: "application/zip",
|
|
1719
|
-
/** GZIP 压缩文件(.gz) */
|
|
1720
|
-
GZIP: "application/gzip",
|
|
1721
|
-
/** TAR 归档文件(.tar) */
|
|
1722
|
-
TAR: "application/x-tar",
|
|
1723
|
-
/** BZip 归档(.bz) */
|
|
1724
|
-
BZIP: "application/x-bzip",
|
|
1725
|
-
/** BZip2 归档(.bz2) */
|
|
1726
|
-
BZIP2: "application/x-bzip2",
|
|
1727
|
-
/** 7-Zip 压缩文件(.7z) */
|
|
1728
|
-
SEVEN_Z: "application/x-7z-compressed",
|
|
1729
|
-
/** RAR 压缩文件(.rar) */
|
|
1730
|
-
RAR: "application/vnd.rar",
|
|
1731
|
-
/** XZ 压缩文件(.xz) */
|
|
1732
|
-
XZ: "application/x-xz",
|
|
1733
|
-
/** Zstandard 压缩文件(.zst) */
|
|
1734
|
-
ZSTD: "application/zstd",
|
|
1735
|
-
/** ISO 光盘镜像(.iso) */
|
|
1736
|
-
ISO9660_IMAGE: "application/x-iso9660-image",
|
|
1737
|
-
/** JSON 数据格式(.json) */
|
|
1738
|
-
JSON: "application/json",
|
|
1739
|
-
/** JSON-LD 格式(.jsonld) */
|
|
1740
|
-
LD_JSON: "application/ld+json",
|
|
1741
|
-
/** Web App Manifest(.webmanifest) */
|
|
1742
|
-
MANIFEST: "application/manifest+json",
|
|
1743
|
-
/** Java 归档文件(.jar) */
|
|
1744
|
-
JAR: "application/java-archive",
|
|
1745
|
-
/** WebAssembly 二进制指令格式(.wasm) */
|
|
1746
|
-
WASM: "application/wasm",
|
|
1747
|
-
/** MS 嵌入式 OpenType 字体(.eot) */
|
|
1748
|
-
EOT: "application/vnd.ms-fontobject",
|
|
1749
|
-
/** OpenType 字体(.otf) */
|
|
1750
|
-
OTF: "font/otf",
|
|
1751
|
-
/** WOFF 字体(.woff) */
|
|
1752
|
-
WOFF: "font/woff",
|
|
1753
|
-
/** WOFF2 字体(.woff2) */
|
|
1754
|
-
WOFF2: "font/woff2",
|
|
1755
|
-
/** TrueType 字体(.ttf) */
|
|
1756
|
-
TTF: "font/ttf",
|
|
1757
|
-
/** Excel 97-2003 工作簿(.xls) */
|
|
1758
|
-
XLS: "application/vnd.ms-excel",
|
|
1759
|
-
/** Microsoft XPS 文档(.xps) */
|
|
1760
|
-
XPS: "application/vnd.ms-xpsdocument",
|
|
1761
|
-
/** Word 启用宏文档(.docm) */
|
|
1762
|
-
DOCM: "application/vnd.ms-word.document.macroEnabled.12"
|
|
1763
|
-
};
|
|
1764
|
-
/**
|
|
1765
|
-
* 协议/内容类型 MIME 常量
|
|
1766
|
-
* - 用于 HTTP 请求/响应内容协商,无对应文件扩展名
|
|
1767
|
-
*/
|
|
1768
|
-
static PROTOCOL_MIME = {
|
|
1769
|
-
/** 通用二进制数据流 */
|
|
1770
|
-
OCTET_STREAM: "application/octet-stream",
|
|
1771
|
-
/** URL 编码表单 */
|
|
1772
|
-
FORM_URLENCODED: "application/x-www-form-urlencoded",
|
|
1773
|
-
/** multipart 表单 */
|
|
1774
|
-
FORM_DATA: "multipart/form-data",
|
|
1775
|
-
/** Server-Sent Events 数据流 */
|
|
1776
|
-
EVENT_STREAM: "text/event-stream",
|
|
1777
|
-
/** 问题详情 JSON(RFC 9457) */
|
|
1778
|
-
PROBLEM_JSON: "application/problem+json",
|
|
1779
|
-
/** JSON Patch(RFC 6902) */
|
|
1780
|
-
JSON_PATCH: "application/json-patch+json",
|
|
1781
|
-
/** JSON Merge Patch(RFC 7386) */
|
|
1782
|
-
MERGE_PATCH_JSON: "application/merge-patch+json"
|
|
1783
|
-
};
|
|
1784
|
-
/**
|
|
1785
|
-
* 根据文件后缀名获取对应的标准 MIME 类型(含历史兼容值)
|
|
1786
|
-
* - 支持带 `.` 或不带 `.` 的后缀名,不区分大小写
|
|
1787
|
-
* - 元组第一项始终为 IANA 官方标准 MIME,后续项为历史兼容值
|
|
1788
|
-
* - 仅查询文件类型 MIME,不包含无后缀对应的协议类型
|
|
1789
|
-
*
|
|
1790
|
-
* @param extension 文件后缀名(如 `".png"` / `"png"` / `".PNG"`)
|
|
1791
|
-
* @returns 标准 MIME + 兼容值的元组;如无匹配则返回 `undefined`
|
|
1792
|
-
* @example
|
|
1793
|
-
* ```ts
|
|
1794
|
-
* MimeUtil.fromExtension(".png"); // ["image/png"]
|
|
1795
|
-
* MimeUtil.fromExtension("ico"); // ["image/vnd.microsoft.icon", "image/x-icon"]
|
|
1796
|
-
* MimeUtil.fromExtension(".xml"); // ["application/xml", "text/xml"]
|
|
1797
|
-
* MimeUtil.fromExtension(".xyz"); // undefined
|
|
1798
|
-
* ```
|
|
1799
|
-
*/
|
|
1800
|
-
static fromExtension(extension) {
|
|
1801
|
-
const ext = StringUtil.cast(extension).toLowerCase();
|
|
1802
|
-
const key = ext.startsWith(".") ? ext : `.${ext}`;
|
|
1803
|
-
return EXT_TO_MIME[key];
|
|
1804
|
-
}
|
|
1805
|
-
/**
|
|
1806
|
-
* 根据 MIME 类型获取对应的文件后缀名列表
|
|
1807
|
-
* - 一个 MIME 类型可能对应多个后缀名(如 `text/html` → `.html` / `.htm`)
|
|
1808
|
-
* - 兼容值和标准值映射到相同的后缀(如 `image/x-icon` 和 `image/vnd.microsoft.icon` 均返回 `[".ico"]`)
|
|
1809
|
-
* - 仅查询文件类型 MIME,协议类型无对应后缀
|
|
1810
|
-
*
|
|
1811
|
-
* @param mime MIME 类型字符串(如 `"image/png"` / `"IMAGE/PNG"`)
|
|
1812
|
-
* @returns 文件后缀名列表;如无匹配则返回 `undefined`
|
|
1813
|
-
* @example
|
|
1814
|
-
* ```ts
|
|
1815
|
-
* MimeUtil.toExtension("IMAGE/PNG"); // [".png"]
|
|
1816
|
-
* MimeUtil.toExtension("text/html"); // [".html", ".htm"]
|
|
1817
|
-
* MimeUtil.toExtension("image/jpeg"); // [".jpg", ".jpeg"]
|
|
1818
|
-
* MimeUtil.toExtension("application/octet-stream"); // undefined
|
|
1819
|
-
* ```
|
|
1820
|
-
*/
|
|
1821
|
-
static toExtension(mime) {
|
|
1822
|
-
const m = StringUtil.cast(mime).toLowerCase();
|
|
1823
|
-
return MIME_TO_EXT.get(m);
|
|
1824
|
-
}
|
|
1825
|
-
};
|
|
1826
|
-
const EXT_TO_MIME = {
|
|
1827
|
-
".txt": [MimeUtil.FILE_MIME.TEXT],
|
|
1828
|
-
".html": [MimeUtil.FILE_MIME.HTML],
|
|
1829
|
-
".htm": [MimeUtil.FILE_MIME.HTML],
|
|
1830
|
-
".css": [MimeUtil.FILE_MIME.CSS],
|
|
1831
|
-
".csv": [MimeUtil.FILE_MIME.CSV],
|
|
1832
|
-
".tsv": [MimeUtil.FILE_MIME.TSV],
|
|
1833
|
-
".xml": [MimeUtil.FILE_MIME.XML, MimeUtil.FILE_MIME.XML_LEGACY],
|
|
1834
|
-
".xhtml": [MimeUtil.FILE_MIME.XHTML],
|
|
1835
|
-
".xht": [MimeUtil.FILE_MIME.XHTML],
|
|
1836
|
-
".js": [MimeUtil.FILE_MIME.JS],
|
|
1837
|
-
".ts": [MimeUtil.FILE_MIME.TS],
|
|
1838
|
-
".py": [MimeUtil.FILE_MIME.PY],
|
|
1839
|
-
".sh": [MimeUtil.FILE_MIME.SH],
|
|
1840
|
-
".c": [MimeUtil.FILE_MIME.C],
|
|
1841
|
-
".cpp": [MimeUtil.FILE_MIME.CPP],
|
|
1842
|
-
".cc": [MimeUtil.FILE_MIME.CPP],
|
|
1843
|
-
".cxx": [MimeUtil.FILE_MIME.CPP],
|
|
1844
|
-
".cs": [MimeUtil.FILE_MIME.CSHARP],
|
|
1845
|
-
".java": [MimeUtil.FILE_MIME.JAVA],
|
|
1846
|
-
".go": [MimeUtil.FILE_MIME.GO],
|
|
1847
|
-
".rs": [MimeUtil.FILE_MIME.RUST],
|
|
1848
|
-
".php": [MimeUtil.FILE_MIME.PHP],
|
|
1849
|
-
".rb": [MimeUtil.FILE_MIME.RUBY],
|
|
1850
|
-
".swift": [MimeUtil.FILE_MIME.SWIFT],
|
|
1851
|
-
".yaml": [MimeUtil.FILE_MIME.YAML, MimeUtil.FILE_MIME.YAML_LEGACY],
|
|
1852
|
-
".yml": [MimeUtil.FILE_MIME.YAML, MimeUtil.FILE_MIME.YAML_LEGACY],
|
|
1853
|
-
".toml": [MimeUtil.FILE_MIME.TOML, MimeUtil.FILE_MIME.TOML_LEGACY],
|
|
1854
|
-
".sql": [MimeUtil.FILE_MIME.SQL, MimeUtil.FILE_MIME.SQL_LEGACY],
|
|
1855
|
-
".md": [MimeUtil.FILE_MIME.MARKDOWN],
|
|
1856
|
-
".markdown": [MimeUtil.FILE_MIME.MARKDOWN],
|
|
1857
|
-
".rtf": [MimeUtil.FILE_MIME.RTF],
|
|
1858
|
-
".ics": [MimeUtil.FILE_MIME.CALENDAR],
|
|
1859
|
-
".jpg": [MimeUtil.FILE_MIME.JPEG],
|
|
1860
|
-
".jpeg": [MimeUtil.FILE_MIME.JPEG],
|
|
1861
|
-
".png": [MimeUtil.FILE_MIME.PNG],
|
|
1862
|
-
".gif": [MimeUtil.FILE_MIME.GIF],
|
|
1863
|
-
".bmp": [MimeUtil.FILE_MIME.BMP],
|
|
1864
|
-
".svg": [MimeUtil.FILE_MIME.SVG],
|
|
1865
|
-
".apng": [MimeUtil.FILE_MIME.APNG],
|
|
1866
|
-
".avif": [MimeUtil.FILE_MIME.AVIF],
|
|
1867
|
-
".ico": [MimeUtil.FILE_MIME.ICO, MimeUtil.FILE_MIME.ICO_LEGACY],
|
|
1868
|
-
".webp": [MimeUtil.FILE_MIME.WEBP],
|
|
1869
|
-
".tif": [MimeUtil.FILE_MIME.TIFF],
|
|
1870
|
-
".tiff": [MimeUtil.FILE_MIME.TIFF],
|
|
1871
|
-
".heic": [MimeUtil.FILE_MIME.HEIC],
|
|
1872
|
-
".heif": [MimeUtil.FILE_MIME.HEIF],
|
|
1873
|
-
".psd": [MimeUtil.FILE_MIME.PSD],
|
|
1874
|
-
".mp3": [MimeUtil.FILE_MIME.MP3],
|
|
1875
|
-
".aac": [MimeUtil.FILE_MIME.AAC],
|
|
1876
|
-
".mid": [MimeUtil.FILE_MIME.MIDI],
|
|
1877
|
-
".midi": [MimeUtil.FILE_MIME.MIDI],
|
|
1878
|
-
".oga": [MimeUtil.FILE_MIME.OGG_AUDIO],
|
|
1879
|
-
".opus": [MimeUtil.FILE_MIME.OPUS],
|
|
1880
|
-
".flac": [MimeUtil.FILE_MIME.FLAC],
|
|
1881
|
-
".wav": [MimeUtil.FILE_MIME.WAV],
|
|
1882
|
-
".weba": [MimeUtil.FILE_MIME.WEBM_AUDIO],
|
|
1883
|
-
".ra": [MimeUtil.FILE_MIME.REAL_AUDIO],
|
|
1884
|
-
".ram": [MimeUtil.FILE_MIME.REAL_AUDIO],
|
|
1885
|
-
".mp4": [MimeUtil.FILE_MIME.MP4],
|
|
1886
|
-
".mpeg": [MimeUtil.FILE_MIME.MPEG],
|
|
1887
|
-
".mpg": [MimeUtil.FILE_MIME.MPEG],
|
|
1888
|
-
".ogv": [MimeUtil.FILE_MIME.OGG_VIDEO],
|
|
1889
|
-
".avi": [MimeUtil.FILE_MIME.AVI],
|
|
1890
|
-
".3gp": [MimeUtil.FILE_MIME.THREE_GPP],
|
|
1891
|
-
".3g2": [MimeUtil.FILE_MIME.THREE_GPP2],
|
|
1892
|
-
".webm": [MimeUtil.FILE_MIME.WEBM],
|
|
1893
|
-
".mkv": [MimeUtil.FILE_MIME.MKV],
|
|
1894
|
-
".mka": [MimeUtil.FILE_MIME.MKA],
|
|
1895
|
-
".mov": [MimeUtil.FILE_MIME.QUICKTIME],
|
|
1896
|
-
".pdf": [MimeUtil.FILE_MIME.PDF],
|
|
1897
|
-
".doc": [MimeUtil.FILE_MIME.DOC],
|
|
1898
|
-
".docx": [MimeUtil.FILE_MIME.DOCX],
|
|
1899
|
-
".xlsx": [MimeUtil.FILE_MIME.XLSX],
|
|
1900
|
-
".xlsm": [MimeUtil.FILE_MIME.XLSM],
|
|
1901
|
-
".xltx": [MimeUtil.FILE_MIME.XLTX],
|
|
1902
|
-
".pptx": [MimeUtil.FILE_MIME.PPTX],
|
|
1903
|
-
".ppt": [MimeUtil.FILE_MIME.PPT],
|
|
1904
|
-
".odt": [MimeUtil.FILE_MIME.ODT],
|
|
1905
|
-
".ods": [MimeUtil.FILE_MIME.ODS],
|
|
1906
|
-
".odp": [MimeUtil.FILE_MIME.ODP],
|
|
1907
|
-
".epub": [MimeUtil.FILE_MIME.EPUB],
|
|
1908
|
-
".azw": [MimeUtil.FILE_MIME.AZW],
|
|
1909
|
-
".zip": [MimeUtil.FILE_MIME.ZIP],
|
|
1910
|
-
".gz": [MimeUtil.FILE_MIME.GZIP],
|
|
1911
|
-
".tar": [MimeUtil.FILE_MIME.TAR],
|
|
1912
|
-
".bz": [MimeUtil.FILE_MIME.BZIP],
|
|
1913
|
-
".bz2": [MimeUtil.FILE_MIME.BZIP2],
|
|
1914
|
-
".7z": [MimeUtil.FILE_MIME.SEVEN_Z],
|
|
1915
|
-
".rar": [MimeUtil.FILE_MIME.RAR],
|
|
1916
|
-
".xz": [MimeUtil.FILE_MIME.XZ],
|
|
1917
|
-
".zst": [MimeUtil.FILE_MIME.ZSTD],
|
|
1918
|
-
".iso": [MimeUtil.FILE_MIME.ISO9660_IMAGE],
|
|
1919
|
-
".json": [MimeUtil.FILE_MIME.JSON],
|
|
1920
|
-
".jsonld": [MimeUtil.FILE_MIME.LD_JSON],
|
|
1921
|
-
".webmanifest": [MimeUtil.FILE_MIME.MANIFEST],
|
|
1922
|
-
".jar": [MimeUtil.FILE_MIME.JAR],
|
|
1923
|
-
".wasm": [MimeUtil.FILE_MIME.WASM],
|
|
1924
|
-
".eot": [MimeUtil.FILE_MIME.EOT],
|
|
1925
|
-
".otf": [MimeUtil.FILE_MIME.OTF],
|
|
1926
|
-
".woff": [MimeUtil.FILE_MIME.WOFF],
|
|
1927
|
-
".woff2": [MimeUtil.FILE_MIME.WOFF2],
|
|
1928
|
-
".ttf": [MimeUtil.FILE_MIME.TTF],
|
|
1929
|
-
".xls": [MimeUtil.FILE_MIME.XLS],
|
|
1930
|
-
".xps": [MimeUtil.FILE_MIME.XPS],
|
|
1931
|
-
".docm": [MimeUtil.FILE_MIME.DOCM]
|
|
1932
|
-
};
|
|
1933
|
-
const MIME_TO_EXT = (() => {
|
|
1934
|
-
const map = /* @__PURE__ */ new Map();
|
|
1935
|
-
for (const [ext, mimes] of Object.entries(EXT_TO_MIME)) for (const mime of mimes) {
|
|
1936
|
-
const exts = map.get(mime);
|
|
1937
|
-
if (exts) {
|
|
1938
|
-
if (!exts.includes(ext)) exts.push(ext);
|
|
1939
|
-
} else map.set(mime, [ext]);
|
|
1940
|
-
}
|
|
1941
|
-
return map;
|
|
1942
|
-
})();
|
|
1943
|
-
/**
|
|
1944
|
-
* 对象工具类
|
|
1945
|
-
*/
|
|
1946
|
-
var ObjectUtil = class {
|
|
1947
|
-
static keys(value) {
|
|
1948
|
-
return Object.keys(value);
|
|
1949
|
-
}
|
|
1950
|
-
static values(value) {
|
|
1951
|
-
return Object.values(value);
|
|
1952
|
-
}
|
|
1953
|
-
static entries(value) {
|
|
1954
|
-
return Object.entries(value);
|
|
1955
|
-
}
|
|
1956
|
-
/**
|
|
1957
|
-
* 映射对象条目
|
|
1958
|
-
* - 将对象的键值对映射为新的键值对
|
|
1959
|
-
*
|
|
1960
|
-
* @param plainObject 对象
|
|
1961
|
-
* @param toEntry 映射函数
|
|
1962
|
-
* @returns 映射后的新对象
|
|
1963
|
-
* @example
|
|
1964
|
-
* ```ts
|
|
1965
|
-
* const obj = { a: 1, b: 2 };
|
|
1966
|
-
*
|
|
1967
|
-
* ObjectUtil.entriesMap(obj, (k, v) => [k, v * 2]); // { a: 2, b: 4 }
|
|
1968
|
-
*
|
|
1969
|
-
* ObjectUtil.entriesMap(obj, (k, v) => [`prefix_${String(k)}`, `${v}x`]); // { prefix_a: "1x", prefix_b: "2x" }
|
|
1970
|
-
* ```
|
|
1971
|
-
*/
|
|
1972
|
-
static entriesMap(plainObject, toEntry) {
|
|
1973
|
-
const defaultResult = {};
|
|
1974
|
-
if (!TypeUtil.isPlainObject(plainObject)) return defaultResult;
|
|
1975
|
-
return this.entries(plainObject).reduce((acc, [key, value]) => {
|
|
1976
|
-
const [newKey, newValue] = toEntry(key, value);
|
|
1977
|
-
acc[newKey] = newValue;
|
|
1978
|
-
return acc;
|
|
1979
|
-
}, defaultResult);
|
|
1980
|
-
}
|
|
1981
|
-
static pick(obj, keys) {
|
|
1982
|
-
const result = {};
|
|
1983
|
-
if (!TypeUtil.isPlainObject(obj)) return result;
|
|
1984
|
-
if (!TypeUtil.isArray(keys)) return obj;
|
|
1985
|
-
return keys.reduce((acc, key) => {
|
|
1986
|
-
if (key in obj) acc[key] = obj[key];
|
|
1987
|
-
return acc;
|
|
1988
|
-
}, result);
|
|
1989
|
-
}
|
|
1990
|
-
static omit(obj, keys) {
|
|
1991
|
-
const result = {};
|
|
1992
|
-
if (!TypeUtil.isPlainObject(obj)) return result;
|
|
1993
|
-
if (!TypeUtil.isArray(keys)) return obj;
|
|
1994
|
-
const keysToOmit = new Set(keys);
|
|
1995
|
-
return Object.keys(obj).reduce((acc, key) => {
|
|
1996
|
-
if (!keysToOmit.has(key)) acc[key] = obj[key];
|
|
1997
|
-
return acc;
|
|
1998
|
-
}, result);
|
|
1999
|
-
}
|
|
2000
|
-
static invert(obj) {
|
|
2001
|
-
const result = {};
|
|
2002
|
-
if (!TypeUtil.isPlainObject(obj)) return result;
|
|
2003
|
-
for (const [k, v] of this.entries(obj)) if (TypeUtil.isString(v) || TypeUtil.isNumber(v) || TypeUtil.isSymbol(v)) result[v] = k;
|
|
2004
|
-
return result;
|
|
2005
|
-
}
|
|
2006
|
-
static crush(obj) {
|
|
2007
|
-
if (!obj) return {};
|
|
2008
|
-
function crushReducer(crushed, value, path) {
|
|
2009
|
-
if (TypeUtil.isPlainObject(value) || TypeUtil.isArray(value)) for (const [prop, propValue] of Object.entries(value)) crushReducer(crushed, propValue, path ? `${path}.${prop}` : prop);
|
|
2010
|
-
else crushed[path] = value;
|
|
2011
|
-
return crushed;
|
|
2012
|
-
}
|
|
2013
|
-
return crushReducer({}, obj, "");
|
|
2014
|
-
}
|
|
2015
|
-
static enumKeys(enumeration) {
|
|
2016
|
-
const [isEnum, isBidirectionalEnum] = TypeUtil.isEnumeration(enumeration);
|
|
2017
|
-
if (!isEnum) throw Error("function [enumKeys] expected parameter to be a enum, and requires at least one member");
|
|
2018
|
-
const keys = this.keys(enumeration);
|
|
2019
|
-
if (isBidirectionalEnum) return keys.splice(keys.length / 2, keys.length / 2);
|
|
2020
|
-
return keys;
|
|
2021
|
-
}
|
|
2022
|
-
static enumValues(enumeration) {
|
|
2023
|
-
const [isEnum, isBidirectionalEnum] = TypeUtil.isEnumeration(enumeration);
|
|
2024
|
-
if (!isEnum) throw Error("function [enumValues] expected parameter to be a enum, and requires at least one member");
|
|
2025
|
-
const values = this.values(enumeration);
|
|
2026
|
-
if (isBidirectionalEnum) return values.splice(values.length / 2, values.length / 2);
|
|
2027
|
-
return values;
|
|
2028
|
-
}
|
|
2029
|
-
static enumEntries(enumeration) {
|
|
2030
|
-
const [isEnum, isBidirectionalEnum] = TypeUtil.isEnumeration(enumeration);
|
|
2031
|
-
if (!isEnum) throw Error("function [enumEntries] expected parameter to be a enum, and requires at least one member");
|
|
2032
|
-
const entries = this.entries(enumeration);
|
|
2033
|
-
if (isBidirectionalEnum) return entries.splice(entries.length / 2, entries.length / 2);
|
|
2034
|
-
return entries;
|
|
2035
|
-
}
|
|
2036
|
-
};
|
|
2037
|
-
//#endregion
|
|
2038
16
|
//#region src/react/useMount.ts
|
|
2039
17
|
/**
|
|
2040
18
|
* 在组件初始化时执行的 Hook
|
|
@@ -2069,423 +47,6 @@ function useMount(effect) {
|
|
|
2069
47
|
}, [effectRef]);
|
|
2070
48
|
}
|
|
2071
49
|
//#endregion
|
|
2072
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/_internal/globalThis.mjs
|
|
2073
|
-
const globalThis_ = typeof globalThis === "object" && globalThis || typeof window === "object" && window || typeof self === "object" && self || typeof global === "object" && global || (function() {
|
|
2074
|
-
return this;
|
|
2075
|
-
})();
|
|
2076
|
-
//#endregion
|
|
2077
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/function/noop.mjs
|
|
2078
|
-
/**
|
|
2079
|
-
* A no-operation function that does nothing.
|
|
2080
|
-
* This can be used as a placeholder or default function.
|
|
2081
|
-
*
|
|
2082
|
-
* @example
|
|
2083
|
-
* noop(); // Does nothing
|
|
2084
|
-
*
|
|
2085
|
-
* @returns This function does not return anything.
|
|
2086
|
-
*/
|
|
2087
|
-
function noop() {}
|
|
2088
|
-
//#endregion
|
|
2089
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isPrimitive.mjs
|
|
2090
|
-
/**
|
|
2091
|
-
* Checks whether a value is a JavaScript primitive.
|
|
2092
|
-
* JavaScript primitives include null, undefined, strings, numbers, booleans, symbols, and bigints.
|
|
2093
|
-
*
|
|
2094
|
-
* @param value The value to check.
|
|
2095
|
-
* @returns Returns true if `value` is a primitive, false otherwise.
|
|
2096
|
-
*
|
|
2097
|
-
* @example
|
|
2098
|
-
* isPrimitive(null); // true
|
|
2099
|
-
* isPrimitive(undefined); // true
|
|
2100
|
-
* isPrimitive('123'); // true
|
|
2101
|
-
* isPrimitive(false); // true
|
|
2102
|
-
* isPrimitive(true); // true
|
|
2103
|
-
* isPrimitive(Symbol('a')); // true
|
|
2104
|
-
* isPrimitive(123n); // true
|
|
2105
|
-
* isPrimitive({}); // false
|
|
2106
|
-
* isPrimitive(new Date()); // false
|
|
2107
|
-
* isPrimitive(new Map()); // false
|
|
2108
|
-
* isPrimitive(new Set()); // false
|
|
2109
|
-
* isPrimitive([1, 2, 3]); // false
|
|
2110
|
-
*/
|
|
2111
|
-
function isPrimitive(value) {
|
|
2112
|
-
return value == null || typeof value !== "object" && typeof value !== "function";
|
|
2113
|
-
}
|
|
2114
|
-
//#endregion
|
|
2115
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isTypedArray.mjs
|
|
2116
|
-
/**
|
|
2117
|
-
* Checks if a value is a TypedArray.
|
|
2118
|
-
* @param x The value to check.
|
|
2119
|
-
* @returns Returns true if `x` is a TypedArray, false otherwise.
|
|
2120
|
-
*
|
|
2121
|
-
* @example
|
|
2122
|
-
* const arr = new Uint8Array([1, 2, 3]);
|
|
2123
|
-
* isTypedArray(arr); // true
|
|
2124
|
-
*
|
|
2125
|
-
* const regularArray = [1, 2, 3];
|
|
2126
|
-
* isTypedArray(regularArray); // false
|
|
2127
|
-
*
|
|
2128
|
-
* const buffer = new ArrayBuffer(16);
|
|
2129
|
-
* isTypedArray(buffer); // false
|
|
2130
|
-
*/
|
|
2131
|
-
function isTypedArray(x) {
|
|
2132
|
-
return ArrayBuffer.isView(x) && !(x instanceof DataView);
|
|
2133
|
-
}
|
|
2134
|
-
//#endregion
|
|
2135
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/object/clone.mjs
|
|
2136
|
-
/**
|
|
2137
|
-
* Creates a shallow clone of the given object.
|
|
2138
|
-
*
|
|
2139
|
-
* @template T - The type of the object.
|
|
2140
|
-
* @param obj - The object to clone.
|
|
2141
|
-
* @returns A shallow clone of the given object.
|
|
2142
|
-
*
|
|
2143
|
-
* @example
|
|
2144
|
-
* // Clone a primitive value
|
|
2145
|
-
* const num = 29;
|
|
2146
|
-
* const clonedNum = clone(num);
|
|
2147
|
-
* console.log(clonedNum); // 29
|
|
2148
|
-
* console.log(clonedNum === num); // true
|
|
2149
|
-
*
|
|
2150
|
-
* @example
|
|
2151
|
-
* // Clone an array
|
|
2152
|
-
* const arr = [1, 2, 3];
|
|
2153
|
-
* const clonedArr = clone(arr);
|
|
2154
|
-
* console.log(clonedArr); // [1, 2, 3]
|
|
2155
|
-
* console.log(clonedArr === arr); // false
|
|
2156
|
-
*
|
|
2157
|
-
* @example
|
|
2158
|
-
* // Clone an object
|
|
2159
|
-
* const obj = { a: 1, b: 'es-toolkit', c: [1, 2, 3] };
|
|
2160
|
-
* const clonedObj = clone(obj);
|
|
2161
|
-
* console.log(clonedObj); // { a: 1, b: 'es-toolkit', c: [1, 2, 3] }
|
|
2162
|
-
* console.log(clonedObj === obj); // false
|
|
2163
|
-
*/
|
|
2164
|
-
function clone(obj) {
|
|
2165
|
-
if (isPrimitive(obj)) return obj;
|
|
2166
|
-
if (Array.isArray(obj) || isTypedArray(obj) || obj instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && obj instanceof SharedArrayBuffer) return obj.slice(0);
|
|
2167
|
-
const prototype = Object.getPrototypeOf(obj);
|
|
2168
|
-
if (prototype == null) return Object.assign(Object.create(prototype), obj);
|
|
2169
|
-
const Constructor = prototype.constructor;
|
|
2170
|
-
if (obj instanceof Date || obj instanceof Map || obj instanceof Set) return new Constructor(obj);
|
|
2171
|
-
if (obj instanceof RegExp) {
|
|
2172
|
-
const newRegExp = new Constructor(obj);
|
|
2173
|
-
newRegExp.lastIndex = obj.lastIndex;
|
|
2174
|
-
return newRegExp;
|
|
2175
|
-
}
|
|
2176
|
-
if (obj instanceof DataView) return new Constructor(obj.buffer.slice(0));
|
|
2177
|
-
if (obj instanceof Error) {
|
|
2178
|
-
let newError;
|
|
2179
|
-
if (obj instanceof AggregateError) newError = new Constructor(obj.errors, obj.message, { cause: obj.cause });
|
|
2180
|
-
else newError = new Constructor(obj.message, { cause: obj.cause });
|
|
2181
|
-
newError.stack = obj.stack;
|
|
2182
|
-
Object.assign(newError, obj);
|
|
2183
|
-
return newError;
|
|
2184
|
-
}
|
|
2185
|
-
if (typeof File !== "undefined" && obj instanceof File) return new Constructor([obj], obj.name, {
|
|
2186
|
-
type: obj.type,
|
|
2187
|
-
lastModified: obj.lastModified
|
|
2188
|
-
});
|
|
2189
|
-
if (typeof obj === "object") return Object.assign(Object.create(prototype), obj);
|
|
2190
|
-
return obj;
|
|
2191
|
-
}
|
|
2192
|
-
//#endregion
|
|
2193
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isBuffer.mjs
|
|
2194
|
-
/**
|
|
2195
|
-
* Checks if the given value is a Buffer instance.
|
|
2196
|
-
*
|
|
2197
|
-
* This function tests whether the provided value is an instance of Buffer.
|
|
2198
|
-
* It returns `true` if the value is a Buffer, and `false` otherwise.
|
|
2199
|
-
*
|
|
2200
|
-
* This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `Buffer`.
|
|
2201
|
-
*
|
|
2202
|
-
* @param x - The value to check if it is a Buffer.
|
|
2203
|
-
* @returns Returns `true` if `x` is a Buffer, else `false`.
|
|
2204
|
-
*
|
|
2205
|
-
* @example
|
|
2206
|
-
* const buffer = Buffer.from("test");
|
|
2207
|
-
* console.log(isBuffer(buffer)); // true
|
|
2208
|
-
*
|
|
2209
|
-
* const notBuffer = "not a buffer";
|
|
2210
|
-
* console.log(isBuffer(notBuffer)); // false
|
|
2211
|
-
*/
|
|
2212
|
-
function isBuffer(x) {
|
|
2213
|
-
return typeof globalThis_.Buffer !== "undefined" && globalThis_.Buffer.isBuffer(x);
|
|
2214
|
-
}
|
|
2215
|
-
//#endregion
|
|
2216
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/compat/_internal/getSymbols.mjs
|
|
2217
|
-
function getSymbols(object) {
|
|
2218
|
-
return Object.getOwnPropertySymbols(object).filter((symbol) => Object.prototype.propertyIsEnumerable.call(object, symbol));
|
|
2219
|
-
}
|
|
2220
|
-
//#endregion
|
|
2221
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/compat/_internal/getTag.mjs
|
|
2222
|
-
/**
|
|
2223
|
-
* Gets the `toStringTag` of `value`.
|
|
2224
|
-
*
|
|
2225
|
-
* @private
|
|
2226
|
-
* @param {T} value The value to query.
|
|
2227
|
-
* @returns {string} Returns the `Object.prototype.toString.call` result.
|
|
2228
|
-
*/
|
|
2229
|
-
function getTag(value) {
|
|
2230
|
-
if (value == null) return value === void 0 ? "[object Undefined]" : "[object Null]";
|
|
2231
|
-
return Object.prototype.toString.call(value);
|
|
2232
|
-
}
|
|
2233
|
-
//#endregion
|
|
2234
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/compat/_internal/tags.mjs
|
|
2235
|
-
const regexpTag = "[object RegExp]";
|
|
2236
|
-
const stringTag = "[object String]";
|
|
2237
|
-
const numberTag = "[object Number]";
|
|
2238
|
-
const booleanTag = "[object Boolean]";
|
|
2239
|
-
const symbolTag = "[object Symbol]";
|
|
2240
|
-
const dateTag = "[object Date]";
|
|
2241
|
-
const mapTag = "[object Map]";
|
|
2242
|
-
const setTag = "[object Set]";
|
|
2243
|
-
const arrayTag = "[object Array]";
|
|
2244
|
-
const functionTag = "[object Function]";
|
|
2245
|
-
const arrayBufferTag = "[object ArrayBuffer]";
|
|
2246
|
-
const objectTag = "[object Object]";
|
|
2247
|
-
const errorTag = "[object Error]";
|
|
2248
|
-
const dataViewTag = "[object DataView]";
|
|
2249
|
-
const uint8ArrayTag = "[object Uint8Array]";
|
|
2250
|
-
const uint8ClampedArrayTag = "[object Uint8ClampedArray]";
|
|
2251
|
-
const uint16ArrayTag = "[object Uint16Array]";
|
|
2252
|
-
const uint32ArrayTag = "[object Uint32Array]";
|
|
2253
|
-
const bigUint64ArrayTag = "[object BigUint64Array]";
|
|
2254
|
-
const int8ArrayTag = "[object Int8Array]";
|
|
2255
|
-
const int16ArrayTag = "[object Int16Array]";
|
|
2256
|
-
const int32ArrayTag = "[object Int32Array]";
|
|
2257
|
-
const bigInt64ArrayTag = "[object BigInt64Array]";
|
|
2258
|
-
const float32ArrayTag = "[object Float32Array]";
|
|
2259
|
-
const float64ArrayTag = "[object Float64Array]";
|
|
2260
|
-
//#endregion
|
|
2261
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs
|
|
2262
|
-
/**
|
|
2263
|
-
* Checks if a given value is a plain object.
|
|
2264
|
-
*
|
|
2265
|
-
* @param value - The value to check.
|
|
2266
|
-
* @returns True if the value is a plain object, otherwise false.
|
|
2267
|
-
*
|
|
2268
|
-
* @example
|
|
2269
|
-
* ```typescript
|
|
2270
|
-
* // ✅👇 True
|
|
2271
|
-
*
|
|
2272
|
-
* isPlainObject({ }); // ✅
|
|
2273
|
-
* isPlainObject({ key: 'value' }); // ✅
|
|
2274
|
-
* isPlainObject({ key: new Date() }); // ✅
|
|
2275
|
-
* isPlainObject(new Object()); // ✅
|
|
2276
|
-
* isPlainObject(Object.create(null)); // ✅
|
|
2277
|
-
* isPlainObject({ nested: { key: true} }); // ✅
|
|
2278
|
-
* isPlainObject(new Proxy({}, {})); // ✅
|
|
2279
|
-
* isPlainObject({ [Symbol('tag')]: 'A' }); // ✅
|
|
2280
|
-
*
|
|
2281
|
-
* // ✅👇 (cross-realms, node context, workers, ...)
|
|
2282
|
-
* const runInNewContext = await import('node:vm').then(
|
|
2283
|
-
* (mod) => mod.runInNewContext
|
|
2284
|
-
* );
|
|
2285
|
-
* isPlainObject(runInNewContext('({})')); // ✅
|
|
2286
|
-
*
|
|
2287
|
-
* // ❌👇 False
|
|
2288
|
-
*
|
|
2289
|
-
* class Test { };
|
|
2290
|
-
* isPlainObject(new Test()) // ❌
|
|
2291
|
-
* isPlainObject(10); // ❌
|
|
2292
|
-
* isPlainObject(null); // ❌
|
|
2293
|
-
* isPlainObject('hello'); // ❌
|
|
2294
|
-
* isPlainObject([]); // ❌
|
|
2295
|
-
* isPlainObject(new Date()); // ❌
|
|
2296
|
-
* isPlainObject(new Uint8Array([1])); // ❌
|
|
2297
|
-
* isPlainObject(Buffer.from('ABC')); // ❌
|
|
2298
|
-
* isPlainObject(Promise.resolve({})); // ❌
|
|
2299
|
-
* isPlainObject(Object.create({})); // ❌
|
|
2300
|
-
* isPlainObject(new (class Cls {})); // ❌
|
|
2301
|
-
* isPlainObject(globalThis); // ❌,
|
|
2302
|
-
* ```
|
|
2303
|
-
*/
|
|
2304
|
-
function isPlainObject(value) {
|
|
2305
|
-
if (!value || typeof value !== "object") return false;
|
|
2306
|
-
const proto = Object.getPrototypeOf(value);
|
|
2307
|
-
if (!(proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null)) return false;
|
|
2308
|
-
return Object.prototype.toString.call(value) === "[object Object]";
|
|
2309
|
-
}
|
|
2310
|
-
//#endregion
|
|
2311
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/compat/util/eq.mjs
|
|
2312
|
-
/**
|
|
2313
|
-
* Performs a `SameValueZero` comparison between two values to determine if they are equivalent.
|
|
2314
|
-
*
|
|
2315
|
-
* @param value The value to compare.
|
|
2316
|
-
* @param other The other value to compare.
|
|
2317
|
-
* @returns Returns `true` if the values are equivalent, else `false`.
|
|
2318
|
-
*
|
|
2319
|
-
* @example
|
|
2320
|
-
* eq(1, 1); // true
|
|
2321
|
-
* eq(0, -0); // true
|
|
2322
|
-
* eq(NaN, NaN); // true
|
|
2323
|
-
* eq('a', Object('a')); // false
|
|
2324
|
-
*/
|
|
2325
|
-
function eq(value, other) {
|
|
2326
|
-
return value === other || Number.isNaN(value) && Number.isNaN(other);
|
|
2327
|
-
}
|
|
2328
|
-
//#endregion
|
|
2329
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isEqualWith.mjs
|
|
2330
|
-
/**
|
|
2331
|
-
* Compares two values for equality using a custom comparison function.
|
|
2332
|
-
*
|
|
2333
|
-
* The custom function allows for fine-tuned control over the comparison process. If it returns a boolean, that result determines the equality. If it returns undefined, the function falls back to the default equality comparison.
|
|
2334
|
-
*
|
|
2335
|
-
* This function also uses the custom equality function to compare values inside objects,
|
|
2336
|
-
* arrays, maps, sets, and other complex structures, ensuring a deep comparison.
|
|
2337
|
-
*
|
|
2338
|
-
* This approach provides flexibility in handling complex comparisons while maintaining efficient default behavior for simpler cases.
|
|
2339
|
-
*
|
|
2340
|
-
* The custom comparison function can take up to six parameters:
|
|
2341
|
-
* - `x`: The value from the first object `a`.
|
|
2342
|
-
* - `y`: The value from the second object `b`.
|
|
2343
|
-
* - `property`: The property key used to get `x` and `y`.
|
|
2344
|
-
* - `xParent`: The parent of the first value `x`.
|
|
2345
|
-
* - `yParent`: The parent of the second value `y`.
|
|
2346
|
-
* - `stack`: An internal stack (Map) to handle circular references.
|
|
2347
|
-
*
|
|
2348
|
-
* @param a - The first value to compare.
|
|
2349
|
-
* @param b - The second value to compare.
|
|
2350
|
-
* @param areValuesEqual - A function to customize the comparison.
|
|
2351
|
-
* If it returns a boolean, that result will be used. If it returns undefined,
|
|
2352
|
-
* the default equality comparison will be used.
|
|
2353
|
-
* @returns `true` if the values are equal according to the customizer, otherwise `false`.
|
|
2354
|
-
*
|
|
2355
|
-
* @example
|
|
2356
|
-
* const customizer = (a, b) => {
|
|
2357
|
-
* if (typeof a === 'string' && typeof b === 'string') {
|
|
2358
|
-
* return a.toLowerCase() === b.toLowerCase();
|
|
2359
|
-
* }
|
|
2360
|
-
* };
|
|
2361
|
-
* isEqualWith('Hello', 'hello', customizer); // true
|
|
2362
|
-
* isEqualWith({ a: 'Hello' }, { a: 'hello' }, customizer); // true
|
|
2363
|
-
* isEqualWith([1, 2, 3], [1, 2, 3], customizer); // true
|
|
2364
|
-
*/
|
|
2365
|
-
function isEqualWith(a, b, areValuesEqual) {
|
|
2366
|
-
return isEqualWithImpl(a, b, void 0, void 0, void 0, void 0, areValuesEqual);
|
|
2367
|
-
}
|
|
2368
|
-
function isEqualWithImpl(a, b, property, aParent, bParent, stack, areValuesEqual) {
|
|
2369
|
-
const result = areValuesEqual(a, b, property, aParent, bParent, stack);
|
|
2370
|
-
if (result !== void 0) return result;
|
|
2371
|
-
if (typeof a === typeof b) switch (typeof a) {
|
|
2372
|
-
case "bigint":
|
|
2373
|
-
case "string":
|
|
2374
|
-
case "boolean":
|
|
2375
|
-
case "symbol":
|
|
2376
|
-
case "undefined": return a === b;
|
|
2377
|
-
case "number": return a === b || Object.is(a, b);
|
|
2378
|
-
case "function": return a === b;
|
|
2379
|
-
case "object": return areObjectsEqual(a, b, stack, areValuesEqual);
|
|
2380
|
-
}
|
|
2381
|
-
return areObjectsEqual(a, b, stack, areValuesEqual);
|
|
2382
|
-
}
|
|
2383
|
-
function areObjectsEqual(a, b, stack, areValuesEqual) {
|
|
2384
|
-
if (Object.is(a, b)) return true;
|
|
2385
|
-
let aTag = getTag(a);
|
|
2386
|
-
let bTag = getTag(b);
|
|
2387
|
-
if (aTag === "[object Arguments]") aTag = objectTag;
|
|
2388
|
-
if (bTag === "[object Arguments]") bTag = objectTag;
|
|
2389
|
-
if (aTag !== bTag) return false;
|
|
2390
|
-
switch (aTag) {
|
|
2391
|
-
case stringTag: return a.toString() === b.toString();
|
|
2392
|
-
case numberTag: return eq(a.valueOf(), b.valueOf());
|
|
2393
|
-
case booleanTag:
|
|
2394
|
-
case dateTag:
|
|
2395
|
-
case symbolTag: return Object.is(a.valueOf(), b.valueOf());
|
|
2396
|
-
case regexpTag: return a.source === b.source && a.flags === b.flags;
|
|
2397
|
-
case functionTag: return a === b;
|
|
2398
|
-
}
|
|
2399
|
-
stack = stack ?? /* @__PURE__ */ new Map();
|
|
2400
|
-
const aStack = stack.get(a);
|
|
2401
|
-
const bStack = stack.get(b);
|
|
2402
|
-
if (aStack != null && bStack != null) return aStack === b;
|
|
2403
|
-
stack.set(a, b);
|
|
2404
|
-
stack.set(b, a);
|
|
2405
|
-
try {
|
|
2406
|
-
switch (aTag) {
|
|
2407
|
-
case mapTag:
|
|
2408
|
-
if (a.size !== b.size) return false;
|
|
2409
|
-
for (const [key, value] of a.entries()) if (!b.has(key) || !isEqualWithImpl(value, b.get(key), key, a, b, stack, areValuesEqual)) return false;
|
|
2410
|
-
return true;
|
|
2411
|
-
case setTag: {
|
|
2412
|
-
if (a.size !== b.size) return false;
|
|
2413
|
-
const aValues = Array.from(a.values());
|
|
2414
|
-
const bValues = Array.from(b.values());
|
|
2415
|
-
for (let i = 0; i < aValues.length; i++) {
|
|
2416
|
-
const aValue = aValues[i];
|
|
2417
|
-
const index = bValues.findIndex((bValue) => {
|
|
2418
|
-
return isEqualWithImpl(aValue, bValue, void 0, a, b, stack, areValuesEqual);
|
|
2419
|
-
});
|
|
2420
|
-
if (index === -1) return false;
|
|
2421
|
-
bValues.splice(index, 1);
|
|
2422
|
-
}
|
|
2423
|
-
return true;
|
|
2424
|
-
}
|
|
2425
|
-
case arrayTag:
|
|
2426
|
-
case uint8ArrayTag:
|
|
2427
|
-
case uint8ClampedArrayTag:
|
|
2428
|
-
case uint16ArrayTag:
|
|
2429
|
-
case uint32ArrayTag:
|
|
2430
|
-
case bigUint64ArrayTag:
|
|
2431
|
-
case int8ArrayTag:
|
|
2432
|
-
case int16ArrayTag:
|
|
2433
|
-
case int32ArrayTag:
|
|
2434
|
-
case bigInt64ArrayTag:
|
|
2435
|
-
case float32ArrayTag:
|
|
2436
|
-
case float64ArrayTag:
|
|
2437
|
-
if (isBuffer(a) !== isBuffer(b)) return false;
|
|
2438
|
-
if (a.length !== b.length) return false;
|
|
2439
|
-
for (let i = 0; i < a.length; i++) if (!isEqualWithImpl(a[i], b[i], i, a, b, stack, areValuesEqual)) return false;
|
|
2440
|
-
return true;
|
|
2441
|
-
case arrayBufferTag:
|
|
2442
|
-
if (a.byteLength !== b.byteLength) return false;
|
|
2443
|
-
return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
|
|
2444
|
-
case dataViewTag:
|
|
2445
|
-
if (a.byteLength !== b.byteLength || a.byteOffset !== b.byteOffset) return false;
|
|
2446
|
-
return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
|
|
2447
|
-
case errorTag: return a.name === b.name && a.message === b.message;
|
|
2448
|
-
case objectTag: {
|
|
2449
|
-
if (!(areObjectsEqual(a.constructor, b.constructor, stack, areValuesEqual) || isPlainObject(a) && isPlainObject(b))) return false;
|
|
2450
|
-
const aKeys = [...Object.keys(a), ...getSymbols(a)];
|
|
2451
|
-
const bKeys = [...Object.keys(b), ...getSymbols(b)];
|
|
2452
|
-
if (aKeys.length !== bKeys.length) return false;
|
|
2453
|
-
for (let i = 0; i < aKeys.length; i++) {
|
|
2454
|
-
const propKey = aKeys[i];
|
|
2455
|
-
const aProp = a[propKey];
|
|
2456
|
-
if (!Object.hasOwn(b, propKey)) return false;
|
|
2457
|
-
const bProp = b[propKey];
|
|
2458
|
-
if (!isEqualWithImpl(aProp, bProp, propKey, a, b, stack, areValuesEqual)) return false;
|
|
2459
|
-
}
|
|
2460
|
-
return true;
|
|
2461
|
-
}
|
|
2462
|
-
default: return false;
|
|
2463
|
-
}
|
|
2464
|
-
} finally {
|
|
2465
|
-
stack.delete(a);
|
|
2466
|
-
stack.delete(b);
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
//#endregion
|
|
2470
|
-
//#region ../../node_modules/.pnpm/es-toolkit@1.50.0/node_modules/es-toolkit/dist/predicate/isEqual.mjs
|
|
2471
|
-
/**
|
|
2472
|
-
* Checks if two values are equal, including support for `Date`, `RegExp`, and deep object comparison.
|
|
2473
|
-
*
|
|
2474
|
-
* @param a - The first value to compare.
|
|
2475
|
-
* @param b - The second value to compare.
|
|
2476
|
-
* @returns `true` if the values are equal, otherwise `false`.
|
|
2477
|
-
*
|
|
2478
|
-
* @example
|
|
2479
|
-
* isEqual(1, 1); // true
|
|
2480
|
-
* isEqual({ a: 1 }, { a: 1 }); // true
|
|
2481
|
-
* isEqual(/abc/g, /abc/g); // true
|
|
2482
|
-
* isEqual(new Date('2020-01-01'), new Date('2020-01-01')); // true
|
|
2483
|
-
* isEqual([1, 2, 3], [1, 2, 3]); // true
|
|
2484
|
-
*/
|
|
2485
|
-
function isEqual(a, b) {
|
|
2486
|
-
return isEqualWith(a, b, noop);
|
|
2487
|
-
}
|
|
2488
|
-
//#endregion
|
|
2489
50
|
//#region src/react/useResponsive.ts
|
|
2490
51
|
/** 屏幕响应断点 token 配置 */
|
|
2491
52
|
const BREAK_POINT_TOKEN = {
|