@codady/utils 0.0.16 → 0.0.18
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 +20 -0
- package/dist/utils.cjs.js +44 -22
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +44 -22
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd.js +44 -22
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/package.json +1 -1
- package/src/deepClone.js +1 -1
- package/src/deepClone.ts +1 -1
- package/src/deepMerge.js +47 -21
- package/src/deepMerge.ts +56 -22
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All changes to Utils including new features, updates, and removals are documented here.
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
## [v0.0.18] - 2025-12-27
|
|
7
|
+
|
|
8
|
+
### Distribution Files
|
|
9
|
+
* **JS**: https://unpkg.com/@codady/utils@0.0.18/dist/js/utils.js
|
|
10
|
+
* **Zip**:https://unpkg.com/@codady/utils@0.0.18/dist.zip
|
|
11
|
+
|
|
12
|
+
### Changes
|
|
13
|
+
|
|
14
|
+
#### Fixed
|
|
15
|
+
* Null
|
|
16
|
+
|
|
17
|
+
#### Added
|
|
18
|
+
* Modified the `deepMerge` function to add `nullBehavior` and `undefinedBehavior` properties to the parameters for handling `null` and `undefined` values.修改了`deepMerge`函数,对参数增加`nullBehavior`和`undefinedBehavior`属性,用来处理null和undefined值。
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
#### Removed
|
|
22
|
+
* Null
|
|
23
|
+
|
|
24
|
+
|
|
5
25
|
## [v0.0.16] - 2025-12-26
|
|
6
26
|
|
|
7
27
|
### Distribution Files
|
package/dist/utils.cjs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2025-12-
|
|
3
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.18
|
|
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}
|
|
@@ -514,6 +514,8 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
514
514
|
// Whether to allow merging key=symbol key-value pairs when target is {} type.
|
|
515
515
|
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
516
516
|
useSymbol: true,
|
|
517
|
+
nullBehavior: 'preserve',
|
|
518
|
+
undefinedBehavior: 'preserve',
|
|
517
519
|
// Options passed to the deepClone function when targetClone is true
|
|
518
520
|
// 当targetClone为true时传递给deepClone函数的选项
|
|
519
521
|
deepClone: {},
|
|
@@ -527,10 +529,10 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
527
529
|
// Main helper function for recursive merging
|
|
528
530
|
// 递归合并的主辅助函数
|
|
529
531
|
smartMerger = (target, source, options) => {
|
|
530
|
-
let targetType = getDataType(target), sourceType = getDataType(source), flag = true,
|
|
532
|
+
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, result;
|
|
531
533
|
// Check interceptor - if it returns a value (not null/undefined), use it directly
|
|
532
534
|
if (options.interceptor && typeof options.interceptor === 'function') {
|
|
533
|
-
let interceptorResult = options.interceptor({ target, source, parent: options.parent });
|
|
535
|
+
let interceptorResult = options.interceptor({ target, source, targetType, sourceType, parent: options.parent });
|
|
534
536
|
if ((interceptorResult ?? false)) {
|
|
535
537
|
//如果不是返回{target,source},那么直接返回interceptorResult
|
|
536
538
|
if (interceptorResult?.target === null || interceptorResult?.source === null) {
|
|
@@ -544,31 +546,31 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
544
546
|
}
|
|
545
547
|
// If interceptor returns null/undefined, continue with normal cloning process
|
|
546
548
|
}
|
|
547
|
-
options?.onBeforeMerge?.({ target, source, parent: options.parent });
|
|
549
|
+
options?.onBeforeMerge?.({ target, source, targetType, sourceType, parent: options.parent });
|
|
548
550
|
// Determine the type and perform appropriate merging
|
|
549
551
|
// 确定类型并执行相应的合并
|
|
550
552
|
if (targetType === 'Object' && sourceType === 'Object') {
|
|
551
553
|
result = deepMergeObjects(target, source, options);
|
|
552
|
-
|
|
554
|
+
mergeType = 'Object';
|
|
553
555
|
}
|
|
554
556
|
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
555
557
|
result = deepMergeArrays(target, source, options);
|
|
556
|
-
|
|
558
|
+
mergeType = 'Array';
|
|
557
559
|
}
|
|
558
560
|
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
559
561
|
result = deepMergeSets(target, source, options);
|
|
560
|
-
|
|
562
|
+
mergeType = 'Set';
|
|
561
563
|
}
|
|
562
564
|
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
563
565
|
result = deepMergeMaps(target, source, options);
|
|
564
|
-
|
|
566
|
+
mergeType = 'Map';
|
|
565
567
|
}
|
|
566
568
|
else {
|
|
567
569
|
flag = false;
|
|
568
570
|
result = target;
|
|
569
571
|
}
|
|
570
|
-
options?.onAfterMerge?.({ result, target, source,
|
|
571
|
-
return { result, flag,
|
|
572
|
+
options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
|
|
573
|
+
return { result, flag, mergeType };
|
|
572
574
|
},
|
|
573
575
|
// Special handling for objects with enable property
|
|
574
576
|
// 对具有enable属性的对象进行特殊处理
|
|
@@ -602,37 +604,57 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
602
604
|
// 如果是复制方法,则先复制target
|
|
603
605
|
result = options.targetClone ? shallowCopy(target) : target;
|
|
604
606
|
for (let k in source) {
|
|
607
|
+
const _result = result[k], _source = source[k];
|
|
605
608
|
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
606
|
-
|
|
609
|
+
const resp = smartMerger(_result, _source, { ...opts, parent: result });
|
|
607
610
|
//resp={result,flag,type}
|
|
608
|
-
//flag=true
|
|
611
|
+
//flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
|
|
609
612
|
if (!resp.flag) {
|
|
610
613
|
//类型不同则直接覆盖
|
|
611
|
-
|
|
612
|
-
|
|
614
|
+
let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
|
|
615
|
+
if (_result !== tmp && tmp === null) {
|
|
616
|
+
if (options.nullBehavior === 'ignore') ;
|
|
617
|
+
else if (options.nullBehavior === 'delete') {
|
|
618
|
+
//删除属性
|
|
619
|
+
Reflect.deleteProperty(result, k);
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
//替换
|
|
623
|
+
result[k] = tmp;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
else if (_result !== tmp && tmp === undefined) {
|
|
627
|
+
if (options.undefinedBehavior === 'ignore') ;
|
|
628
|
+
else if (options.undefinedBehavior === 'delete') {
|
|
629
|
+
//删除属性
|
|
630
|
+
Reflect.deleteProperty(result, k);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
//替换
|
|
634
|
+
result[k] = _source;
|
|
635
|
+
}
|
|
613
636
|
}
|
|
614
637
|
else {
|
|
615
|
-
|
|
616
|
-
result[k] = source[k];
|
|
638
|
+
result[k] = _source;
|
|
617
639
|
}
|
|
618
640
|
}
|
|
619
641
|
else {
|
|
620
642
|
//类型相同
|
|
621
|
-
if (resp.
|
|
622
|
-
if (resp.
|
|
643
|
+
if (resp.mergeType) {
|
|
644
|
+
if (resp.mergeType === 'Object') {
|
|
623
645
|
//如果遇上对象则深度复制
|
|
624
646
|
result[k] = resp.result;
|
|
625
647
|
}
|
|
626
648
|
}
|
|
627
649
|
else {
|
|
628
650
|
//其他类型则直接覆盖
|
|
629
|
-
result[k] =
|
|
651
|
+
result[k] = _source;
|
|
630
652
|
}
|
|
631
653
|
}
|
|
632
654
|
}
|
|
633
655
|
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
634
656
|
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
635
|
-
result[k] =
|
|
657
|
+
result[k] = _source;
|
|
636
658
|
}
|
|
637
659
|
}
|
|
638
660
|
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
@@ -699,7 +721,7 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
699
721
|
}
|
|
700
722
|
else {
|
|
701
723
|
// If both target and source are objects, merge them recursively
|
|
702
|
-
resp.
|
|
724
|
+
resp.mergeType === 'Object' && result.set(key, resp.result);
|
|
703
725
|
}
|
|
704
726
|
}
|
|
705
727
|
else {
|
package/dist/utils.cjs.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-
|
|
2
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.18
|
|
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),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,
|
|
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,nullBehavior:"preserve",undefinedBehavior:"preserve",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,targetType:s,sourceType:l,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,targetType:s,sourceType:l,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,targetType:s,sourceType:l,mergeType:o,parent:r.parent}),{result:n,flag:i,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 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){const a=s[e],o=t[e];if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){const t=smartMerger(a,o,{...r,parent:s});if(t.flag)t.mergeType?"Object"===t.mergeType&&(s[e]=t.result):s[e]=o;else{let t=n.useEnable?mergeEnableObject(a,o):o;a!==t&&null===t?"ignore"===n.nullBehavior||("delete"===n.nullBehavior?Reflect.deleteProperty(s,e):s[e]=t):a!==t&&void 0===t?"ignore"===n.undefinedBehavior||("delete"===n.undefinedBehavior?Reflect.deleteProperty(s,e):s[e]=o):s[e]=o}}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=o)}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.mergeType&&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-
|
|
3
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.18
|
|
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}
|
|
@@ -512,6 +512,8 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
512
512
|
// Whether to allow merging key=symbol key-value pairs when target is {} type.
|
|
513
513
|
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
514
514
|
useSymbol: true,
|
|
515
|
+
nullBehavior: 'preserve',
|
|
516
|
+
undefinedBehavior: 'preserve',
|
|
515
517
|
// Options passed to the deepClone function when targetClone is true
|
|
516
518
|
// 当targetClone为true时传递给deepClone函数的选项
|
|
517
519
|
deepClone: {},
|
|
@@ -525,10 +527,10 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
525
527
|
// Main helper function for recursive merging
|
|
526
528
|
// 递归合并的主辅助函数
|
|
527
529
|
smartMerger = (target, source, options) => {
|
|
528
|
-
let targetType = getDataType(target), sourceType = getDataType(source), flag = true,
|
|
530
|
+
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, result;
|
|
529
531
|
// Check interceptor - if it returns a value (not null/undefined), use it directly
|
|
530
532
|
if (options.interceptor && typeof options.interceptor === 'function') {
|
|
531
|
-
let interceptorResult = options.interceptor({ target, source, parent: options.parent });
|
|
533
|
+
let interceptorResult = options.interceptor({ target, source, targetType, sourceType, parent: options.parent });
|
|
532
534
|
if ((interceptorResult ?? false)) {
|
|
533
535
|
//如果不是返回{target,source},那么直接返回interceptorResult
|
|
534
536
|
if (interceptorResult?.target === null || interceptorResult?.source === null) {
|
|
@@ -542,31 +544,31 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
542
544
|
}
|
|
543
545
|
// If interceptor returns null/undefined, continue with normal cloning process
|
|
544
546
|
}
|
|
545
|
-
options?.onBeforeMerge?.({ target, source, parent: options.parent });
|
|
547
|
+
options?.onBeforeMerge?.({ target, source, targetType, sourceType, parent: options.parent });
|
|
546
548
|
// Determine the type and perform appropriate merging
|
|
547
549
|
// 确定类型并执行相应的合并
|
|
548
550
|
if (targetType === 'Object' && sourceType === 'Object') {
|
|
549
551
|
result = deepMergeObjects(target, source, options);
|
|
550
|
-
|
|
552
|
+
mergeType = 'Object';
|
|
551
553
|
}
|
|
552
554
|
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
553
555
|
result = deepMergeArrays(target, source, options);
|
|
554
|
-
|
|
556
|
+
mergeType = 'Array';
|
|
555
557
|
}
|
|
556
558
|
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
557
559
|
result = deepMergeSets(target, source, options);
|
|
558
|
-
|
|
560
|
+
mergeType = 'Set';
|
|
559
561
|
}
|
|
560
562
|
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
561
563
|
result = deepMergeMaps(target, source, options);
|
|
562
|
-
|
|
564
|
+
mergeType = 'Map';
|
|
563
565
|
}
|
|
564
566
|
else {
|
|
565
567
|
flag = false;
|
|
566
568
|
result = target;
|
|
567
569
|
}
|
|
568
|
-
options?.onAfterMerge?.({ result, target, source,
|
|
569
|
-
return { result, flag,
|
|
570
|
+
options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
|
|
571
|
+
return { result, flag, mergeType };
|
|
570
572
|
},
|
|
571
573
|
// Special handling for objects with enable property
|
|
572
574
|
// 对具有enable属性的对象进行特殊处理
|
|
@@ -600,37 +602,57 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
600
602
|
// 如果是复制方法,则先复制target
|
|
601
603
|
result = options.targetClone ? shallowCopy(target) : target;
|
|
602
604
|
for (let k in source) {
|
|
605
|
+
const _result = result[k], _source = source[k];
|
|
603
606
|
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
604
|
-
|
|
607
|
+
const resp = smartMerger(_result, _source, { ...opts, parent: result });
|
|
605
608
|
//resp={result,flag,type}
|
|
606
|
-
//flag=true
|
|
609
|
+
//flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
|
|
607
610
|
if (!resp.flag) {
|
|
608
611
|
//类型不同则直接覆盖
|
|
609
|
-
|
|
610
|
-
|
|
612
|
+
let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
|
|
613
|
+
if (_result !== tmp && tmp === null) {
|
|
614
|
+
if (options.nullBehavior === 'ignore') ;
|
|
615
|
+
else if (options.nullBehavior === 'delete') {
|
|
616
|
+
//删除属性
|
|
617
|
+
Reflect.deleteProperty(result, k);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
//替换
|
|
621
|
+
result[k] = tmp;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
else if (_result !== tmp && tmp === undefined) {
|
|
625
|
+
if (options.undefinedBehavior === 'ignore') ;
|
|
626
|
+
else if (options.undefinedBehavior === 'delete') {
|
|
627
|
+
//删除属性
|
|
628
|
+
Reflect.deleteProperty(result, k);
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
//替换
|
|
632
|
+
result[k] = _source;
|
|
633
|
+
}
|
|
611
634
|
}
|
|
612
635
|
else {
|
|
613
|
-
|
|
614
|
-
result[k] = source[k];
|
|
636
|
+
result[k] = _source;
|
|
615
637
|
}
|
|
616
638
|
}
|
|
617
639
|
else {
|
|
618
640
|
//类型相同
|
|
619
|
-
if (resp.
|
|
620
|
-
if (resp.
|
|
641
|
+
if (resp.mergeType) {
|
|
642
|
+
if (resp.mergeType === 'Object') {
|
|
621
643
|
//如果遇上对象则深度复制
|
|
622
644
|
result[k] = resp.result;
|
|
623
645
|
}
|
|
624
646
|
}
|
|
625
647
|
else {
|
|
626
648
|
//其他类型则直接覆盖
|
|
627
|
-
result[k] =
|
|
649
|
+
result[k] = _source;
|
|
628
650
|
}
|
|
629
651
|
}
|
|
630
652
|
}
|
|
631
653
|
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
632
654
|
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
633
|
-
result[k] =
|
|
655
|
+
result[k] = _source;
|
|
634
656
|
}
|
|
635
657
|
}
|
|
636
658
|
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
@@ -697,7 +719,7 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
697
719
|
}
|
|
698
720
|
else {
|
|
699
721
|
// If both target and source are objects, merge them recursively
|
|
700
|
-
resp.
|
|
722
|
+
resp.mergeType === 'Object' && result.set(key, resp.result);
|
|
701
723
|
}
|
|
702
724
|
}
|
|
703
725
|
else {
|
package/dist/utils.esm.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-
|
|
2
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.18
|
|
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({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,
|
|
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,nullBehavior:"preserve",undefinedBehavior:"preserve",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,targetType:s,sourceType:l,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,targetType:s,sourceType:l,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,targetType:s,sourceType:l,mergeType:o,parent:r.parent}),{result:n,flag:i,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 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){const a=s[e],o=t[e];if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){const t=smartMerger(a,o,{...r,parent:s});if(t.flag)t.mergeType?"Object"===t.mergeType&&(s[e]=t.result):s[e]=o;else{let t=n.useEnable?mergeEnableObject(a,o):o;a!==t&&null===t?"ignore"===n.nullBehavior||("delete"===n.nullBehavior?Reflect.deleteProperty(s,e):s[e]=t):a!==t&&void 0===t?"ignore"===n.undefinedBehavior||("delete"===n.undefinedBehavior?Reflect.deleteProperty(s,e):s[e]=o):s[e]=o}}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.inheritMissing&&(s[e]=o)}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.mergeType&&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-
|
|
3
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.18
|
|
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}
|
|
@@ -518,6 +518,8 @@
|
|
|
518
518
|
// Whether to allow merging key=symbol key-value pairs when target is {} type.
|
|
519
519
|
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
520
520
|
useSymbol: true,
|
|
521
|
+
nullBehavior: 'preserve',
|
|
522
|
+
undefinedBehavior: 'preserve',
|
|
521
523
|
// Options passed to the deepClone function when targetClone is true
|
|
522
524
|
// 当targetClone为true时传递给deepClone函数的选项
|
|
523
525
|
deepClone: {},
|
|
@@ -531,10 +533,10 @@
|
|
|
531
533
|
// Main helper function for recursive merging
|
|
532
534
|
// 递归合并的主辅助函数
|
|
533
535
|
smartMerger = (target, source, options) => {
|
|
534
|
-
let targetType = getDataType(target), sourceType = getDataType(source), flag = true,
|
|
536
|
+
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, result;
|
|
535
537
|
// Check interceptor - if it returns a value (not null/undefined), use it directly
|
|
536
538
|
if (options.interceptor && typeof options.interceptor === 'function') {
|
|
537
|
-
let interceptorResult = options.interceptor({ target, source, parent: options.parent });
|
|
539
|
+
let interceptorResult = options.interceptor({ target, source, targetType, sourceType, parent: options.parent });
|
|
538
540
|
if ((interceptorResult ?? false)) {
|
|
539
541
|
//如果不是返回{target,source},那么直接返回interceptorResult
|
|
540
542
|
if (interceptorResult?.target === null || interceptorResult?.source === null) {
|
|
@@ -548,31 +550,31 @@
|
|
|
548
550
|
}
|
|
549
551
|
// If interceptor returns null/undefined, continue with normal cloning process
|
|
550
552
|
}
|
|
551
|
-
options?.onBeforeMerge?.({ target, source, parent: options.parent });
|
|
553
|
+
options?.onBeforeMerge?.({ target, source, targetType, sourceType, parent: options.parent });
|
|
552
554
|
// Determine the type and perform appropriate merging
|
|
553
555
|
// 确定类型并执行相应的合并
|
|
554
556
|
if (targetType === 'Object' && sourceType === 'Object') {
|
|
555
557
|
result = deepMergeObjects(target, source, options);
|
|
556
|
-
|
|
558
|
+
mergeType = 'Object';
|
|
557
559
|
}
|
|
558
560
|
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
559
561
|
result = deepMergeArrays(target, source, options);
|
|
560
|
-
|
|
562
|
+
mergeType = 'Array';
|
|
561
563
|
}
|
|
562
564
|
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
563
565
|
result = deepMergeSets(target, source, options);
|
|
564
|
-
|
|
566
|
+
mergeType = 'Set';
|
|
565
567
|
}
|
|
566
568
|
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
567
569
|
result = deepMergeMaps(target, source, options);
|
|
568
|
-
|
|
570
|
+
mergeType = 'Map';
|
|
569
571
|
}
|
|
570
572
|
else {
|
|
571
573
|
flag = false;
|
|
572
574
|
result = target;
|
|
573
575
|
}
|
|
574
|
-
options?.onAfterMerge?.({ result, target, source,
|
|
575
|
-
return { result, flag,
|
|
576
|
+
options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
|
|
577
|
+
return { result, flag, mergeType };
|
|
576
578
|
},
|
|
577
579
|
// Special handling for objects with enable property
|
|
578
580
|
// 对具有enable属性的对象进行特殊处理
|
|
@@ -606,37 +608,57 @@
|
|
|
606
608
|
// 如果是复制方法,则先复制target
|
|
607
609
|
result = options.targetClone ? shallowCopy(target) : target;
|
|
608
610
|
for (let k in source) {
|
|
611
|
+
const _result = result[k], _source = source[k];
|
|
609
612
|
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
610
|
-
|
|
613
|
+
const resp = smartMerger(_result, _source, { ...opts, parent: result });
|
|
611
614
|
//resp={result,flag,type}
|
|
612
|
-
//flag=true
|
|
615
|
+
//flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
|
|
613
616
|
if (!resp.flag) {
|
|
614
617
|
//类型不同则直接覆盖
|
|
615
|
-
|
|
616
|
-
|
|
618
|
+
let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
|
|
619
|
+
if (_result !== tmp && tmp === null) {
|
|
620
|
+
if (options.nullBehavior === 'ignore') ;
|
|
621
|
+
else if (options.nullBehavior === 'delete') {
|
|
622
|
+
//删除属性
|
|
623
|
+
Reflect.deleteProperty(result, k);
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
//替换
|
|
627
|
+
result[k] = tmp;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else if (_result !== tmp && tmp === undefined) {
|
|
631
|
+
if (options.undefinedBehavior === 'ignore') ;
|
|
632
|
+
else if (options.undefinedBehavior === 'delete') {
|
|
633
|
+
//删除属性
|
|
634
|
+
Reflect.deleteProperty(result, k);
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
//替换
|
|
638
|
+
result[k] = _source;
|
|
639
|
+
}
|
|
617
640
|
}
|
|
618
641
|
else {
|
|
619
|
-
|
|
620
|
-
result[k] = source[k];
|
|
642
|
+
result[k] = _source;
|
|
621
643
|
}
|
|
622
644
|
}
|
|
623
645
|
else {
|
|
624
646
|
//类型相同
|
|
625
|
-
if (resp.
|
|
626
|
-
if (resp.
|
|
647
|
+
if (resp.mergeType) {
|
|
648
|
+
if (resp.mergeType === 'Object') {
|
|
627
649
|
//如果遇上对象则深度复制
|
|
628
650
|
result[k] = resp.result;
|
|
629
651
|
}
|
|
630
652
|
}
|
|
631
653
|
else {
|
|
632
654
|
//其他类型则直接覆盖
|
|
633
|
-
result[k] =
|
|
655
|
+
result[k] = _source;
|
|
634
656
|
}
|
|
635
657
|
}
|
|
636
658
|
}
|
|
637
659
|
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
638
660
|
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
639
|
-
result[k] =
|
|
661
|
+
result[k] = _source;
|
|
640
662
|
}
|
|
641
663
|
}
|
|
642
664
|
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
@@ -703,7 +725,7 @@
|
|
|
703
725
|
}
|
|
704
726
|
else {
|
|
705
727
|
// If both target and source are objects, merge them recursively
|
|
706
|
-
resp.
|
|
728
|
+
resp.mergeType === 'Object' && result.set(key, resp.result);
|
|
707
729
|
}
|
|
708
730
|
}
|
|
709
731
|
else {
|
package/dist/utils.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-
|
|
2
|
+
* @since Last modified: 2025-12-27 14:35:7
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.18
|
|
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({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
|
|
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 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,nullBehavior:"preserve",undefinedBehavior:"preserve",deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),smartMerger=(e,t,n)=>{let o,a,s=getDataType(e),i=getDataType(t),l=!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"):(l=!1,a=e),n?.onAfterMerge?.({result:a,target:e,source:t,targetType:s,sourceType:i,mergeType:o,parent:r.parent}),{result:a,flag:l,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){const n=s[e],o=t[e];if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){const t=smartMerger(n,o,{...r,parent:s});if(t.flag)t.mergeType?"Object"===t.mergeType&&(s[e]=t.result):s[e]=o;else{let t=a.useEnable?mergeEnableObject(n,o):o;n!==t&&null===t?"ignore"===a.nullBehavior||("delete"===a.nullBehavior?Reflect.deleteProperty(s,e):s[e]=t):n!==t&&void 0===t?"ignore"===a.undefinedBehavior||("delete"===a.undefinedBehavior?Reflect.deleteProperty(s,e):s[e]=o):s[e]=o}}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=o)}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.
|
|
3
|
+
"version": "0.0.18",
|
|
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
package/src/deepClone.ts
CHANGED
package/src/deepMerge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since Last modified: 2025/12/
|
|
2
|
+
* @since Last modified: 2025/12/27 14:35:01
|
|
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.
|
|
@@ -57,6 +57,8 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
57
57
|
// Whether to allow merging key=symbol key-value pairs when target is {} type.
|
|
58
58
|
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
59
59
|
useSymbol: true,
|
|
60
|
+
nullBehavior: 'preserve',
|
|
61
|
+
undefinedBehavior: 'preserve',
|
|
60
62
|
// Options passed to the deepClone function when targetClone is true
|
|
61
63
|
// 当targetClone为true时传递给deepClone函数的选项
|
|
62
64
|
deepClone: {},
|
|
@@ -70,10 +72,10 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
70
72
|
// Main helper function for recursive merging
|
|
71
73
|
// 递归合并的主辅助函数
|
|
72
74
|
smartMerger = (target, source, options) => {
|
|
73
|
-
let targetType = getDataType(target), sourceType = getDataType(source), flag = true,
|
|
75
|
+
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, mergeType, result;
|
|
74
76
|
// Check interceptor - if it returns a value (not null/undefined), use it directly
|
|
75
77
|
if (options.interceptor && typeof options.interceptor === 'function') {
|
|
76
|
-
let interceptorResult = options.interceptor({ target, source, parent: options.parent });
|
|
78
|
+
let interceptorResult = options.interceptor({ target, source, targetType, sourceType, parent: options.parent });
|
|
77
79
|
if ((interceptorResult ?? false)) {
|
|
78
80
|
//如果不是返回{target,source},那么直接返回interceptorResult
|
|
79
81
|
if (interceptorResult?.target === null || interceptorResult?.source === null) {
|
|
@@ -87,31 +89,31 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
87
89
|
}
|
|
88
90
|
// If interceptor returns null/undefined, continue with normal cloning process
|
|
89
91
|
}
|
|
90
|
-
options?.onBeforeMerge?.({ target, source, parent: options.parent });
|
|
92
|
+
options?.onBeforeMerge?.({ target, source, targetType, sourceType, parent: options.parent });
|
|
91
93
|
// Determine the type and perform appropriate merging
|
|
92
94
|
// 确定类型并执行相应的合并
|
|
93
95
|
if (targetType === 'Object' && sourceType === 'Object') {
|
|
94
96
|
result = deepMergeObjects(target, source, options);
|
|
95
|
-
|
|
97
|
+
mergeType = 'Object';
|
|
96
98
|
}
|
|
97
99
|
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
98
100
|
result = deepMergeArrays(target, source, options);
|
|
99
|
-
|
|
101
|
+
mergeType = 'Array';
|
|
100
102
|
}
|
|
101
103
|
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
102
104
|
result = deepMergeSets(target, source, options);
|
|
103
|
-
|
|
105
|
+
mergeType = 'Set';
|
|
104
106
|
}
|
|
105
107
|
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
106
108
|
result = deepMergeMaps(target, source, options);
|
|
107
|
-
|
|
109
|
+
mergeType = 'Map';
|
|
108
110
|
}
|
|
109
111
|
else {
|
|
110
112
|
flag = false;
|
|
111
113
|
result = target;
|
|
112
114
|
}
|
|
113
|
-
options?.onAfterMerge?.({ result, target, source,
|
|
114
|
-
return { result, flag,
|
|
115
|
+
options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
|
|
116
|
+
return { result, flag, mergeType };
|
|
115
117
|
},
|
|
116
118
|
// Special handling for objects with enable property
|
|
117
119
|
// 对具有enable属性的对象进行特殊处理
|
|
@@ -145,37 +147,61 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
145
147
|
// 如果是复制方法,则先复制target
|
|
146
148
|
result = options.targetClone ? shallowCopy(target) : target;
|
|
147
149
|
for (let k in source) {
|
|
150
|
+
const _result = result[k], _source = source[k];
|
|
148
151
|
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
149
|
-
|
|
152
|
+
const resp = smartMerger(_result, _source, { ...opts, parent: result });
|
|
150
153
|
//resp={result,flag,type}
|
|
151
|
-
//flag=true
|
|
154
|
+
//flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
|
|
152
155
|
if (!resp.flag) {
|
|
153
156
|
//类型不同则直接覆盖
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
|
|
158
|
+
if (_result !== tmp && tmp === null) {
|
|
159
|
+
if (options.nullBehavior === 'ignore') {
|
|
160
|
+
//不处理
|
|
161
|
+
}
|
|
162
|
+
else if (options.nullBehavior === 'delete') {
|
|
163
|
+
//删除属性
|
|
164
|
+
Reflect.deleteProperty(result, k);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
//替换
|
|
168
|
+
result[k] = tmp;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (_result !== tmp && tmp === undefined) {
|
|
172
|
+
if (options.undefinedBehavior === 'ignore') {
|
|
173
|
+
//不处理
|
|
174
|
+
}
|
|
175
|
+
else if (options.undefinedBehavior === 'delete') {
|
|
176
|
+
//删除属性
|
|
177
|
+
Reflect.deleteProperty(result, k);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
//替换
|
|
181
|
+
result[k] = _source;
|
|
182
|
+
}
|
|
156
183
|
}
|
|
157
184
|
else {
|
|
158
|
-
|
|
159
|
-
result[k] = source[k];
|
|
185
|
+
result[k] = _source;
|
|
160
186
|
}
|
|
161
187
|
}
|
|
162
188
|
else {
|
|
163
189
|
//类型相同
|
|
164
|
-
if (resp.
|
|
165
|
-
if (resp.
|
|
190
|
+
if (resp.mergeType) {
|
|
191
|
+
if (resp.mergeType === 'Object') {
|
|
166
192
|
//如果遇上对象则深度复制
|
|
167
193
|
result[k] = resp.result;
|
|
168
194
|
}
|
|
169
195
|
}
|
|
170
196
|
else {
|
|
171
197
|
//其他类型则直接覆盖
|
|
172
|
-
result[k] =
|
|
198
|
+
result[k] = _source;
|
|
173
199
|
}
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
202
|
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
177
203
|
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
178
|
-
result[k] =
|
|
204
|
+
result[k] = _source;
|
|
179
205
|
}
|
|
180
206
|
}
|
|
181
207
|
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
@@ -242,7 +268,7 @@ const deepMerge = (target, source, opts = {}) => {
|
|
|
242
268
|
}
|
|
243
269
|
else {
|
|
244
270
|
// If both target and source are objects, merge them recursively
|
|
245
|
-
resp.
|
|
271
|
+
resp.mergeType === 'Object' && result.set(key, resp.result);
|
|
246
272
|
}
|
|
247
273
|
}
|
|
248
274
|
else {
|
package/src/deepMerge.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since Last modified: 2025/12/
|
|
2
|
+
* @since Last modified: 2025/12/27 14:35:01
|
|
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.
|
|
@@ -42,6 +42,10 @@ export interface DeepMergeOptions {
|
|
|
42
42
|
// Mode for handling array items
|
|
43
43
|
// 处理数组成员的模式
|
|
44
44
|
dataMode?: 'clear' | 'replace' | 'concat';
|
|
45
|
+
//如果source值=null,target如何处理,ignore表示不理会null保持target;preserve将覆盖target,delete将删除target(key)
|
|
46
|
+
nullBehavior?: 'ignore' | 'preserve' | 'delete';
|
|
47
|
+
//如果source值=undefined,target如何处理,ignore表示不理会undefined保持target;preserve将覆盖target,delete将删除target(key)
|
|
48
|
+
undefinedBehavior?: 'ignore' | 'preserve' | 'delete';
|
|
45
49
|
// Whether to append properties (for objects)
|
|
46
50
|
// 是否追加属性(针对对象)
|
|
47
51
|
inheritMissing?: boolean;
|
|
@@ -67,6 +71,8 @@ export interface DeepMergeOptions {
|
|
|
67
71
|
target: any;
|
|
68
72
|
source: any;
|
|
69
73
|
parent?: any;
|
|
74
|
+
targetType: string;
|
|
75
|
+
sourceType: string;
|
|
70
76
|
}) => any;
|
|
71
77
|
|
|
72
78
|
/**
|
|
@@ -77,6 +83,8 @@ export interface DeepMergeOptions {
|
|
|
77
83
|
target: any;
|
|
78
84
|
source: any;
|
|
79
85
|
parent?: any;
|
|
86
|
+
targetType: string;
|
|
87
|
+
sourceType: string;
|
|
80
88
|
}) => void;
|
|
81
89
|
|
|
82
90
|
/**
|
|
@@ -88,7 +96,9 @@ export interface DeepMergeOptions {
|
|
|
88
96
|
target: any;
|
|
89
97
|
source: any;
|
|
90
98
|
parent?: any;
|
|
91
|
-
|
|
99
|
+
targetType: string;
|
|
100
|
+
sourceType: string;
|
|
101
|
+
mergeType?: '' | 'Object' | 'Array' | 'Map' | 'Set';
|
|
92
102
|
}) => void;
|
|
93
103
|
|
|
94
104
|
/**
|
|
@@ -130,6 +140,10 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
|
|
|
130
140
|
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
131
141
|
useSymbol: true,
|
|
132
142
|
|
|
143
|
+
nullBehavior:'preserve',
|
|
144
|
+
|
|
145
|
+
undefinedBehavior:'preserve',
|
|
146
|
+
|
|
133
147
|
// Options passed to the deepClone function when targetClone is true
|
|
134
148
|
// 当targetClone为true时传递给deepClone函数的选项
|
|
135
149
|
deepClone: {},
|
|
@@ -148,12 +162,12 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
|
|
|
148
162
|
let targetType = getDataType(target),
|
|
149
163
|
sourceType = getDataType(source),
|
|
150
164
|
flag = true,
|
|
151
|
-
|
|
165
|
+
mergeType: any,
|
|
152
166
|
result;
|
|
153
167
|
|
|
154
168
|
// Check interceptor - if it returns a value (not null/undefined), use it directly
|
|
155
169
|
if (options.interceptor && typeof options.interceptor === 'function') {
|
|
156
|
-
let interceptorResult = options.interceptor({ target, source, parent: options.parent });
|
|
170
|
+
let interceptorResult = options.interceptor({ target, source, targetType, sourceType, parent: options.parent });
|
|
157
171
|
if ((interceptorResult ?? false)) {
|
|
158
172
|
//如果不是返回{target,source},那么直接返回interceptorResult
|
|
159
173
|
if (interceptorResult?.target === null || interceptorResult?.source === null) {
|
|
@@ -167,28 +181,28 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
|
|
|
167
181
|
// If interceptor returns null/undefined, continue with normal cloning process
|
|
168
182
|
}
|
|
169
183
|
|
|
170
|
-
options?.onBeforeMerge?.({ target, source, parent: options.parent });
|
|
184
|
+
options?.onBeforeMerge?.({ target, source, targetType, sourceType, parent: options.parent });
|
|
171
185
|
|
|
172
186
|
// Determine the type and perform appropriate merging
|
|
173
187
|
// 确定类型并执行相应的合并
|
|
174
188
|
if (targetType === 'Object' && sourceType === 'Object') {
|
|
175
189
|
result = deepMergeObjects(target, source, options);
|
|
176
|
-
|
|
190
|
+
mergeType = 'Object';
|
|
177
191
|
} else if (targetType === 'Array' && sourceType === 'Array') {
|
|
178
192
|
result = deepMergeArrays(target, source, options);
|
|
179
|
-
|
|
193
|
+
mergeType = 'Array';
|
|
180
194
|
} else if (targetType === 'Set' && sourceType === 'Set') {
|
|
181
195
|
result = deepMergeSets(target, source, options);
|
|
182
|
-
|
|
196
|
+
mergeType = 'Set';
|
|
183
197
|
} else if (targetType === 'Map' && sourceType === 'Map') {
|
|
184
198
|
result = deepMergeMaps(target, source, options);
|
|
185
|
-
|
|
199
|
+
mergeType = 'Map';
|
|
186
200
|
} else {
|
|
187
201
|
flag = false;
|
|
188
202
|
result = target;
|
|
189
203
|
}
|
|
190
|
-
options?.onAfterMerge?.({ result, target, source,
|
|
191
|
-
return { result, flag,
|
|
204
|
+
options?.onAfterMerge?.({ result, target, source, targetType, sourceType, mergeType, parent: opts.parent });
|
|
205
|
+
return { result, flag, mergeType };
|
|
192
206
|
},
|
|
193
207
|
// Special handling for objects with enable property
|
|
194
208
|
// 对具有enable属性的对象进行特殊处理
|
|
@@ -224,35 +238,55 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
|
|
|
224
238
|
result = options.targetClone ? shallowCopy(target) : target;
|
|
225
239
|
|
|
226
240
|
for (let k in source) {
|
|
241
|
+
const _result = (result as any)[k],
|
|
242
|
+
_source = source[k];
|
|
227
243
|
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
228
244
|
|
|
229
|
-
|
|
245
|
+
const resp = smartMerger(_result, _source, { ...opts, parent: result });
|
|
230
246
|
//resp={result,flag,type}
|
|
231
|
-
//flag=true
|
|
247
|
+
//flag=true表示类型一致(object/array/map/set)并完成了合并,false表示并没有合并需要直接赋值
|
|
232
248
|
if (!resp.flag) {
|
|
233
249
|
//类型不同则直接覆盖
|
|
234
|
-
|
|
235
|
-
|
|
250
|
+
let tmp = options.useEnable ? mergeEnableObject(_result, _source) : _source;
|
|
251
|
+
if (_result !== tmp && tmp === null) {
|
|
252
|
+
if (options.nullBehavior === 'ignore') {
|
|
253
|
+
//不处理
|
|
254
|
+
} else if (options.nullBehavior === 'delete') {
|
|
255
|
+
//删除属性
|
|
256
|
+
Reflect.deleteProperty(result, k);
|
|
257
|
+
} else {
|
|
258
|
+
//替换
|
|
259
|
+
(result as any)[k] = tmp;
|
|
260
|
+
}
|
|
261
|
+
} else if (_result !== tmp && tmp === undefined) {
|
|
262
|
+
if (options.undefinedBehavior === 'ignore') {
|
|
263
|
+
//不处理
|
|
264
|
+
} else if (options.undefinedBehavior === 'delete') {
|
|
265
|
+
//删除属性
|
|
266
|
+
Reflect.deleteProperty(result, k);
|
|
267
|
+
} else {
|
|
268
|
+
//替换
|
|
269
|
+
(result as any)[k] = _source;
|
|
270
|
+
}
|
|
236
271
|
} else {
|
|
237
|
-
|
|
238
|
-
(result as any)[k] = source[k];
|
|
272
|
+
(result as any)[k] = _source;
|
|
239
273
|
}
|
|
240
274
|
} else {
|
|
241
275
|
//类型相同
|
|
242
|
-
if (resp.
|
|
243
|
-
if (resp.
|
|
276
|
+
if (resp.mergeType) {
|
|
277
|
+
if (resp.mergeType === 'Object') {
|
|
244
278
|
//如果遇上对象则深度复制
|
|
245
279
|
(result as any)[k] = resp.result;
|
|
246
280
|
}
|
|
247
281
|
} else {
|
|
248
282
|
//其他类型则直接覆盖
|
|
249
|
-
(result as any)[k] =
|
|
283
|
+
(result as any)[k] = _source;
|
|
250
284
|
}
|
|
251
285
|
}
|
|
252
286
|
|
|
253
287
|
} else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
254
288
|
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
255
|
-
(result as any)[k] =
|
|
289
|
+
(result as any)[k] = _source;
|
|
256
290
|
}
|
|
257
291
|
}
|
|
258
292
|
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
@@ -322,7 +356,7 @@ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, sourc
|
|
|
322
356
|
result.set(key, _source);
|
|
323
357
|
} else {
|
|
324
358
|
// If both target and source are objects, merge them recursively
|
|
325
|
-
resp.
|
|
359
|
+
resp.mergeType === 'Object' && result.set(key, resp.result);
|
|
326
360
|
}
|
|
327
361
|
} else {
|
|
328
362
|
// If the key doesn't exist in the target, add the entry from the source Map
|