@codady/utils 0.0.14 → 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/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-26 9:45:49
3
+ * @since Last modified: 2025-12-26 15:47:37
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.14
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
@@ -88,8 +82,6 @@
88
82
  let newData, cloned = true;
89
83
  if (dataType === 'Object' && opts.cloneObject) {
90
84
  const newObj = {}, symbols = Object.getOwnPropertySymbols(data);
91
- //存储parent对象,在下一次深复制时使用
92
- opts.parent = data;
93
85
  // Clone regular properties
94
86
  for (const key in data) {
95
87
  //临时保存父对象
@@ -98,30 +90,27 @@
98
90
  // Clone Symbol properties
99
91
  if (symbols.length > 0) {
100
92
  for (const symbol of symbols) {
101
- newObj[symbol] = deepClone(data[symbol], opts);
93
+ newObj[symbol] = deepClone(data[symbol], { ...opts, parent: data });
102
94
  }
103
95
  }
104
96
  newData = newObj;
105
97
  }
106
98
  else if (dataType === 'Array' && opts.cloneArray) {
107
- opts.parent = data;
108
- newData = data.map(item => deepClone(item, opts));
99
+ newData = data.map(item => deepClone(item, { ...opts, parent: data }));
109
100
  }
110
101
  else if (dataType === 'Map' && opts.cloneMap) {
111
102
  const newMap = new Map();
112
- opts.parent = data;
113
103
  for (const [key, value] of data) {
114
104
  // Both Map keys and values need deep cloning
115
- newMap.set(deepClone(key, opts), deepClone(value, opts));
105
+ newMap.set(deepClone(key, opts), deepClone(value, { ...opts, parent: data }));
116
106
  }
117
107
  newData = newMap;
118
108
  }
119
109
  else if (dataType === 'Set' && opts.cloneSet) {
120
110
  const newSet = new Set();
121
- opts.parent = data;
122
111
  for (const value of data) {
123
112
  // Set values need deep cloning
124
- newSet.add(deepClone(value, opts));
113
+ newSet.add(deepClone(value, { ...opts, parent: data }));
125
114
  }
126
115
  newData = newSet;
127
116
  }
@@ -541,8 +530,25 @@
541
530
  }, opts),
542
531
  // Main helper function for recursive merging
543
532
  // 递归合并的主辅助函数
544
- deepMergeHelper = (target, source, options) => {
533
+ smartMerger = (target, source, options) => {
545
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 });
546
552
  // Determine the type and perform appropriate merging
547
553
  // 确定类型并执行相应的合并
548
554
  if (targetType === 'Object' && sourceType === 'Object') {
@@ -565,6 +571,7 @@
565
571
  flag = false;
566
572
  result = target;
567
573
  }
574
+ options?.onAfterMerge?.({ result, target, source, type, parent: opts.parent });
568
575
  return { result, flag, type };
569
576
  },
570
577
  // Special handling for objects with enable property
@@ -593,7 +600,6 @@
593
600
  if (targetType !== 'Object' || sourceType !== 'Object') {
594
601
  return target;
595
602
  }
596
- opts?.onBeforeMerge?.(target, source);
597
603
  const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
598
604
  let result = {};
599
605
  // If cloning is enabled, clone the target first
@@ -601,7 +607,7 @@
601
607
  result = options.targetClone ? shallowCopy(target) : target;
602
608
  for (let k in source) {
603
609
  if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
604
- let resp = deepMergeHelper(result[k], source[k], opts);
610
+ let resp = smartMerger(result[k], source[k], { ...opts, parent: result });
605
611
  //resp={result,flag,type}
606
612
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
607
613
  if (!resp.flag) {
@@ -641,13 +647,11 @@
641
647
  result[k] = source[k];
642
648
  }
643
649
  }
644
- options?.onAfterMerge?.(result, target, source);
645
650
  return result;
