@codady/utils 0.0.9 → 0.0.11

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/utils.cjs.js +488 -28
  3. package/dist/utils.cjs.min.js +3 -3
  4. package/dist/utils.esm.js +488 -28
  5. package/dist/utils.esm.min.js +3 -3
  6. package/dist/utils.umd - /345/211/257/346/234/254.js" +749 -0
  7. package/dist/utils.umd.js +490 -32
  8. package/dist/utils.umd.min.js +3 -3
  9. package/dist.zip +0 -0
  10. package/modules.js +24 -4
  11. package/modules.ts +24 -4
  12. package/package.json +1 -1
  13. package/src/arrayMutableMethods - /345/211/257/346/234/254.js" +5 -0
  14. package/src/arrayMutableMethods.js +5 -0
  15. package/src/{mutableMethods.ts → arrayMutableMethods.ts} +3 -3
  16. package/src/deepClone.js +151 -26
  17. package/src/deepClone.ts +194 -35
  18. package/src/deepCloneToJSON - /345/211/257/346/234/254.js" +47 -0
  19. package/src/deepEqual.js +48 -0
  20. package/src/deepEqual.ts +46 -0
  21. package/src/deepMerge.js +34 -0
  22. package/src/deepMerge.ts +40 -0
  23. package/src/deepMergeArrays.js +45 -0
  24. package/src/deepMergeArrays.ts +62 -0
  25. package/src/deepMergeHelper.js +40 -0
  26. package/src/deepMergeHelper.ts +45 -0
  27. package/src/deepMergeMaps - /345/211/257/346/234/254.js" +78 -0
  28. package/src/deepMergeMaps.js +57 -0
  29. package/src/deepMergeMaps.ts +67 -0
  30. package/src/deepMergeObjects.js +82 -0
  31. package/src/deepMergeObjects.ts +85 -0
  32. package/src/deepMergeSets.js +48 -0
  33. package/src/deepMergeSets.ts +55 -0
  34. package/src/getUniqueId.js +11 -7
  35. package/src/getUniqueId.ts +16 -9
  36. package/src/mapMutableMethods.js +5 -0
  37. package/src/mapMutableMethods.ts +15 -0
  38. package/src/mutableMethods.js +2 -2
  39. package/src/setMutableMethods - /345/211/257/346/234/254.js" +5 -0
  40. package/src/setMutableMethods.js +5 -0
  41. package/src/setMutableMethods.ts +14 -0
  42. package/src/wrapArrayMethods.js +5 -5
  43. package/src/wrapArrayMethods.ts +7 -7
  44. package/src/wrapMap - /345/211/257/346/234/254.js" +119 -0
  45. package/src/wrapMapMethods.js +118 -0
  46. package/src/wrapMapMethods.ts +226 -0
  47. package/src/wrapSetMethods.js +112 -0
  48. package/src/wrapSetMethods.ts +215 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-19 15:23:38
