@pawover/kit 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2300 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_math = require("./math-BznvO4qI.cjs");
3
+ //#region src/array/arrayUtil.ts
4
+ /**
5
+ * 数组工具类
6
+ */
7
+ var ArrayUtil = class {
8
+ static cast(candidate, checkNullish = true) {
9
+ if (checkNullish && require_math.TypeUtil.isNullish(candidate)) return [];
10
+ return require_math.TypeUtil.isArray(candidate) ? [...candidate] : [candidate];
11
+ }
12
+ static first(initialList, fallback) {
13
+ if (!require_math.TypeUtil.isArray(initialList) || initialList.length === 0) return fallback;
14
+ return initialList[0];
15
+ }
16
+ static last(initialList, fallback) {
17
+ if (!require_math.TypeUtil.isArray(initialList) || initialList.length === 0) return fallback;
18
+ return initialList[initialList.length - 1];
19
+ }
20
+ /**
21
+ * 数组竞选
22
+ * - 返回在匹配函数的比较条件中获胜的最终项目,适用于更复杂的最小值/最大值计算
23
+ *
24
+ * @param initialList 数组
25
+ * @param match 匹配函数
26
+ * @returns 获胜的元素,如果数组为空或参数无效则返回 `null`
27
+ * @example
28
+ * ```ts
29
+ * const list = [1, 10, 5];
30
+ * ArrayUtil.compete(list, (a, b) => (a > b ? a : b)); // 10
31
+ * ArrayUtil.compete(list, (a, b) => (a < b ? a : b)); // 1
32
+ * ```
33
+ */
34
+ static compete(initialList, match) {
35
+ if (!require_math.TypeUtil.isArray(initialList) || initialList.length === 0 || !require_math.TypeUtil.isFunction(match)) return null;
36
+ return initialList.reduce(match);
37
+ }
38
+ /**
39
+ * 统计数组的项目出现次数
40
+ * - 通过给定的标识符匹配函数,返回一个对象,其中键是回调函数返回的 key 值,每个值是一个整数,表示该 key 出现的次数
41
+ *
42
+ * @param initialList 初始数组
43
+ * @param match 匹配函数
44
+ * @returns 统计对象
45
+ * @example
46
+ * ```ts
47
+ * const list = ["a", "b", "a", "c"];
48
+ * ArrayUtil.count(list, (x) => x); // { a: 2, b: 1, c: 1 }
49
+ *
50
+ * const users = [{ id: 1, group: "A" }, { id: 2, group: "B" }, { id: 3, group: "A" }];
51
+ * ArrayUtil.count(users, (u) => u.group); // { A: 2, B: 1 }
52
+ * ```
53
+ */
54
+ static count(initialList, match) {
55
+ if (!require_math.TypeUtil.isArray(initialList) || !require_math.TypeUtil.isFunction(match)) return {};
56
+ return initialList.reduce((prev, curr, index) => {
57
+ const id = match(curr, index).toString();
58
+ prev[id] = (prev[id] ?? 0) + 1;
59
+ return prev;
60
+ }, {});
61
+ }
62
+ /**
63
+ * 获取数组差集
64
+ * - 返回在 `initialList` 中存在,但在 `diffList` 中不存在的元素
65
+ *
66
+ * @param initialList 初始数组
67
+ * @param diffList 对比数组
68
+ * @param match 匹配函数
69
+ * @returns 差集数组
70
+ * @example
71
+ * ```ts
72
+ * // 重载 1: 按元素本身比较(自动去重)
73
+ * ArrayUtil.difference([1, 2, 3], [2, 3, 4]); // [1]
74
+ * ArrayUtil.difference([1, 1, 2], [2]); // [1],重复项会被去重
75
+ *
76
+ * // 重载 2: 按 match 结果比较(不去重,保留 initialList 原始重复项与顺序)
77
+ * ArrayUtil.difference([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // [{ id: 1 }]
78
+ * ArrayUtil.difference([{ id: 1 }, { id: 1 }], [{ id: 2 }], (x) => x.id); // [{ id: 1 }, { id: 1 }]
79
+ * ```
80
+ */
81
+ static difference(initialList, diffList, match) {
82
+ if (!require_math.TypeUtil.isArray(initialList) && !require_math.TypeUtil.isArray(diffList)) return [];
83
+ if (!require_math.TypeUtil.isArray(initialList) || !initialList.length) return [];
84
+ if (!require_math.TypeUtil.isArray(diffList) || !diffList.length) return [...initialList];
85
+ if (!require_math.TypeUtil.isFunction(match)) {
86
+ const arraySet = new Set(diffList);
87
+ return Array.from(new Set(initialList.filter((item) => !arraySet.has(item))));
88
+ }
89
+ const map = /* @__PURE__ */ new Map();
90
+ diffList.forEach((item, index) => {
91
+ map.set(match(item, index), true);
92
+ });
93
+ return initialList.filter((item, index) => !map.get(match(item, index)));
94
+ }
95
+ static intersection(initialList, diffList, match) {
96
+ if (!require_math.TypeUtil.isArray(initialList) || !require_math.TypeUtil.isArray(diffList)) return [];
97
+ if (!initialList.length || !diffList.length) return [];
98
+ if (!require_math.TypeUtil.isFunction(match)) {
99
+ const diffSet = new Set(diffList);
100
+ return initialList.filter((item) => diffSet.has(item));
101
+ }
102
+ const diffKeys = new Set(diffList.map((item, index) => match(item, index)));
103
+ return initialList.filter((item, index) => diffKeys.has(match(item, index)));
104
+ }
105
+ static merge(initialList, mergeList, match) {
106
+ if (!require_math.TypeUtil.isArray(initialList)) return [];
107
+ if (!require_math.TypeUtil.isArray(mergeList)) return [...initialList];
108
+ if (!require_math.TypeUtil.isFunction(match)) return Array.from(/* @__PURE__ */ new Set([...initialList, ...mergeList]));
109
+ const keys = /* @__PURE__ */ new Map();
110
+ mergeList.forEach((item, index) => {
111
+ keys.set(match(item, index), item);
112
+ });
113
+ return initialList.map((prevItem, index) => {
114
+ const key = match(prevItem, index);
115
+ return keys.has(key) ? keys.get(key) : prevItem;
116
+ });
117
+ }
118
+ static pick(initialList, filter, mapper) {
119
+ if (!require_math.TypeUtil.isArray(initialList)) return [];
120
+ if (!require_math.TypeUtil.isFunction(filter)) return [...initialList];
121
+ const hasMapper = require_math.TypeUtil.isFunction(mapper);
122
+ return initialList.reduce((prev, curr, index) => {
123
+ if (!filter(curr, index)) return prev;
124
+ if (hasMapper) prev.push(mapper(curr, index));
125
+ else prev.push(curr);
126
+ return prev;
127
+ }, []);
128
+ }
129
+ static replace(initialList, newItem, match) {
130
+ if (!require_math.TypeUtil.isArray(initialList) || !initialList.length) return [];
131
+ if (!require_math.TypeUtil.isFunction(match)) return [...initialList];
132
+ for (let i = 0; i < initialList.length; i++) {
133
+ const item = initialList[i];
134
+ if (match(item, i)) return [
135
+ ...initialList.slice(0, i),
136
+ newItem,
137
+ ...initialList.slice(i + 1, initialList.length)
138
+ ];
139
+ }
140
+ return [...initialList];
141
+ }
142
+ /**
143
+ * 数组项替换并移动
144
+ * - 在给定的数组中,替换并移动符合匹配函数结果的项目
145
+ * - 只替换和移动第一个匹配项
146
+ * - 未匹配时,根据 `position` 在指定位置插入 `newItem`
147
+ * - ⚠️ `position` 为负数或非正整数(如 `-1`、`2.5`)时不生效,静默回退为 `push`(追加到末尾)
148
+ *
149
+ * @param initialList 初始数组
150
+ * @param newItem 替换项
151
+ * @param match 匹配函数
152
+ * @param position 移动位置,可选 `start` | `end` | 索引位置, 默认为 `end`
153
+ * @returns
154
+ * @example
155
+ * ```ts
156
+ * ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, 0); // [5, 1, 3, 4]
157
+ * ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, 2); // [1, 3, 5, 4]
158
+ * ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, "start"); // [5, 1, 3, 4]
159
+ * ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2); // [1, 3, 4, 5]
160
+ *
161
+ * // position 为负数 → 静默回退为 push
162
+ * ArrayUtil.replaceMove([1, 2, 3, 4], 5, (n) => n === 2, -1); // [1, 3, 4, 5]
163
+ * ```
164
+ */
165
+ static replaceMove(initialList, newItem, match, position) {
166
+ if (!require_math.TypeUtil.isArray(initialList)) return [];
167
+ if (!initialList.length) return [newItem];
168
+ if (!require_math.TypeUtil.isFunction(match)) return [...initialList];
169
+ const result = [...initialList];
170
+ const matchIndex = initialList.findIndex(match);
171
+ if (matchIndex !== -1) result.splice(matchIndex, 1);
172
+ if (position === "start") result.unshift(newItem);
173
+ else if (position === 0 || require_math.TypeUtil.isPositiveInteger(position, false)) result.splice(Math.min(position, result.length), 0, newItem);
174
+ else result.push(newItem);
175
+ return result;
176
+ }
177
+ /**
178
+ * 数组切分
179
+ * - 将数组以指定的长度切分后,组合在高维数组中
180
+ *
181
+ * @param initialList 初始数组
182
+ * @param size 分割尺寸,默认 `10`
183
+ * @returns 切分后的二维数组
184
+ * @example
185
+ * ```ts
186
+ * ArrayUtil.split([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
187
+ * ```
188
+ */
189
+ static split(initialList, size = 10) {
190
+ if (!require_math.TypeUtil.isArray(initialList)) return [];
191
+ if (!require_math.TypeUtil.isPositiveInteger(size, false)) return [];
192
+ const count = Math.ceil(initialList.length / size);
193
+ return Array.from({ length: count }).fill(null).map((_c, i) => {
194
+ return initialList.slice(i * size, i * size + size);
195
+ });
196
+ }
197
+ /**
198
+ * 数组分组过滤
199
+ * - 给定一个数组和一个条件,返回一个由两个数组组成的元组,其中第一个数组包含所有满足条件的项,第二个数组包含所有不满足条件的项
200
+ *
201
+ * @param initialList 初始数组
202
+ * @param match 条件匹配函数
203
+ * @returns [满足条件的项[], 不满足条件的项[]]
204
+ * @example
205
+ * ```ts
206
+ * ArrayUtil.fork([1, 2, 3, 4], (n) => n % 2 === 0); // [[2, 4], [1, 3]]
207
+ * ```
208
+ */
209
+ static fork(initialList, match) {
210
+ const forked = [[], []];
211
+ if (require_math.TypeUtil.isArray(initialList)) initialList.forEach((item, index) => {
212
+ forked[match(item, index) ? 0 : 1].push(item);
213
+ });
214
+ return forked;
215
+ }
216
+ /**
217
+ * 数组解压
218
+ * - `ArrayUtil.zip` 的反向操作
219
+ * - 默认按最长数组补齐 `undefined`
220
+ *
221
+ * @param arrayList 压缩后的数组
222
+ * @param options 配置项(`truncate` 为 `true` 时按最短数组截断)
223
+ * @returns 解压后的二维数组
224
+ * @example
225
+ * ```ts
226
+ * ArrayUtil.unzip([[1, "a"], [2, "b"]]); // [[1, 2], ["a", "b"]]
227
+ *
228
+ * // 补齐语义
229
+ * ArrayUtil.unzip([[1, 2], [3]]); // [[1, 3], [2, undefined]]
230
+ *
231
+ * // 截断语义
232
+ * ArrayUtil.unzip([[1, 2], [3]], { truncate: true }); // [[1, 3]]
233
+ * ```
234
+ */
235
+ static unzip(arrayList, options) {
236
+ if (!require_math.TypeUtil.isArray(arrayList) || !arrayList.length) return [];
237
+ const length = options?.truncate ? arrayList.reduce((min, arr) => Math.min(min, arr.length), Infinity) : arrayList.reduce((max, arr) => Math.max(max, arr.length), 0);
238
+ const out = new Array(length);
239
+ let index = 0;
240
+ const get = (array) => array[index];
241
+ for (; index < out.length; index++) out[index] = Array.from(arrayList, get);
242
+ return out;
243
+ }
244
+ static zip(...arraysAndOptions) {
245
+ const last = arraysAndOptions[arraysAndOptions.length - 1];
246
+ const options = last && !require_math.TypeUtil.isArray(last) ? last : void 0;
247
+ const arrays = options ? arraysAndOptions.slice(0, -1) : arraysAndOptions;
248
+ return this.unzip(arrays, options);
249
+ }
250
+ static zipToObject(keys, values) {
251
+ const result = {};
252
+ if (!require_math.TypeUtil.isArray(keys) || !keys.length) return result;
253
+ const getValue = require_math.TypeUtil.isFunction(values) ? values : require_math.TypeUtil.isArray(values) ? (_k, i) => values[i] : (_k, _i) => values;
254
+ return keys.reduce((acc, key, idx) => {
255
+ Object.defineProperty(acc, key, {
256
+ value: getValue(key, idx),
257
+ enumerable: true,
258
+ writable: true,
259
+ configurable: true
260
+ });
261
+ return acc;
262
+ }, result);
263
+ }
264
+ };
265
+ //#endregion
266
+ //#region src/currency/currencyUtil.ts
267
+ /**
268
+ * 货币工具类
269
+ * - 基于 [`Intl.NumberFormat`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) 进行本地化格式化
270
+ * - 支持精确小数位处理(依赖 `mathjs`)
271
+ */
272
+ var CurrencyUtil = class {
273
+ /**
274
+ * 货币代码到 Locale 的映射枚举
275
+ * - 键为 ISO 4217 货币代码,值为 BCP 47 语言标签
276
+ * - 用于 `Intl.NumberFormat` 的本地化数字格式化
277
+ * - 格式示例基于 `Intl.NumberFormat` 对 `1,234,567.89` 的输出
278
+ *
279
+ * @example
280
+ * ```ts
281
+ * import { CurrencyUtil } from "@pawover/kit/utils";
282
+ * // 获取人民币的格式化 locale
283
+ * const locale = CurrencyUtil.CURRENCY_ENUM.CNY; // "zh-CN"
284
+ *
285
+ * // 结合 Intl.NumberFormat 使用
286
+ * new Intl.NumberFormat(CurrencyUtil.CURRENCY_ENUM.USD, {
287
+ * style: "currency",
288
+ * currency: "USD",
289
+ * }).format(1234.56); // "$1,234.56"
290
+ * ```
291
+ */
292
+ static CURRENCY_ENUM = {
293
+ /** 美元(美国及美元化国家,Locale: 美式英语) → 1,234,567.89 */
294
+ USD: "en-US",
295
+ /** 加拿大元(加拿大,Locale: 加拿大英语) → 1,234,567.89 */
296
+ CAD: "en-CA",
297
+ /** 墨西哥比索(墨西哥,Locale: 墨西哥西班牙语) → 1,234,567.89 */
298
+ MXN: "es-MX",
299
+ /** 巴西雷亚尔(巴西,Locale: 巴西葡萄牙语) → 1.234.567,89 */
300
+ BRL: "pt-BR",
301
+ /** 阿根廷比索(阿根廷,Locale: 阿根廷西班牙语) → 1.234.567,89 */
302
+ ARS: "es-AR",
303
+ /** 智利比索(智利,Locale: 智利西班牙语) → 1.234.567,89 */
304
+ CLP: "es-CL",
305
+ /** 秘鲁新索尔(秘鲁,Locale: 秘鲁西班牙语) → 1,234,567.89 */
306
+ PEN: "es-PE",
307
+ /** 哥伦比亚比索(哥伦比亚,Locale: 哥伦比亚西班牙语) → 1.234.567,89 */
308
+ COP: "es-CO",
309
+ /** 哥斯达黎加科朗(哥斯达黎加,Locale: 哥斯达黎加西班牙语) → 1 234 567,89(空格千分位) */
310
+ CRC: "es-CR",
311
+ /** 人民币(中国,Locale: 简体中文) → 1,234,567.89 */
312
+ CNY: "zh-CN",
313
+ /** 港元(中国香港,Locale: 繁体中文+香港) → 1,234,567.89 */
314
+ HKD: "zh-HK",
315
+ /** 澳门元(中国澳门,Locale: 繁体中文+澳门) → 1,234,567.89 */
316
+ MOP: "zh-MO",
317
+ /** 日元(日本,Locale: 日语) → 1,234,567.89 */
318
+ JPY: "ja-JP",
319
+ /** 韩元(韩国,Locale: 韩语) → 1,234,567.89 */
320
+ KRW: "ko-KR",
321
+ /** 新加坡元(新加坡,Locale: 英语+新加坡) → 1,234,567.89 */
322
+ SGD: "en-SG",
323
+ /** 泰铢(泰国,Locale: 泰语) → 1,234,567.89 */
324
+ THB: "th-TH",
325
+ /** 印度卢比(印度,Locale: 英语+印度) → 12,34,567.89(2,2,3 分组) */
326
+ INR: "en-IN",
327
+ /** 沙特里亚尔(沙特,Locale: 阿拉伯语+沙特) → ١٬٢٣٤٬٥٦٧٫٨٩(阿拉伯数字) */
328
+ SAR: "ar-SA",
329
+ /** 阿联酋迪拉姆(阿联酋,Locale: 阿拉伯语+阿联酋) → 1,234,567.89 */
330
+ AED: "ar-AE",
331
+ /** 印尼盾(印尼,Locale: 印尼语) → 1.234.567,89 */
332
+ IDR: "id-ID",
333
+ /** 马来西亚林吉特(马来西亚,Locale: 马来语) → 1,234,567.89 */
334
+ MYR: "ms-MY",
335
+ /** 越南盾(越南,Locale: 越南语) → 1.234.567,89 */
336
+ VND: "vi-VN",
337
+ /** 菲律宾比索(菲律宾,Locale: 英语+菲律宾) → 1,234,567.89 */
338
+ PHP: "en-PH",
339
+ /** 巴基斯坦卢比(巴基斯坦,Locale: 英语+巴基斯坦) → 1,234,567.89 */
340
+ PKR: "en-PK",
341
+ /** 新台币(中国台湾地区,Locale: 繁体中文+台湾) → 1,234,567.89 */
342
+ TWD: "zh-TW",
343
+ /** 欧元(德国,Locale: 德语+德国,代表欧元区) → 1.234.567,89 */
344
+ EUR: "de-DE",
345
+ /** 英镑(英国,Locale: 英式英语) → 1,234,567.89 */
346
+ GBP: "en-GB",
347
+ /** 瑞士法郎(瑞士,Locale: 德语+瑞士) → 1'234'567.89 */
348
+ CHF: "de-CH",
349
+ /** 瑞典克朗(瑞典,Locale: 瑞典语) → 1 234 567,89(空格千分位) */
350
+ SEK: "sv-SE",
351
+ /** 挪威克朗(挪威,Locale: 挪威语) → 1 234 567,89(空格千分位) */
352
+ NOK: "no-NO",
353
+ /** 丹麦克朗(丹麦,Locale: 丹麦语) → 1.234.567,89 */
354
+ DKK: "da-DK",
355
+ /** 波兰兹罗提(波兰,Locale: 波兰语) → 1 234 567,89(空格千分位) */
356
+ PLN: "pl-PL",
357
+ /** 捷克克朗(捷克,Locale: 捷克语) → 1 234 567,89(空格千分位) */
358
+ CZK: "cs-CZ",
359
+ /** 匈牙利福林(匈牙利,Locale: 匈牙利语) → 1 234 567,89(空格千分位) */
360
+ HUF: "hu-HU",
361
+ /** 俄罗斯卢布(俄罗斯,Locale: 俄语) → 1 234 567,89(空格千分位) */
362
+ RUB: "ru-RU",
363
+ /** 罗马尼亚列伊(罗马尼亚,Locale: 罗马尼亚语) → 1.234.567,89 */
364
+ RON: "ro-RO",
365
+ /** 乌克兰格里夫纳(乌克兰,Locale: 乌克兰语) → 1 234 567,89(空格千分位) */
366
+ UAH: "uk-UA",
367
+ /** 澳大利亚元(澳大利亚,Locale: 澳大利亚英语) → 1,234,567.89 */
368
+ AUD: "en-AU",
369
+ /** 新西兰元(新西兰,Locale: 新西兰英语) → 1,234,567.89 */
370
+ NZD: "en-NZ",
371
+ /** 南非兰特(南非,Locale: 英语+南非) → 1 234 567,89(空格千分位) */
372
+ ZAR: "en-ZA",
373
+ /** 埃及镑(埃及,Locale: 阿拉伯语+埃及) → ١٬٢٣٤٬٥٦٧٫٨٩(阿拉伯数字) */
374
+ EGP: "ar-EG",
375
+ /** 土耳其里拉(土耳其,Locale: 土耳其语) → 1.234.567,89 */
376
+ TRY: "tr-TR",
377
+ /** 以色列新谢克尔(以色列,Locale: 希伯来语) → 1,234,567.89 */
378
+ ILS: "he-IL",
379
+ /** 摩洛哥迪拉姆(摩洛哥,Locale: 阿拉伯语+摩洛哥) → 1.234.567,89 */
380
+ MAD: "ar-MA",
381
+ /** 科威特第纳尔(科威特,Locale: 阿拉伯语+科威特) → ١٬٢٣٤٬٥٦٧٫٨٩(阿拉伯数字) */
382
+ KWD: "ar-KW",
383
+ /** 卡塔尔里亚尔(卡塔尔,Locale: 阿拉伯语+卡塔尔) → ١٬٢٣٤٬٥٦٧٫٨٩(阿拉伯数字) */
384
+ QAR: "ar-QA",
385
+ /** 尼日利亚奈拉(尼日利亚,Locale: 英语+尼日利亚) → 1,234,567.89 */
386
+ NGN: "en-NG",
387
+ /** 太平洋法郎(法属波利尼西亚,Locale: 法语+太平洋) → 1[U+202F]234[U+202F]567,89(窄空格千分位) */
388
+ XPF: "fr-PF"
389
+ };
390
+ static currencyFormatter(value, options) {
391
+ if (require_math.TypeUtil.isNullish(value)) return null;
392
+ const { currencySign, currencySignPosition, locales, currencyFormatOptions } = options;
393
+ const numberValue = Number(value);
394
+ if (Number.isNaN(numberValue)) return null;
395
+ let formatedValue = numberValue.toLocaleString(locales, currencyFormatOptions).replace(currencySign, "").trim();
396
+ if (currencySignPosition === "start") formatedValue = `${currencySign} ${formatedValue}`;
397
+ if (currencySignPosition === "end") formatedValue = `${formatedValue} ${currencySign}`;
398
+ return formatedValue;
399
+ }
400
+ static toRealValue(mathJsInstance, value, precision, stringMode) {
401
+ if (require_math.TypeUtil.isNullish(value)) return null;
402
+ const precisionValue = require_math.MathUtil.toDecimal(mathJsInstance, value, precision);
403
+ return stringMode === false ? Number(precisionValue) : precisionValue;
404
+ }
405
+ };
406
+ //#endregion
407
+ //#region src/dateTime/dateTimeUtil.ts
408
+ /**
409
+ * 日期工具类
410
+ */
411
+ var DateTimeUtil = class {
412
+ /**
413
+ * 每秒的毫秒数
414
+ * @example
415
+ * ```ts
416
+ * DateTimeUtil.MILLISECONDS_PER_SECOND; // 1000
417
+ * ```
418
+ */
419
+ static MILLISECONDS_PER_SECOND = 1e3;
420
+ /**
421
+ * 每分钟的秒数
422
+ * @example
423
+ * ```ts
424
+ * DateTimeUtil.SECOND_PER_MINUTE; // 60
425
+ * ```
426
+ */
427
+ static SECOND_PER_MINUTE = 60;
428
+ /**
429
+ * 每小时的分钟数
430
+ * @example
431
+ * ```ts
432
+ * DateTimeUtil.MINUTE_PER_HOUR; // 60
433
+ * ```
434
+ */
435
+ static MINUTE_PER_HOUR = 60;
436
+ /**
437
+ * 每小时的秒数
438
+ * @example
439
+ * ```ts
440
+ * DateTimeUtil.SECOND_PER_HOUR; // 3600
441
+ * ```
442
+ */
443
+ static SECOND_PER_HOUR = this.SECOND_PER_MINUTE ** 2;
444
+ /**
445
+ * 每天小时数
446
+ * @example
447
+ * ```ts
448
+ * DateTimeUtil.HOUR_PER_DAY; // 24
449
+ * ```
450
+ */
451
+ static HOUR_PER_DAY = 24;
452
+ /**
453
+ * 每天秒数
454
+ * @example
455
+ * ```ts
456
+ * DateTimeUtil.SECOND_PER_DAY; // 86400
457
+ * ```
458
+ */
459
+ static SECOND_PER_DAY = this.SECOND_PER_HOUR * this.HOUR_PER_DAY;
460
+ /**
461
+ * 每周天数
462
+ * @example
463
+ * ```ts
464
+ * DateTimeUtil.DAY_PER_WEEK; // 7
465
+ * ```
466
+ */
467
+ static DAY_PER_WEEK = 7;
468
+ /**
469
+ * 每月天数
470
+ * @example
471
+ * ```ts
472
+ * DateTimeUtil.DAY_PER_MONTH; // 30
473
+ * ```
474
+ */
475
+ static DAY_PER_MONTH = 30;
476
+ /**
477
+ * 每年天数
478
+ * @example
479
+ * ```ts
480
+ * DateTimeUtil.DAY_PER_YEAR; // 365
481
+ * ```
482
+ */
483
+ static DAY_PER_YEAR = 365;
484
+ /**
485
+ * 每年月数
486
+ * @example
487
+ * ```ts
488
+ * DateTimeUtil.MONTH_PER_YEAR; // 12
489
+ * ```
490
+ */
491
+ static MONTH_PER_YEAR = 12;
492
+ /**
493
+ * 每年平均周
494
+ * @example
495
+ * ```ts
496
+ * DateTimeUtil.WEEK_PER_YEAR; // 52
497
+ * ```
498
+ */
499
+ static WEEK_PER_YEAR = 52;
500
+ /**
501
+ * 每月平均周
502
+ * @example
503
+ * ```ts
504
+ * DateTimeUtil.WEEK_PER_MONTH; // 4
505
+ * ```
506
+ */
507
+ static WEEK_PER_MONTH = 4;
508
+ /**
509
+ * 常用时间格式模板集合
510
+ *
511
+ * @example
512
+ * ```ts
513
+ * DateTimeUtil.FORMAT.ISO_DATE; // "yyyy-MM-dd"
514
+ * DateTimeUtil.FORMAT.CN_DATE_TIME; // "yyyy年MM月dd日 HH时mm分ss秒"
515
+ * ```
516
+ */
517
+ static FORMAT = {
518
+ ISO_DATE: "yyyy-MM-dd",
519
+ ISO_TIME: "HH:mm:ss",
520
+ ISO_DATE_TIME: "yyyy-MM-dd HH:mm:ss",
521
+ ISO_DATE_TIME_MS: "yyyy-MM-dd HH:mm:ss.SSS",
522
+ ISO_DATETIME_TZ: "yyyy-MM-dd'T'HH:mm:ssXXX",
523
+ ISO_DATETIME_TZ_MS: "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
524
+ US_DATE: "MM/dd/yyyy",
525
+ US_DATE_TIME: "MM/dd/yyyy HH:mm:ss",
526
+ US_DATE_SHORT_YEAR: "MM/dd/yy",
527
+ EU_DATE: "dd/MM/yyyy",
528
+ EU_DATE_TIME: "dd/MM/yyyy HH:mm:ss",
529
+ CN_DATE: "yyyy年MM月dd日",
530
+ CN_DATE_TIME: "yyyy年MM月dd日 HH时mm分ss秒",
531
+ CN_DATE_WEEKDAY: "yyyy年MM月dd日 EEE",
532
+ CN_WEEKDAY_FULL: "EEEE",
533
+ SHORT_DATE: "yy-MM-dd",
534
+ SHORT_DATE_SLASH: "yy/MM/dd",
535
+ MONTH_DAY: "MM-dd",
536
+ MONTH_DAY_CN: "MM月dd日",
537
+ DATE_WITH_WEEKDAY_SHORT: "yyyy-MM-dd (EEE)",
538
+ DATE_WITH_WEEKDAY_FULL: "yyyy-MM-dd (EEEE)",
539
+ TIME_24: "HH:mm:ss",
540
+ TIME_24_NO_SEC: "HH:mm",
541
+ TIME_12: "hh:mm:ss a",
542
+ TIME_12_NO_SEC: "hh:mm a",
543
+ TIMESTAMP: "yyyyMMddHHmmss",
544
+ TIMESTAMP_MS: "yyyyMMddHHmmssSSS",
545
+ RFC2822: "EEE, dd MMM yyyy HH:mm:ss xxx",
546
+ READABLE_DATE: "MMM dd, yyyy",
547
+ READABLE_DATE_TIME: "MMM dd, yyyy HH:mm",
548
+ COMPACT_DATETIME: "yyyyMMdd_HHmmss"
549
+ };
550
+ /**
551
+ * 获取当前时区信息
552
+ *
553
+ * @returns 时区信息对象 (UTC偏移和时区名称)
554
+ * @example
555
+ * ```ts
556
+ * DateTimeUtil.getTimeZone(); // { UTC: "UTC+8", timeZone: "Asia/Shanghai" }
557
+ * ```
558
+ */
559
+ static getTimeZone() {
560
+ const offsetMinutes = 0 - (/* @__PURE__ */ new Date()).getTimezoneOffset();
561
+ const sign = offsetMinutes >= 0 ? "+" : "-";
562
+ const absMinutes = Math.abs(offsetMinutes);
563
+ const hours = Math.floor(absMinutes / this.MINUTE_PER_HOUR);
564
+ const minutes = absMinutes % this.MINUTE_PER_HOUR;
565
+ return {
566
+ UTC: `UTC${sign}${hours}${minutes ? `:${String(minutes).padStart(2, "0")}` : ""}`,
567
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
568
+ };
569
+ }
570
+ };
571
+ //#endregion
572
+ //#region src/env/envUtil.ts
573
+ /**
574
+ * 环境检查工具类
575
+ * - ⚠️ `isBrowser` / `isWebWorker` / `isReactNative` 基于静态字段判定,在**模块加载时**求值一次。
576
+ * SSR 场景下若在 Node 端 import(此时 `window` 未定义),结果会永久为 `false`,不会随运行时环境变化重算。
577
+ */
578
+ var EnvUtil = class {
579
+ static _isBrowser = typeof window !== "undefined" && require_math.TypeUtil.isFunction(window?.document?.createElement);
580
+ static _isWebWorker = typeof window === "undefined" && typeof self !== "undefined" && "importScripts" in self;
581
+ static _isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
582
+ /**
583
+ * 检测是否处于浏览器环境
584
+ *
585
+ * @returns 是否为浏览器环境
586
+ * @example
587
+ * ```ts
588
+ * EnvUtil.isBrowser(); // true: 浏览器, false: Node.js
589
+ * ```
590
+ */
591
+ static isBrowser() {
592
+ return this._isBrowser;
593
+ }
594
+ /**
595
+ * 检测是否处于 Web Worker 环境
596
+ *
597
+ * @returns 是否为 Web Worker 环境
598
+ * @example
599
+ * ```ts
600
+ * EnvUtil.isWebWorker(); // true: Worker, false: 主线程/Node.js
601
+ * ```
602
+ */
603
+ static isWebWorker() {
604
+ return this._isWebWorker;
605
+ }
606
+ /**
607
+ * 检测是否处于 React Native 环境
608
+ *
609
+ * @returns 是否为 React Native 环境
610
+ * @example
611
+ * ```ts
612
+ * EnvUtil.isReactNative(); // true: React Native, false: Web/Node.js
613
+ * ```
614
+ */
615
+ static isReactNative() {
616
+ return this._isReactNative;
617
+ }
618
+ /**
619
+ * 检查是否在 iframe 环境中
620
+ *
621
+ * @returns 是否在 iframe 中
622
+ * @example
623
+ * ```ts
624
+ * EnvUtil.isIframe(); // true: 当前页面在 iframe 中
625
+ * ```
626
+ */
627
+ static isIframe() {
628
+ if (typeof window === "undefined") return false;
629
+ try {
630
+ return window.top !== window.self;
631
+ } catch (error) {
632
+ if (error.name === "SecurityError") return true;
633
+ return false;
634
+ }
635
+ }
636
+ /**
637
+ * 检测当前设备是否为桌面设备
638
+ *
639
+ * @param minWidth - 桌面设备最小宽度(默认 1200px)
640
+ * @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
641
+ * @param dpi - 标准 DPI 基准(默认 160)
642
+ * @returns 是否为桌面设备
643
+ * @example
644
+ * ```ts
645
+ * // 假设 window.innerWidth = 1920
646
+ * EnvUtil.isDesktop(); // true
647
+ *
648
+ * // 自定义阈值
649
+ * EnvUtil.isDesktop(1440, 13); // 更严格的桌面检测
650
+ * ```
651
+ */
652
+ static isDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
653
+ if (typeof window === "undefined" || !require_math.TypeUtil.isPositiveInteger(minWidth) || !require_math.TypeUtil.isPositiveInteger(minScreenSize)) return false;
654
+ if (window.innerWidth < minWidth) return false;
655
+ try {
656
+ const widthPx = window.screen.width;
657
+ const heightPx = window.screen.height;
658
+ const DPI = dpi * (window.devicePixelRatio || 1);
659
+ const widthInch = widthPx / DPI;
660
+ const heightInch = heightPx / DPI;
661
+ return Math.sqrt(widthInch ** 2 + heightInch ** 2) >= minScreenSize;
662
+ } catch {
663
+ return true;
664
+ }
665
+ }
666
+ /**
667
+ * 检测当前设备是否为 Windows 桌面设备
668
+ *
669
+ * @param minWidth - 桌面设备最小宽度(默认 1200px)
670
+ * @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
671
+ * @param dpi - 标准 DPI 基准(默认 160)
672
+ * @returns 是否为 Windows 桌面设备
673
+ * @example
674
+ * ```ts
675
+ * // UA contains Windows
676
+ * EnvUtil.isWindowsDesktop(); // true
677
+ * ```
678
+ */
679
+ static isWindowsDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
680
+ if (typeof navigator === "undefined" || !navigator.userAgent) return false;
681
+ return /Windows/i.test(navigator.userAgent) && this.isDesktop(minWidth, minScreenSize, dpi);
682
+ }
683
+ /**
684
+ * 检测当前设备是否为 macOS 桌面设备
685
+ *
686
+ * @param minWidth - 桌面设备最小宽度(默认 1200px)
687
+ * @param minScreenSize - 桌面设备最小屏幕尺寸(默认 10英寸)
688
+ * @param dpi - 标准 DPI 基准(默认 160)
689
+ * @returns 是否为 macOS 桌面设备
690
+ * @example
691
+ * ```ts
692
+ * // UA contains Macintosh
693
+ * EnvUtil.isMacOSDesktop(); // true
694
+ * ```
695
+ */
696
+ static isMacOSDesktop(minWidth = 1200, minScreenSize = 10, dpi = 160) {
697
+ if (typeof navigator === "undefined" || !navigator.userAgent) return false;
698
+ return /Macintosh/i.test(navigator.userAgent) && this.isDesktop(minWidth, minScreenSize, dpi);
699
+ }
700
+ /**
701
+ * 检测当前设备是否为移动设备
702
+ *
703
+ * @param maxWidth - 移动设备最大宽度(默认 768px)
704
+ * @param dpi - 标准 DPI 基准(默认 160)
705
+ * @returns 是否为移动设备
706
+ * @example
707
+ * ```ts
708
+ * // 假设 window.innerWidth = 500
709
+ * EnvUtil.isMobile(); // true
710
+ * ```
711
+ */
712
+ static isMobile(maxWidth = 768, dpi = 160) {
713
+ if (typeof window === "undefined" || !require_math.TypeUtil.isPositiveInteger(maxWidth)) return false;
714
+ if (window.innerWidth >= maxWidth) return false;
715
+ try {
716
+ const widthPx = window.screen.width;
717
+ const heightPx = window.screen.height;
718
+ const DPI = dpi * (window.devicePixelRatio || 1);
719
+ const widthInch = widthPx / DPI;
720
+ const heightInch = heightPx / DPI;
721
+ return Math.sqrt(widthInch ** 2 + heightInch ** 2) < 7;
722
+ } catch {
723
+ return true;
724
+ }
725
+ }
726
+ /**
727
+ * 检测当前设备是否为IOS移动设备
728
+ *
729
+ * @param maxWidth - 移动设备最大宽度(默认 768px)
730
+ * @param dpi - 标准 DPI 基准(默认 160)
731
+ * @returns 是否为 iOS 移动设备 (iPhone/iPod)
732
+ * @example
733
+ * ```ts
734
+ * // UA contains iPhone
735
+ * EnvUtil.isIOSMobile(); // true
736
+ * ```
737
+ */
738
+ static isIOSMobile(maxWidth = 768, dpi = 160) {
739
+ if (typeof navigator === "undefined" || !navigator.userAgent) return false;
740
+ return /iPhone|iPad|iPod/i.test(navigator.userAgent) && this.isMobile(maxWidth, dpi);
741
+ }
742
+ /**
743
+ * 检测当前设备是否为平板
744
+ *
745
+ * @param minWidth - 平板最小宽度(默认 768px)
746
+ * @param maxWidth - 平板最大宽度(默认 1200px)
747
+ * @param dpi - 标准 DPI 基准(默认 160)
748
+ * @returns 是否为平板设备
749
+ * - 宽度命中 `[minWidth, maxWidth]` 区间,或 CSS/DPI 折算尺寸落在 `[7, 13)` 英寸(排除 DPR=1 的 1920×1080 桌面)
750
+ * @example
751
+ * ```ts
752
+ * // 假设 window.innerWidth = 1000
753
+ * EnvUtil.isTablet(); // true
754
+ * ```
755
+ */
756
+ static isTablet(minWidth = 768, maxWidth = 1200, dpi = 160) {
757
+ if (typeof window === "undefined" || !require_math.TypeUtil.isPositiveInteger(minWidth) || !require_math.TypeUtil.isPositiveInteger(maxWidth)) return false;
758
+ const width = window.innerWidth;
759
+ const isWithinWidthRange = width >= minWidth && width <= maxWidth;
760
+ try {
761
+ const widthPx = window.screen.width;
762
+ const heightPx = window.screen.height;
763
+ const DPI = dpi * (window.devicePixelRatio || 1);
764
+ const widthInch = widthPx / DPI;
765
+ const heightInch = heightPx / DPI;
766
+ const screenInches = Math.sqrt(widthInch ** 2 + heightInch ** 2);
767
+ return isWithinWidthRange || screenInches >= 7 && screenInches < 13;
768
+ } catch {
769
+ return isWithinWidthRange;
770
+ }
771
+ }
772
+ };
773
+ //#endregion
774
+ //#region src/function/functionUtil.ts
775
+ /**
776
+ * 函数工具类
777
+ */
778
+ var FunctionUtil = class {
779
+ /**
780
+ *将 Promise 转换为 `[err, result]` 格式,方便 async/await 错误处理
781
+ *
782
+ * @param promise 待处理的 Promise
783
+ * @param errorExt 附加到 error 对象的扩展信息(注意:如果原 error 是 Error 实例,扩展属性可能会覆盖或无法正确合并非枚举属性)
784
+ * @returns `[err, null]` 或 `[null, data]`
785
+ * @example
786
+ * ```ts
787
+ * const [err, data] = await FunctionUtil.to(someAsyncFunc());
788
+ * ```
789
+ */
790
+ static to(promise, errorExt) {
791
+ return promise.then((data) => [null, data]).catch((err) => {
792
+ if (errorExt) {
793
+ const parsedError = {
794
+ name: "",
795
+ message: "",
796
+ stack: ""
797
+ };
798
+ if (err instanceof Error) {
799
+ parsedError.message = err.message;
800
+ parsedError.name = err.name;
801
+ parsedError.stack = err.stack;
802
+ Object.getOwnPropertyNames(err).forEach((key) => {
803
+ if (!(key in parsedError)) parsedError[key] = err[key];
804
+ });
805
+ } else {
806
+ Object.assign(parsedError, err);
807
+ if (!parsedError.message) parsedError.message = String(err);
808
+ }
809
+ Object.assign(parsedError, errorExt);
810
+ return [parsedError, void 0];
811
+ }
812
+ return [err ? err : /* @__PURE__ */ new Error("defaultError"), void 0];
813
+ });
814
+ }
815
+ /**
816
+ * 将 Arguments 对象转换为数组
817
+ *
818
+ * ⚠️ 注意:TypeScript 官方推荐使用 rest parameters (...args) 替代 arguments
819
+ * 本函数仅用于处理遗留代码或特殊场景(如装饰器中需保留 this 绑定)
820
+ *
821
+ * @param args Arguments 对象(必须为类数组对象)
822
+ * @param start 起始索引(可选,默认为 0)
823
+ * @returns 转换后的数组,元素类型为 T
824
+ *
825
+ * @throws TypeError 如果 args 为 null 或 undefined
826
+ *
827
+ * @example
828
+ * ```ts
829
+ * // 遗留代码场景
830
+ * function legacyFn(a: number, b: string) {
831
+ * const argsArray = FunctionUtil.toArgs(arguments);
832
+ * // argsArray: unknown[]
833
+ * }
834
+ *
835
+ * // 现代替代方案(推荐)
836
+ * function modernFn(a: number, b: string, ...rest: unknown[]) {
837
+ * // rest 已经是数组,无需 toArgs
838
+ * }
839
+ *
840
+ * // 参数截取
841
+ * function skipFirst(...args: unknown[]) {
842
+ * const rest = FunctionUtil.toArgs(arguments, 1);
843
+ * // rest: unknown[],跳过第一个参数
844
+ * }
845
+ * ```
846
+ */
847
+ static toArgs(args, start) {
848
+ if (args === null || args === void 0) throw new TypeError(`function [toArgs] Expected parameter [args] to be a arguments object, got ${typeof args}`);
849
+ return Array.prototype.slice.call(args, start);
850
+ }
851
+ /**
852
+ * 将同步或异步函数统一包装为 Promise
853
+ * - 自动捕获同步异常
854
+ *
855
+ * @param fn 返回值可为同步值或 Promise 的函数
856
+ * @returns 标准化的 Promise
857
+ *
858
+ * @example
859
+ * ```ts
860
+ * // 同步函数
861
+ * FunctionUtil.toPromise(() => 42).then(v => console.log(v)); // 42
862
+ *
863
+ * // 异步函数
864
+ * FunctionUtil.toPromise(async () => await fetchData()).then(data => ...);
865
+ *
866
+ * // 异常处理
867
+ * FunctionUtil.toPromise(() => { throw new Error('fail'); }).catch(err => console.error(err)); // 捕获同步异常
868
+ * ```
869
+ */
870
+ static toPromise(fn) {
871
+ try {
872
+ return Promise.resolve(fn());
873
+ } catch (error) {
874
+ return Promise.reject(error);
875
+ }
876
+ }
877
+ };
878
+ //#endregion
879
+ //#region src/mime/mimeUtil.ts
880
+ /**
881
+ * MIME 工具类
882
+ */
883
+ var MimeUtil = class {
884
+ /**
885
+ * 文件类型 MIME 常量
886
+ * - 每个类型对应具体的文件扩展名
887
+ */
888
+ static FILE_MIME = {
889
+ /** 普通文本文件(.txt) */
890
+ TEXT: "text/plain",
891
+ /** 超文本标记语言文档(.html/.htm) */
892
+ HTML: "text/html",
893
+ /** 层叠样式表文件(.css) */
894
+ CSS: "text/css",
895
+ /** 逗号分隔值文件/表格数据(.csv) */
896
+ CSV: "text/csv",
897
+ /** 制表符分隔值文件(.tsv) */
898
+ TSV: "text/tab-separated-values",
899
+ /** XML 文档(.xml) */
900
+ XML: "application/xml",
901
+ /** XML 文档/兼容值 */
902
+ XML_LEGACY: "text/xml",
903
+ /** XHTML 文档(.xhtml/.xht) */
904
+ XHTML: "application/xhtml+xml",
905
+ /** JavaScript 文件(.js) */
906
+ JS: "text/javascript",
907
+ /** TypeScript 文件(.ts) */
908
+ TS: "text/typescript",
909
+ /** Python 文件(.py) */
910
+ PY: "text/x-python",
911
+ /** Shell 脚本 (.sh) */
912
+ SH: "text/x-sh",
913
+ /** C 语言源文件(.c) */
914
+ C: "text/x-c",
915
+ /** C++ 源文件(.cpp/.cc/.cxx) */
916
+ CPP: "text/x-c++",
917
+ /** C# 源文件(.cs) */
918
+ CSHARP: "text/x-csharp",
919
+ /** Java 源文件(.java) */
920
+ JAVA: "text/x-java",
921
+ /** Go 源文件(.go) */
922
+ GO: "text/x-go",
923
+ /** Rust 源文件(.rs) */
924
+ RUST: "text/x-rust",
925
+ /** PHP 文件(.php) */
926
+ PHP: "text/x-php",
927
+ /** Ruby 文件(.rb) */
928
+ RUBY: "text/x-ruby",
929
+ /** Swift 源文件(.swift) */
930
+ SWIFT: "text/x-swift",
931
+ /** YAML 文档(.yaml/.yml) */
932
+ YAML: "application/yaml",
933
+ /** YAML 文档/兼容值 */
934
+ YAML_LEGACY: "text/vnd.yaml",
935
+ /** TOML 文档(.toml) */
936
+ TOML: "application/toml",
937
+ /** TOML 文档/兼容值 */
938
+ TOML_LEGACY: "text/x-toml",
939
+ /** SQL 脚本(.sql) */
940
+ SQL: "application/sql",
941
+ /** SQL 脚本/兼容值 */
942
+ SQL_LEGACY: "text/x-sql",
943
+ /** Markdown 格式文档(.md/.markdown) */
944
+ MARKDOWN: "text/markdown",
945
+ /** 富文本格式文档(.rtf) */
946
+ RTF: "application/rtf",
947
+ /** iCalendar 日历格式(.ics) */
948
+ CALENDAR: "text/calendar",
949
+ /** JPEG 图像(.jpg/.jpeg) */
950
+ JPEG: "image/jpeg",
951
+ /** JPG 图像(JPEG 别名,.jpg) */
952
+ JPG: "image/jpeg",
953
+ /** PNG 图像/无损压缩,支持透明(.png) */
954
+ PNG: "image/png",
955
+ /** GIF 图像/支持动画(.gif) */
956
+ GIF: "image/gif",
957
+ /** Windows 位图(.bmp) */
958
+ BMP: "image/bmp",
959
+ /** SVG 向量图形(.svg) */
960
+ SVG: "image/svg+xml",
961
+ /** APNG 动态图像(.apng) */
962
+ APNG: "image/apng",
963
+ /** AVIF 图像/高效压缩(.avif) */
964
+ AVIF: "image/avif",
965
+ /** 图标文件格式(.ico) */
966
+ ICO: "image/vnd.microsoft.icon",
967
+ /** 图标文件格式/兼容值(.ico) */
968
+ ICO_LEGACY: "image/x-icon",
969
+ /** WebP 图像/高效压缩(.webp) */
970
+ WEBP: "image/webp",
971
+ /** TIFF 图像(.tif/.tiff) */
972
+ TIFF: "image/tiff",
973
+ /** HEIC 图像/高效编码(.heic) */
974
+ HEIC: "image/heic",
975
+ /** HEIF 图像/高效编码(.heif) */
976
+ HEIF: "image/heif",
977
+ /** Adobe Photoshop 文件(.psd) */
978
+ PSD: "image/vnd.adobe.photoshop",
979
+ /** MP3 音频(.mp3) */
980
+ MP3: "audio/mpeg",
981
+ /** AAC 音频(.aac) */
982
+ AAC: "audio/aac",
983
+ /** MIDI 音乐文件(.mid/.midi) */
984
+ MIDI: "audio/midi",
985
+ /** OGG 音频(.oga) */
986
+ OGG_AUDIO: "audio/ogg",
987
+ /** Opus 音频(.opus) */
988
+ OPUS: "audio/opus",
989
+ /** FLAC 无损音频(.flac) */
990
+ FLAC: "audio/flac",
991
+ /** WAV 音频(.wav) */
992
+ WAV: "audio/wav",
993
+ /** WebM 音频(.weba) */
994
+ WEBM_AUDIO: "audio/webm",
995
+ /** RealAudio 音频(.ra/.ram) */
996
+ REAL_AUDIO: "audio/x-pn-realaudio",
997
+ /** MP4 视频(.mp4) */
998
+ MP4: "video/mp4",
999
+ /** MPEG 视频(.mpeg/.mpg) */
1000
+ MPEG: "video/mpeg",
1001
+ /** OGG 视频(.ogv) */
1002
+ OGG_VIDEO: "video/ogg",
1003
+ /** AVI 视频(.avi) */
1004
+ AVI: "video/x-msvideo",
1005
+ /** 3GPP 视频(.3gp) */
1006
+ THREE_GPP: "video/3gpp",
1007
+ /** 3GPP2 视频(.3g2) */
1008
+ THREE_GPP2: "video/3gpp2",
1009
+ /** WebM 视频(.webm) */
1010
+ WEBM: "video/webm",
1011
+ /** Matroska 视频(.mkv) */
1012
+ MKV: "video/x-matroska",
1013
+ /** Matroska 音频(.mka) */
1014
+ MKA: "audio/x-matroska",
1015
+ /** QuickTime 视频(.mov) */
1016
+ QUICKTIME: "video/quicktime",
1017
+ /** PDF 文档(.pdf) */
1018
+ PDF: "application/pdf",
1019
+ /** Word 97-2003 文档(.doc) */
1020
+ DOC: "application/msword",
1021
+ /** Word 2007+ 文档(.docx) */
1022
+ DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1023
+ /** Excel 2007+ 工作簿(.xlsx) */
1024
+ XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1025
+ /** 启用宏的Excel工作簿(.xlsm) */
1026
+ XLSM: "application/vnd.ms-excel.sheet.macroEnabled.12",
1027
+ /** Excel模板文件(.xltx) */
1028
+ XLTX: "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
1029
+ /** PowerPoint 2007+ 演示文稿(.pptx) */
1030
+ PPTX: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1031
+ /** PowerPoint 97-2003 演示文稿(.ppt) */
1032
+ PPT: "application/vnd.ms-powerpoint",
1033
+ /** OpenDocument 文本文档(.odt) */
1034
+ ODT: "application/vnd.oasis.opendocument.text",
1035
+ /** OpenDocument 表格文档(.ods) */
1036
+ ODS: "application/vnd.oasis.opendocument.spreadsheet",
1037
+ /** OpenDocument 演示文稿(.odp) */
1038
+ ODP: "application/vnd.oasis.opendocument.presentation",
1039
+ /** EPUB 电子书(.epub) */
1040
+ EPUB: "application/epub+zip",
1041
+ /** Kindle 电子书(.azw) */
1042
+ AZW: "application/vnd.amazon.ebook",
1043
+ /** ZIP 压缩文件(.zip) */
1044
+ ZIP: "application/zip",
1045
+ /** GZIP 压缩文件(.gz) */
1046
+ GZIP: "application/gzip",
1047
+ /** TAR 归档文件(.tar) */
1048
+ TAR: "application/x-tar",
1049
+ /** BZip 归档(.bz) */
1050
+ BZIP: "application/x-bzip",
1051
+ /** BZip2 归档(.bz2) */
1052
+ BZIP2: "application/x-bzip2",
1053
+ /** 7-Zip 压缩文件(.7z) */
1054
+ SEVEN_Z: "application/x-7z-compressed",
1055
+ /** RAR 压缩文件(.rar) */
1056
+ RAR: "application/vnd.rar",
1057
+ /** XZ 压缩文件(.xz) */
1058
+ XZ: "application/x-xz",
1059
+ /** Zstandard 压缩文件(.zst) */
1060
+ ZSTD: "application/zstd",
1061
+ /** ISO 光盘镜像(.iso) */
1062
+ ISO9660_IMAGE: "application/x-iso9660-image",
1063
+ /** JSON 数据格式(.json) */
1064
+ JSON: "application/json",
1065
+ /** JSON-LD 格式(.jsonld) */
1066
+ LD_JSON: "application/ld+json",
1067
+ /** Web App Manifest(.webmanifest) */
1068
+ MANIFEST: "application/manifest+json",
1069
+ /** Java 归档文件(.jar) */
1070
+ JAR: "application/java-archive",
1071
+ /** WebAssembly 二进制指令格式(.wasm) */
1072
+ WASM: "application/wasm",
1073
+ /** MS 嵌入式 OpenType 字体(.eot) */
1074
+ EOT: "application/vnd.ms-fontobject",
1075
+ /** OpenType 字体(.otf) */
1076
+ OTF: "font/otf",
1077
+ /** WOFF 字体(.woff) */
1078
+ WOFF: "font/woff",
1079
+ /** WOFF2 字体(.woff2) */
1080
+ WOFF2: "font/woff2",
1081
+ /** TrueType 字体(.ttf) */
1082
+ TTF: "font/ttf",
1083
+ /** Excel 97-2003 工作簿(.xls) */
1084
+ XLS: "application/vnd.ms-excel",
1085
+ /** Microsoft XPS 文档(.xps) */
1086
+ XPS: "application/vnd.ms-xpsdocument",
1087
+ /** Word 启用宏文档(.docm) */
1088
+ DOCM: "application/vnd.ms-word.document.macroEnabled.12"
1089
+ };
1090
+ /**
1091
+ * 协议/内容类型 MIME 常量
1092
+ * - 用于 HTTP 请求/响应内容协商,无对应文件扩展名
1093
+ */
1094
+ static PROTOCOL_MIME = {
1095
+ /** 通用二进制数据流 */
1096
+ OCTET_STREAM: "application/octet-stream",
1097
+ /** URL 编码表单 */
1098
+ FORM_URLENCODED: "application/x-www-form-urlencoded",
1099
+ /** multipart 表单 */
1100
+ FORM_DATA: "multipart/form-data",
1101
+ /** Server-Sent Events 数据流 */
1102
+ EVENT_STREAM: "text/event-stream",
1103
+ /** 问题详情 JSON(RFC 9457) */
1104
+ PROBLEM_JSON: "application/problem+json",
1105
+ /** JSON Patch(RFC 6902) */
1106
+ JSON_PATCH: "application/json-patch+json",
1107
+ /** JSON Merge Patch(RFC 7386) */
1108
+ MERGE_PATCH_JSON: "application/merge-patch+json"
1109
+ };
1110
+ /**
1111
+ * 根据文件后缀名获取对应的标准 MIME 类型(含历史兼容值)
1112
+ * - 支持带 `.` 或不带 `.` 的后缀名,不区分大小写
1113
+ * - 元组第一项始终为 IANA 官方标准 MIME,后续项为历史兼容值
1114
+ * - 仅查询文件类型 MIME,不包含无后缀对应的协议类型
1115
+ *
1116
+ * @param extension 文件后缀名(如 `".png"` / `"png"` / `".PNG"`)
1117
+ * @returns 标准 MIME + 兼容值的元组;如无匹配则返回 `undefined`
1118
+ * @example
1119
+ * ```ts
1120
+ * MimeUtil.fromExtension(".png"); // ["image/png"]
1121
+ * MimeUtil.fromExtension("ico"); // ["image/vnd.microsoft.icon", "image/x-icon"]
1122
+ * MimeUtil.fromExtension(".xml"); // ["application/xml", "text/xml"]
1123
+ * MimeUtil.fromExtension(".xyz"); // undefined
1124
+ * ```
1125
+ */
1126
+ static fromExtension(extension) {
1127
+ const ext = require_math.StringUtil.cast(extension).toLowerCase();
1128
+ const key = ext.startsWith(".") ? ext : `.${ext}`;
1129
+ return EXT_TO_MIME[key];
1130
+ }
1131
+ /**
1132
+ * 根据 MIME 类型获取对应的文件后缀名列表
1133
+ * - 一个 MIME 类型可能对应多个后缀名(如 `text/html` → `.html` / `.htm`)
1134
+ * - 兼容值和标准值映射到相同的后缀(如 `image/x-icon` 和 `image/vnd.microsoft.icon` 均返回 `[".ico"]`)
1135
+ * - 仅查询文件类型 MIME,协议类型无对应后缀
1136
+ *
1137
+ * @param mime MIME 类型字符串(如 `"image/png"` / `"IMAGE/PNG"`)
1138
+ * @returns 文件后缀名列表;如无匹配则返回 `undefined`
1139
+ * @example
1140
+ * ```ts
1141
+ * MimeUtil.toExtension("IMAGE/PNG"); // [".png"]
1142
+ * MimeUtil.toExtension("text/html"); // [".html", ".htm"]
1143
+ * MimeUtil.toExtension("image/jpeg"); // [".jpg", ".jpeg"]
1144
+ * MimeUtil.toExtension("application/octet-stream"); // undefined
1145
+ * ```
1146
+ */
1147
+ static toExtension(mime) {
1148
+ const m = require_math.StringUtil.cast(mime).toLowerCase();
1149
+ return MIME_TO_EXT.get(m);
1150
+ }
1151
+ };
1152
+ const EXT_TO_MIME = {
1153
+ ".txt": [MimeUtil.FILE_MIME.TEXT],
1154
+ ".html": [MimeUtil.FILE_MIME.HTML],
1155
+ ".htm": [MimeUtil.FILE_MIME.HTML],
1156
+ ".css": [MimeUtil.FILE_MIME.CSS],
1157
+ ".csv": [MimeUtil.FILE_MIME.CSV],
1158
+ ".tsv": [MimeUtil.FILE_MIME.TSV],
1159
+ ".xml": [MimeUtil.FILE_MIME.XML, MimeUtil.FILE_MIME.XML_LEGACY],
1160
+ ".xhtml": [MimeUtil.FILE_MIME.XHTML],
1161
+ ".xht": [MimeUtil.FILE_MIME.XHTML],
1162
+ ".js": [MimeUtil.FILE_MIME.JS],
1163
+ ".ts": [MimeUtil.FILE_MIME.TS],
1164
+ ".py": [MimeUtil.FILE_MIME.PY],
1165
+ ".sh": [MimeUtil.FILE_MIME.SH],
1166
+ ".c": [MimeUtil.FILE_MIME.C],
1167
+ ".cpp": [MimeUtil.FILE_MIME.CPP],
1168
+ ".cc": [MimeUtil.FILE_MIME.CPP],
1169
+ ".cxx": [MimeUtil.FILE_MIME.CPP],
1170
+ ".cs": [MimeUtil.FILE_MIME.CSHARP],
1171
+ ".java": [MimeUtil.FILE_MIME.JAVA],
1172
+ ".go": [MimeUtil.FILE_MIME.GO],
1173
+ ".rs": [MimeUtil.FILE_MIME.RUST],
1174
+ ".php": [MimeUtil.FILE_MIME.PHP],
1175
+ ".rb": [MimeUtil.FILE_MIME.RUBY],
1176
+ ".swift": [MimeUtil.FILE_MIME.SWIFT],
1177
+ ".yaml": [MimeUtil.FILE_MIME.YAML, MimeUtil.FILE_MIME.YAML_LEGACY],
1178
+ ".yml": [MimeUtil.FILE_MIME.YAML, MimeUtil.FILE_MIME.YAML_LEGACY],
1179
+ ".toml": [MimeUtil.FILE_MIME.TOML, MimeUtil.FILE_MIME.TOML_LEGACY],
1180
+ ".sql": [MimeUtil.FILE_MIME.SQL, MimeUtil.FILE_MIME.SQL_LEGACY],
1181
+ ".md": [MimeUtil.FILE_MIME.MARKDOWN],
1182
+ ".markdown": [MimeUtil.FILE_MIME.MARKDOWN],
1183
+ ".rtf": [MimeUtil.FILE_MIME.RTF],
1184
+ ".ics": [MimeUtil.FILE_MIME.CALENDAR],
1185
+ ".jpg": [MimeUtil.FILE_MIME.JPEG],
1186
+ ".jpeg": [MimeUtil.FILE_MIME.JPEG],
1187
+ ".png": [MimeUtil.FILE_MIME.PNG],
1188
+ ".gif": [MimeUtil.FILE_MIME.GIF],
1189
+ ".bmp": [MimeUtil.FILE_MIME.BMP],
1190
+ ".svg": [MimeUtil.FILE_MIME.SVG],
1191
+ ".apng": [MimeUtil.FILE_MIME.APNG],
1192
+ ".avif": [MimeUtil.FILE_MIME.AVIF],
1193
+ ".ico": [MimeUtil.FILE_MIME.ICO, MimeUtil.FILE_MIME.ICO_LEGACY],
1194
+ ".webp": [MimeUtil.FILE_MIME.WEBP],
1195
+ ".tif": [MimeUtil.FILE_MIME.TIFF],
1196
+ ".tiff": [MimeUtil.FILE_MIME.TIFF],
1197
+ ".heic": [MimeUtil.FILE_MIME.HEIC],
1198
+ ".heif": [MimeUtil.FILE_MIME.HEIF],
1199
+ ".psd": [MimeUtil.FILE_MIME.PSD],
1200
+ ".mp3": [MimeUtil.FILE_MIME.MP3],
1201
+ ".aac": [MimeUtil.FILE_MIME.AAC],
1202
+ ".mid": [MimeUtil.FILE_MIME.MIDI],
1203
+ ".midi": [MimeUtil.FILE_MIME.MIDI],
1204
+ ".oga": [MimeUtil.FILE_MIME.OGG_AUDIO],
1205
+ ".opus": [MimeUtil.FILE_MIME.OPUS],
1206
+ ".flac": [MimeUtil.FILE_MIME.FLAC],
1207
+ ".wav": [MimeUtil.FILE_MIME.WAV],
1208
+ ".weba": [MimeUtil.FILE_MIME.WEBM_AUDIO],
1209
+ ".ra": [MimeUtil.FILE_MIME.REAL_AUDIO],
1210
+ ".ram": [MimeUtil.FILE_MIME.REAL_AUDIO],
1211
+ ".mp4": [MimeUtil.FILE_MIME.MP4],
1212
+ ".mpeg": [MimeUtil.FILE_MIME.MPEG],
1213
+ ".mpg": [MimeUtil.FILE_MIME.MPEG],
1214
+ ".ogv": [MimeUtil.FILE_MIME.OGG_VIDEO],
1215
+ ".avi": [MimeUtil.FILE_MIME.AVI],
1216
+ ".3gp": [MimeUtil.FILE_MIME.THREE_GPP],
1217
+ ".3g2": [MimeUtil.FILE_MIME.THREE_GPP2],
1218
+ ".webm": [MimeUtil.FILE_MIME.WEBM],
1219
+ ".mkv": [MimeUtil.FILE_MIME.MKV],
1220
+ ".mka": [MimeUtil.FILE_MIME.MKA],
1221
+ ".mov": [MimeUtil.FILE_MIME.QUICKTIME],
1222
+ ".pdf": [MimeUtil.FILE_MIME.PDF],
1223
+ ".doc": [MimeUtil.FILE_MIME.DOC],
1224
+ ".docx": [MimeUtil.FILE_MIME.DOCX],
1225
+ ".xlsx": [MimeUtil.FILE_MIME.XLSX],
1226
+ ".xlsm": [MimeUtil.FILE_MIME.XLSM],
1227
+ ".xltx": [MimeUtil.FILE_MIME.XLTX],
1228
+ ".pptx": [MimeUtil.FILE_MIME.PPTX],
1229
+ ".ppt": [MimeUtil.FILE_MIME.PPT],
1230
+ ".odt": [MimeUtil.FILE_MIME.ODT],
1231
+ ".ods": [MimeUtil.FILE_MIME.ODS],
1232
+ ".odp": [MimeUtil.FILE_MIME.ODP],
1233
+ ".epub": [MimeUtil.FILE_MIME.EPUB],
1234
+ ".azw": [MimeUtil.FILE_MIME.AZW],
1235
+ ".zip": [MimeUtil.FILE_MIME.ZIP],
1236
+ ".gz": [MimeUtil.FILE_MIME.GZIP],
1237
+ ".tar": [MimeUtil.FILE_MIME.TAR],
1238
+ ".bz": [MimeUtil.FILE_MIME.BZIP],
1239
+ ".bz2": [MimeUtil.FILE_MIME.BZIP2],
1240
+ ".7z": [MimeUtil.FILE_MIME.SEVEN_Z],
1241
+ ".rar": [MimeUtil.FILE_MIME.RAR],
1242
+ ".xz": [MimeUtil.FILE_MIME.XZ],
1243
+ ".zst": [MimeUtil.FILE_MIME.ZSTD],
1244
+ ".iso": [MimeUtil.FILE_MIME.ISO9660_IMAGE],
1245
+ ".json": [MimeUtil.FILE_MIME.JSON],
1246
+ ".jsonld": [MimeUtil.FILE_MIME.LD_JSON],
1247
+ ".webmanifest": [MimeUtil.FILE_MIME.MANIFEST],
1248
+ ".jar": [MimeUtil.FILE_MIME.JAR],
1249
+ ".wasm": [MimeUtil.FILE_MIME.WASM],
1250
+ ".eot": [MimeUtil.FILE_MIME.EOT],
1251
+ ".otf": [MimeUtil.FILE_MIME.OTF],
1252
+ ".woff": [MimeUtil.FILE_MIME.WOFF],
1253
+ ".woff2": [MimeUtil.FILE_MIME.WOFF2],
1254
+ ".ttf": [MimeUtil.FILE_MIME.TTF],
1255
+ ".xls": [MimeUtil.FILE_MIME.XLS],
1256
+ ".xps": [MimeUtil.FILE_MIME.XPS],
1257
+ ".docm": [MimeUtil.FILE_MIME.DOCM]
1258
+ };
1259
+ const MIME_TO_EXT = (() => {
1260
+ const map = /* @__PURE__ */ new Map();
1261
+ for (const [ext, mimes] of Object.entries(EXT_TO_MIME)) for (const mime of mimes) {
1262
+ const exts = map.get(mime);
1263
+ if (exts) {
1264
+ if (!exts.includes(ext)) exts.push(ext);
1265
+ } else map.set(mime, [ext]);
1266
+ }
1267
+ return map;
1268
+ })();
1269
+ //#endregion
1270
+ //#region src/number/numberUtil.ts
1271
+ /**
1272
+ * 数字工具类
1273
+ */
1274
+ var NumberUtil = class {
1275
+ /**
1276
+ * 数字区间检查函数
1277
+ *
1278
+ * @param input 待检查数字
1279
+ * @param interval 由两个数字组成的元组 [left, right]
1280
+ * @param includeLeft 是否包含左边界(默认 true)
1281
+ * @param includeRight 是否包含右边界(默认 false)
1282
+ * @returns 是否在区间内
1283
+ * @example
1284
+ * ```ts
1285
+ * NumberUtil.within(5, [1, 10]); // true
1286
+ * NumberUtil.within(1, [1, 10], false); // false
1287
+ * ```
1288
+ */
1289
+ static within(input, interval, includeLeft = true, includeRight = false) {
1290
+ if (!require_math.TypeUtil.isNumber(input) || require_math.TypeUtil.isInfinity(input)) throw new Error("function [within] Expected parameter [input] to be a finite number.");
1291
+ if (!require_math.TypeUtil.isArray(interval) || interval.length !== 2) throw new Error("function [within] Expected parameter [interval] to be a tuple with 2 numbers.");
1292
+ const [left, right] = interval;
1293
+ if (left > right) throw new Error(`Invalid interval: left (${left}) must be <= right (${right}).`);
1294
+ if (includeLeft && includeRight) return input >= left && input <= right;
1295
+ else if (includeLeft) return input >= left && input < right;
1296
+ else if (includeRight) return input > left && input <= right;
1297
+ else return input > left && input < right;
1298
+ }
1299
+ };
1300
+ //#endregion
1301
+ //#region src/object/objectUtil.ts
1302
+ /**
1303
+ * 对象工具类
1304
+ */
1305
+ var ObjectUtil = class {
1306
+ static keys(value) {
1307
+ return Object.keys(value);
1308
+ }
1309
+ static values(value) {
1310
+ return Object.values(value);
1311
+ }
1312
+ static entries(value) {
1313
+ return Object.entries(value);
1314
+ }
1315
+ /**
1316
+ * 映射对象条目
1317
+ * - 将对象的键值对映射为新的键值对
1318
+ *
1319
+ * @param plainObject 对象
1320
+ * @param toEntry 映射函数
1321
+ * @returns 映射后的新对象
1322
+ * @example
1323
+ * ```ts
1324
+ * const obj = { a: 1, b: 2 };
1325
+ *
1326
+ * ObjectUtil.entriesMap(obj, (k, v) => [k, v * 2]); // { a: 2, b: 4 }
1327
+ *
1328
+ * ObjectUtil.entriesMap(obj, (k, v) => [`prefix_${String(k)}`, `${v}x`]); // { prefix_a: "1x", prefix_b: "2x" }
1329
+ * ```
1330
+ */
1331
+ static entriesMap(plainObject, toEntry) {
1332
+ const defaultResult = {};
1333
+ if (!require_math.TypeUtil.isPlainObject(plainObject)) return defaultResult;
1334
+ return this.entries(plainObject).reduce((acc, [key, value]) => {
1335
+ const [newKey, newValue] = toEntry(key, value);
1336
+ Object.defineProperty(acc, newKey, {
1337
+ value: newValue,
1338
+ enumerable: true,
1339
+ writable: true,
1340
+ configurable: true
1341
+ });
1342
+ return acc;
1343
+ }, defaultResult);
1344
+ }
1345
+ static pick(obj, keys) {
1346
+ const result = {};
1347
+ if (!require_math.TypeUtil.isPlainObject(obj)) return result;
1348
+ if (!require_math.TypeUtil.isArray(keys)) return obj;
1349
+ return keys.reduce((acc, key) => {
1350
+ if (key in obj) Object.defineProperty(acc, key, {
1351
+ value: obj[key],
1352
+ enumerable: true,
1353
+ writable: true,
1354
+ configurable: true
1355
+ });
1356
+ return acc;
1357
+ }, result);
1358
+ }
1359
+ static omit(obj, keys) {
1360
+ const result = {};
1361
+ if (!require_math.TypeUtil.isPlainObject(obj)) return result;
1362
+ if (!require_math.TypeUtil.isArray(keys)) return obj;
1363
+ const keysToOmit = new Set(keys);
1364
+ return Object.keys(obj).reduce((acc, key) => {
1365
+ if (!keysToOmit.has(key)) Object.defineProperty(acc, key, {
1366
+ value: obj[key],
1367
+ enumerable: true,
1368
+ writable: true,
1369
+ configurable: true
1370
+ });
1371
+ return acc;
1372
+ }, result);
1373
+ }
1374
+ static invert(obj) {
1375
+ const result = {};
1376
+ if (!require_math.TypeUtil.isPlainObject(obj)) return result;
1377
+ for (const [k, v] of this.entries(obj)) if (require_math.TypeUtil.isString(v) || require_math.TypeUtil.isNumber(v) || require_math.TypeUtil.isSymbol(v)) result[v] = k;
1378
+ return result;
1379
+ }
1380
+ static crush(obj) {
1381
+ if (!obj) return {};
1382
+ function crushReducer(crushed, value, path) {
1383
+ if (require_math.TypeUtil.isPlainObject(value) || require_math.TypeUtil.isArray(value)) for (const [prop, propValue] of Object.entries(value)) crushReducer(crushed, propValue, path ? `${path}.${prop}` : prop);
1384
+ else crushed[path] = value;
1385
+ return crushed;
1386
+ }
1387
+ return crushReducer({}, obj, "");
1388
+ }
1389
+ static enumKeys(enumeration) {
1390
+ const [isEnum, isBidirectionalEnum] = require_math.TypeUtil.isEnumeration(enumeration);
1391
+ if (!isEnum) throw Error("function [enumKeys] expected parameter to be a enum, and requires at least one member");
1392
+ const keys = this.keys(enumeration);
1393
+ if (isBidirectionalEnum) return keys.splice(keys.length / 2, keys.length / 2);
1394
+ return keys;
1395
+ }
1396
+ static enumValues(enumeration) {
1397
+ const [isEnum, isBidirectionalEnum] = require_math.TypeUtil.isEnumeration(enumeration);
1398
+ if (!isEnum) throw Error("function [enumValues] expected parameter to be a enum, and requires at least one member");
1399
+ const values = this.values(enumeration);
1400
+ if (isBidirectionalEnum) return values.splice(values.length / 2, values.length / 2);
1401
+ return values;
1402
+ }
1403
+ static enumEntries(enumeration) {
1404
+ const [isEnum, isBidirectionalEnum] = require_math.TypeUtil.isEnumeration(enumeration);
1405
+ if (!isEnum) throw Error("function [enumEntries] expected parameter to be a enum, and requires at least one member");
1406
+ const entries = this.entries(enumeration);
1407
+ if (isBidirectionalEnum) return entries.splice(entries.length / 2, entries.length / 2);
1408
+ return entries;
1409
+ }
1410
+ };
1411
+ //#endregion
1412
+ //#region src/theme/themeUtil.ts
1413
+ /**
1414
+ * 主题工具类
1415
+ */
1416
+ var ThemeUtil = class {
1417
+ /**
1418
+ * 固定主题类型(仅亮色/暗色)
1419
+ *
1420
+ * @example
1421
+ * ```ts
1422
+ * ThemeUtil.THEME.LIGHT; // "light"
1423
+ * ThemeUtil.THEME.DARK; // "dark"
1424
+ * ```
1425
+ */
1426
+ static THEME = {
1427
+ LIGHT: "light",
1428
+ DARK: "dark"
1429
+ };
1430
+ /**
1431
+ * 主题模式(支持跟随系统)
1432
+ *
1433
+ * @example
1434
+ * ```ts
1435
+ * ThemeUtil.THEME_MODE.SYSTEM; // "system"
1436
+ * ThemeUtil.THEME_MODE.DARK; // "dark"
1437
+ * ```
1438
+ */
1439
+ static THEME_MODE = {
1440
+ LIGHT: "light",
1441
+ DARK: "dark",
1442
+ SYSTEM: "system"
1443
+ };
1444
+ };
1445
+ //#endregion
1446
+ //#region src/tree/utils.ts
1447
+ function getFinalChildrenKey(tree, meta, options) {
1448
+ if (require_math.TypeUtil.isFunction(options.getChildrenKey)) {
1449
+ const dynamicChildrenKey = options.getChildrenKey(tree, meta);
1450
+ if (dynamicChildrenKey && dynamicChildrenKey !== null) return dynamicChildrenKey;
1451
+ }
1452
+ return options.childrenKey;
1453
+ }
1454
+ //#endregion
1455
+ //#region src/tree/filter.ts
1456
+ function preImpl$3(row, callback, options) {
1457
+ if (!callback(row, options)) return;
1458
+ const finalChildrenKey = getFinalChildrenKey(row, options, options);
1459
+ const children = row[finalChildrenKey];
1460
+ let newChildren;
1461
+ if (require_math.TypeUtil.isArray(children)) {
1462
+ const nextLevelOptions = {
1463
+ ...options,
1464
+ parents: [...options.parents, row],
1465
+ depth: options.depth + 1
1466
+ };
1467
+ newChildren = children.map((c) => preImpl$3(c, callback, nextLevelOptions)).filter((c) => !!c);
1468
+ }
1469
+ return {
1470
+ ...row,
1471
+ [finalChildrenKey]: newChildren
1472
+ };
1473
+ }
1474
+ function postImpl$3(row, callback, options) {
1475
+ const finalChildrenKey = getFinalChildrenKey(row, options, options);
1476
+ const children = row[finalChildrenKey];
1477
+ let newChildren;
1478
+ if (require_math.TypeUtil.isArray(children)) {
1479
+ const nextLevelOptions = {
1480
+ ...options,
1481
+ parents: [...options.parents, row],
1482
+ depth: options.depth + 1
1483
+ };
1484
+ newChildren = children.map((c) => postImpl$3(c, callback, nextLevelOptions)).filter((c) => !!c);
1485
+ }
1486
+ if (!callback(row, options)) return;
1487
+ return {
1488
+ ...row,
1489
+ [finalChildrenKey]: newChildren
1490
+ };
1491
+ }
1492
+ function breadthImpl$3(row, callback, options) {
1493
+ const queue = [{
1494
+ queueRow: row,
1495
+ queueOptions: options
1496
+ }];
1497
+ const resultCache = /* @__PURE__ */ new WeakMap();
1498
+ const newNodeCache = /* @__PURE__ */ new WeakMap();
1499
+ const childrenKeyCache = /* @__PURE__ */ new WeakMap();
1500
+ let result;
1501
+ const runQueue = () => {
1502
+ if (queue.length === 0) return result;
1503
+ const { queueRow, queueOptions } = queue.shift();
1504
+ const finalChildrenKey = getFinalChildrenKey(queueRow, queueOptions, queueOptions);
1505
+ const children = queueRow[finalChildrenKey];
1506
+ if (require_math.TypeUtil.isArray(children)) {
1507
+ const nextLevelOptions = {
1508
+ ...queueOptions,
1509
+ parents: [...queueOptions.parents, queueRow],
1510
+ depth: queueOptions.depth + 1
1511
+ };
1512
+ const subQueueItems = children.map((queueRow) => ({
1513
+ queueRow,
1514
+ queueOptions: nextLevelOptions
1515
+ }));
1516
+ queue.push(...subQueueItems);
1517
+ }
1518
+ const parent = ArrayUtil.last(queueOptions.parents);
1519
+ const isTopNode = queueOptions.depth === 0;
1520
+ const parentResult = parent && resultCache.get(parent);
1521
+ if (!isTopNode && !parentResult) return runQueue();
1522
+ const callbackResult = callback(queueRow, queueOptions);
1523
+ if (isTopNode && !callbackResult) return;
1524
+ const newNode = {
1525
+ ...queueRow,
1526
+ [finalChildrenKey]: void 0
1527
+ };
1528
+ if (isTopNode) result = newNode;
1529
+ resultCache.set(queueRow, callbackResult);
1530
+ newNodeCache.set(queueRow, newNode);
1531
+ childrenKeyCache.set(queueRow, finalChildrenKey);
1532
+ if (callbackResult && parent) {
1533
+ const parentNewNode = newNodeCache.get(parent);
1534
+ const parentChildrenKey = childrenKeyCache.get(parent);
1535
+ if (parentNewNode && parentChildrenKey) {
1536
+ if (!parentNewNode[parentChildrenKey]) parentNewNode[parentChildrenKey] = [];
1537
+ parentNewNode[parentChildrenKey].push(newNode);
1538
+ }
1539
+ }
1540
+ return runQueue();
1541
+ };
1542
+ return runQueue();
1543
+ }
1544
+ const treeFilterStrategies = {
1545
+ pre: preImpl$3,
1546
+ post: postImpl$3,
1547
+ breadth: breadthImpl$3
1548
+ };
1549
+ //#endregion
1550
+ //#region src/tree/find.ts
1551
+ function preImpl$2(row, callback, options) {
1552
+ if (callback(row, options)) return row;
1553
+ const children = row[getFinalChildrenKey(row, options, options)];
1554
+ if (require_math.TypeUtil.isArray(children)) for (const child of children) {
1555
+ const result = preImpl$2(child, callback, {
1556
+ ...options,
1557
+ parents: [...options.parents, row],
1558
+ depth: options.depth + 1
1559
+ });
1560
+ if (result) return result;
1561
+ }
1562
+ }
1563
+ function postImpl$2(row, callback, options) {
1564
+ const children = row[getFinalChildrenKey(row, options, options)];
1565
+ if (require_math.TypeUtil.isArray(children)) for (const child of children) {
1566
+ const result = postImpl$2(child, callback, {
1567
+ ...options,
1568
+ parents: [...options.parents, row],
1569
+ depth: options.depth + 1
1570
+ });
1571
+ if (result) return result;
1572
+ }
1573
+ if (callback(row, options)) return row;
1574
+ }
1575
+ function breadthImpl$2(row, callback, options) {
1576
+ const queue = [{
1577
+ queueRow: row,
1578
+ queueOptions: options
1579
+ }];
1580
+ const runQueue = () => {
1581
+ if (queue.length === 0) return;
1582
+ const { queueRow, queueOptions } = queue.shift();
1583
+ const children = queueRow[getFinalChildrenKey(queueRow, queueOptions, queueOptions)];
1584
+ if (require_math.TypeUtil.isArray(children)) {
1585
+ const nextLevelOptions = {
1586
+ ...queueOptions,
1587
+ parents: [...queueOptions.parents, queueRow],
1588
+ depth: queueOptions.depth + 1
1589
+ };
1590
+ const subQueueItems = children.map((queueRow) => ({
1591
+ queueRow,
1592
+ queueOptions: nextLevelOptions
1593
+ }));
1594
+ queue.push(...subQueueItems);
1595
+ }
1596
+ if (callback(queueRow, queueOptions)) return queueRow;
1597
+ return runQueue();
1598
+ };
1599
+ return runQueue();
1600
+ }
1601
+ const treeFindStrategies = {
1602
+ pre: preImpl$2,
1603
+ post: postImpl$2,
1604
+ breadth: breadthImpl$2
1605
+ };
1606
+ //#endregion
1607
+ //#region src/tree/forEach.ts
1608
+ function preImpl$1(row, callback, options) {
1609
+ callback(row, options);
1610
+ const children = row[getFinalChildrenKey(row, options, options)];
1611
+ if (require_math.TypeUtil.isArray(children)) {
1612
+ const nextLevelOptions = {
1613
+ ...options,
1614
+ parents: [...options.parents, row],
1615
+ depth: options.depth + 1
1616
+ };
1617
+ for (const child of children) preImpl$1(child, callback, nextLevelOptions);
1618
+ }
1619
+ }
1620
+ function postImpl$1(row, callback, options) {
1621
+ const children = row[getFinalChildrenKey(row, options, options)];
1622
+ if (require_math.TypeUtil.isArray(children)) {
1623
+ const nextLevelOptions = {
1624
+ ...options,
1625
+ parents: [...options.parents, row],
1626
+ depth: options.depth + 1
1627
+ };
1628
+ for (const child of children) postImpl$1(child, callback, nextLevelOptions);
1629
+ }
1630
+ callback(row, options);
1631
+ }
1632
+ function breadthImpl$1(row, callback, options) {
1633
+ const queue = [{
1634
+ queueRow: row,
1635
+ queueOptions: options
1636
+ }];
1637
+ const runQueue = () => {
1638
+ if (queue.length === 0) return;
1639
+ const { queueRow, queueOptions } = queue.shift();
1640
+ const children = queueRow[getFinalChildrenKey(queueRow, queueOptions, queueOptions)];
1641
+ if (require_math.TypeUtil.isArray(children)) {
1642
+ const nextLevelOptions = {
1643
+ ...queueOptions,
1644
+ parents: [...queueOptions.parents, queueRow],
1645
+ depth: queueOptions.depth + 1
1646
+ };
1647
+ const subQueueItems = children.map((queueRow) => ({
1648
+ queueRow,
1649
+ queueOptions: nextLevelOptions
1650
+ }));
1651
+ queue.push(...subQueueItems);
1652
+ }
1653
+ callback(queueRow, queueOptions);
1654
+ runQueue();
1655
+ };
1656
+ runQueue();
1657
+ }
1658
+ const treeForEachStrategies = {
1659
+ pre: preImpl$1,
1660
+ post: postImpl$1,
1661
+ breadth: breadthImpl$1
1662
+ };
1663
+ //#endregion
1664
+ //#region src/tree/map.ts
1665
+ function preImpl(row, callback, options) {
1666
+ const finalChildrenKey = getFinalChildrenKey(row, options, options);
1667
+ const result = callback(row, options);
1668
+ const children = row[finalChildrenKey];
1669
+ let newChildren;
1670
+ if (require_math.TypeUtil.isArray(children)) {
1671
+ const nextLevelOptions = {
1672
+ ...options,
1673
+ parents: [...options.parents, row],
1674
+ depth: options.depth + 1
1675
+ };
1676
+ newChildren = children.map((c) => preImpl(c, callback, nextLevelOptions));
1677
+ }
1678
+ return {
1679
+ ...result,
1680
+ [finalChildrenKey]: newChildren
1681
+ };
1682
+ }
1683
+ function postImpl(row, callback, options) {
1684
+ const finalChildrenKey = getFinalChildrenKey(row, options, options);
1685
+ const children = row[finalChildrenKey];
1686
+ let newChildren;
1687
+ if (require_math.TypeUtil.isArray(children)) {
1688
+ const nextLevelOptions = {
1689
+ ...options,
1690
+ parents: [...options.parents, row],
1691
+ depth: options.depth + 1
1692
+ };
1693
+ newChildren = children.map((c) => postImpl(c, callback, nextLevelOptions));
1694
+ }
1695
+ return {
1696
+ ...callback(row, options),
1697
+ [finalChildrenKey]: newChildren
1698
+ };
1699
+ }
1700
+ function breadthImpl(row, callback, options) {
1701
+ const queue = [{
1702
+ queueRow: row,
1703
+ queueOptions: options
1704
+ }];
1705
+ const cache = /* @__PURE__ */ new WeakMap();
1706
+ const childrenKeyCache = /* @__PURE__ */ new WeakMap();
1707
+ let result;
1708
+ const runQueue = () => {
1709
+ if (queue.length === 0) return result;
1710
+ const { queueRow, queueOptions } = queue.shift();
1711
+ const finalChildrenKey = getFinalChildrenKey(queueRow, queueOptions, queueOptions);
1712
+ const children = queueRow[finalChildrenKey];
1713
+ if (require_math.TypeUtil.isArray(children)) {
1714
+ const nextLevelOptions = {
1715
+ ...queueOptions,
1716
+ parents: [...queueOptions.parents, queueRow],
1717
+ depth: queueOptions.depth + 1
1718
+ };
1719
+ const subQueueItems = children.map((queueRow) => ({
1720
+ queueRow,
1721
+ queueOptions: nextLevelOptions
1722
+ }));
1723
+ queue.push(...subQueueItems);
1724
+ }
1725
+ const res = callback(queueRow, queueOptions);
1726
+ cache.set(queueRow, res);
1727
+ childrenKeyCache.set(queueRow, finalChildrenKey);
1728
+ const parent = ArrayUtil.last(queueOptions.parents);
1729
+ if (parent) {
1730
+ const newParent = cache.get(parent);
1731
+ const parentChildrenKey = childrenKeyCache.get(parent);
1732
+ if (newParent && parentChildrenKey) if (newParent[parentChildrenKey]) newParent[parentChildrenKey].push(res);
1733
+ else newParent[parentChildrenKey] = [res];
1734
+ }
1735
+ if (queueOptions.depth === 0) result = res;
1736
+ return runQueue();
1737
+ };
1738
+ return runQueue();
1739
+ }
1740
+ const treeMapStrategies = {
1741
+ pre: preImpl,
1742
+ post: postImpl,
1743
+ breadth: breadthImpl
1744
+ };
1745
+ //#endregion
1746
+ //#region src/tree/treeUtil.ts
1747
+ /**
1748
+ * 树结构工具类
1749
+ *
1750
+ * 引用策略约定:
1751
+ * - 转换类方法(`rowsToTree` / `treeToRows` / `filter` / `map`):不突变输入;输出的每个节点均为**新对象引用**(来源节点的浅拷贝,仅自有可枚举属性;非枚举属性、原型链、getter 及深层嵌套对象不保证)。
1752
+ * - 查询类方法(`find` / `forEach`):按查询语义直接使用**原对象引用**。
1753
+ */
1754
+ var TreeUtil = class {
1755
+ /**
1756
+ * 行结构 转 树结构
1757
+ * - 将平铺的数组转换为树形结构
1758
+ * - 返回的树结构与输入行无共享节点(新对象引用),输入行不会被突变
1759
+ * - 重复 id 的行只取首次出现;仅叶子/缺失父节点的 id 会作为根节点,且每个根节点只输出一次
1760
+ *
1761
+ * @param rows 行数据数组
1762
+ * @param options 配置项
1763
+ * @returns 树结构数组(所有节点均包含 children 数组)
1764
+ * @example
1765
+ * ```ts
1766
+ * const rows = [
1767
+ * { id: 1, parentId: null },
1768
+ * { id: 2, parentId: 1 },
1769
+ * ];
1770
+ * TreeUtil.rowsToTree(rows); // [{ id: 1, parentId: null, children: [{ id: 2, parentId: 1, children: [] }] }]
1771
+ * ```
1772
+ */
1773
+ static rowsToTree(rows, options) {
1774
+ const { parentIdKey = "parentId", rowKey = "id", childrenKey = "children" } = options || {};
1775
+ const result = [];
1776
+ const map = /* @__PURE__ */ new Map();
1777
+ const processedIds = /* @__PURE__ */ new Set();
1778
+ for (const row of rows) {
1779
+ const id = row[rowKey];
1780
+ if (!map.get(id)) map.set(id, { ...row });
1781
+ }
1782
+ for (const row of rows) {
1783
+ const id = row[rowKey];
1784
+ if (processedIds.has(id)) continue;
1785
+ processedIds.add(id);
1786
+ const parentId = row[parentIdKey];
1787
+ const node = map.get(id);
1788
+ if (!node) continue;
1789
+ if (require_math.TypeUtil.isNullish(parentId) || parentId === id || !map.has(parentId)) {
1790
+ result.push(node);
1791
+ continue;
1792
+ }
1793
+ const parent = map.get(parentId);
1794
+ const siblings = parent[childrenKey];
1795
+ if (require_math.TypeUtil.isNullish(siblings)) parent[childrenKey] = [node];
1796
+ else if (Array.isArray(siblings)) siblings.push(node);
1797
+ else {
1798
+ const message = `The key "${childrenKey.toString()}" in parent item is not an array.`;
1799
+ throw new Error(message);
1800
+ }
1801
+ }
1802
+ for (const root of result) this.forEach(root, (node) => {
1803
+ const record = node;
1804
+ const children = record[childrenKey];
1805
+ if (require_math.TypeUtil.isNullish(children)) record[childrenKey] = [];
1806
+ else if (!Array.isArray(children)) {
1807
+ const message = `The key "${childrenKey.toString()}" in parent item is not an array.`;
1808
+ throw new Error(message);
1809
+ }
1810
+ }, { childrenKey });
1811
+ return result;
1812
+ }
1813
+ /**
1814
+ * 树结构 转 行结构
1815
+ * - 将树形结构扁平化为数组
1816
+ *
1817
+ * @param tree 树结构数据 (单个节点或节点数组)
1818
+ * @param options 配置项
1819
+ * @returns 扁平化后的数组
1820
+ * @example
1821
+ * ```ts
1822
+ * const tree = [{ id: 1, children: [{ id: 2 }] }];
1823
+ * TreeUtil.treeToRows(tree); // [{ id: 1, children: undefined }, { id: 2, children: undefined }]
1824
+ * ```
1825
+ */
1826
+ static treeToRows(tree, options = {}) {
1827
+ const { childrenKey = "children" } = options;
1828
+ const result = [];
1829
+ if (!tree) return result;
1830
+ this.forEach(tree, (t) => result.push({
1831
+ ...t,
1832
+ [childrenKey]: void 0
1833
+ }), options);
1834
+ return result;
1835
+ }
1836
+ /**
1837
+ * 遍历树节点
1838
+ *
1839
+ * @param tree 树结构数据
1840
+ * @param callback 回调函数
1841
+ * @param options 配置项
1842
+ * @example
1843
+ * ```ts
1844
+ * const tree = [{ id: 1, children: [{ id: 2 }] }];
1845
+ * const ids: number[] = [];
1846
+ * TreeUtil.forEach(tree, (node) => ids.push(node.id)); // ids: [1, 2] (pre-order default)
1847
+ * ```
1848
+ */
1849
+ static forEach(tree, callback, options = {}) {
1850
+ const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
1851
+ const traversalMethod = treeForEachStrategies[strategy];
1852
+ const innerOptions = {
1853
+ childrenKey,
1854
+ depth: 0,
1855
+ parents: [],
1856
+ getChildrenKey
1857
+ };
1858
+ if (require_math.TypeUtil.isArray(tree)) for (const row of tree) traversalMethod(row, callback, innerOptions);
1859
+ else traversalMethod(tree, callback, innerOptions);
1860
+ }
1861
+ /**
1862
+ * 查找树节点
1863
+ * - 返回第一个回调返回 true 的节点
1864
+ *
1865
+ * @param tree 树结构数据
1866
+ * @param callback 回调函数
1867
+ * @param options 配置项
1868
+ * @returns 找到的节点,未找到则返回 undefined
1869
+ * @example
1870
+ * ```ts
1871
+ * const tree = [{ id: 1, children: [{ id: 2 }] }];
1872
+ * TreeUtil.find(tree, (node) => node.id === 2); // { id: 2, ... }
1873
+ * ```
1874
+ */
1875
+ static find(tree, callback, options = {}) {
1876
+ const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
1877
+ const traversalMethod = treeFindStrategies[strategy];
1878
+ const innerOptions = {
1879
+ childrenKey,
1880
+ depth: 0,
1881
+ parents: [],
1882
+ getChildrenKey
1883
+ };
1884
+ if (require_math.TypeUtil.isArray(tree)) {
1885
+ for (const row of tree) {
1886
+ const result = traversalMethod(row, callback, innerOptions);
1887
+ if (result) return result;
1888
+ }
1889
+ return;
1890
+ }
1891
+ return traversalMethod(tree, callback, innerOptions);
1892
+ }
1893
+ static filter(tree, callback, options = {}) {
1894
+ const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
1895
+ const traversalMethod = treeFilterStrategies[strategy];
1896
+ const innerOptions = {
1897
+ childrenKey,
1898
+ depth: 0,
1899
+ parents: [],
1900
+ getChildrenKey
1901
+ };
1902
+ return require_math.TypeUtil.isArray(tree) ? tree.map((row) => traversalMethod(row, callback, innerOptions)).filter((t) => !!t) : traversalMethod(tree, callback, innerOptions) || [];
1903
+ }
1904
+ static map(tree, callback, options = {}) {
1905
+ const { childrenKey = "children", strategy = "pre", getChildrenKey } = options;
1906
+ const traversalMethod = treeMapStrategies[strategy];
1907
+ const innerOptions = {
1908
+ childrenKey,
1909
+ depth: 0,
1910
+ parents: [],
1911
+ getChildrenKey
1912
+ };
1913
+ return require_math.TypeUtil.isArray(tree) ? tree.map((row) => traversalMethod(row, callback, innerOptions)) : traversalMethod(tree, callback, innerOptions);
1914
+ }
1915
+ };
1916
+ //#endregion
1917
+ //#region src/validate/validateUtil.ts
1918
+ /**
1919
+ * 验证工具类
1920
+ */
1921
+ var ValidateUtil = class {
1922
+ static _phone = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
1923
+ /**
1924
+ * 验证是否为手机号码
1925
+ * @example
1926
+ * ```ts
1927
+ * ValidateUtil.isPhone("13800138000"); // true
1928
+ * ```
1929
+ */
1930
+ static isPhone(input) {
1931
+ return this._phone.test(input.toString());
1932
+ }
1933
+ static _telephone = /^(((0\d{2,3})-)?((\d{7,8})|(400\d{7})|(800\d{7}))(-(\d{1,4}))?)$/;
1934
+ /**
1935
+ * 验证是否为固定电话
1936
+ * @example
1937
+ * ```ts
1938
+ * ValidateUtil.isTelephone("010-12345678"); // true
1939
+ * ```
1940
+ */
1941
+ static isTelephone(input) {
1942
+ return this._telephone.test(input.toString());
1943
+ }
1944
+ static _IMEI = /^\d{15,17}$/;
1945
+ /**
1946
+ * 验证是否为移动设备识别码
1947
+ * @example
1948
+ * ```ts
1949
+ * ValidateUtil.isIMEI("490154203237518"); // true
1950
+ * ```
1951
+ */
1952
+ static isIMEI(input) {
1953
+ return this._IMEI.test(input.toString());
1954
+ }
1955
+ static _email = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-z\-0-9]+\.)+[a-z]{2,}))$/i;
1956
+ /**
1957
+ * 验证是否为电子邮箱
1958
+ * @example
1959
+ * ```ts
1960
+ * ValidateUtil.isEmail("dev@example.com"); // true
1961
+ * ```
1962
+ */
1963
+ static isEmail(input) {
1964
+ return this._email.test(input.toString());
1965
+ }
1966
+ static _link = /^(https?:\/\/)?(([\w-]+(\.[\w-]+)*\.[a-z]{2,6})|((\d{1,3}\.){3}\d{1,3}))(:\d+)?(\/\S*)?$/i;
1967
+ /**
1968
+ * 验证是否为 http(s) 链接
1969
+ * @example
1970
+ * ```ts
1971
+ * ValidateUtil.isHttpLink("https://example.com/path"); // true
1972
+ * ```
1973
+ */
1974
+ static isHttpLink(input) {
1975
+ return this._link.test(input.toString());
1976
+ }
1977
+ static _portLink = /^(https?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$/i;
1978
+ /**
1979
+ * 验证是否为端口号链接
1980
+ * @example
1981
+ * ```ts
1982
+ * ValidateUtil.isPortLink("http://example.com:8080"); // true
1983
+ * ```
1984
+ */
1985
+ static isPortLink(input) {
1986
+ return this._portLink.test(input.toString());
1987
+ }
1988
+ static _thunderLink = /^thunderx?:\/\/[a-zA-Z\d]+=$/i;
1989
+ /**
1990
+ * 验证是否为迅雷链接
1991
+ * @example
1992
+ * ```ts
1993
+ * ValidateUtil.isThunderLink("thunder://QUFodHRwOi8vZXhhbXBsZS5jb20vZmlsZQ=="); // true
1994
+ * ```
1995
+ */
1996
+ static isThunderLink(input) {
1997
+ return this._thunderLink.test(input.toString());
1998
+ }
1999
+ static _uscc = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/;
2000
+ /**
2001
+ * 验证是否为统一社会信用代码(USCC / USCI / USCCS)
2002
+ * - 固定 18 位:1 位登记管理部门码 + 1 位机构类别码 + 6 位行政区划码 + 9 位主体标识码 + 1 位校验码
2003
+ * - 字符集:数字 0-9 + 大写英文字母(排除 I、O、Z、S、V,防视觉混淆)
2004
+ * - 第 1-2 位允许字母(如登记管理部门码 `A`,代表"其他"),第 3-8 位行政区划码为纯数字
2005
+ *
2006
+ * @param input 待校验字符串
2007
+ * @returns 是否为合法格式的统一社会信用代码
2008
+ * @example
2009
+ * ```ts
2010
+ * ValidateUtil.isUSCC("91350100M000100Y43"); // true
2011
+ * ValidateUtil.isUSCC("A1350100M000100Y43"); // true (A 开头"其他"部门码)
2012
+ * ```
2013
+ */
2014
+ static isUSCC(input) {
2015
+ return this._uscc.test(input.toString());
2016
+ }
2017
+ /**
2018
+ * 验证是否为统一社会信用代码(同 `isUSCC`)
2019
+ * - USCC / USCI / USCCS 均指统一社会信用代码,固定 18 位
2020
+ * - 15 位旧税务登记号在 2015 年"三证合一"前使用,现已作废,视为无效
2021
+ *
2022
+ * @param input 待校验字符串
2023
+ * @returns 是否为合法代码
2024
+ * @example
2025
+ * ```ts
2026
+ * ValidateUtil.isUSCCS("91350100M000100Y43"); // true (18位)
2027
+ * ValidateUtil.isUSCCS("91350100M000100"); // false (15位旧号,已作废)
2028
+ * ```
2029
+ */
2030
+ static isUSCCS(input) {
2031
+ return this.isUSCC(input);
2032
+ }
2033
+ static _dirPathWindows = /^[a-z]:\\(?:\w+\\?)*$/i;
2034
+ /**
2035
+ * 验证是否为 Windows 系统文件夹路径
2036
+ * @example
2037
+ * ```ts
2038
+ * ValidateUtil.isDirPathWindows("C:\\Users\\pawover\\"); // true
2039
+ * ```
2040
+ */
2041
+ static isDirPathWindows(input) {
2042
+ return this._dirPathWindows.test(input.toString());
2043
+ }
2044
+ static _filePathWindows = /^[a-z]:\\(?:\w+\\)*\w+\.\w+$/i;
2045
+ /**
2046
+ * 验证是否为 Windows 系统文件路径
2047
+ * @example
2048
+ * ```ts
2049
+ * ValidateUtil.isFilePathWindows("C:\\Users\\pawover\\a.txt"); // true
2050
+ * ```
2051
+ */
2052
+ static isFilePathWindows(input) {
2053
+ return this._filePathWindows.test(input.toString());
2054
+ }
2055
+ static _dirPathLinux = /^\/(?:[^\\/\s]+\/)*$/;
2056
+ /**
2057
+ * 验证是否为 Linux 系统文件夹路径
2058
+ * @example
2059
+ * ```ts
2060
+ * ValidateUtil.isDirPathLinux("/usr/local/"); // true
2061
+ * ```
2062
+ */
2063
+ static isDirPathLinux(input) {
2064
+ return this._dirPathLinux.test(input.toString());
2065
+ }
2066
+ static _filePathLinux = /^(\/$|\/(?:[^\\/\s]+\/)*[^\\/\s]+$)/;
2067
+ /**
2068
+ * 验证是否为 Linux 系统文件路径
2069
+ * @example
2070
+ * ```ts
2071
+ * ValidateUtil.isFilePathLinux("/usr/local/bin/node"); // true
2072
+ * ```
2073
+ */
2074
+ static isFilePathLinux(input) {
2075
+ return this._filePathLinux.test(input.toString());
2076
+ }
2077
+ static _EVCarNumber = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z](([DF]((?![IO])[a-zA-Z0-9](?![IO]))\d{4})|(\d{5}[DF]))$/;
2078
+ /**
2079
+ * 验证是否为新能源车牌号
2080
+ * @example
2081
+ * ```ts
2082
+ * ValidateUtil.isEVCarNumber("粤AD12345"); // true
2083
+ * ```
2084
+ */
2085
+ static isEVCarNumber(input) {
2086
+ return this._EVCarNumber.test(input.toString());
2087
+ }
2088
+ static _GVCarNumber = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/;
2089
+ /**
2090
+ * 验证是否为燃油车车牌号
2091
+ * @example
2092
+ * ```ts
2093
+ * ValidateUtil.isGVCarNumber("粤B12345"); // true
2094
+ * ```
2095
+ */
2096
+ static isGVCarNumber(input) {
2097
+ return this._GVCarNumber.test(input.toString());
2098
+ }
2099
+ static _chineseName = /^[一-龢][一·-龢]*$/;
2100
+ /**
2101
+ * 验证是否为中文姓名
2102
+ * @example
2103
+ * ```ts
2104
+ * ValidateUtil.isChineseName("张三"); // true
2105
+ * ```
2106
+ */
2107
+ static isChineseName(input) {
2108
+ return this._chineseName.test(input.toString());
2109
+ }
2110
+ static _chineseId = /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))([\dX])$/i;
2111
+ /**
2112
+ * 验证是否为中国身份证号
2113
+ * - ⚠️ 仅校验 18 位格式(含生日合法性),**不验证第 18 位校验位**,伪造码可通过校验
2114
+ * @example
2115
+ * ```ts
2116
+ * ValidateUtil.isChineseID("11010519491231002X"); // true
2117
+ * ```
2118
+ */
2119
+ static isChineseID(input) {
2120
+ return this._chineseId.test(input.toString());
2121
+ }
2122
+ static _chineseProvince = /^(?:安徽|澳门|北京|重庆|福建|甘肃|广东|广西|贵州|海南|河北|河南|黑龙江|湖北|湖南|吉林|江苏|江西|辽宁|内蒙古|宁夏|青海|山东|山西|陕西|上海|四川|台湾|天津|西藏|香港|新疆|云南|浙江)$/;
2123
+ /**
2124
+ * 验证是否为中国省份
2125
+ * @example
2126
+ * ```ts
2127
+ * ValidateUtil.isChineseProvince("浙江"); // true
2128
+ * ```
2129
+ */
2130
+ static isChineseProvince(input) {
2131
+ return this._chineseProvince.test(input.toString());
2132
+ }
2133
+ static _chineseNation = /^(?:汉族|蒙古族|回族|藏族|维吾尔族|苗族|彝族|壮族|布依族|朝鲜族|满族|侗族|瑶族|白族|土家族|哈尼族|哈萨克族|傣族|黎族|傈僳族|佤族|畲族|高山族|拉祜族|水族|东乡族|纳西族|景颇族|柯尔克孜族|土族|达斡尔族|仫佬族|羌族|布朗族|撒拉族|毛南族|仡佬族|锡伯族|阿昌族|普米族|塔吉克族|怒族|乌孜别克族|俄罗斯族|鄂温克族|德昂族|保安族|裕固族|京族|塔塔尔族|独龙族|鄂伦春族|赫哲族|门巴族|珞巴族|基诺族|其它未识别民族|外国人入中国籍)$/;
2134
+ /**
2135
+ * 验证是否为中华民族
2136
+ * @example
2137
+ * ```ts
2138
+ * ValidateUtil.isChineseNation("汉族"); // true
2139
+ * ```
2140
+ */
2141
+ static isChineseNation(input) {
2142
+ return this._chineseNation.test(input.toString());
2143
+ }
2144
+ static _letter = /^[a-z]+$/i;
2145
+ /**
2146
+ * 验证是否只包含字母
2147
+ * @example
2148
+ * ```ts
2149
+ * ValidateUtil.isLetter("abcDEF"); // true
2150
+ * ```
2151
+ */
2152
+ static isLetter(input) {
2153
+ return this._letter.test(input.toString());
2154
+ }
2155
+ static _letterLowercase = /^[a-z]+$/;
2156
+ /**
2157
+ * 验证是否只包含小写字母
2158
+ * @example
2159
+ * ```ts
2160
+ * ValidateUtil.isLetterLowercase("abc"); // true
2161
+ * ```
2162
+ */
2163
+ static isLetterLowercase(input) {
2164
+ return this._letterLowercase.test(input.toString());
2165
+ }
2166
+ static _letterUppercase = /^[A-Z]+$/;
2167
+ /**
2168
+ * 验证是否只包含大写字母
2169
+ * @example
2170
+ * ```ts
2171
+ * ValidateUtil.isLetterUppercase("ABC"); // true
2172
+ * ```
2173
+ */
2174
+ static isLetterUppercase(input) {
2175
+ return this._letterUppercase.test(input.toString());
2176
+ }
2177
+ static _letterOmit = /^[^A-Z]*$/i;
2178
+ /**
2179
+ * 验证是否不包含字母
2180
+ * @example
2181
+ * ```ts
2182
+ * ValidateUtil.isLetterOmit("123_-"); // true
2183
+ * ```
2184
+ */
2185
+ static isLetterOmit(input) {
2186
+ return this._letterOmit.test(input.toString());
2187
+ }
2188
+ static _LetterAndNumber = /^[A-Z0-9]+$/i;
2189
+ /**
2190
+ * 验证是否为数字和字母组合
2191
+ * @example
2192
+ * ```ts
2193
+ * ValidateUtil.isLetterAndNumber("A1B2"); // true
2194
+ * ```
2195
+ */
2196
+ static isLetterAndNumber(input) {
2197
+ return this._LetterAndNumber.test(input.toString());
2198
+ }
2199
+ static _signedFloat = /^[+-]?(\d+(\.\d+)?|\.\d+)$/;
2200
+ /**
2201
+ * 验证是否为有符号浮点数
2202
+ * @example
2203
+ * ```ts
2204
+ * ValidateUtil.isSignedFloat("-12.34"); // true
2205
+ * ```
2206
+ */
2207
+ static isSignedFloat(input) {
2208
+ return this._signedFloat.test(input.toString());
2209
+ }
2210
+ static _unsignedFloat = /^\+?(\d+(\.\d+)?|\.\d+)$/;
2211
+ /**
2212
+ * 验证是否为无符号浮点数
2213
+ * @example
2214
+ * ```ts
2215
+ * ValidateUtil.isUnsignedFloat("12.34"); // true
2216
+ * ```
2217
+ */
2218
+ static isUnsignedFloat(input) {
2219
+ return this._unsignedFloat.test(input.toString());
2220
+ }
2221
+ static _signedInteger = /^[+-]?\d+$/;
2222
+ /**
2223
+ * 验证是否为有符号整数
2224
+ * @example
2225
+ * ```ts
2226
+ * ValidateUtil.isSignedInteger("-12"); // true
2227
+ * ```
2228
+ */
2229
+ static isSignedInteger(input) {
2230
+ return this._signedInteger.test(input.toString());
2231
+ }
2232
+ static _unsignedInteger = /^\+?\d+$/;
2233
+ /**
2234
+ * 验证是否为无符号整数
2235
+ * @example
2236
+ * ```ts
2237
+ * ValidateUtil.isUnsignedInteger("12"); // true
2238
+ * ```
2239
+ */
2240
+ static isUnsignedInteger(input) {
2241
+ return this._unsignedInteger.test(input.toString());
2242
+ }
2243
+ static _spaceInclude = /\s/;
2244
+ /**
2245
+ * 验证是否包含空格
2246
+ * @example
2247
+ * ```ts
2248
+ * ValidateUtil.isSpaceInclude("a b"); // true
2249
+ * ```
2250
+ */
2251
+ static isSpaceInclude(input) {
2252
+ return this._spaceInclude.test(input.toString());
2253
+ }
2254
+ static _spaceStart = /^\s/;
2255
+ /**
2256
+ * 验证是否以空格开头
2257
+ * @example
2258
+ * ```ts
2259
+ * ValidateUtil.isSpaceStart(" abc"); // true
2260
+ * ```
2261
+ */
2262
+ static isSpaceStart(input) {
2263
+ return this._spaceStart.test(input.toString());
2264
+ }
2265
+ static _spaceEnd = /\s$/;
2266
+ /**
2267
+ * 验证是否以空格结尾
2268
+ * @example
2269
+ * ```ts
2270
+ * ValidateUtil.isSpaceEnd("abc "); // true
2271
+ * ```
2272
+ */
2273
+ static isSpaceEnd(input) {
2274
+ return this._spaceEnd.test(input.toString());
2275
+ }
2276
+ /**
2277
+ * 验证是否以空格开头或结尾
2278
+ * @example
2279
+ * ```ts
2280
+ * ValidateUtil.isSpaceStartOrEnd(" abc"); // true
2281
+ * ```
2282
+ */
2283
+ static isSpaceStartOrEnd(input) {
2284
+ return this.isSpaceStart(input) || this.isSpaceEnd(input);
2285
+ }
2286
+ };
2287
+ //#endregion
2288
+ exports.ArrayUtil = ArrayUtil;
2289
+ exports.CurrencyUtil = CurrencyUtil;
2290
+ exports.DateTimeUtil = DateTimeUtil;
2291
+ exports.EnvUtil = EnvUtil;
2292
+ exports.FunctionUtil = FunctionUtil;
2293
+ exports.MimeUtil = MimeUtil;
2294
+ exports.NumberUtil = NumberUtil;
2295
+ exports.ObjectUtil = ObjectUtil;
2296
+ exports.StringUtil = require_math.StringUtil;
2297
+ exports.ThemeUtil = ThemeUtil;
2298
+ exports.TreeUtil = TreeUtil;
2299
+ exports.TypeUtil = require_math.TypeUtil;
2300
+ exports.ValidateUtil = ValidateUtil;