646
651
  }, deepMergeArrays = (target, source, options = {}) => {
647
652
  // Ensure both target and source are arrays
648
653
  if (!Array.isArray(target) || !Array.isArray(source))
649
654
  return target;
650
- options?.onBeforeMerge?.(target, source);
651
655
  // Merge options, with default values
652
656
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
653
657
  // If cloning is enabled, create a deep copy of the target array
@@ -660,7 +664,7 @@
660
664
  // 如果不允许添加超过长度
661
665
  if (!opts.inheritMissing && i >= result.length)
662
666
  break;
663
- let resp = deepMergeHelper(result[i], source[i], opts);
667
+ let resp = smartMerger(result[i], source[i], { ...opts, parent: result });
664
668
  //resp={result,flag,type}
665
669
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
666
670
  if (!resp.flag) {
@@ -677,13 +681,11 @@
677
681
  result.length = 0;
678
682
  result.push(...source);
679
683
  }
680
- options?.onAfterMerge?.(result, target, source);
681
684
  return result;
682
685
  }, deepMergeMaps = (target, source, options = {}) => {
683
686
  // Ensure both target and source are Maps
684
687
  if (!(target instanceof Map) || !(source instanceof Map))
685
688
  return target;
686
- options?.onBeforeMerge?.(target, source);
687
689
  // Merge options, with default values
688
690
  const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
689
691
  // If cloning is enabled, create a deep copy of the target Map
@@ -692,7 +694,7 @@
692
694
  for (const [key, value] of source.entries())
693
695
  // Check if the key already exists in the target Map
694
696
  if (result.has(key)) {
695
- 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);
696
698
  //resp={result,flag,type}
697
699
  //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
698
700
  if (!resp.flag) {
@@ -708,13 +710,11 @@
708
710
  // If the key doesn't exist in the target, add the entry from the source Map
709
711
  options.inheritMissing && result.set(key, value);
710
712
  }
711
- options?.onAfterMerge?.(result, target, source);
712
713
  return result;
713
714
  }, deepMergeSets = (target, source, options = {}) => {
714
715
  // Ensure both target and source are Sets
715
716
  if (!(target instanceof Set) || !(source instanceof Set))
716
717
  return target;
717
- options?.onBeforeMerge?.(target, source);
718
718
  // Merge options, with default values
719
719
  const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
720
720
  // If cloning is enabled, create a deep copy of the target Set
@@ -722,7 +722,7 @@
722
722
  // Handle different merge strategies based on dataMode
723
723
  if (opts.dataMode === 'replace') {
724
724
  // Replace mode: recursively merge items in the Sets
725
- const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
725
+ const _result = [...result], _source = [...source], resp = smartMerger(_result, _source, opts);
726
726
  result.clear();
727
727
  for (let item of resp.result)
728
728
  result.add(item);
@@ -738,10 +738,9 @@
738
738
  for (let item of source)
739
739
  result.add(item);
740
740
  }
741
- options?.onAfterMerge?.(result, target, source);
742
741
  return result;
743
742
  };
744
- return deepMergeHelper(target, source, options).result;
743
+ return smartMerger(target, source, options).result;
745
744
  };
746
745
 