2
+ * @since Last modified: 2025-12-24 17:50:8
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.9
4
+ * @version 0.0.11
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=>{const t=getDataType(e);if("Object"===t){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r]);if(r.length>0)for(const o of r)t[o]=deepClone(e[o]);return t}if("Array"===t)return e.map(e=>deepClone(e));if("Date"===t)return new Date(e.getTime());if("RegExp"===t){const t=e;return new RegExp(t.source,t.flags)}return e},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},mutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:o,props:a={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=mutableMethods);const s={};for(let n of o)s[n]=function(...o){const s={},i=e.length;switch(n){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedValue=e[i-1];break;case"shift":s.shiftedValue=e[0];break;case"splice":const[t,r]=o,a=t<0?Math.max(i+t,0):Math.min(t,i),n=void 0===r?i-a:r;s.deletedItems=e.slice(a,a+n);break;case"sort":case"reverse":s.oldSnapshot=[...e];break;case"fill":case"copyWithin":const p=o[1]||0,l=void 0===o[2]?i:o[2];s.oldItems=e.slice(p,l),s.start=p,s.end=l}t?.(s);const p=Array.prototype[n].apply(e,o),l={value:p,key:n,args:o,context:s,target:e,...a};return r?.(l),p};return s},requireTypes=(e,t,r)=>{let o=Array.isArray(t)?t:[t],a=getDataType(e),s=a.toLowerCase(),n=o.map(e=>e.toLowerCase()),i=s.includes("html")?"element":s;if(r)try{if(!n.includes(i))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${i}`)}catch(e){r(e,a)}else if(!n.includes(i))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${i}`);return a},getUniqueId=(e,t=!0)=>`${e?e+"_":""}${Date.now()}_${Math.random().toString(36).substring(2,11)}${t?"_"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}`,utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,mutableMethods:mutableMethods,getUniqueId:getUniqueId};module.exports=utils;
15
+ "use strict";var assert=require("assert");const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=(e,t={})=>{const r=getDataType(e),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor(e,r);if(t)return a.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e}),t}a.onBeforeClone?.(e,r);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);o=t}else if("Array"===r&&a.cloneArray)o=e.map(e=>deepClone(e,a));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,a),deepClone(o,a));o=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,a));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}),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={},p=e.length;switch(s){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[p-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,o=t<0?Math.max(p+t,0):Math.min(t,p),s=void 0===r?p-o:r;n.deletedItems=e.slice(o,o+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const l=a[1]||0,c=void 0===a[2]?p:a[2];n.oldItems=e.slice(l,c),n.start=l,n.end=c}t?.(n);const l=Array.prototype[s].apply(e,a),c={value:l,key:s,args:a,context:n,target:e,...o};return r?.(c),l};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()),p=n.includes("html")?"element":n;if(r)try{if(!s.includes(p))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${p}`)}catch(e){r(e,o)}else if(!s.includes(p))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${p}`);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 p=e[a].apply(e,n),l={method:a,result:p,args:n,context:s,target:e,...o};return r(l),p};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 p=e[a].apply(e,n),l={method:a,result:p,args:n,context:s,target:e,...o};return r(l),p};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),o=getDataType(t);if("Object"!==a||"Object"!==o)return e;const n=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),s=n.targetClone?deepClone(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let a=deepMergeHelper(s[e],t[e],r);a.flag?"Object"===a.type&&(s[e]=a.result):n.useEnable&&s.hasOwnProperty(e)&&s[e]?.hasOwnProperty("enable")&&"boolean"==typeof t[e]?s[e]?.hasOwnProperty("enable")&&"boolean"==typeof t[e]?s[e].enable=t[e]:t[e]?.hasOwnProperty("enable")&&"boolean"==typeof s[e]?s=Object.assign({enable:s[e]},t[e]):s[e]=t[e]:s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&n.propAppend&&(s[e]=t[e]);if(n.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length>0)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1},r),o=a.targetClone?[...e]:e;if("replace"===a.itemMode)return o.length=0,o.push(...t),o;if("concat"===a.itemMode)return o.push(...t),o;for(let e=0;e<t.length;e++){deepMergeHelper(o[e],t[e],a).flag||(o[e]=t[e])}return o},deepMergeMaps=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Map(e):e;return"replace"===a.itemMode?(o.clear(),t.forEach((e,t)=>o.set(t,e)),o):"concat"===a.itemMode?(t.forEach((e,t)=>o.set(t,e)),o):(t.forEach((e,t)=>{if(o.has(t)){const r=o.get(t),n=e,s=deepMergeHelper(r,n,a);s.flag?"Object"===s.type&&o.set(t,s.result):o.set(t,n)}else o.set(t,e)}),o)},deepEqual=(e,t)=>{if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!deepEqual(e[r],t[r]))return!1;return!0}if("object"==typeof e&&"object"==typeof t){const r=Object.keys(e),a=Object.keys(t);if(r.length!==a.length)return!1;for(let o of r)if(!a.includes(o)||!deepEqual(e[o],t[o]))return!1;return!0}return e===t},deepMergeSets=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!(e instanceof Set&&t instanceof Set))return e;const a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Set(e):e;if("replace"===a.itemMode){o.clear();for(let e of t)o.add(e);return o}if("concat"===a.itemMode){for(let e of t)o.add(e);return o}for(let e of t){let t=[...o].find(t=>deepEqual(t,e));!deepMergeHelper(t,e,a).flag&&o.add(e)}return o},deepMergeHelper=(e,t,r)=>{let a,o,n=getDataType(e),s=getDataType(t),p=!0;return"Object"===n&&"Object"===s?(o=deepMergeObjects(e,t,r),a="Object"):"Array"===n&&"Array"===s?(o=deepMergeArrays(e,t,r),a="Array"):"Set"===n&&"Set"===s?(o=deepMergeSets(e,t,r),a="Set"):"Map"===n&&"Map"===s?(o=deepMergeMaps(e,t,r),a="Map"):(p=!1,o=e),{result:o,flag:p,type:a}},deepMerge=(e,t,r={})=>{let a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r);return deepMergeHelper(e,t,a)},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepEqual:assert.deepEqual,deepMerge:deepMerge,deepMergeArrays:deepMergeArrays,deepMergeMaps:deepMergeMaps,deepMergeObjects:deepMergeObjects,deepMergeSets:deepMergeSets};module.exports=utils;
package/dist/utils.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-19 15:23:38
3
+ * @since Last modified: 2025-12-24 17:50:8
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.9
5
+ * @version 0.0.11
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}
@@ -14,6 +14,8 @@
14
14
  * @license MIT license
