@codady/utils 0.0.15 → 0.0.17

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 11:26:20
3
+ * @since Last modified: 2025-12-26 16:3:51
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.15
5
+ * @version 0.0.17
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,31 +530,49 @@
536
530
  }, opts),
537
531
  // Main helper function for recursive merging
538
532
  // 递归合并的主辅助函数
539
- deepMergeHelper = (target, source, options) => {
540
- let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
533
+ smartMerger = (target, source, options) => {
534
+ let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, 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, targetType, sourceType, 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, targetType, sourceType, parent: options.parent });
541
552
  // Determine the type and perform appropriate merging
542
553
  // 确定类型并执行相应的合并
543
554
  if (targetType === 'Object' && sourceType === 'Object') {
544
555
  result = deepMergeObjects(target, source, options);
545
- type = 'Object';
556
+ mergeType = 'Object';
546
557
  }
547
558
  else if (targetType === 'Array' && sourceType === 'Array') {
548
559
  result = deepMergeArrays(target, source, options);
549
- type = 'Array';
560
+ mergeType = 'Array';
550
561
  }
551
562
  else if (targetType === 'Set' && sourceType === 'Set') {
552
563
  result = deepMergeSets(target, source, options);
553
- type = 'Set';
564
+ mergeType = 'Set';
554
565
  }
555
566
  else if (targetType === 'Map' && sourceType === 'Map') {
556
567
  result = deepMergeMaps(target, source, options);
557
- type = 'Map';
568
+ mergeType = 'Map';
558
569
  }
559
570
  else {
560
571
  flag = false;
561
572
  result = target;
562
573
  }
563
- return { result, flag, type };
574
+ options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
575
+ return { result, flag, mergeType };
564
576
  },
565
577
  // Special handling for objects with enable property
566
578
  // 对具有enable属性的对象进行特殊处理
@@ -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) {
@@ -611,8 +622,8 @@
611
622
  }
612
623
  else {
613
624
  //类型相同
614
- if (resp.type) {
615
- if (resp.type === 'Object') {
625
+ if (resp.mergeType) {
626
+ if (resp.mergeType === 'Object') {
616
627
  //如果遇上对象则深度复制
617
628
  result[k] = resp.result;
618
629
  }
@@ -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) {
@@ -696,20 +703,18 @@
696
703
  }
697
704
  else {
698
705
  // If both target and source are objects, merge them recursively
699
- resp.type === 'Object' && result.set(key, resp.result);
706
+ resp.mergeType === 'Object' && result.set(key, resp.result);
700
707
  }
701
708
  }
702
709
  else {
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 16:3:51
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.15
4
+ * @version 0.0.17
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,targetType:s,sourceType:i,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,targetType:s,sourceType:i,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,targetType:s,sourceType:i,mergeType:o,parent:r.parent}),{result:a,flag:c,mergeType: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.mergeType?"Object"===n.mergeType&&(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.mergeType&&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.17",
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 16:03:37
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,31 +69,49 @@ const deepMerge = (target, source, opts = {}) => {
69
69
  }, opts),
70
70
  // Main helper function for recursive merging
71
71
  // 递归合并的主辅助函数
72
- deepMergeHelper = (target, source, options) => {
73
- let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
72
+ smartMerger = (target, source, options) => {
73
+ let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, 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, targetType, sourceType, 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, targetType, sourceType, parent: options.parent });
74
91
  // Determine the type and perform appropriate merging
75
92
  // 确定类型并执行相应的合并
76
93
  if (targetType === 'Object' && sourceType === 'Object') {
77
94
  result = deepMergeObjects(target, source, options);
78
- type = 'Object';
95
+ mergeType = 'Object';
79
96
  }
80
97
  else if (targetType === 'Array' && sourceType === 'Array') {
81
98
  result = deepMergeArrays(target, source, options);
82
- type = 'Array';
99
+ mergeType = 'Array';
83
100
  }
84
101
  else if (targetType === 'Set' && sourceType === 'Set') {
85
102
  result = deepMergeSets(target, source, options);
86
- type = 'Set';
103
+ mergeType = 'Set';
87
104
  }
88
105
  else if (targetType === 'Map' && sourceType === 'Map') {
89
106
  result = deepMergeMaps(target, source, options);
90
- type = 'Map';
107
+ mergeType = 'Map';
91
108
  }
92
109
  else {
93
110
  flag = false;
94
111
  result = target;
95
112
  }
96
- return { result, flag, type };
113
+ options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
114
+ return { result, flag, mergeType };
97
115
  },
98
116
  // Special handling for objects with enable property
99
117
  // 对具有enable属性的对象进行特殊处理
@@ -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) {
@@ -144,8 +161,8 @@ const deepMerge = (target, source, opts = {}) => {
144
161
  }
145
162
  else {
146
163
  //类型相同
147
- if (resp.type) {
148
- if (resp.type === 'Object') {
164
+ if (resp.mergeType) {
165
+ if (resp.mergeType === 'Object') {
149
166
  //如果遇上对象则深度复制
150
167
  result[k] = resp.result;
151
168
  }
@@ -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) {
@@ -229,20 +242,18 @@ const deepMerge = (target, source, opts = {}) => {
229
242
  }
230
243
  else {
231
244
  // If both target and source are objects, merge them recursively
232
- resp.type === 'Object' && result.set(key, resp.result);
245
+ resp.mergeType === 'Object' && result.set(key, resp.result);
233
246
  }
234
247
  }
235
248
  else {
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;