@codady/utils 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  All changes to Utils including new features, updates, and removals are documented here.
4
4
 
5
+ ## [v0.0.16] - 2025-12-26
6
+
7
+ ### Distribution Files
8
+ * **JS**: https://unpkg.com/@codady/utils@0.0.16/dist/js/utils.js
9
+ * **Zip**:https://unpkg.com/@codady/utils@0.0.16/dist.zip
10
+
11
+ ### Changes
12
+
13
+ #### Fixed
14
+ * Null
15
+
16
+ #### Added
17
+ * Modified the `deepMerge` function to include an `interceptor` parameter, which can be used to intercept the merging process and handle it manually when needed.修改了`deepMerge`函数,对参数增加`interceptor`属性,用来拦截合并,当需要手动处理合并时可使用该参数。
18
+
19
+
20
+ #### Removed
21
+ * Null
5
22
 
6
23
  ## [v0.0.14] - 2025-12-26
7
24
 
@@ -16,6 +33,8 @@ All changes to Utils including new features, updates, and removals are documente
16
33
 
17
34
  #### Added
18
35
  * The `onBeforeClone` and `onAfterClone` callbacks of the `deepClone` function now include a new `parent` property, which can temporarily store the parent object being cloned. deepClone函数的onBeforeClone和onAfterClone新增属性parent,可临时存储被拷贝的父对象。
36
+ * Modified the `deepMerge` function to include an `interceptor` parameter, which can be used to intercept the merging process and handle it manually when needed.修改了`deepMerge`函数,对参数增加`interceptor`属性,用来拦截合并,当需要手动处理合并时可使用该参数。
37
+
19
38
 
20
39
  #### Removed
21
40
  * Null
package/dist/utils.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-26 11:26:20
3
+ * @since Last modified: 2025-12-26 15:47:37
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.15
5
+ * @version 0.0.16
6
6
  * @author AXUI development team <3217728223@qq.com>
7
7
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
8
8
  * @see {@link https://www.axui.cn|Official website}
@@ -61,16 +61,10 @@ const deepClone = (data, options = {}) => {
61
61
  }, options);
62
62
  // Check interceptor - if it returns a value (not null/undefined), use it directly
63
63
  if (opts.interceptor && typeof opts.interceptor === 'function') {
64
- let result = opts.interceptor(data, dataType);
64
+ let result = opts.interceptor({ input: data, type: dataType, parent: opts.parent });
65
65
  if ((result ?? false)) {
66
66
  // Call onAfterClone if set
67
- opts.onAfterClone?.({
68
- output: result,
69
- input: data,
70
- type: dataType,
71
- cloned: result !== data,
72
- parent: opts.parent
73
- });
67
+
74
68
  return result;
75
69
  }
76
70
  // If interceptor returns null/undefined, continue with normal cloning process
@@ -532,8 +526,25 @@ const deepMerge = (target, source, opts = {}) => {
532
526
  }, opts),
533
527
  // Main helper function for recursive merging
534
528
  // 递归合并的主辅助函数
