@pawover/kit 0.0.0-beta.32 → 0.0.0-beta.40

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.
@@ -1,5 +1,7 @@
1
+ import { clone, cloneDeep, cloneDeepWith } from "lodash-es";
2
+
1
3
  //#region src/utils/typeof/types.ts
2
- const PROTOTYPE_TAGS = {
4
+ const PROTOTYPE_TAGS = Object.freeze({
3
5
  abortSignal: "[object AbortSignal]",
4
6
  array: "[object Array]",
5
7
  asyncFunction: "[object AsyncFunction]",
@@ -12,6 +14,7 @@ const PROTOTYPE_TAGS = {
12
14
  file: "[object File]",
13
15
  function: "[object Function]",
14
16
  generatorFunction: "[object GeneratorFunction]",
17
+ global: "[object global]",
15
18
  iframe: "[object HTMLIFrameElement]",
16
19
  map: "[object Map]",
17
20
  null: "[object Null]",
@@ -29,7 +32,7 @@ const PROTOTYPE_TAGS = {
29
32
  weakSet: "[object WeakSet]",
30
33
  webSocket: "[object WebSocket]",
31
34
  window: "[object Window]"
32
- };
35
+ });
33
36
  const TYPED_ARRAY_TAGS = new Set([
34
37
  "[object Int8Array]",
35
38
  "[object Uint8Array]",
@@ -219,20 +222,50 @@ function isDate(value, invalidCheck = true) {
219
222
  //#endregion
220
223
  //#region src/utils/typeof/isEnumeration.ts
221
224
  /**
222
- * 判断一个值是否为有效的枚举
223
- * - 枚举不能为空
224
- * - 枚举所有的值必须是 string 或 number
225
+ * 判断一个对象是否为有效的枚举
226
+ * - 枚举成员不能为空
227
+ * - 枚举成员的键不能具有数值名
228
+ * - 枚举成员的值必须类型一致且为 `string` 或 `number` 类型
229
+ * - 枚举成员的值不能重复
230
+ * - 枚举成员的值必须全部为双向映射或非双向映射
225
231
  *
226
232
  * @param enumeration 待检查值
227
- * @returns 是否为有效的枚举
233
+ * @returns [是否为有效的枚举, 是否为双向枚举]
228
234
  */
229
235
  function isEnumeration(enumeration) {
230
- if (!isObject(enumeration)) return [false, false];
236
+ if (typeof enumeration !== "object" || enumeration === null) return [false, false];
231
237
  const keys = Object.keys(enumeration);
232
- if (!keys.length) return [false, false];
233
- const values = Object.values(enumeration);
234
- if (!values.every((v) => typeof v === "string" || typeof v === "number")) return [false, false];
235
- return [true, keys.every((k) => values.some((v) => v.toString() === k))];
238
+ if (keys.length === 0) return [false, false];
239
+ const originalKeys = [];
240
+ const numericKeys = [];
241
+ for (const key of keys) if (/^\d+$/.test(key)) numericKeys.push(key);
242
+ else originalKeys.push(key);
243
+ if (originalKeys.length === 0) return [false, false];
244
+ let valueType = null;
245
+ const values = [];
246
+ for (const key of originalKeys) {
247
+ const value = enumeration[key];
248
+ const type = typeof value;
249
+ if (type !== "string" && type !== "number") return [false, false];
250
+ if (valueType === null) valueType = type;
251
+ else if (type !== valueType) return [false, false];
252
+ values.push(value);
253
+ }
254
+ if (new Set(values).size !== values.length) return [false, false];
255
+ let isBidirectional = false;
256
+ if (numericKeys.length > 0) {
257
+ if (numericKeys.length !== originalKeys.length) return [false, false];
258
+ const reverseMappedNames = /* @__PURE__ */ new Set();
259
+ for (const numKey of numericKeys) {
260
+ const reverseValue = enumeration[numKey];
261
+ if (typeof reverseValue !== "string") return [false, false];
262
+ if (!originalKeys.includes(reverseValue)) return [false, false];
263
+ reverseMappedNames.add(reverseValue);
264
+ }
265
+ if (reverseMappedNames.size !== originalKeys.length) return [false, false];
266
+ isBidirectional = true;
267
+ }
268
+ return [true, isBidirectional];
236
269
  }
237
270
 
238
271
  //#endregion
@@ -249,18 +282,26 @@ function isEnumeration(enumeration) {
249
282
  * ```
250
283
  */
251
284
  function isEqual(x, y) {
252
- if (Object.is(x, y)) return true;
253
- if (isDate(x) && isDate(y)) return x.getTime() === y.getTime();
254
- if (isRegExp(x) && isRegExp(y)) return x.toString() === y.toString();
255
- if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) return false;
256
- const keysX = Reflect.ownKeys(x);
257
- const keysY = Reflect.ownKeys(y);
258
- if (keysX.length !== keysY.length) return false;
259
- for (const key of keysX) {
260
- if (!Reflect.has(y, key)) return false;
261
- if (!isEqual(x[key], y[key])) return false;
285
+ const seen = /* @__PURE__ */ new WeakMap();
286
+ function _isEqual(a, b) {
287
+ if (Object.is(a, b)) return true;
288
+ if (isDate(a) && isDate(b)) return a.getTime() === b.getTime();
289
+ if (isRegExp(a) && isRegExp(b)) return a.toString() === b.toString();
290
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
291
+ if (seen.has(a)) {
292
+ if (seen.get(a).has(b)) return true;
293
+ } else seen.set(a, /* @__PURE__ */ new Set());
294
+ seen.get(a).add(b);
295
+ const keysA = Reflect.ownKeys(a);
296
+ const keysB = Reflect.ownKeys(b);
297
+ if (keysA.length !== keysB.length) return false;
298
+ for (const key of keysA) {
299
+ if (!Reflect.has(b, key)) return false;
300
+ if (!_isEqual(a[key], b[key])) return false;
301
+ }
302
+ return true;
262
303
  }
263
- return true;
304
+ return _isEqual(x, y);
264
305
  }
265
306
 
266
307
  //#endregion
@@ -287,7 +328,28 @@ function isFalsy(value) {
287
328
  }
288
329
  function isFalsyLike(value) {
289
330
  if (isFalsy(value)) return true;
290
- return typeof value === "string" && (value === "null" || value === "undefined" || value === "NaN" || value === "false" || value === "0" || value === "0n");
331
+ return typeof value === "string" && (value === "null" || value === "undefined" || value === "NaN" || value === "false" || value === "0" || value === "-0" || value === "0n");
332
+ }
333
+
334
+ //#endregion
335
+ //#region src/utils/typeof/isIframe.ts
336
+ /**
337
+ * 检查 value 是否为 HTMLIFrameElement
338
+ * @param value 待检查值
339
+ * @returns 是否为 HTMLIFrameElement
340
+ */
341
+ function isIframe(value) {
342
+ if (typeof window === "undefined") return false;
343
+ return resolvePrototypeString(value) === PROTOTYPE_TAGS.iframe;
344
+ }
345
+ function isInIframe() {
346
+ if (typeof window === "undefined") return false;
347
+ try {
348
+ return window.top !== window.self;
349
+ } catch (error) {
350
+ if (error.name === "SecurityError") return true;
351
+ return false;
352
+ }
291
353
  }
292
354
 
293
355
  //#endregion
@@ -362,7 +424,7 @@ function isNaN(value) {
362
424
  * 检查 value 是否为整数
363
425
  *
364
426
  * @param value 待检查值
365
- * @param safeCheck 是否附加安全数检查
427
+ * @param safeCheck 是否附加安全整数检查
366
428
  * @returns 是否为整数
367
429
  */
368
430
  function isInteger(value, safeCheck = true) {
@@ -374,7 +436,7 @@ function isInteger(value, safeCheck = true) {
374
436
  * - 此函数中 `0` 不被视为正整数
375
437
  *
376
438
  * @param value 待检查值
377
- * @param safeCheck 是否附加安全数检查
439
+ * @param safeCheck 是否附加安全整数检查
378
440
  */
379
441
  function isPositiveInteger(value, safeCheck = true) {
380
442
  return isInteger(value, safeCheck) && value > 0;
@@ -384,7 +446,7 @@ function isPositiveInteger(value, safeCheck = true) {
384
446
  * - 此函数中 `0` 不被视为负整数
385
447
  *
386
448
  * @param value 待检查值
387
- * @param safeCheck 是否附加安全数检查
449
+ * @param safeCheck 是否附加安全整数检查
388
450
  */
389
451
  function isNegativeInteger(value, safeCheck = true) {
390
452
  return isInteger(value, safeCheck) && value < 0;
@@ -417,7 +479,7 @@ function isInfinityLike(value) {
417
479
  //#endregion
418
480
  //#region src/utils/typeof/isObject.ts
419
481
  /**
420
- * 判断是否为对象类型
482
+ * 判断是否为普通对象类型
421
483
  * - 可选是否检查原型为 `Object.prototype`,防止原型链污染
422
484
  *
423
485
  * @param value 待检查值
@@ -426,8 +488,11 @@ function isInfinityLike(value) {
426
488
  * @example
427
489
  * ```ts
428
490
  * isObject({}); // true
491
+ * isObject([]); // false
429
492
  * isObject(new Date()); // false (because prototype is not Object.prototype)
430
493
  * isObject(new Date(), false); // true (is object type)
494
+ * isObject(Object.create(null)) // false
495
+ * isObject(Object.create(null), false) // true
431
496
  * ```
432
497
  */
433
498
  function isObject(value, prototypeCheck = true) {
@@ -457,16 +522,12 @@ function isPromiseLike(value) {
457
522
  //#endregion
458
523
  //#region src/utils/typeof/isReadableStream.ts
459
524
  /**
460
- * Checks if a value is a WHATWG ReadableStream instance.
461
- *
525
+ * 检查 value 是否为 ReadableStream
462
526
  * - Uses `Object.prototype.toString` where supported (modern browsers, Node.js ≥18).
463
527
  * - Falls back to duck-typing in older environments.
464
528
  * - Resistant to basic forgery, but not 100% secure in all polyfill scenarios.
529
+ * - ⚠️ Note: In older Node.js (<18) or with non-compliant polyfills, this may return false positives or negatives.
465
530
  *
466
- * ⚠️ Note: In older Node.js (<18) or with non-compliant polyfills, this may return false positives or negatives.
467
- */
468
- /**
469
- * 检查 value 是否为 ReadableStream
470
531
  * @param value 待检查值
471
532
  * @returns 是否为 ReadableStream
472
533
  */
@@ -702,20 +763,6 @@ function arrayFork(initialList, match) {
702
763
 
703
764
  //#endregion
704
765
  //#region src/utils/array/arrayIntersection.ts
705
- /**
706
- * 求数组交集
707
- * - 返回在 `initialList` 和 `diffList` 中都存在的元素
708
- *
709
- * @param initialList 初始数组
710
- * @param diffList 对比数组
711
- * @param match 匹配函数
712
- * @returns 交集数组
713
- * @example
714
- * ```ts
715
- * arrayIntersection([1, 2], [2, 3]); // [2]
716
- * arrayIntersection([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // [{ id: 2 }]
717
- * ```
718
- */
719
766
  function arrayIntersection(initialList, diffList, match) {
720
767
  if (!isArray(initialList) || !isArray(diffList)) return [];
721
768
  if (!initialList.length || !diffList.length) return [];
@@ -736,27 +783,6 @@ function arrayLast(initialList, saveValue) {
736
783
 
737
784
  //#endregion
738
785
  //#region src/utils/array/arrayMerge.ts
739
- /**
740
- * 数组合并
741
- * - 如果未提供 `match` 函数,则合并两个数组并去重(Union)
742
- * - 如果提供了 `match` 函数,则仅更新 `initialList` 中匹配到的项(Left Join Update),不会追加 `mergeList` 中新增的项
743
- *
744
- * @param initialList 初始数组
745
- * @param mergeList 待合并数组
746
- * @param match 匹配函数
747
- * @returns 合并后的数组
748
- * @example
749
- * ```ts
750
- * // 基础合并去重
751
- * arrayMerge([1, 2], [2, 3]); // [1, 2, 3]
752
- *
753
- * // 按条件更新
754
- * const source = [{ id: 1, val: "a" }, { id: 2, val: "b" }];
755
- * const update = [{ id: 2, val: "new" }, { id: 3, val: "c" }];
756
- * arrayMerge(source, update, (x) => x.id);
757
- * // [{ id: 1, val: "a" }, { id: 2, val: "new" }] -> id:3 被忽略
758
- * ```
759
- */
760
786
  function arrayMerge(initialList, mergeList, match) {
761
787
  if (!isArray(initialList)) return [];
762
788
  if (!isArray(mergeList)) return [...initialList];
@@ -787,26 +813,12 @@ function arrayPick(initialList, filter, mapper) {
787
813
 
788
814
  //#endregion
789
815
  //#region src/utils/array/arrayReplace.ts
790
- /**
791
- * 数组项替换
792
- * - 在给定的数组中,替换符合匹配函数结果的项目
793
- * - 只替换第一个匹配项
794
- *
795
- * @param initialList 初始数组
796
- * @param newItem 替换项
797
- * @param match 匹配函数
798
- * @returns 替换后的新数组
799
- * @example
800
- * ```ts
801
- * arrayReplace([1, 2, 3], 4, (n) => n === 2); // [1, 4, 3]
802
- * ```
803
- */
804
816
  function arrayReplace(initialList, newItem, match) {
805
817
  if (!isArray(initialList) || !initialList.length) return [];
806
- if (newItem === void 0 || !isFunction(match)) return [...initialList];
818
+ if (!isFunction(match)) return [...initialList];
807
819
  for (let i = 0; i < initialList.length; i++) {
808
820
  const item = initialList[i];
809
- if (item !== void 0 && match(item, i)) return [
821
+ if (match(item, i)) return [
810
822
  ...initialList.slice(0, i),
811
823
  newItem,
812
824
  ...initialList.slice(i + 1, initialList.length)
@@ -839,7 +851,7 @@ function arrayReplace(initialList, newItem, match) {
839
851
  function arrayReplaceMove(initialList, newItem, match, position) {
840
852
  if (!isArray(initialList)) return [];
841
853
  if (!initialList.length) return [newItem];
842
- if (newItem === void 0 || !isFunction(match)) return [...initialList];
854
+ if (!isFunction(match)) return [...initialList];
843
855
  const result = [...initialList];
844
856
  const matchIndex = initialList.findIndex(match);
845
857
  if (matchIndex !== -1) result.splice(matchIndex, 1);
@@ -865,6 +877,7 @@ function arrayReplaceMove(initialList, newItem, match, position) {
865
877
  */
866
878
  function arraySplit(initialList, size = 10) {
867
879
  if (!isArray(initialList)) return [];
880
+ if (!isPositiveInteger(size, false)) return [];
868
881
  const count = Math.ceil(initialList.length / size);
869
882
  return Array.from({ length: count }).fill(null).map((_c, i) => {
870
883
  return initialList.slice(i * size, i * size + size);
@@ -1003,13 +1016,19 @@ function to(promise, errorExt) {
1003
1016
  return promise.then((data) => [null, data]).catch((err) => {
1004
1017
  if (errorExt) {
1005
1018
  const parsedError = {
1006
- ...err,
1007
- ...errorExt
1019
+ name: "",
1020
+ message: "",
1021
+ stack: ""
1008
1022
  };
1009
1023
  if (err instanceof Error) {
1010
- parsedError["message"] = err.message;
1011
- parsedError["stack"] = err.stack;
1012
- }
1024
+ parsedError.message = err.message;
1025
+ parsedError.name = err.name;
1026
+ parsedError.stack = err.stack;
1027
+ Object.getOwnPropertyNames(err).forEach((key) => {
1028
+ if (!(key in parsedError)) parsedError[key] = err[key];
1029
+ });
1030
+ } else Object.assign(parsedError, err);
1031
+ Object.assign(parsedError, errorExt);
1013
1032
  return [parsedError, void 0];
1014
1033
  }
1015
1034
  return [err ? err : /* @__PURE__ */ new Error("defaultError"), void 0];
@@ -1021,9 +1040,6 @@ function to(promise, errorExt) {
1021
1040
  const R1$2 = /[^0-9.-]/g;
1022
1041
  /**
1023
1042
  * 从字符串中提取数字字符串
1024
- *
1025
- /**
1026
- * 从字符串中提取数字字符串
1027
1043
  * - 移除非数字字符,保留符号和小数点
1028
1044
  *
1029
1045
  * @param input 待处理字符串
@@ -1035,8 +1051,9 @@ const R1$2 = /[^0-9.-]/g;
1035
1051
  * ```
1036
1052
  */
1037
1053
  function stringToNumber(input) {
1038
- if (!isString(input, true)) return "";
1054
+ if (!isString(input, true)) return "0";
1039
1055
  const cleaned = input.replace(R1$2, "");
1056
+ if (!cleaned) return "0";
1040
1057
  let isDecimal = false;
1041
1058
  let signCount = 0;
1042
1059
  let firstIndex = -1;
@@ -1062,7 +1079,7 @@ function stringToNumber(input) {
1062
1079
  }
1063
1080
 
1064
1081
  //#endregion
1065
- //#region src/utils/math/toMathBignumber.ts
1082
+ //#region src/utils/math/mathToBignumber.ts
1066
1083
  /**
1067
1084
  * 将任意类型的值转换为 `math.bignumber`
1068
1085
  *
@@ -1074,10 +1091,10 @@ function stringToNumber(input) {
1074
1091
  * ```ts
1075
1092
  * import { create, all } from "mathjs";
1076
1093
  * const math = create(all);
1077
- * toMathBignumber(math, "0.1");
1094
+ * mathToBignumber(math, "0.1");
1078
1095
  * ```
1079
1096
  */
1080
- function toMathBignumber(mathJsInstance, value, saveValue) {
1097
+ function mathToBignumber(mathJsInstance, value, saveValue) {
1081
1098
  const errorValue = saveValue ?? mathJsInstance.bignumber(0);
1082
1099
  if (isFalsyLike(value) || isInfinityLike(value)) return errorValue;
1083
1100
  try {
@@ -1088,9 +1105,9 @@ function toMathBignumber(mathJsInstance, value, saveValue) {
1088
1105
  }
1089
1106
 
1090
1107
  //#endregion
1091
- //#region src/utils/math/toMathDecimal.ts
1092
- function toMathDecimal(mathJsInstance, value, precision, isFormat = true) {
1093
- const bigNumber = toMathBignumber(mathJsInstance, value);
1108
+ //#region src/utils/math/mathToDecimal.ts
1109
+ function mathToDecimal(mathJsInstance, value, precision, isFormat = true) {
1110
+ const bigNumber = mathToBignumber(mathJsInstance, value);
1094
1111
  return isFormat ? mathJsInstance.format(bigNumber, {
1095
1112
  notation: "fixed",
1096
1113
  precision
@@ -1098,7 +1115,7 @@ function toMathDecimal(mathJsInstance, value, precision, isFormat = true) {
1098
1115
  }
1099
1116
 
1100
1117
  //#endregion
1101
- //#region src/utils/math/toMathEvaluate.ts
1118
+ //#region src/utils/math/mathToEvaluate.ts
1102
1119
  /**
1103
1120
  * 数学表达式求值
1104
1121
  *
@@ -1108,16 +1125,16 @@ function toMathDecimal(mathJsInstance, value, precision, isFormat = true) {
1108
1125
  * @returns 计算结果的字符串表示
1109
1126
  * @example
1110
1127
  * ```ts
1111
- * toMathEvaluate(math, "a + b", { a: 1, b: 2 }); // "3"
1128
+ * mathToEvaluate(math, "a + b", { a: 1, b: 2 }); // "3"
1112
1129
  * ```
1113
1130
  */
1114
- function toMathEvaluate(mathJsInstance, expr, scope) {
1131
+ function mathToEvaluate(mathJsInstance, expr, scope) {
1115
1132
  const evaluateValue = `${mathJsInstance.evaluate(expr, scope || {})}`;
1116
- return mathJsInstance.format(toMathBignumber(mathJsInstance, evaluateValue), { notation: "fixed" });
1133
+ return mathJsInstance.format(mathToBignumber(mathJsInstance, evaluateValue), { notation: "fixed" });
1117
1134
  }
1118
1135
 
1119
1136
  //#endregion
1120
- //#region src/utils/number/isWithinInterval.ts
1137
+ //#region src/utils/number/numberWithin.ts
1121
1138
  /**
1122
1139
  * 数字区间检查函数
1123
1140
  *
@@ -1128,11 +1145,11 @@ function toMathEvaluate(mathJsInstance, expr, scope) {
1128
1145
  * @returns 是否在区间内
1129
1146
  * @example
1130
1147
  * ```ts
1131
- * isWithinInterval(5, [1, 10]); // true
1132
- * isWithinInterval(1, [1, 10], false); // false
1148
+ * numberWithin(5, [1, 10]); // true
1149
+ * numberWithin(1, [1, 10], false); // false
1133
1150
  * ```
1134
1151
  */
1135
- function isWithinInterval(input, interval, includeLeft = true, includeRight = false) {
1152
+ function numberWithin(input, interval, includeLeft = true, includeRight = false) {
1136
1153
  if (!isNumber(input)) throw new Error("params [input] mast be a number.");
1137
1154
  if (isInfinity(input)) throw new Error("params [input] mast be a finite number.");
1138
1155
  const [left, right] = interval;
@@ -1143,114 +1160,33 @@ function isWithinInterval(input, interval, includeLeft = true, includeRight = fa
1143
1160
  else return input > left && input < right;
1144
1161
  }
1145
1162
 
1146
- //#endregion
1147
- //#region src/utils/object/cloneDeep.ts
1148
- const defaultCloneStrategy = {
1149
- cloneMap,
1150
- cloneSet,
1151
- cloneDate,
1152
- cloneArray,
1153
- cloneObject,
1154
- cloneOther
1155
- };
1156
- function cloneMap(input, track, clone) {
1157
- const output = track(/* @__PURE__ */ new Map());
1158
- for (const [key, value] of input) output.set(key, clone(value));
1159
- return output;
1160
- }
1161
- function cloneSet(input, track, clone) {
1162
- const output = track(/* @__PURE__ */ new Set());
1163
- for (const value of input) output.add(clone(value));
1164
- return output;
1165
- }
1166
- function cloneDate(input, track) {
1167
- return track(new Date(input));
1168
- }
1169
- function cloneArray(input, track, clone) {
1170
- const output = track(new Array(input.length));
1171
- input.forEach((value, index) => {
1172
- output[index] = clone(value);
1173
- });
1174
- return output;
1175
- }
1176
- function cloneObject(input, track, clone) {
1177
- const output = track(Object.create(Object.getPrototypeOf(input)));
1178
- for (const key of Reflect.ownKeys(input)) {
1179
- const descriptor = Object.getOwnPropertyDescriptor(input, key);
1180
- if ("value" in descriptor) descriptor.value = clone(descriptor.value);
1181
- Object.defineProperty(output, key, descriptor);
1182
- }
1183
- return output;
1184
- }
1185
- function cloneOther(input, track) {
1186
- return track(input);
1187
- }
1188
- /**
1189
- * 深度拷贝对象
1190
- * - 支持 Array, Object, Map, Set
1191
- * - 自动处理循环引用
1192
- *
1193
- * @param root 需要拷贝的对象
1194
- * @param customStrategy 自定义拷贝策略
1195
- * @returns 拷贝后的对象
1196
- * @example
1197
- * ```ts
1198
- * const original = { a: 1, b: { c: 2 } };
1199
- * const copy = cloneDeep(original);
1200
- * copy.b.c = 3;
1201
- * // original.b.c === 2
1202
- * ```
1203
- * @reference https://github.com/radashi-org/radashi/blob/main/src/object/cloneDeep.ts
1204
- */
1205
- function cloneDeep(root, customStrategy) {
1206
- const strategy = {
1207
- ...defaultCloneStrategy,
1208
- ...customStrategy
1209
- };
1210
- const tracked = /* @__PURE__ */ new Map();
1211
- const track = (parent, newParent) => {
1212
- tracked.set(parent, newParent);
1213
- return newParent;
1214
- };
1215
- const clone = (value) => {
1216
- return value && typeof value === "object" ? tracked.get(value) ?? cloneDeep$1(value, strategy) : value;
1217
- };
1218
- const cloneDeep$1 = (parent, strategy$1) => {
1219
- const newParent = (isObject(parent) ? strategy$1.cloneObject : isArray(parent) ? strategy$1.cloneArray : isMap(parent) ? strategy$1.cloneMap : isSet(parent) ? strategy$1.cloneSet : isDate(parent, false) ? strategy$1.cloneDate : strategy$1.cloneOther)(parent, track.bind(null, parent), clone);
1220
- if (!newParent) return cloneDeep$1(parent, defaultCloneStrategy);
1221
- tracked.set(parent, newParent);
1222
- return newParent;
1223
- };
1224
- return cloneDeep$1(root, strategy);
1225
- }
1226
-
1227
1163
  //#endregion
1228
1164
  //#region src/utils/object/enumEntries.ts
1229
1165
  function enumEntries(enumeration) {
1230
- const [isEnum, isTwoWayEnum] = isEnumeration(enumeration);
1166
+ const [isEnum, isBidirectionalEnum] = isEnumeration(enumeration);
1231
1167
  if (!isEnum) throw Error("function enumEntries expected parameter is a enum, and requires at least one member");
1232
1168
  const entries = objectEntries(enumeration);
1233
- if (isTwoWayEnum) return entries.splice(entries.length / 2, entries.length / 2);
1169
+ if (isBidirectionalEnum) return entries.splice(entries.length / 2, entries.length / 2);
1234
1170
  return entries;
1235
1171
  }
1236
1172
 
1237
1173
  //#endregion
1238
1174
  //#region src/utils/object/enumKeys.ts
1239
1175
  function enumKeys(enumeration) {
1240
- const [isEnum, isTwoWayEnum] = isEnumeration(enumeration);
1176
+ const [isEnum, isBidirectionalEnum] = isEnumeration(enumeration);
1241
1177
  if (!isEnum) throw Error("function enumKeys expected parameter is a enum, and requires at least one member");
1242
1178
  const keys = objectKeys(enumeration);
1243
- if (isTwoWayEnum) return keys.splice(keys.length / 2, keys.length / 2);
1179
+ if (isBidirectionalEnum) return keys.splice(keys.length / 2, keys.length / 2);
1244
1180
  return keys;
1245
1181
  }
1246
1182
 
1247
1183
  //#endregion
1248
1184
  //#region src/utils/object/enumValues.ts
1249
1185
  function enumValues(enumeration) {
1250
- const [isEnum, isTwoWayEnum] = isEnumeration(enumeration);
1186
+ const [isEnum, isBidirectionalEnum] = isEnumeration(enumeration);
1251
1187
  if (!isEnum) throw Error("function enumValues expected parameter is a enum, and requires at least one member");
1252
1188
  const values = objectValues(enumeration);
1253
- if (isTwoWayEnum) return values.splice(values.length / 2, values.length / 2);
1189
+ if (isBidirectionalEnum) return values.splice(values.length / 2, values.length / 2);
1254
1190
  return values;
1255
1191
  }
1256
1192
 
@@ -1261,24 +1197,24 @@ function objectEntries(value) {
1261
1197
  }
1262
1198
 
1263
1199
  //#endregion
1264
- //#region src/utils/object/mapEntries.ts
1200
+ //#region src/utils/object/objectMapEntries.ts
1265
1201
  /**
1266
1202
  * 映射对象条目
1267
1203
  * - 将对象的键值对映射为新的键值对
1268
1204
  *
1269
- * @param obj 对象
1205
+ * @param plainObject 对象
1270
1206
  * @param toEntry 映射函数
1271
1207
  * @returns 映射后的新对象
1272
1208
  * @example
1273
1209
  * ```ts
1274
1210
  * const obj = { a: 1, b: 2 };
1275
- * mapEntries(obj, (k, v) => [k, v * 2]); // { a: 2, b: 4 }
1211
+ * objectMapEntries(obj, (k, v) => [k, v * 2]); // { a: 2, b: 4 }
1276
1212
  * ```
1277
1213
  */
1278
- function mapEntries(obj, toEntry) {
1214
+ function objectMapEntries(plainObject, toEntry) {
1279
1215
  const defaultResult = {};
1280
- if (!obj) return defaultResult;
1281
- return objectEntries(obj).reduce((acc, [key, value]) => {
1216
+ if (!isObject(plainObject)) return defaultResult;
1217
+ return objectEntries(plainObject).reduce((acc, [key, value]) => {
1282
1218
  const [newKey, newValue] = toEntry(key, value);
1283
1219
  acc[newKey] = newValue;
1284
1220
  return acc;
@@ -1287,13 +1223,30 @@ function mapEntries(obj, toEntry) {
1287
1223
 
1288
1224
  //#endregion
1289
1225
  //#region src/utils/object/objectAssign.ts
1290
- function objectAssign(initial, override) {
1291
- if (!isObject(initial) || !isObject(override)) return initial ?? override ?? {};
1292
- const proto = Object.getPrototypeOf(initial);
1293
- const assigned = proto ? { ...initial } : Object.assign(Object.create(proto), initial);
1294
- for (const key of Object.keys(override)) assigned[key] = isObject(initial[key]) && isObject(override[key]) ? objectAssign(initial[key], override[key]) : override[key];
1226
+ const OBJECT_PROTO = Object.prototype;
1227
+ /**
1228
+ * 为对象创建一个具有相同原型的新副本
1229
+ * 这个辅助函数是保留原型的关键。
1230
+ */
1231
+ function cloneWithProto(obj) {
1232
+ const proto = Object.getPrototypeOf(obj);
1233
+ return proto === OBJECT_PROTO ? { ...obj } : Object.assign(Object.create(proto), obj);
1234
+ }
1235
+ function _objectAssign(initial, override, _seen) {
1236
+ if (!isObject(initial, false) && !isObject(override, false)) return {};
1237
+ if (!isObject(initial, false)) return cloneWithProto(override);
1238
+ if (!isObject(override, false)) return cloneWithProto(initial);
1239
+ if (_seen.has(initial)) return cloneWithProto(override);
1240
+ _seen.add(initial);
1241
+ const assigned = cloneWithProto(initial);
1242
+ for (const key of Object.keys(override)) if (isObject(initial[key]) && isObject(override[key])) assigned[key] = _objectAssign(initial[key], override[key], _seen);
1243
+ else assigned[key] = override[key];
1244
+ _seen.delete(initial);
1295
1245
  return assigned;
1296
1246
  }
1247
+ function objectAssign(initial, override) {
1248
+ return _objectAssign(initial, override, /* @__PURE__ */ new WeakSet());
1249
+ }
1297
1250
 
1298
1251
  //#endregion
1299
1252
  //#region src/utils/object/objectCrush.ts
@@ -1420,9 +1373,7 @@ function stringReplace(input, search, replacement) {
1420
1373
  const R1 = /\{\{(.+?)\}\}/g;
1421
1374
  /**
1422
1375
  * 字符串模板替换
1423
- *
1424
- /**
1425
- * 字符串模板替换
1376
+ * - 使用对象的属性值替换字符串中的 {{key}} 模板
1426
1377
  *
1427
1378
  * @param input 待处理字符串
1428
1379
  * @param template 模板对象
@@ -1435,11 +1386,14 @@ const R1 = /\{\{(.+?)\}\}/g;
1435
1386
  */
1436
1387
  function stringTemplate(input, template, regex = R1) {
1437
1388
  if (!isString(input, true)) return "";
1389
+ regex.lastIndex = 0;
1438
1390
  let result = "";
1439
1391
  let from = 0;
1440
1392
  let match;
1441
1393
  while (match = regex.exec(input)) {
1442
- result += input.slice(from, match.index) + template[match[1]];
1394
+ const replacement = template[match[1]];
1395
+ const valueToInsert = replacement === null || replacement === void 0 ? match[0] : replacement;
1396
+ result += input.slice(from, match.index) + valueToInsert;
1443
1397
  from = regex.lastIndex;
1444
1398
  }
1445
1399
  return result + input.slice(from);
@@ -1475,23 +1429,35 @@ function stringToJson(input, safeValue) {
1475
1429
  //#region src/utils/string/stringToPosix.ts
1476
1430
  /**
1477
1431
  * 将路径转换为 POSIX 风格
1478
- *
1479
- /**
1480
- * 将路径转换为 POSIX 风格
1481
- * - 统一使用正斜杠
1482
- * - 处理 Windows 盘符
1432
+ * - 统一使用正斜杠 (/)
1433
+ * - 可选移除 Windows 盘符 (如 C:)
1434
+ * - 可选移除开头的斜杠
1435
+ * - 规范化连续斜杠为单个斜杠
1483
1436
  *
1484
1437
  * @param input 待处理字符串
1485
- * @param removeLeadingSlash 是否移除开头斜杠,默认为 `false`
1486
- * @returns 转换后的路径
1438
+ * @param removeLeadingSlash 是否移除开头斜杠,默认为 `false`。如果移除了盘符,路径通常会以 / 开头,此参数可控制是否保留该 /
1439
+ * @returns 转换后的路径,如果输入无效则返回空字符串
1440
+ *
1487
1441
  * @example
1488
1442
  * ```ts
1489
- * stringToPosix("C:\\Windows\\System32"); // "/Windows/System32"
1443
+ * stringToPosix("C:\\Windows\\System32");
1444
+ * // 默认: "/Windows/System32" (移除了 C: 并标准化)
1445
+ *
1446
+ * stringToPosix("C:\\Windows\\System32", true);
1447
+ * // 移除开头斜杠: "Windows/System32"
1448
+ *
1449
+ * stringToPosix("\\\\server\\share\\file.txt");
1450
+ * // UNC 路径: "/server/share/file.txt"
1451
+ *
1452
+ * stringToPosix("folder\\subfolder\\file.txt");
1453
+ * // 相对路径: "folder/subfolder/file.txt"
1490
1454
  * ```
1491
1455
  */
1492
1456
  function stringToPosix(input, removeLeadingSlash = false) {
1493
1457
  if (!isString(input, true)) return "";
1494
- let normalized = input.replace(/^[A-Za-z]:[\\/]?/, "").replace(/^[\\/]+/, "/");
1458
+ let normalized = input.replace(/^[A-Za-z]:([\\/])?/, (_, separator) => {
1459
+ return separator ? "/" : "";
1460
+ });
1495
1461
  normalized = normalized.replace(/\\/g, "/");
1496
1462
  normalized = normalized.replace(/\/+/g, "/");
1497
1463
  if (removeLeadingSlash && normalized.startsWith("/")) normalized = normalized.substring(1);
@@ -1535,7 +1501,6 @@ function stringTrim(input, charsToTrim = " ") {
1535
1501
  //#endregion
1536
1502
  //#region src/utils/string/stringTruncate.ts
1537
1503
  /**
1538
- /**
1539
1504
  * 截取字符串
1540
1505
  * - 支持自定义省略符,不会截断在汉字中间(因为JS字符串本身按字符处理)
1541
1506
  *
@@ -1550,10 +1515,12 @@ function stringTrim(input, charsToTrim = " ") {
1550
1515
  */
1551
1516
  function stringTruncate(input, maxLength, ellipsis = "...") {
1552
1517
  if (!isString(input, true)) return "";
1553
- if (!isPositiveInteger(maxLength)) return input;
1554
- if (input.length <= maxLength) return input;
1555
- const truncated = input.slice(0, maxLength - ellipsis.length);
1556
- return truncated.length > 0 ? truncated + ellipsis : "";
1518
+ const codePoints = Array.from(input);
1519
+ if (!isInteger(maxLength) || maxLength < 0) return input;
1520
+ if (codePoints.length <= maxLength) return input;
1521
+ const availableLength = maxLength - ellipsis.length;
1522
+ if (availableLength <= 0) return "";
1523
+ return codePoints.slice(0, availableLength).join("") + ellipsis;
1557
1524
  }
1558
1525
 
1559
1526
  //#endregion
@@ -2033,5 +2000,5 @@ function treeToRows(tree, options = {}) {
2033
2000
  }
2034
2001
 
2035
2002
  //#endregion
2036
- export { arrayCounting as $, toMathEvaluate as A, isEnumeration as At, arrayZipToObject as B, isBigInt as Bt, mapEntries as C, isMap as Ct, enumEntries as D, isFalsyLike as Dt, enumKeys as E, isFalsy as Et, isTablet as F, isFunction as Ft, arrayReplace as G, arrayZip as H, isTypedArray as Ht, isIOSMobile as I, isGeneratorFunction as It, arrayLast as J, arrayPick as K, isMobile as L, isBoolean as Lt, toMathBignumber as M, isClass as Mt, stringToNumber as N, isAsyncFunction as Nt, cloneDeep as O, isError as Ot, to as P, isAsyncGeneratorFunction as Pt, arrayDifference as Q, isBrowser as R, isBlob as Rt, objectAssign as S, isNull as St, enumValues as T, isIterable as Tt, arraySplit as U, isAbortSignal as Ut, arrayUnzip as V, isArray as Vt, arrayReplaceMove as W, arrayFork as X, arrayIntersection as Y, arrayFirst as Z, objectPick as _, isInteger as _t, treeFind as a, isUndefined as at, objectInvert as b, isNumber as bt, stringTruncate as c, isWeakSet as ct, stringToPosix as d, isReadableStream as dt, arrayCompete as et, stringToJson as f, isPromise as ft, objectValues as g, isInfinityLike as gt, stringInitialCase as h, isInfinity as ht, treeForEach as i, isURLSearchParams as it, toMathDecimal as j, isDate as jt, isWithinInterval as k, isEqual as kt, stringTrim as l, isRegExp as lt, stringReplace as m, isObject as mt, rowsToTree as n, isWindow as nt, treeFilter as o, isSymbol as ot, stringTemplate as p, isPromiseLike as pt, arrayMerge as q, treeMap as r, isWebSocket as rt, getTimeZone as s, isSet as st, treeToRows as t, arrayCast as tt, stringToValues as u, isString as ut, objectOmit as v, isNaN as vt, objectEntries as w, isWeakMap as wt, objectCrush as x, isPositiveInteger as xt, objectKeys as y, isNegativeInteger as yt, isWebWorker as z, isFile as zt };
2037
- //# sourceMappingURL=utils-RGh-N7TJ.js.map
2003
+ export { arrayFirst as $, mathToDecimal as A, isFalsy as At, isBrowser as B, isGeneratorFunction as Bt, objectMapEntries as C, isPositiveInteger as Ct, enumEntries as D, isIterable as Dt, enumKeys as E, isWeakMap as Et, cloneDeepWith as F, isDate as Ft, arraySplit as G, isArray as Gt, arrayZipToObject as H, isBlob as Ht, to as I, isClass as It, arrayPick as J, arrayReplaceMove as K, isTypedArray as Kt, isTablet as L, isAsyncFunction as Lt, stringToNumber as M, isError as Mt, clone as N, isEqual as Nt, numberWithin as O, isIframe as Ot, cloneDeep as P, isEnumeration as Pt, arrayFork as Q, isIOSMobile as R, isAsyncGeneratorFunction as Rt, objectAssign as S, isNumber as St, enumValues as T, isMap as Tt, arrayUnzip as U, isFile as Ut, isWebWorker as V, isBoolean as Vt, arrayZip as W, isBigInt as Wt, arrayLast as X, arrayMerge as Y, arrayIntersection as Z, objectPick as _, isInfinity as _t, treeFind as a, isWebSocket as at, objectInvert as b, isNaN as bt, stringTruncate as c, isSymbol as ct, stringToPosix as d, isRegExp as dt, arrayDifference as et, stringToJson as f, isString as ft, objectValues as g, isObject as gt, stringInitialCase as h, isPromiseLike as ht, treeForEach as i, isWindow as it, mathToBignumber as j, isFalsyLike as jt, mathToEvaluate as k, isInIframe as kt, stringTrim as l, isSet as lt, stringReplace as m, isPromise as mt, rowsToTree as n, arrayCompete as nt, treeFilter as o, isURLSearchParams as ot, stringTemplate as p, isReadableStream as pt, arrayReplace as q, isAbortSignal as qt, treeMap as r, arrayCast as rt, getTimeZone as s, isUndefined as st, treeToRows as t, arrayCounting as tt, stringToValues as u, isWeakSet as ut, objectOmit as v, isInfinityLike as vt, objectEntries as w, isNull as wt, objectCrush as x, isNegativeInteger as xt, objectKeys as y, isInteger as yt, isMobile as z, isFunction as zt };
2004
+ //# sourceMappingURL=utils-DbMbll5L.js.map