15
15
  */
16
16
 
17
+ import { deepEqual as deepEqual$1 } from 'assert';
18
+
17
19
  const getDataType = (obj) => {
18
20
  let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
19
21
  if (tmp === 'Function' && /^\s*class\s+/.test(obj.toString())) {
@@ -39,37 +41,100 @@ const getDataType = (obj) => {
39
41
  //document.createElementNS('http://www.w3.org/1998/Math/MathML', 'math'); -> MathMLElement
40
42
  };
41
43
 
42
- const deepClone = (data) => {
43
- const dataType = getDataType(data);
44
- if (dataType === 'Object') {
45
- const newObj = {};
46
- const symbols = Object.getOwnPropertySymbols(data);
44
+ //支持原始值的复制,包括Number、String、Boolean、Null
45
+ //支持Date和Regex对象值复制(值转换)
46
+ //支持{},[],Set和Map的遍历
47
+ const deepClone = (data, options = {}) => {
48
+ const dataType = getDataType(data),
49
+ // Default options
50
+ opts = Object.assign({
51
+ cloneSet: true,
52
+ cloneMap: true,
53
+ cloneObject: true,
54
+ cloneArray: true,
55
+ //可重新构建
56
+ cloneDate: true,
57
+ cloneRegex: true,
58
+ //节点默认不复制
59
+ //cloneElement: false,
60
+ //cloneFragment: false,
61
+ }, options);
62
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
63
+ if (opts.interceptor && typeof opts.interceptor === 'function') {
64
+ let result = opts.interceptor(data, dataType);
65
+ if ((result ?? false)) {
66
+ // Call onAfterClone if set
67
+ opts.onAfterClone?.({
68
+ output: result,
69
+ input: data,
70
+ type: dataType,
71
+ cloned: result !== data,
72
+ });
73
+ return result;
74
+ }
75
+ // If interceptor returns null/undefined, continue with normal cloning process
76
+ }
77
+ // Callback before cloning
78
+ opts.onBeforeClone?.(data, dataType);
79
+ let newData, cloned = true;
80
+ if (dataType === 'Object' && opts.cloneObject) {
81
+ const newObj = {}, symbols = Object.getOwnPropertySymbols(data);
47
82
  // Clone regular properties
48
83
  for (const key in data) {
49
- newObj[key] = deepClone(data[key]);
84
+ newObj[key] = deepClone(data[key], opts);
50
85
  }
51
86
  // Clone Symbol properties
52
87
  if (symbols.length > 0) {
53
88
  for (const symbol of symbols) {
54
- newObj[symbol] = deepClone(data[symbol]);
89
+ newObj[symbol] = deepClone(data[symbol], opts);
55
90
  }
56
91
  }
57
- return newObj;
92
+ newData = newObj;
58
93
  }
59
- else if (dataType === 'Array') {
60
- return data.map(item => deepClone(item));
94
+ else if (dataType === 'Array' && opts.cloneArray) {
95
+ newData = data.map(item => deepClone(item, opts));
96
+ }
97
+ else if (dataType === 'Map' && opts.cloneMap) {
98
+ const newMap = new Map();
99
+ for (const [key, value] of data) {
100
+ // Both Map keys and values need deep cloning
101
+ newMap.set(deepClone(key, opts), deepClone(value, opts));
102
+ }
103
+ newData = newMap;
61
104
  }
62
- else if (dataType === 'Date') {
63
- return new Date(data.getTime());
105
+ else if (dataType === 'Set' && opts.cloneSet) {
106
+ const newSet = new Set();
107
+ for (const value of data) {
108
+ // Set values need deep cloning
109
+ newSet.add(deepClone(value, opts));
110
+ }
111
+ newData = newSet;
64
112
  }
65
- else if (dataType === 'RegExp') {
113
+ else if (dataType === 'Date' && opts.cloneDate) {
114
+ newData = new Date(data.getTime());
115
+ }
116
+ else if (dataType === 'RegExp' && opts.cloneRegex) {
66
117
  const regex = data;
67
- return new RegExp(regex.source, regex.flags);
118
+ newData = new RegExp(regex.source, regex.flags);
119
+ // } else if ((dataType.includes('HTML') && opts.cloneElement) ||
120
+ // (dataType === 'DocumentFragment' && opts.cloneFragment)
121
+ //) {
122
+ //Text,Comment,HTML*Element,DocumentFragment,Attr
123
+ // newData = (data as any).cloneNode(true) as T;
68
124
  }
69
125
  else {
70
- // Number, String, Boolean, Symbol,Text,Comment,Set,Map, HTML*Element, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
71
- return data;
126
+ // Number, String, Boolean, Symbol, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
127
+ newData = data;
128
+ cloned = false;
72
129
  }
130
+ // Callback after cloning
131
+ opts.onAfterClone?.({
132
+ output: newData,
133
+ input: data,
134
+ type: dataType,
135
+ cloned,
136
+ });
137
+ return newData;
73
138
  };
74
139
 
75
140
  const deepCloneToJSON = (data) => {
@@ -100,7 +165,7 @@ const deepCloneToJSON = (data) => {
100
165
  }
101
166
  };
102
167
 
103
- const mutableMethods = [
168
+ const arrayMutableMethods = [
104
169
  'push', 'pop', 'shift', 'unshift', 'splice',
105
170
  'sort', 'reverse', 'copyWithin', 'fill'
106
171
  ];
@@ -112,7 +177,7 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
112
177
  }
113
178
  //使用默认
114
179
  if (!allowList || allowList?.length) {
115
- allowList = mutableMethods;
180
+ allowList = arrayMutableMethods;
116
181
  }
117
182
  const methods = {};
118
183
  for (let method of allowList) {
@@ -128,10 +193,10 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
128
193
  context.addedItems = [...args];
129
194
  break;
130
195
  case 'pop':
131
- context.poppedValue = target[len - 1];
196
+ context.poppedItem = target[len - 1];
132
197
  break;
133
198
  case 'shift':
134
- context.shiftedValue = target[0];
199
+ context.shiftedItem = target[0];
135
200
  break;
136
201
  case 'splice':
137
202
  const [s, d] = args,
@@ -201,20 +266,405 @@ const requireTypes = (data, require, cb) => {
201
266
  return dataType;
202
267
  };
203
268
 
204
- const getUniqueId = (prefix, extra = true) => {
269
+ const getUniqueId = (options = {}) => {
270
+ const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
205
271
  // Current timestamp in milliseconds (since Unix epoch)
206
272
  // This provides the primary uniqueness guarantee
207
273
  const timestamp = Date.now(),
208
274
  // Generate a base-36 random string (0-9, a-z)
209
275
  // Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
210
276
  // substring(2, 11) extracts 9 characters starting from index 2
211
- random = Math.random().toString(36).substring(2, 11),
277
+ //0.259854635->0.9crs03e8v2
278
+ base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
212
279
  // Additional 4-digit random number for extra randomness
213
280
  // This helps avoid collisions in high-frequency generation scenarios
214
- extraRandom = extra ? '_' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '_' : '';
281
+ base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
215
282
  // Construct the final ID string
216
283
  // Format: [prefix_]timestamp_randomBase36_extraRandom
217
- return `${prefixString}${timestamp}_${random}${extraRandom}`;
284
+ return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
285
+ };
286
+
287
+ const setMutableMethods = ['add', 'delete', 'clear'];
288
+
289
+ const mapMutableMethods = ['set', 'delete', 'clear'];
290
+
291
+ const wrapSetMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList = setMutableMethods, props = {}, }) => {
292
+ // Validation: Ensure target is a Set
293
+ if (!(target instanceof Set)) {
294
+ throw new TypeError("The 'target' parameter must be a Set.");
295
+ }
296
+ // Create method wrappers
297
+ const methods = {};
298
+ // Helper to create wrapped method
299
+ const createWrappedMethod = (method) => {
300
+ return function (...args) {
301
+ const context = {};
302
+ // Capture pre-mutation context based on method
303
+ switch (method) {
304
+ case 'add': {
305
+ const [value] = args;
306
+ context.addedItem = value;
307
+ //context.existed=true,说明值重复
308
+ context.existed = target.has(value);
309
+ break;
310
+ }
311
+ case 'delete': {
312
+ const [value] = args;
313
+ context.existed = target.has(value);
314
+ context.deletedItem = context.existed ? value : undefined;
315
+ break;
316
+ }
317
+ case 'clear': {
318
+ context.clearedItems = Array.from(target);
319
+ //用来做验证
320
+ context.previousSize = target.size;
321
+ break;
322
+ }
323
+ }
324
+ // Execute before mutation callback
325
+ onBeforeMutate(context);
326
+ // Execute the native Set method
327
+ const result = target[method].apply(target, args);
328
+ // Construct patch object
329
+ const patch = {
330
+ method,
331
+ result,
332
+ args,
333
+ context,
334
+ target,
335
+ ...props
336
+ };
337
+ // Execute after mutation callback
338
+ onAfterMutate(patch);
339
+ return result;
340
+ };
341
+ };
342
+ // Wrap allowed methods
343
+ for (const method of allowList) {
344
+ if (setMutableMethods.includes(method)) {
345
+ methods[method] = createWrappedMethod(method);
346
+ }
347
+ }
348
+ // Add target reference
349
+ Object.defineProperty(methods, 'target', {
350
+ get: () => target,
351
+ enumerable: false,
352
+ configurable: false
353
+ });
354
+ return methods;
355
+ };
356
+
357
+ const wrapMapMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList = mapMutableMethods, props = {}, }) => {
358
+ // Validation: Ensure target is a Map
359
+ if (!(target instanceof Map)) {
360
+ throw new TypeError("The 'target' parameter must be a Map.");
361
+ }
362
+ // Create method wrappers
363
+ const methods = {};
364
+ // Helper to create wrapped method
365
+ const createWrappedMethod = (method) => {
366
+ return function (...args) {
367
+ const context = {};
368
+ // Capture pre-mutation context based on method
369
+ switch (method) {
370
+ case 'set': {
371
+ const [key, newValue] = args;
372
+ context.key = key;
373
+ context.newValue = newValue;
374
+ context.existed = target.has(key);
375
+ context.oldValue = context.existed ? target.get(key) : undefined;
376
+ break;
377
+ }
378
+ case 'delete': {
379
+ const [key] = args;
380
+ context.key = key;
381
+ context.existed = target.has(key);
382
+ context.value = context.existed ? target.get(key) : undefined;
383
+ break;
384
+ }
385
+ case 'clear': {
386
+ context.clearedItems = Array.from(target.entries());
387
+ //用来做验证
388
+ context.previousSize = target.size;
389
+ break;
390
+ }
391
+ }
392
+ // Execute before mutation callback
393
+ onBeforeMutate(context);
394
+ // Execute the native Map method
395
+ const result = target[method].apply(target, args);
396
+ // Construct patch object
397
+ const patch = {
398
+ method,
399
+ result,
400
+ args,
401
+ context,
402
+ target,
403
+ ...props
404
+ };
405
+ // Execute after mutation callback
406
+ onAfterMutate(patch);
407
+ return result;
408
+ };
409
+ };
410
+ // Wrap allowed methods
411
+ for (const method of allowList) {
412
+ if (mapMutableMethods.includes(method)) {
413
+ methods[method] = createWrappedMethod(method);
414
+ }
415
+ }
416
+ // Add target reference
417
+ Object.defineProperty(methods, 'target', {
418
+ get: () => target,
419
+ enumerable: false,
420
+ configurable: false
421
+ });
422
+ return methods;
423
+ };
424
+
425
+ const deepMergeObjects = (target, source, opts = {}) => {
426
+ let targetType = getDataType(target), sourceType = getDataType(source);
427
+ //target不是对象或者source为空则直接返回
428
+ if (targetType !== 'Object' || sourceType !== 'Object') {
429
+ return target;
430
+ }
431
+ const options = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, opts),
432
+ //如果是复制方法,则先复制target
433
+ result = options.targetClone ? deepClone(target) : target;
434
+ for (let k in source) {
435
+ if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
436
+ let resp = deepMergeHelper(result[k], source[k], opts);
437
+ //resp={result,flag,type}
438
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
439
+ if (!resp.flag) {
440
+ //类型不同则直接覆盖
441
+ if (options.useEnable && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
442
+ //部分替换,仅针对result={enable:true/false,a:''},source=false/true这种情况和相反的情况,因为这种情况再笨框架比较多见
443
+ if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
444
+ //result={enable:true,a:'',b:''},source[k]=false=>result={enable:false,a:'',b:''}
445
+ result[k].enable = source[k];
446
+ }
447
+ else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
448
+ //source={enable:true,a:'',b:''},(result as any)[k]=false=>result={enable:false,a:'',b:''}
449
+ result = Object.assign({ enable: result[k] }, source[k]);
450
+ }
451
+ else {
452
+ //完全替换
453
+ result[k] = source[k];
454
+ }
455
+ }
456
+ else {
457
+ //完全替换
458
+ result[k] = source[k];
459
+ }
460
+ }
461
+ else {
462
+ // If both target and source are objects, merge them recursively
463
+ if (resp.type === 'Object') {
464
+ result[k] = resp.result;
465
+ }
466
+ }
467
+ }
468
+ else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
469
+ //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
470
+ result[k] = source[k];
471
+ }
472
+ }
473
+ //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
474
+ if (options.useSymbol) {
475
+ let symbols = Object.getOwnPropertySymbols(source);
476
+ if (symbols.length > 0) {
477
+ for (let k of symbols) {
478
+ result[k] = source[k];
479
+ }
480
+ }
481
+ }
482
+ return result;
483
+ };
484
+
485
+ const deepMergeArrays = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
486
+ // Ensure both target and source are arrays
487
+ if (!Array.isArray(target) || !Array.isArray(source))
488
+ return target;
489
+ // Merge options, with default values
490
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false }, options),
491
+ // If cloning is enabled, create a deep copy of the target array
492
+ result = opts.targetClone ? [...target] : target;
493
+ // Handle different merge strategies based on itemMode
494
+ if (opts.itemMode === 'replace') {
495
+ // Replace mode: clear the target array and push all items from the source array
496
+ result.length = 0;
497
+ result.push(...source);
498
+ return result;
499
+ }
500
+ else if (opts.itemMode === 'concat') {
501
+ // Concatenate mode: append all items from the source array to the target array
502
+ result.push(...source);
503
+ return result;
504
+ }
505
+ else {
506
+ // Default "merge" mode: recursively merge items in the arrays
507
+ for (let i = 0; i < source.length; i++) {
508
+ let resp = deepMergeHelper(result[i], source[i], opts);
509
+ //resp={result,flag,type}
510
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
511
+ if (!resp.flag) {
512
+ result[i] = source[i];
513
+ }
514
+ }
515
+ return result;
516
+ }
517
+ };
518
+
519
+ const deepMergeMaps = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
520
+ // Ensure both target and source are Maps
521
+ if (!(target instanceof Map) || !(source instanceof Map))
522
+ return target;
523
+ // Merge options, with default values
524
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
525
+ // If cloning is enabled, create a deep copy of the target Map
526
+ result = opts.targetClone ? new Map(target) : target;
527
+ // Handle different merge strategies based on itemMode
528
+ if (opts.itemMode === 'replace') {
529
+ // Replace mode: clear the target Map and add all entries from the source Map
530
+ result.clear();
531
+ source.forEach((value, key) => result.set(key, value));
532
+ return result;
533
+ }
534
+ else if (opts.itemMode === 'concat') {
535
+ // Concatenate mode: add all entries from the source Map to the target Map
536
+ source.forEach((value, key) => result.set(key, value));
537
+ return result;
538
+ }
539
+ else {
540
+ // Default "merge" mode: recursively merge entries in the Maps
541
+ source.forEach((value, key) => {
542
+ // Check if the key already exists in the target Map
543
+ if (result.has(key)) {
544
+ const targetValue = result.get(key), sourceValue = value, resp = deepMergeHelper(targetValue, sourceValue, opts);
545
+ //resp={result,flag,type}
546
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
547
+ if (!resp.flag) {
548
+ // For simple values, overwrite the target value with the source value
549
+ result.set(key, sourceValue);
550
+ }
551
+ else {
552
+ // If both target and source are objects, merge them recursively
553
+ resp.type === 'Object' && result.set(key, resp.result);
554
+ }
555
+ }
556
+ else {
557
+ // If the key doesn't exist in the target, add the entry from the source Map
558
+ result.set(key, value);
559
+ }
560
+ });
561
+ return result;
562
+ }
563
+ };
564
+
565
+ const deepEqual = (a, b) => {
566
+ // If both are equal by reference
567
+ if (a === b)
568
+ return true;
569
+ // If both are arrays, check equality recursively
570
+ if (Array.isArray(a) && Array.isArray(b)) {
571
+ if (a.length !== b.length)
572
+ return false;
573
+ for (let i = 0; i < a.length; i++) {
574
+ if (!deepEqual(a[i], b[i]))
575
+ return false;
576
+ }
577
+ return true;
578
+ }
579
+ // If both are objects, check equality recursively
580
+ if (typeof a === 'object' && typeof b === 'object') {
581
+ const keysA = Object.keys(a), keysB = Object.keys(b);
582
+ if (keysA.length !== keysB.length)
583
+ return false;
584
+ for (let key of keysA) {
585
+ if (!keysB.includes(key) || !deepEqual(a[key], b[key]))
586
+ return false;
587
+ }
588
+ return true;
589
+ }
590
+ // For other types, direct comparison
591
+ return a === b;
592
+ };
593
+
594
+ const deepMergeSets = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
595
+ // Ensure both target and source are Sets
596
+ if (!(target instanceof Set) || !(source instanceof Set))
597
+ return target;
598
+ // Merge options, with default values
599
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
600
+ // If cloning is enabled, create a deep copy of the target Set
601
+ result = opts.targetClone ? new Set(target) : target;
602
+ // Handle different merge strategies based on itemMode
603
+ if (opts.itemMode === 'replace') {
604
+ // Replace mode: clear the target Set and add all items from the source Set
605
+ result.clear();
606
+ for (let item of source)
607
+ result.add(item);
608
+ return result;
609
+ }
610
+ else if (opts.itemMode === 'concat') {
611
+ // Concatenate mode: add all items from the source Set to the target Set
612
+ for (let item of source)
613
+ result.add(item);
614
+ return result;
615
+ }
616
+ else {
617
+ // Default "merge" mode: recursively merge items in the Sets
618
+ for (let item of source) {
619
+ // Check the type of the target and source items
620
+ let _target = [...result].find(val => deepEqual(val, item)), resp = deepMergeHelper(_target, item, opts);
621
+ //resp={result,flag}
622
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
623
+ !resp.flag && result.add(item);
624
+ }
625
+ return result;
626
+ }
627
+ };
628
+
629
+ // deepMergeHelper.ts
630
+
631
+
632
+ const deepMergeHelper = (target, source, options) => {
633
+ let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
634
+ if (targetType === 'Object' && sourceType === 'Object') {
635
+ result = deepMergeObjects(target, source, options);
636
+ type = 'Object';
637
+ }
638
+ else if (targetType === 'Array' && sourceType === 'Array') {
639
+ result = deepMergeArrays(target, source, options);
640
+ type = 'Array';
641
+ }
642
+ else if (targetType === 'Set' && sourceType === 'Set') {
643
+ result = deepMergeSets(target, source, options);
644
+ type = 'Set';
645
+ }
646
+ else if (targetType === 'Map' && sourceType === 'Map') {
647
+ result = deepMergeMaps(target, source, options);
648
+ type = 'Map';
649
+ }
650
+ else {
651
+ flag = false;
652
+ result = target; // Default case, replace primitive values
653
+ }
654
+ return {
655
+ result, flag, type
656
+ };
657
+ };
658
+
659
+ const deepMerge = (target, source, opts = {}) => {
660
+ // Get the data types of the target and source
661
+ let options = Object.assign({
662
+ itemMode: 'merge', // Default merge mode
663
+ propAppend: true, // Default to appending properties from source to target
664
+ targetClone: false, // Do not clone target by default
665
+ useEnable: true // Enable special handling for objects with an `enable` property
666
+ }, opts);
667
+ return deepMergeHelper(target, source, options);
218
668
  };
219
669
 
220
670
  const utils = {
@@ -226,8 +676,18 @@ const utils = {
226
676
  deepClone,
227
677
  deepCloneToJSON,
228
678
  wrapArrayMethods,
229
- mutableMethods,
230
- getUniqueId
679
+ arrayMutableMethods,
680
+ setMutableMethods,
681
+ mapMutableMethods,
682
+ wrapSetMethods,
683
+ wrapMapMethods,
684
+ getUniqueId,
685
+ deepEqual: deepEqual$1,
686
+ deepMerge,
687
+ deepMergeArrays,
688
+ deepMergeMaps,
689
+ deepMergeObjects,
690
+ deepMergeSets,
231
691
  };
232
692
 
233
693
  export { utils as default };