535
- deepMergeHelper = (target, source, options) => {
529
+ smartMerger = (target, source, options) => {
536
530
  let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
531
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
532
+ if (options.interceptor && typeof options.interceptor === 'function') {
533
+ let interceptorResult = options.interceptor({ target, source, parent: options.parent });
534
+ if ((interceptorResult ?? false)) {
535
+ //如果不是返回{target,source},那么直接返回interceptorResult
536
+ if (interceptorResult?.target === null || interceptorResult?.source === null) {
537
+ return interceptorResult;
538
+ }
539
+ else {
540
+ //interceptorResult={target,source}
541
+ target = interceptorResult.target;
542
+ source = interceptorResult.source;
543
+ }
544
+ }
545
+ // If interceptor returns null/undefined, continue with normal cloning process
546
+ }
547
+ options?.onBeforeMerge?.({ target, source, parent: options.parent });
537
548
  // Determine the type and perform appropriate merging
538
549
  // 确定类型并执行相应的合并
539
550
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -556,6 +567,7 @@ const deepMerge = (target, source, opts = {}) => {
556
567
  flag = false;
557
568
  result = target;
558
569
  }
570
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
559
571
  return { result, flag, type };
560
572
  },
561
573
  // Special handling for objects with enable property
@@ -584,7 +596,6 @@ const deepMerge = (target, source, opts = {}) => {
584
596
  if (targetType !== 'Object' || sourceType !== 'Object') {
585
597
  return target;
586
598
  }
587
- opts?.onBeforeMerge?.(target, source);
588
599
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
589
600
  let result = {};
590
601
  // If cloning is enabled, clone the target first
@@ -592,7 +603,7 @@ const deepMerge = (target, source, opts = {}) => {
592
603
  result = options.targetClone ? shallowCopy(target) : target;
593
604
  for (let k in source) {
594
605
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
595
- let resp = deepMergeHelper(result[k], source[k], opts);
606
+ let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
596
607
  //resp={result,flag,type}
597
608
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
598
609
  if (!resp.flag) {
@@ -632,13 +643,11 @@ const deepMerge = (target, source, opts = {}) => {
632
643
  result[k] = source[k];
633
644
  }
634
645
  }
635
- options?.onAfterMerge?.(result, target, source);
636
646
  return result;
637
647
  }, deepMergeArrays = (target, source, options = {}) => {
638
648
  // Ensure both target and source are arrays
639
649
  if (!Array.isArray(target) || !Array.isArray(source))
640
650
  return target;
641
- options?.onBeforeMerge?.(target, source);
642
651
  // Merge options, with default values
643
652
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
644
653
  // If cloning is enabled, create a deep copy of the target array
@@ -651,7 +660,7 @@ const deepMerge = (target, source, opts = {}) => {
651
660
  // 如果不允许添加超过长度
652
661
  if (!opts.inheritMissing && i >= result.length)
653
662
  break;
654
- let resp = deepMergeHelper(result[i], source[i], opts);
663
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
655
664
  //resp={result,flag,type}
656
665
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
657
666
  if (!resp.flag) {
@@ -668,13 +677,11 @@ const deepMerge = (target, source, opts = {}) => {
668
677
  result.length = 0;
669
678
  result.push(...source);
670
679
  }
671
- options?.onAfterMerge?.(result, target, source);
672
680
  return result;
673
681
  }, deepMergeMaps = (target, source, options = {}) => {
674
682
  // Ensure both target and source are Maps
675
683
  if (!(target instanceof Map) || !(source instanceof Map))
676
684
  return target;
677
- options?.onBeforeMerge?.(target, source);
678
685
  // Merge options, with default values
679
686
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
680
687
  // If cloning is enabled, create a deep copy of the target Map
@@ -683,7 +690,7 @@ const deepMerge = (target, source, opts = {}) => {
683
690
  for (const [key, value] of source.entries())
684
691
  // Check if the key already exists in the target Map
685
692
  if (result.has(key)) {
686
- const _target = result.get(key), _source = value, resp = deepMergeHelper(_target, _source, opts);
693
+ const _target = result.get(key), _source = value, resp = smartMerger(_target, _source, opts);
687
694
  //resp={result,flag,type}
688
695
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
689
696
  if (!resp.flag) {
@@ -699,13 +706,11 @@ const deepMerge = (target, source, opts = {}) => {
699
706
  // If the key doesn't exist in the target, add the entry from the source Map
700
707
  options.inheritMissing && result.set(key, value);
701
708
  }
702
- options?.onAfterMerge?.(result, target, source);
703
709
  return result;
704
710
  }, deepMergeSets = (target, source, options = {}) => {
705
711
  // Ensure both target and source are Sets
706
712
  if (!(target instanceof Set) || !(source instanceof Set))
707
713
  return target;
708
- options?.onBeforeMerge?.(target, source);
709
714
  // Merge options, with default values
710
715
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
711
716
  // If cloning is enabled, create a deep copy of the target Set
@@ -713,7 +718,7 @@ const deepMerge = (target, source, opts = {}) => {
713
718
  // Handle different merge strategies based on dataMode
714
719
  if (opts.dataMode === 'replace') {
715
720
  // Replace mode: recursively merge items in the Sets
716
- const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
721
+ const _result = [...result], _source = [...source], resp = smartMerger(_result, _source, opts);
717
722
  result.clear();
718
723
  for (let item of resp.result)
719
724
  result.add(item);
@@ -729,10 +734,9 @@ const deepMerge = (target, source, opts = {}) => {
729
734
  for (let item of source)
730
735
  result.add(item);
731
736
  }
732
- options?.onAfterMerge?.(result, target, source);
733
737
  return result;
734
738
  };
735
- return deepMergeHelper(target, source, options).result;
739
+ return smartMerger(target, source, options).result;
736
740
  };
737
741
 
738
742
  const utils = {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-26 11:26:20
2
+ * @since Last modified: 2025-12-26 15:47:37
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.15
4
+ * @version 0.0.16
5
5
  * @author AXUI development team <3217728223@qq.com>
6
6
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
7
7
  * @see {@link https://www.axui.cn|Official website}
@@ -12,4 +12,4 @@
12
12
  * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
13
13
  * @license MIT license
14
14
  */
15
- "use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),o=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(o.interceptor&&"function"==typeof o.interceptor){let t=o.interceptor(e,r);if(t)return o.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e,parent:o.parent}),t}o.onBeforeClone?.({input:e,type:r,parent:o.parent});let a,n=!0;if("Object"===r&&o.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],o);if(r.length>0)for(const a of r)t[a]=deepClone(e[a],{...o,parent:e});a=t}else if("Array"===r&&o.cloneArray)a=e.map(t=>deepClone(t,{...o,parent:e}));else if("Map"===r&&o.cloneMap){const t=new Map;for(const[r,a]of e)t.set(deepClone(r,o),deepClone(a,{...o,parent:e}));a=t}else if("Set"===r&&o.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...o,parent:e}));a=t}else if("Date"===r&&o.cloneDate)a=new Date(e.getTime());else if("RegExp"===r&&o.cloneRegex){const t=e;a=new RegExp(t.source,t.flags)}else a=e,n=!1;return o.onAfterClone?.({output:a,input:e,type:r,cloned:n,parent:o.parent}),a},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=arrayMutableMethods);const n={};for(let s of o)n[s]=function(...o){const n={},l=e.length;switch(s){case"push":case"unshift":n.addedItems=[...o];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=o,a=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===r?l-a:r;n.deletedItems=e.slice(a,a+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=o[1]||0,p=void 0===o[2]?l:o[2];n.oldItems=e.slice(i,p),n.start=i,n.end=p}t?.(n);const i=Array.prototype[s].apply(e,o),p={value:i,key:s,args:o,context:n,target:e,...a};return r?.(p),i};return n},requireTypes=(e,t,r)=>{let o=Array.isArray(t)?t:[t],a=getDataType(e),n=a.toLowerCase(),s=o.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,a)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return a},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,o=e.base10,a=e.base36;return`${t?t+"-":""}${Date.now()}${a?"-"+Math.random().toString(36).substring(2,11):""}${o?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:o=setMutableMethods,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=o=>function(...n){const s={};switch(o){case"add":{const[t]=n;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=n;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}t(s);const l=e[o].apply(e,n),i={method:o,result:l,args:n,context:s,target:e,...a};return r(i),l};for(const e of o)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:o=mapMutableMethods,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=o=>function(...n){const s={};switch(o){case"set":{const[t,r]=n;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=n;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const l=e[o].apply(e,n),i={method:o,result:l,args:n,context:s,target:e,...a};return r(i),l};for(const e of o)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),deepMergeHelper=(e,t,r)=>{let o,a,n=getDataType(e),s=getDataType(t),l=!0;return"Object"===n&&"Object"===s?(a=deepMergeObjects(e,t,r),o="Object"):"Array"===n&&"Array"===s?(a=deepMergeArrays(e,t,r),o="Array"):"Set"===n&&"Set"===s?(a=deepMergeSets(e,t,r),o="Set"):"Map"===n&&"Map"===s?(a=deepMergeMaps(e,t,r),o="Map"):(l=!1,a=e),{result:a,flag:l,type:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let o=getDataType(e),a=getDataType(t);if("Object"!==o||"Object"!==a)return e;r?.onBeforeMerge?.(e,t);const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=n.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let o=deepMergeHelper(s[e],t[e],r);o.flag?o.type?"Object"===o.type&&(s[e]=o.result):s[e]=t[e]:n.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=t[e]);if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return n?.onAfterMerge?.(s,e,t),s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),a=o.targetClone?[...e]:e;if("replace"===o.dataMode)for(let e=0;e<t.length&&(o.inheritMissing||!(e>=a.length));e++){deepMergeHelper(a[e],t[e],o).flag||(a[e]=t[e])}else"concat"===o.dataMode||(a.length=0),a.push(...t);return r?.onAfterMerge?.(a,e,t),a},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=o.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(a.has(e)){const t=a.get(e),r=n,s=deepMergeHelper(t,r,o);s.flag?"Object"===s.type&&a.set(e,s.result):a.set(e,r)}else r.inheritMissing&&a.set(e,n);return r?.onAfterMerge?.(a,e,t),a},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),a=o.targetClone?new Set(...e):e;if("replace"===o.dataMode){const e=[...a],r=[...t],n=deepMergeHelper(e,r,o);a.clear();for(let e of n.result)a.add(e)}else if("concat"===o.dataMode)for(let e of t)a.add(e);else{a.clear();for(let e of t)a.add(e)}return r?.onAfterMerge?.(a,e,t),a};return deepMergeHelper(e,t,o).result},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol};module.exports=utils;
15
+ "use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let o,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...a,parent:e});o=t}else if("Array"===r&&a.cloneArray)o=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,a),deepClone(o,{...a,parent:e}));o=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));o=t}else if("Date"===r&&a.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,n=!1;return a.onAfterClone?.({output:o,input:e,type:r,cloned:n,parent:a.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:o={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let s of a)n[s]=function(...a){const n={},l=e.length;switch(s){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,o=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===r?l-o:r;n.deletedItems=e.slice(o,o+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,p=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,p),n.start=i,n.end=p}t?.(n);const i=Array.prototype[s].apply(e,a),p={value:i,key:s,args:a,context:n,target:e,...o};return r?.(p),i};return n},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],o=getDataType(e),n=o.toLowerCase(),s=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,o)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return o},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:o={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"add":{const[t]=n;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=n;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:o={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"set":{const[t,r]=n;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=n;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let o,n,s=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,parent:a.parent}),"Object"===s&&"Object"===l?(n=deepMergeObjects(e,t,a),o="Object"):"Array"===s&&"Array"===l?(n=deepMergeArrays(e,t,a),o="Array"):"Set"===s&&"Set"===l?(n=deepMergeSets(e,t,a),o="Set"):"Map"===s&&"Map"===l?(n=deepMergeMaps(e,t,a),o="Map"):(i=!1,n=e),a?.onAfterMerge?.({result:n,target:e,source:t,type:o,parent:r.parent}),{result:n,flag:i,type:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),o=getDataType(t);if("Object"!==a||"Object"!==o)return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=n.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let a=smartMerger(s[e],t[e],{...r,parent:s});a.flag?a.type?"Object"===a.type&&(s[e]=a.result):s[e]=t[e]:n.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=t[e]);if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=o.length));e++){smartMerger(o[e],t[e],{...a,parent:o}).flag||(o[e]=t[e])}else"concat"===a.dataMode||(o.length=0),o.push(...t);return o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(o.has(e)){const t=o.get(e),r=n,s=smartMerger(t,r,a);s.flag?"Object"===s.type&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,n);return o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...o],r=[...t],n=smartMerger(e,r,a);o.clear();for(let e of n.result)o.add(e)}else if("concat"===a.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return o};return smartMerger(e,t,a).result},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol};module.exports=utils;
package/dist/utils.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-26 11:26:20
3
+ * @since Last modified: 2025-12-26 15:47:37
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.15
5
+ * @version 0.0.16
6
6
  * @author AXUI development team <3217728223@qq.com>
7
7
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
8
8
  * @see {@link https://www.axui.cn|Official website}
@@ -59,16 +59,10 @@ const deepClone = (data, options = {}) => {
59
59
  }, options);
60
60
  // Check interceptor - if it returns a value (not null/undefined), use it directly
61
61
  if (opts.interceptor && typeof opts.interceptor === 'function') {
62
- let result = opts.interceptor(data, dataType);
62
+ let result = opts.interceptor({ input: data, type: dataType, parent: opts.parent });
63
63
  if ((result ?? false)) {
64
64
  // Call onAfterClone if set
65
- opts.onAfterClone?.({
66
- output: result,
67
- input: data,
68
- type: dataType,
69
- cloned: result !== data,
70
- parent: opts.parent
71
- });
65
+
72
66
  return result;
73
67
  }
74
68
  // If interceptor returns null/undefined, continue with normal cloning process
@@ -530,8 +524,25 @@ const deepMerge = (target, source, opts = {}) => {
530
524
  }, opts),
531
525
  // Main helper function for recursive merging
532
526
  // 递归合并的主辅助函数
533
- deepMergeHelper = (target, source, options) => {
527
+ smartMerger = (target, source, options) => {
534
528
  let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
529
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
530
+ if (options.interceptor && typeof options.interceptor === 'function') {
531
+ let interceptorResult = options.interceptor({ target, source, parent: options.parent });
532
+ if ((interceptorResult ?? false)) {
533
+ //如果不是返回{target,source},那么直接返回interceptorResult
534
+ if (interceptorResult?.target === null || interceptorResult?.source === null) {
535
+ return interceptorResult;
536
+ }
537
+ else {
538
+ //interceptorResult={target,source}
539
+ target = interceptorResult.target;
540
+ source = interceptorResult.source;
541
+ }
542
+ }
543
+ // If interceptor returns null/undefined, continue with normal cloning process
544
+ }
545
+ options?.onBeforeMerge?.({ target, source, parent: options.parent });
535
546
  // Determine the type and perform appropriate merging
536
547
  // 确定类型并执行相应的合并
537
548
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -554,6 +565,7 @@ const deepMerge = (target, source, opts = {}) => {
554
565
  flag = false;
555
566
  result = target;
556
567
  }
568
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
557
569
  return { result, flag, type };
558
570
  },
559
571
  // Special handling for objects with enable property
@@ -582,7 +594,6 @@ const deepMerge = (target, source, opts = {}) => {
582
594
  if (targetType !== 'Object' || sourceType !== 'Object') {
583
595
  return target;
584
596
  }
585
- opts?.onBeforeMerge?.(target, source);
586
597
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
587
598
  let result = {};
588
599
  // If cloning is enabled, clone the target first
@@ -590,7 +601,7 @@ const deepMerge = (target, source, opts = {}) => {
590
601
  result = options.targetClone ? shallowCopy(target) : target;
591
602
  for (let k in source) {
592
603
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
593
- let resp = deepMergeHelper(result[k], source[k], opts);
604
+ let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
594
605
  //resp={result,flag,type}
595
606
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
596
607
  if (!resp.flag) {
@@ -630,13 +641,11 @@ const deepMerge = (target, source, opts = {}) => {
630
641
  result[k] = source[k];
631
642
  }
632
643
  }
633
- options?.onAfterMerge?.(result, target, source);
634
644
  return result;
635
645
  }, deepMergeArrays = (target, source, options = {}) => {
636
646
  // Ensure both target and source are arrays
637
647
  if (!Array.isArray(target) || !Array.isArray(source))
638
648
  return target;
639
- options?.onBeforeMerge?.(target, source);
640
649
  // Merge options, with default values
641
650
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
642
651
  // If cloning is enabled, create a deep copy of the target array
@@ -649,7 +658,7 @@ const deepMerge = (target, source, opts = {}) => {
649
658
  // 如果不允许添加超过长度
650
659
  if (!opts.inheritMissing && i >= result.length)
651
660
  break;
652
- let resp = deepMergeHelper(result[i], source[i], opts);
661
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
653
662
  //resp={result,flag,type}
654
663
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
655
664
  if (!resp.flag) {
@@ -666,13 +675,11 @@ const deepMerge = (target, source, opts = {}) => {
666
675
  result.length = 0;
667
676
  result.push(...source);
668
677
  }
669
- options?.onAfterMerge?.(result, target, source);
670
678
  return result;
671
679
  }, deepMergeMaps = (target, source, options = {}) => {
672
680
  // Ensure both target and source are Maps
673
681
  if (!(target instanceof Map) || !(source instanceof Map))
674
682
  return target;
675
- options?.onBeforeMerge?.(target, source);
676
683
  // Merge options, with default values
677
684
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
678
685
  // If cloning is enabled, create a deep copy of the target Map
@@ -681,7 +688,7 @@ const deepMerge = (target, source, opts = {}) => {
681
688
  for (const [key, value] of source.entries())
682
689
  // Check if the key already exists in the target Map
683
690
  if (result.has(key)) {
684
- const _target = result.get(key), _source = value, resp = deepMergeHelper(_target, _source, opts);
691
+ const _target = result.get(key), _source = value, resp = smartMerger(_target, _source, opts);
685
692
  //resp={result,flag,type}
686
693
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
687
694
  if (!resp.flag) {
@@ -697,13 +704,11 @@ const deepMerge = (target, source, opts = {}) => {
697
704
  // If the key doesn't exist in the target, add the entry from the source Map
698
705
  options.inheritMissing && result.set(key, value);
699
706
  }
700
- options?.onAfterMerge?.(result, target, source);
701
707
  return result;
702
708
  }, deepMergeSets = (target, source, options = {}) => {
703
709
  // Ensure both target and source are Sets
704
710
  if (!(target instanceof Set) || !(source instanceof Set))
705
711
  return target;
706
- options?.onBeforeMerge?.(target, source);
707
712
  // Merge options, with default values
708
713
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
709
714
  // If cloning is enabled, create a deep copy of the target Set
@@ -711,7 +716,7 @@ const deepMerge = (target, source, opts = {}) => {
711
716
  // Handle different merge strategies based on dataMode
712
717
  if (opts.dataMode === 'replace') {
713
718
  // Replace mode: recursively merge items in the Sets
714
- const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
719
+ const _result = [...result], _source = [...source], resp = smartMerger(_result, _source, opts);
715
720
  result.clear();
716
721
  for (let item of resp.result)
717
722
  result.add(item);
@@ -727,10 +732,9 @@ const deepMerge = (target, source, opts = {}) => {
727
732
  for (let item of source)
728
733
  result.add(item);
729
734
  }
730
- options?.onAfterMerge?.(result, target, source);
731
735
  return result;
732
736
  };
733
- return deepMergeHelper(target, source, options).result;
737
+ return smartMerger(target, source, options).result;
734
738
  };
735
739
 
736
740
  const utils = {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-26 11:26:20
2
+ * @since Last modified: 2025-12-26 15:47:37
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.15
4
+ * @version 0.0.16
5
5
  * @author AXUI development team <3217728223@qq.com>
6
6
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
7
7
  * @see {@link https://www.axui.cn|Official website}
@@ -12,4 +12,4 @@
12
12
  * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
13
13
  * @license MIT license
14
14
  */
15
- const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor(e,r);if(t)return a.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e,parent:a.parent}),t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let o,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...a,parent:e});o=t}else if("Array"===r&&a.cloneArray)o=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,a),deepClone(o,{...a,parent:e}));o=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));o=t}else if("Date"===r&&a.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,n=!1;return a.onAfterClone?.({output:o,input:e,type:r,cloned:n,parent:a.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:o={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let s of a)n[s]=function(...a){const n={},l=e.length;switch(s){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,o=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===r?l-o:r;n.deletedItems=e.slice(o,o+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,p=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,p),n.start=i,n.end=p}t?.(n);const i=Array.prototype[s].apply(e,a),p={value:i,key:s,args:a,context:n,target:e,...o};return r?.(p),i};return n},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],o=getDataType(e),n=o.toLowerCase(),s=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,o)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return o},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:o={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"add":{const[t]=n;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=n;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:o={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"set":{const[t,r]=n;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=n;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),deepMergeHelper=(e,t,r)=>{let a,o,n=getDataType(e),s=getDataType(t),l=!0;return"Object"===n&&"Object"===s?(o=deepMergeObjects(e,t,r),a="Object"):"Array"===n&&"Array"===s?(o=deepMergeArrays(e,t,r),a="Array"):"Set"===n&&"Set"===s?(o=deepMergeSets(e,t,r),a="Set"):"Map"===n&&"Map"===s?(o=deepMergeMaps(e,t,r),a="Map"):(l=!1,o=e),{result:o,flag:l,type:a}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),o=getDataType(t);if("Object"!==a||"Object"!==o)return e;r?.onBeforeMerge?.(e,t);const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=n.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let a=deepMergeHelper(s[e],t[e],r);a.flag?a.type?"Object"===a.type&&(s[e]=a.result):s[e]=t[e]:n.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=t[e]);if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return n?.onAfterMerge?.(s,e,t),s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;r?.onBeforeMerge?.(e,t);const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=o.length));e++){deepMergeHelper(o[e],t[e],a).flag||(o[e]=t[e])}else"concat"===a.dataMode||(o.length=0),o.push(...t);return r?.onAfterMerge?.(o,e,t),o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;r?.onBeforeMerge?.(e,t);const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(o.has(e)){const t=o.get(e),r=n,s=deepMergeHelper(t,r,a);s.flag?"Object"===s.type&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,n);return r?.onAfterMerge?.(o,e,t),o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;r?.onBeforeMerge?.(e,t);const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...o],r=[...t],n=deepMergeHelper(e,r,a);o.clear();for(let e of n.result)o.add(e)}else if("concat"===a.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return r?.onAfterMerge?.(o,e,t),o};return deepMergeHelper(e,t,a).result},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol};export{utils as default};
15
+ const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor({input:e,type:r,parent:a.parent});if(t)return t}a.onBeforeClone?.({input:e,type:r,parent:a.parent});let o,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...a,parent:e});o=t}else if("Array"===r&&a.cloneArray)o=e.map(t=>deepClone(t,{...a,parent:e}));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,a),deepClone(o,{...a,parent:e}));o=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...a,parent:e}));o=t}else if("Date"===r&&a.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,n=!1;return a.onAfterClone?.({output:o,input:e,type:r,cloned:n,parent:a.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:o={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let s of a)n[s]=function(...a){const n={},l=e.length;switch(s){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[l-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,o=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===r?l-o:r;n.deletedItems=e.slice(o,o+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const i=a[1]||0,p=void 0===a[2]?l:a[2];n.oldItems=e.slice(i,p),n.start=i,n.end=p}t?.(n);const i=Array.prototype[s].apply(e,a),p={value:i,key:s,args:a,context:n,target:e,...o};return r?.(p),i};return n},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],o=getDataType(e),n=o.toLowerCase(),s=a.map(e=>e.toLowerCase()),l=n.includes("html")?"element":n;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,o)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return o},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:o={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"add":{const[t]=n;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=n;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:o={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){case"set":{const[t,r]=n;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=n;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const l=e[a].apply(e,n),i={method:a,result:l,args:n,context:s,target:e,...o};return r(i),l};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e},deepMerge=(e,t,r={})=>{const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,a)=>{let o,n,s=getDataType(e),l=getDataType(t),i=!0;if(a.interceptor&&"function"==typeof a.interceptor){let r=a.interceptor({target:e,source:t,parent:a.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return a?.onBeforeMerge?.({target:e,source:t,parent:a.parent}),"Object"===s&&"Object"===l?(n=deepMergeObjects(e,t,a),o="Object"):"Array"===s&&"Array"===l?(n=deepMergeArrays(e,t,a),o="Array"):"Set"===s&&"Set"===l?(n=deepMergeSets(e,t,a),o="Set"):"Map"===s&&"Map"===l?(n=deepMergeMaps(e,t,a),o="Map"):(i=!1,n=e),a?.onAfterMerge?.({result:n,target:e,source:t,type:o,parent:r.parent}),{result:n,flag:i,type:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),o=getDataType(t);if("Object"!==a||"Object"!==o)return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=n.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let a=smartMerger(s[e],t[e],{...r,parent:s});a.flag?a.type?"Object"===a.type&&(s[e]=a.result):s[e]=t[e]:n.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=t[e]);if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=a.targetClone?[...e]:e;if("replace"===a.dataMode)for(let e=0;e<t.length&&(a.inheritMissing||!(e>=o.length));e++){smartMerger(o[e],t[e],{...a,parent:o}).flag||(o[e]=t[e])}else"concat"===a.dataMode||(o.length=0),o.push(...t);return o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Map([...e]):e;for(const[e,n]of t.entries())if(o.has(e)){const t=o.get(e),r=n,s=smartMerger(t,r,a);s.flag?"Object"===s.type&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,n);return o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Set(...e):e;if("replace"===a.dataMode){const e=[...o],r=[...t],n=smartMerger(e,r,a);o.clear();for(let e of n.result)o.add(e)}else if("concat"===a.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return o};return smartMerger(e,t,a).result},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepMerge:deepMerge,shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol};export{utils as default};
package/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-26 11:26:20
3
+ * @since Last modified: 2025-12-26 15:47:37
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.15
5
+ * @version 0.0.16
6
6
  * @author AXUI development team <3217728223@qq.com>
7
7
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
8
8
  * @see {@link https://www.axui.cn|Official website}
@@ -65,16 +65,10 @@
65
65
  }, options);
66
66
  // Check interceptor - if it returns a value (not null/undefined), use it directly
67
67
  if (opts.interceptor && typeof opts.interceptor === 'function') {
68
- let result = opts.interceptor(data, dataType);
68
+ let result = opts.interceptor({ input: data, type: dataType, parent: opts.parent });
69
69
  if ((result ?? false)) {
70
70
  // Call onAfterClone if set
71
- opts.onAfterClone?.({
72
- output: result,
73
- input: data,
74
- type: dataType,
75
- cloned: result !== data,
76
- parent: opts.parent
77
- });
71
+
78
72
  return result;
79
73
  }
80
74
  // If interceptor returns null/undefined, continue with normal cloning process
@@ -536,8 +530,25 @@
536
530
  }, opts),
537
531
  // Main helper function for recursive merging
538
532
  // 递归合并的主辅助函数
539
- deepMergeHelper = (target, source, options) => {
533
+ smartMerger = (target, source, options) => {
540
534
  let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
535
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
536
+ if (options.interceptor && typeof options.interceptor === 'function') {
537
+ let interceptorResult = options.interceptor({ target, source, parent: options.parent });
538
+ if ((interceptorResult ?? false)) {
539
+ //如果不是返回{target,source},那么直接返回interceptorResult
540
+ if (interceptorResult?.target === null || interceptorResult?.source === null) {
541
+ return interceptorResult;
542
+ }
543
+ else {
544
+ //interceptorResult={target,source}
545
+ target = interceptorResult.target;
546
+ source = interceptorResult.source;
547
+ }
548
+ }
549
+ // If interceptor returns null/undefined, continue with normal cloning process
550
+ }
551
+ options?.onBeforeMerge?.({ target, source, parent: options.parent });
541
552
  // Determine the type and perform appropriate merging
542
553
  // 确定类型并执行相应的合并
543
554
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -560,6 +571,7 @@
560
571
  flag = false;
561
572
  result = target;
562
573
  }
574
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
563
575
  return { result, flag, type };
564
576
  },
565
577
  // Special handling for objects with enable property
@@ -588,7 +600,6 @@
588
600
  if (targetType !== 'Object' || sourceType !== 'Object') {
589
601
  return target;
590
602
  }
591
- opts?.onBeforeMerge?.(target, source);
592
603
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
593
604
  let result = {};
594
605
  // If cloning is enabled, clone the target first
@@ -596,7 +607,7 @@
596
607
  result = options.targetClone ? shallowCopy(target) : target;
597
608
  for (let k in source) {
598
609
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
599
- let resp = deepMergeHelper(result[k], source[k], opts);
610
+ let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
600
611
  //resp={result,flag,type}
601
612
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
602
613
  if (!resp.flag) {
@@ -636,13 +647,11 @@
636
647
  result[k] = source[k];
637
648
  }
638
649
  }
639
- options?.onAfterMerge?.(result, target, source);
640
650
  return result;
641
651
  }, deepMergeArrays = (target, source, options = {}) => {
642
652
  // Ensure both target and source are arrays
643
653
  if (!Array.isArray(target) || !Array.isArray(source))
644
654
  return target;
645
- options?.onBeforeMerge?.(target, source);
646
655
  // Merge options, with default values
647
656
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
648
657
  // If cloning is enabled, create a deep copy of the target array
@@ -655,7 +664,7 @@
655
664
  // 如果不允许添加超过长度
656
665
  if (!opts.inheritMissing && i >= result.length)
657
666
  break;
658
- let resp = deepMergeHelper(result[i], source[i], opts);
667
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
659
668
  //resp={result,flag,type}
660
669
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
661
670
  if (!resp.flag) {
@@ -672,13 +681,11 @@
672
681
  result.length = 0;
673
682
  result.push(...source);
674
683
  }
675
- options?.onAfterMerge?.(result, target, source);
676
684
  return result;
677
685
  }, deepMergeMaps = (target, source, options = {}) => {
678
686
  // Ensure both target and source are Maps
679
687
  if (!(target instanceof Map) || !(source instanceof Map))
680
688
  return target;
681
- options?.onBeforeMerge?.(target, source);
682
689
  // Merge options, with default values
683
690
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
684
691
  // If cloning is enabled, create a deep copy of the target Map
@@ -687,7 +694,7 @@
687
694
  for (const [key, value] of source.entries())
688
695
  // Check if the key already exists in the target Map
689
696
  if (result.has(key)) {
690
- const _target = result.get(key), _source = value, resp = deepMergeHelper(_target, _source, opts);
697
+ const _target = result.get(key), _source = value, resp = smartMerger(_target, _source, opts);
691
698
  //resp={result,flag,type}
692
699
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
693
700
  if (!resp.flag) {
@@ -703,13 +710,11 @@
703
710
  // If the key doesn't exist in the target, add the entry from the source Map
704
711
  options.inheritMissing && result.set(key, value);
705
712
  }
706
- options?.onAfterMerge?.(result, target, source);
707
713
  return result;
708
714
  }, deepMergeSets = (target, source, options = {}) => {
709
715
  // Ensure both target and source are Sets
710
716
  if (!(target instanceof Set) || !(source instanceof Set))
711
717
  return target;
712
- options?.onBeforeMerge?.(target, source);
713
718
  // Merge options, with default values
714
719
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
715
720
  // If cloning is enabled, create a deep copy of the target Set
@@ -717,7 +722,7 @@
717
722
  // Handle different merge strategies based on dataMode
718
723
  if (opts.dataMode === 'replace') {
719
724
  // Replace mode: recursively merge items in the Sets
720
- const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
725
+ const _result = [...result], _source = [...source], resp = smartMerger(_result, _source, opts);
721
726
  result.clear();
722
727
  for (let item of resp.result)
723
728
  result.add(item);
@@ -733,10 +738,9 @@
733
738
  for (let item of source)
734
739
  result.add(item);
735
740
  }
736
- options?.onAfterMerge?.(result, target, source);
737
741
  return result;
738
742
  };
739
- return deepMergeHelper(target, source, options).result;
743
+ return smartMerger(target, source, options).result;
740
744
  };
741
745
 
742
746
  const utils = {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-26 11:26:20
2
+ * @since Last modified: 2025-12-26 15:47:37
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.15
4
+ * @version 0.0.16
5
5
  * @author AXUI development team <3217728223@qq.com>
6
6
  * @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
7
7
  * @see {@link https://www.axui.cn|Official website}
@@ -12,4 +12,4 @@
12
12
  * @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
13
13
  * @license MIT license
14
14
  */
15
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor(e,r);if(t)return n.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e,parent:n.parent}),t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let o,a=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...n,parent:e});o=t}else if("Array"===r&&n.cloneArray)o=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,n),deepClone(o,{...n,parent:e}));o=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));o=t}else if("Date"===r&&n.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,a=!1;return n.onAfterClone?.({output:o,input:e,type:r,cloned:a,parent:n.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let n=Array.isArray(t)?t:[t],o=getDataType(e),a=o.toLowerCase(),s=n.map(e=>e.toLowerCase()),i=a.includes("html")?"element":a;if(r)try{if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`)}catch(e){r(e,o)}else if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`);return o},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=e);const s={};for(let e of o)s[e]=function(...o){const s={},i=t.length;switch(e){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedItem=t[i-1];break;case"shift":s.shiftedItem=t[0];break;case"splice":const[e,r]=o,n=e<0?Math.max(i+e,0):Math.min(e,i),a=void 0===r?i-n:r;s.deletedItems=t.slice(n,n+a);break;case"sort":case"reverse":s.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=o[1]||0,c=void 0===o[2]?i:o[2];s.oldItems=t.slice(l,c),s.start=l,s.end=c}r?.(s);const l=Array.prototype[e].apply(t,o),c={value:l,key:e,args:o,context:s,target:t,...a};return n?.(c),l};return s},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o=t,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=t=>function(...o){const s={};switch(t){case"add":{const[t]=o;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=o;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}r(s);const i=e[t].apply(e,o),l={method:t,result:i,args:o,context:s,target:e,...a};return n(l),i};for(const e of o)t.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:n=()=>{},allowList:o=r,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...o){const s={};switch(r){case"set":{const[t,r]=o;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=o;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const i=e[r].apply(e,o),l={method:r,result:i,args:o,context:s,target:e,...a};return n(l),i};for(const e of o)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),deepMergeHelper=(e,t,r)=>{let n,o,a=getDataType(e),s=getDataType(t),i=!0;return"Object"===a&&"Object"===s?(o=deepMergeObjects(e,t,r),n="Object"):"Array"===a&&"Array"===s?(o=deepMergeArrays(e,t,r),n="Array"):"Set"===a&&"Set"===s?(o=deepMergeSets(e,t,r),n="Set"):"Map"===a&&"Map"===s?(o=deepMergeMaps(e,t,r),n="Map"):(i=!1,o=e),{result:o,flag:i,type:n}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let n=getDataType(e),o=getDataType(t);if("Object"!==n||"Object"!==o)return e;r?.onBeforeMerge?.(e,t);const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=a.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let n=deepMergeHelper(s[e],t[e],r);n.flag?n.type?"Object"===n.type&&(s[e]=n.result):s[e]=t[e]:a.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=t[e]);if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return a?.onAfterMerge?.(s,e,t),s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;r?.onBeforeMerge?.(e,t);const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=o.length));e++){deepMergeHelper(o[e],t[e],n).flag||(o[e]=t[e])}else"concat"===n.dataMode||(o.length=0),o.push(...t);return r?.onAfterMerge?.(o,e,t),o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;r?.onBeforeMerge?.(e,t);const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Map([...e]):e;for(const[e,a]of t.entries())if(o.has(e)){const t=o.get(e),r=a,s=deepMergeHelper(t,r,n);s.flag?"Object"===s.type&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,a);return r?.onAfterMerge?.(o,e,t),o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;r?.onBeforeMerge?.(e,t);const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...o],r=[...t],a=deepMergeHelper(e,r,n);o.clear();for(let e of a.result)o.add(e)}else if("concat"===n.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return r?.onAfterMerge?.(o,e,t),o};return deepMergeHelper(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol}});
15
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t()}(this,function(){"use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),n=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(n.interceptor&&"function"==typeof n.interceptor){let t=n.interceptor({input:e,type:r,parent:n.parent});if(t)return t}n.onBeforeClone?.({input:e,type:r,parent:n.parent});let o,a=!0;if("Object"===r&&n.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],n);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],{...n,parent:e});o=t}else if("Array"===r&&n.cloneArray)o=e.map(t=>deepClone(t,{...n,parent:e}));else if("Map"===r&&n.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,n),deepClone(o,{...n,parent:e}));o=t}else if("Set"===r&&n.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,{...n,parent:e}));o=t}else if("Date"===r&&n.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&n.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,a=!1;return n.onAfterClone?.({output:o,input:e,type:r,cloned:a,parent:n.parent}),o},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],copyObjectWithSymbol=e=>{if(!e||"object"!=typeof e)return e;const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}},shallowCopy=(e,t={})=>{const r=getDataType(e);return"Set"===r?new Set([...e]):"Map"===r?new Map([...e]):Array.isArray(e)?[...e]:"object"===r?copyObjectWithSymbol(e):"Date"===r?new Date(e.getTime()):"RegExp"===r?new RegExp(e.source,e.flags):"Buffer"===r?Buffer.from(e):"ArrayBuffer"===r||ArrayBuffer.isView(e)?e.slice(0):"WeakSet"===r?new WeakSet([...e]):"WeakMap"===r?new WeakMap([...e]):"Error"===r?new Error(e.message):e};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let n=Array.isArray(t)?t:[t],o=getDataType(e),a=o.toLowerCase(),s=n.map(e=>e.toLowerCase()),i=a.includes("html")?"element":a;if(r)try{if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`)}catch(e){r(e,o)}else if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`);return o},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=e);const s={};for(let e of o)s[e]=function(...o){const s={},i=t.length;switch(e){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedItem=t[i-1];break;case"shift":s.shiftedItem=t[0];break;case"splice":const[e,r]=o,n=e<0?Math.max(i+e,0):Math.min(e,i),a=void 0===r?i-n:r;s.deletedItems=t.slice(n,n+a);break;case"sort":case"reverse":s.oldSnapshot=[...t];break;case"fill":case"copyWithin":const c=o[1]||0,l=void 0===o[2]?i:o[2];s.oldItems=t.slice(c,l),s.start=c,s.end=l}r?.(s);const c=Array.prototype[e].apply(t,o),l={value:c,key:e,args:o,context:s,target:t,...a};return n?.(l),c};return s},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:n=()=>{},allowList:o=t,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=t=>function(...o){const s={};switch(t){case"add":{const[t]=o;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=o;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}r(s);const i=e[t].apply(e,o),c={method:t,result:i,args:o,context:s,target:e,...a};return n(c),i};for(const e of o)t.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:n=()=>{},allowList:o=r,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...o){const s={};switch(r){case"set":{const[t,r]=o;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=o;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const i=e[r].apply(e,o),c={method:r,result:i,args:o,context:s,target:e,...a};return n(c),i};for(const e of o)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,n=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${n?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,n)=>{let o,a,s=getDataType(e),i=getDataType(t),c=!0;if(n.interceptor&&"function"==typeof n.interceptor){let r=n.interceptor({target:e,source:t,parent:n.parent});if(r){if(null===r?.target||null===r?.source)return r;e=r.target,t=r.source}}return n?.onBeforeMerge?.({target:e,source:t,parent:n.parent}),"Object"===s&&"Object"===i?(a=deepMergeObjects(e,t,n),o="Object"):"Array"===s&&"Array"===i?(a=deepMergeArrays(e,t,n),o="Array"):"Set"===s&&"Set"===i?(a=deepMergeSets(e,t,n),o="Set"):"Map"===s&&"Map"===i?(a=deepMergeMaps(e,t,n),o="Map"):(c=!1,a=e),n?.onAfterMerge?.({result:a,target:e,source:t,type:o,parent:r.parent}),{result:a,flag:c,type:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let n=getDataType(e),o=getDataType(t);if("Object"!==n||"Object"!==o)return e;const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=a.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let n=smartMerger(s[e],t[e],{...r,parent:s});n.flag?n.type?"Object"===n.type&&(s[e]=n.result):s[e]=t[e]:a.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=t[e]);if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),o=n.targetClone?[...e]:e;if("replace"===n.dataMode)for(let e=0;e<t.length&&(n.inheritMissing||!(e>=o.length));e++){smartMerger(o[e],t[e],{...n,parent:o}).flag||(o[e]=t[e])}else"concat"===n.dataMode||(o.length=0),o.push(...t);return o},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;const n=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Map([...e]):e;for(const[e,a]of t.entries())if(o.has(e)){const t=o.get(e),r=a,s=smartMerger(t,r,n);s.flag?"Object"===s.type&&o.set(e,s.result):o.set(e,r)}else r.inheritMissing&&o.set(e,a);return o},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;const n=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),o=n.targetClone?new Set(...e):e;if("replace"===n.dataMode){const e=[...o],r=[...t],a=smartMerger(e,r,n);o.clear();for(let e of a.result)o.add(e)}else if("concat"===n.dataMode)for(let e of t)o.add(e);else{o.clear();for(let e of t)o.add(e)}return o};return smartMerger(e,t,n).result},shallowCopy:shallowCopy,copyObjectWithSymbol:copyObjectWithSymbol}});
package/dist.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "author": "AXUI Development Team",
5
5
  "license": "MIT",
6
6
  "description": "This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.",
package/src/deepClone.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 11:26:10
2
+ * @since Last modified: 2025/12/26 15:13:54
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
@@ -100,16 +100,16 @@ const deepClone = (data, options = {}) => {
100
100
  }, options);
101
101
  // Check interceptor - if it returns a value (not null/undefined), use it directly
102
102
  if (opts.interceptor && typeof opts.interceptor === 'function') {
103
- let result = opts.interceptor(data, dataType);
103
+ let result = opts.interceptor({ input: data, type: dataType, parent: opts.parent });
104
104
  if ((result ?? false)) {
105
105
  // Call onAfterClone if set
106
- opts.onAfterClone?.({
107
- output: result,
108
- input: data,
109
- type: dataType,
110
- cloned: result !== data,
111
- parent: opts.parent
112
- });
106
+ /* opts.onAfterClone?.({
107
+ output: result,
108
+ input: data,
109
+ type: dataType,
110
+ cloned: result !== data,
111
+ parent: opts.parent
112
+ }); */
113
113
  return result;
114
114
  }
115
115
  // If interceptor returns null/undefined, continue with normal cloning process
package/src/deepClone.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 11:26:10
2
+ * @since Last modified: 2025/12/26 15:13:54
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
@@ -94,7 +94,7 @@ export interface DeepCloneOptions {
94
94
  /**
95
95
  * Interceptor function. If returns a non-null value, use it as the cloning result.
96
96
  */
97
- interceptor?: <T>(data: T, dataType: string) => T | null | undefined;
97
+ interceptor?: <T>(result: BeforeCloneResult) => T | null | undefined;
98
98
 
99
99
  /**
100
100
  * Callback before cloning.
@@ -147,16 +147,16 @@ const deepClone = <T>(data: T, options: DeepCloneOptions = {}): T => {
147
147
 
148
148
  // Check interceptor - if it returns a value (not null/undefined), use it directly
149
149
  if (opts.interceptor && typeof opts.interceptor === 'function') {
150
- let result = opts.interceptor(data, dataType);
150
+ let result = opts.interceptor({input: data, type: dataType,parent: opts.parent});
151
151
  if ((result ?? false)) {
152
152
  // Call onAfterClone if set
153
- opts.onAfterClone?.({
153
+ /* opts.onAfterClone?.({
154
154
  output: result,
155
155
  input: data,
156
156
  type: dataType,
157
157
  cloned: result !== data,
158
158
  parent: opts.parent
159
- });
159
+ }); */
160
160
  return result as T;
161
161
  }
162
162
  // If interceptor returns null/undefined, continue with normal cloning process
package/src/deepMerge.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/25 12:10:30
2
+ * @since Last modified: 2025/12/26 15:40:50
3
3
  * @function deepMerge
4
4
  * @description Deeply merges two data structures (Object, Array, Map, or Set) based on their types.
5
5
  * This function recursively merges the properties or items of the target and source, depending on their types.
@@ -69,8 +69,25 @@ const deepMerge = (target, source, opts = {}) => {
69
69
  }, opts),
70
70
  // Main helper function for recursive merging
71
71
  // 递归合并的主辅助函数
72
- deepMergeHelper = (target, source, options) => {
72
+ smartMerger = (target, source, options) => {
73
73
  let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
74
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
75
+ if (options.interceptor && typeof options.interceptor === 'function') {
76
+ let interceptorResult = options.interceptor({ target, source, parent: options.parent });
77
+ if ((interceptorResult ?? false)) {
78
+ //如果不是返回{target,source},那么直接返回interceptorResult
79
+ if (interceptorResult?.target === null || interceptorResult?.source === null) {
80
+ return interceptorResult;
81
+ }
82
+ else {
83
+ //interceptorResult={target,source}
84
+ target = interceptorResult.target;
85
+ source = interceptorResult.source;
86
+ }
87
+ }
88
+ // If interceptor returns null/undefined, continue with normal cloning process
89
+ }
90
+ options?.onBeforeMerge?.({ target, source, parent: options.parent });
74
91
  // Determine the type and perform appropriate merging
75
92
  // 确定类型并执行相应的合并
76
93
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -93,6 +110,7 @@ const deepMerge = (target, source, opts = {}) => {
93
110
  flag = false;
94
111
  result = target;
95
112
  }
113
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
96
114
  return { result, flag, type };
97
115
  },
98
116
  // Special handling for objects with enable property
@@ -121,7 +139,6 @@ const deepMerge = (target, source, opts = {}) => {
121
139
  if (targetType !== 'Object' || sourceType !== 'Object') {
122
140
  return target;
123
141
  }
124
- opts?.onBeforeMerge?.(target, source);
125
142
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
126
143
  let result = {};
127
144
  // If cloning is enabled, clone the target first
@@ -129,7 +146,7 @@ const deepMerge = (target, source, opts = {}) => {
129
146
  result = options.targetClone ? shallowCopy(target) : target;
130
147
  for (let k in source) {
131
148
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
132
- let resp = deepMergeHelper(result[k], source[k], opts);
149
+ let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
133
150
  //resp={result,flag,type}
134
151
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
135
152
  if (!resp.flag) {
@@ -169,13 +186,11 @@ const deepMerge = (target, source, opts = {}) => {
169
186
  result[k] = source[k];
170
187
  }
171
188
  }
172
- options?.onAfterMerge?.(result, target, source);
173
189
  return result;
174
190
  }, deepMergeArrays = (target, source, options = {}) => {
175
191
  // Ensure both target and source are arrays
176
192
  if (!Array.isArray(target) || !Array.isArray(source))
177
193
  return target;
178
- options?.onBeforeMerge?.(target, source);
179
194
  // Merge options, with default values
180
195
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
181
196
  // If cloning is enabled, create a deep copy of the target array
@@ -188,7 +203,7 @@ const deepMerge = (target, source, opts = {}) => {
188
203
  // 如果不允许添加超过长度
189
204
  if (!opts.inheritMissing && i >= result.length)
190
205
  break;
191
- let resp = deepMergeHelper(result[i], source[i], opts);
206
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
192
207
  //resp={result,flag,type}
193
208
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
194
209
  if (!resp.flag) {
@@ -205,13 +220,11 @@ const deepMerge = (target, source, opts = {}) => {
205
220
  result.length = 0;
206
221
  result.push(...source);
207
222
  }
208
- options?.onAfterMerge?.(result, target, source);
209
223
  return result;
210
224
  }, deepMergeMaps = (target, source, options = {}) => {
211
225
  // Ensure both target and source are Maps
212
226
  if (!(target instanceof Map) || !(source instanceof Map))
213
227
  return target;
214
- options?.onBeforeMerge?.(target, source);
215
228
  // Merge options, with default values
216
229
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
217
230
  // If cloning is enabled, create a deep copy of the target Map
@@ -220,7 +233,7 @@ const deepMerge = (target, source, opts = {}) => {
220
233
  for (const [key, value] of source.entries())
221
234
  // Check if the key already exists in the target Map
222
235
  if (result.has(key)) {
223
- const _target = result.get(key), _source = value, resp = deepMergeHelper(_target, _source, opts);
236
+ const _target = result.get(key), _source = value, resp = smartMerger(_target, _source, opts);
224
237
  //resp={result,flag,type}
225
238
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
226
239
  if (!resp.flag) {
@@ -236,13 +249,11 @@ const deepMerge = (target, source, opts = {}) => {
236
249
  // If the key doesn't exist in the target, add the entry from the source Map
237
250
  options.inheritMissing && result.set(key, value);
238
251
  }
239
- options?.onAfterMerge?.(result, target, source);
240
252
  return result;
241
253
  }, deepMergeSets = (target, source, options = {}) => {
242
254
  // Ensure both target and source are Sets
243
255
  if (!(target instanceof Set) || !(source instanceof Set))
244
256
  return target;
245
- options?.onBeforeMerge?.(target, source);
246
257
  // Merge options, with default values
247
258
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
248
259
  // If cloning is enabled, create a deep copy of the target Set
@@ -250,7 +261,7 @@ const deepMerge = (target, source, opts = {}) => {
250
261
  // Handle different merge strategies based on dataMode
251
262
  if (opts.dataMode === 'replace') {
252
263
  // Replace mode: recursively merge items in the Sets
253
- const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
264
+ const _result = [...result], _source = [...source], resp = smartMerger(_result, _source, opts);
254
265
  result.clear();
255
266
  for (let item of resp.result)
256
267
  result.add(item);
@@ -266,9 +277,8 @@ const deepMerge = (target, source, opts = {}) => {
266
277
  for (let item of source)
267
278
  result.add(item);
268
279
  }
269
- options?.onAfterMerge?.(result, target, source);
270
280
  return result;
271
281
  };
272
- return deepMergeHelper(target, source, options).result;
282
+ return smartMerger(target, source, options).result;
273
283
  };
274
284
  export default deepMerge;
package/src/deepMerge.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/25 12:10:30
2
+ * @since Last modified: 2025/12/26 15:40:50
3
3
  * @function deepMerge
4
4
  * @description Deeply merges two data structures (Object, Array, Map, or Set) based on their types.
5
5
  * This function recursively merges the properties or items of the target and source, depending on their types.
@@ -59,20 +59,42 @@ export interface DeepMergeOptions {
59
59
  // 启用克隆时传递给deepClone函数的选项
60
60
  deepClone?: Record<string, any>;
61
61
 
62
- // Callback function executed before merging each data structure
63
- // 在每个数据结构合并前执行的回调函数
64
- onBeforeMerge?: (
65
- target: Object | Array<any> | Map<any, any> | Set<any>,
66
- source: Object | Array<any> | Map<any, any> | Set<any> | any
67
- ) => void;
68
-
69
- // Callback function executed after merging each data structure
70
- // 在每个数据结构合并后执行的回调函数
71
- onAfterMerge?: (
72
- result: Object | Array<any> | Map<any, any> | Set<any>,
73
- originalTarget: Object | Array<any> | Map<any, any> | Set<any>,
74
- source: Object | Array<any> | Map<any, any> | Set<any> | any
75
- ) => void;
62
+ /**
63
+ * Interceptor function. If returns a non-null value, use it as the merging result.
64
+ * 拦截器函数。如果返回非null值,则将其用作合并结果。
65
+ */
66
+ interceptor?: (params: {
67
+ target: any;
68
+ source: any;
69
+ parent?: any;
70
+ }) => any;
71
+
72
+ /**
73
+ * Callback function executed before merging each data structure
74
+ * 在每个数据结构合并前执行的回调函数
75
+ */
76
+ onBeforeMerge?: (params: {
77
+ target: any;
78
+ source: any;
79
+ parent?: any;
80
+ }) => void;
81
+
82
+ /**
83
+ * Callback function executed after merging each data structure
84
+ * 在每个数据结构合并后执行的回调函数
85
+ */
86
+ onAfterMerge?: (params: {
87
+ result: any;
88
+ target: any;
89
+ source: any;
90
+ parent?: any;
91
+ type?: '' | 'Object' | 'Array' | 'Map' | 'Set';
92
+ }) => void;
93
+
94
+ /**
95
+ * 深度合并时的临时保存的父对象
96
+ */
97
+ parent?: any;
76
98
  }
77
99
  export type EnableObject = {
78
100
  enable: boolean;
@@ -122,12 +144,31 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
122
144
  }, opts),
123
145
  // Main helper function for recursive merging
124
146
  // 递归合并的主辅助函数
125
- deepMergeHelper = (target: any, source: any, options: DeepMergeOptions): any => {
147
+ smartMerger = (target: any, source: any, options: DeepMergeOptions): any => {
126
148
  let targetType = getDataType(target),
127
149
  sourceType = getDataType(source),
128
150
  flag = true,
129
- type,
151
+ type: any,
130
152
  result;
153
+
154
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
155
+ if (options.interceptor && typeof options.interceptor === 'function') {
156
+ let interceptorResult = options.interceptor({ target, source, parent: options.parent });
157
+ if ((interceptorResult ?? false)) {
158
+ //如果不是返回{target,source},那么直接返回interceptorResult
159
+ if (interceptorResult?.target === null || interceptorResult?.source === null) {
160
+ return interceptorResult;
161
+ } else {
162
+ //interceptorResult={target,source}
163
+ target = interceptorResult.target;
164
+ source = interceptorResult.source;
165
+ }
166
+ }
167
+ // If interceptor returns null/undefined, continue with normal cloning process
168
+ }
169
+
170
+ options?.onBeforeMerge?.({ target, source, parent: options.parent });
171
+
131
172
  // Determine the type and perform appropriate merging
132
173
  // 确定类型并执行相应的合并
133
174
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -146,6 +187,7 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
146
187
  flag = false;
147
188
  result = target;
148
189
  }
190
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
149
191
  return { result, flag, type };
150
192
  },
151
193
  // Special handling for objects with enable property
@@ -174,7 +216,6 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
174
216
  if (targetType !== 'Object' || sourceType !== 'Object') {
175
217
  return target;
176
218
  }
177
- opts?.onBeforeMerge?.(target, source);
178
219
 
179
220
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
180
221
  let result: any = {};
@@ -185,7 +226,7 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
185
226
  for (let k in source) {
186
227
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
187
228
 
188
- let resp = deepMergeHelper((result as any)[k], source[k], opts);
229
+ let resp = smartMerger((result as any)[k], source[k], { ...opts, parent: result });
189
230
  //resp={result,flag,type}
190
231
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
191
232
  if (!resp.flag) {
@@ -221,13 +262,12 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
221
262
  for (let k of symbols) (result as any)[k] = source[k];
222
263
  }
223
264
  }
224
- options?.onAfterMerge?.(result, target, source);
225
265
  return result;
226
266
  },
227
267
  deepMergeArrays = (target: any[], source: any[], options: DeepMergeOptions = {}): any[] => {
228
268
  // Ensure both target and source are arrays
229
269
  if (!Array.isArray(target) || !Array.isArray(source)) return target;
230
- options?.onBeforeMerge?.(target, source);
270
+
231
271
  // Merge options, with default values
232
272
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
233
273
 
@@ -241,7 +281,7 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
241
281
  // If not allowed to add beyond length
242
282
  // 如果不允许添加超过长度
243
283
  if (!opts.inheritMissing && i >= result.length) break;
244
- let resp = deepMergeHelper(result[i], source[i], opts);
284
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
245
285
  //resp={result,flag,type}
246
286
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
247
287
  if (!resp.flag) {
@@ -256,13 +296,12 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
256
296
  result.length = 0;
257
297
  result.push(...source);
258
298
  }
259
- options?.onAfterMerge?.(result, target, source);
260
299
  return result;
261
300
  },
262
301
  deepMergeMaps = (target: Map<any, any>, source: Map<any, any>, options: DeepMergeOptions = {}): Map<any, any> => {
263
302
  // Ensure both target and source are Maps
264
303
  if (!(target instanceof Map) || !(source instanceof Map)) return target;
265
- options?.onBeforeMerge?.(target, source);
304
+
266
305
  // Merge options, with default values
267
306
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
268
307
 
@@ -275,7 +314,7 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
275
314
  if (result.has(key)) {
276
315
  const _target = result.get(key),
277
316
  _source = value,
278
- resp = deepMergeHelper(_target, _source, opts);
317
+ resp = smartMerger(_target, _source, opts);
279
318
  //resp={result,flag,type}
280
319
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
281
320
  if (!resp.flag) {
@@ -289,13 +328,12 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
289
328
  // If the key doesn't exist in the target, add the entry from the source Map
290
329
  options.inheritMissing && result.set(key, value);
291
330
  }
292
- options?.onAfterMerge?.(result, target, source);
293
331
  return result;
294
332
  },
295
333
  deepMergeSets = (target: Set<any>, source: Set<any>, options: DeepMergeOptions = {}): Set<any> => {
296
334
  // Ensure both target and source are Sets
297
335
  if (!(target instanceof Set) || !(source instanceof Set)) return target;
298
- options?.onBeforeMerge?.(target, source);
336
+
299
337
  // Merge options, with default values
300
338
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
301
339
 
@@ -307,11 +345,10 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
307
345
  // Replace mode: recursively merge items in the Sets
308
346
  const _result = [...result],
309
347
  _source = [...source],
310
- resp = deepMergeHelper(_result, _source, opts);
348
+ resp = smartMerger(_result, _source, opts);
311
349
  result.clear();
312
350
  for (let item of resp.result) result.add(item);
313
351
 
314
-
315
352
  } else if (opts.dataMode === 'concat') {
316
353
  // Concatenate mode: add all items from the source Set to the target Set
317
354
  for (let item of source) result.add(item);
@@ -320,9 +357,11 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
320
357
  result.clear();
321
358
  for (let item of source) result.add(item);
322
359
  }
323
- options?.onAfterMerge?.(result, target, source);
360
+
324
361
  return result;
325
362
  };
326
- return deepMergeHelper(target, source, options).result;
363
+
364
+
365
+ return smartMerger(target, source, options).result;
327
366
  }
328
367
  export default deepMerge;