747
746
  const utils = {
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-26 9:45:49
2
+ * @since Last modified: 2025-12-26 15:47:37
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.14
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);n.parent=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);o=t}else if("Array"===r&&n.cloneArray)n.parent=e,o=e.map(e=>deepClone(e,n));else if("Map"===r&&n.cloneMap){const t=new Map;n.parent=e;for(const[r,o]of e)t.set(deepClone(r,n),deepClone(o,n));o=t}else if("Set"===r&&n.cloneSet){const t=new Set;n.parent=e;for(const r of e)t.add(deepClone(r,n));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.14",
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 09:45:33
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
@@ -123,8 +123,6 @@ const deepClone = (data, options = {}) => {
123
123
  let newData, cloned = true;
124
124
  if (dataType === 'Object' && opts.cloneObject) {
125
125
  const newObj = {}, symbols = Object.getOwnPropertySymbols(data);
126
- //存储parent对象,在下一次深复制时使用
127
- opts.parent = data;
128
126
  // Clone regular properties
129
127
  for (const key in data) {
130
128
  //临时保存父对象
@@ -133,30 +131,27 @@ const deepClone = (data, options = {}) => {
133
131
  // Clone Symbol properties
134
132
  if (symbols.length > 0) {
135
133
  for (const symbol of symbols) {
136
- newObj[symbol] = deepClone(data[symbol], opts);
134
+ newObj[symbol] = deepClone(data[symbol], { ...opts, parent: data });
137
135
  }
138
136
  }
139
137
  newData = newObj;
140
138
  }
141
139
  else if (dataType === 'Array' && opts.cloneArray) {
142
- opts.parent = data;
143
- newData = data.map(item => deepClone(item, opts));
140
+ newData = data.map(item => deepClone(item, { ...opts, parent: data }));
144
141
  }
145
142
  else if (dataType === 'Map' && opts.cloneMap) {
146
143
  const newMap = new Map();
147
- opts.parent = data;
148
144
  for (const [key, value] of data) {
149
145
  // Both Map keys and values need deep cloning
150
- newMap.set(deepClone(key, opts), deepClone(value, opts));
146
+ newMap.set(deepClone(key, opts), deepClone(value, { ...opts, parent: data }));
151
147
  }
152
148
  newData = newMap;
153
149
  }
154
150
  else if (dataType === 'Set' && opts.cloneSet) {
155
151
  const newSet = new Set();
156
- opts.parent = data;
157
152
  for (const value of data) {
158
153
  // Set values need deep cloning
159
- newSet.add(deepClone(value, opts));
154
+ newSet.add(deepClone(value, { ...opts, parent: data }));
160
155
  }
161
156
  newData = newSet;
162
157
  }
package/src/deepClone.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/26 09:45:33
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
@@ -176,9 +176,6 @@ const deepClone = <T>(data: T, options: DeepCloneOptions = {}): T => {
176
176
  const newObj: Record<string | symbol, any> = {},
177
177
  symbols = Object.getOwnPropertySymbols(data);
178
178
 
179
- //存储parent对象,在下一次深复制时使用
180
- opts.parent = data as any;
181
-
182
179
  // Clone regular properties
183
180
  for (const key in data) {
184
181
  //临时保存父对象
@@ -188,27 +185,24 @@ const deepClone = <T>(data: T, options: DeepCloneOptions = {}): T => {
188
185
  // Clone Symbol properties
189
186
  if (symbols.length > 0) {
190
187
  for (const symbol of symbols) {
191
- newObj[symbol] = deepClone((data as any)[symbol], opts);
188
+ newObj[symbol] = deepClone((data as any)[symbol], {...opts,parent:data as any});
192
189
  }
193
190
  }
194
191
  newData = newObj as T;
195
192
  } else if (dataType === 'Array' && opts.cloneArray) {
196
- opts.parent = data as any;
197
- newData = (data as any[]).map(item => deepClone(item, opts)) as T;
193
+ newData = (data as any[]).map(item => deepClone(item, {...opts,parent:data as any})) as T;
198
194
  } else if (dataType === 'Map' && opts.cloneMap) {
199
195
  const newMap = new Map();
200
- opts.parent = data as any;
201
196
  for (const [key, value] of data as Map<any, any>) {
202
197
  // Both Map keys and values need deep cloning
203
- newMap.set(deepClone(key, opts), deepClone(value, opts));
198
+ newMap.set(deepClone(key, opts), deepClone(value, {...opts,parent:data as any}));
204
199
  }
205
200
  newData = newMap as T;
206
201
  } else if (dataType === 'Set' && opts.cloneSet) {
207
202
  const newSet = new Set();
208
- opts.parent = data as any;
209
203
  for (const value of data as Set<any>) {
210
204
  // Set values need deep cloning
211
- newSet.add(deepClone(value, opts));
205
+ newSet.add(deepClone(value, {...opts,parent:data as any}));
212
206
  }
213
207
  newData = newSet as T;
214
208
  } else if (dataType === 'Date' && opts.cloneDate) {
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;