@codady/utils 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All changes to Utils including new features, updates, and removals are documented here.
4
4
 
5
+
6
+ ## [v0.0.7] - 2025-12-19
7
+
8
+ ### Distribution Files
9
+ - **JS**: https://unpkg.com/@codady/utils@0.0.7/dist/js/utils.js
10
+ - **Zip**: https://unpkg.com/@codady/utils@0.0.7/dist.zip
11
+
12
+ ### Changes
13
+
14
+ #### Fixed
15
+ - Some problems.
16
+
17
+ #### Added
18
+ - The `mutateArray` function has been renamed to `wrapArrayMethods`.`mutateArray`函数改名为`wrapArrayMethods`。
19
+
20
+
21
+ #### Removed
22
+ - Null
23
+
5
24
  ## [v0.0.6] - 2025-12-19
6
25
 
7
26
  ### Distribution Files
package/dist/utils.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-19 9:4:44
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.6
5
+ * @version 0.0.7
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}
@@ -107,7 +107,7 @@ const mutableMethods = [
107
107
  'sort', 'reverse', 'copyWithin', 'fill'
108
108
  ];
109
109
 
110
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
110
+ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
111
111
  // Validation: Ensure target is an array and method is allowed
112
112
  if (!Array.isArray(target)) {
113
113
  throw new TypeError("The 'target' parameter must be an array.");
@@ -116,62 +116,64 @@ const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, on
116
116
  if (!allowList || allowList?.length) {
117
117
  allowList = mutableMethods;
118
118
  }
119
- if (!allowList?.includes(method)) {
120
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
121
- }
122
- const context = {}, len = target.length;
123
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
124
- switch (method) {
125
- // 'push' and 'unshift' are add operations, in undo/redo,
126
- // we can determine the original data structure from result.length and args.length
127
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
128
- case 'push':
129
- case 'unshift':
130
- context.addedItems = [...args];
131
- break;
132
- case 'pop':
133
- context.poppedValue = target[len - 1];
134
- break;
135
- case 'shift':
136
- context.shiftedValue = target[0];
137
- break;
138
- case 'splice':
139
- const [s, d] = args,
140
- // Calculate actual start index (handling negative values)
141
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
142
- // Handle deleteCount defaults
143
- deleteCount = d === undefined ? len - start : d;
144
- context.deletedItems = target.slice(start, start + deleteCount);
145
- break;
146
- case 'sort':
147
- case 'reverse':
148
- // These methods reorder the whole array; requires a full shallow copy
149
- context.oldSnapshot = [...target];
150
- break;
151
- case 'fill':
152
- case 'copyWithin':
153
- const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
154
- // Overwritten values
155
- context.oldItems = target.slice(startIdx, endIdx);
156
- context.start = startIdx;
157
- context.end = endIdx;
158
- break;
159
- }
160
- // Execute the "onBeforeMutate" callback before mutation
161
- onBeforeMutate?.(context);
162
- // Execute the native array mutation
163
- const value = Array.prototype[method].apply(target, args), patch = {
164
- value,
165
- key: method,
166
- args,
167
- context,
168
- target,
169
- timestamp: Date.now(),
170
- ...props
171
- };
172
- // Construct and trigger the patch callback
173
- onAfterMutate?.(patch);
174
- return value;
119
+ const methods = {};
120
+ for (let method of allowList) {
121
+ methods[method] = function (...args) {
122
+ const context = {}, len = target.length;
123
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
124
+ switch (method) {
125
+ // 'push' and 'unshift' are add operations, in undo/redo,
126
+ // we can determine the original data structure from result.length and args.length
127
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
128
+ case 'push':
129
+ case 'unshift':
130
+ context.addedItems = [...args];
131
+ break;
132
+ case 'pop':
133
+ context.poppedValue = target[len - 1];
134
+ break;
135
+ case 'shift':
136
+ context.shiftedValue = target[0];
137
+ break;
138
+ case 'splice':
139
+ const [s, d] = args,
140
+ // Calculate actual start index (handling negative values)
141
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
142
+ // Handle deleteCount defaults
143
+ deleteCount = d === undefined ? len - start : d;
144
+ context.deletedItems = target.slice(start, start + deleteCount);
145
+ break;
146
+ case 'sort':
147
+ case 'reverse':
148
+ // These methods reorder the whole array; requires a full shallow copy
149
+ context.oldSnapshot = [...target];
150
+ break;
151
+ case 'fill':
152
+ case 'copyWithin':
153
+ const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
154
+ // Overwritten values
155
+ context.oldItems = target.slice(startIdx, endIdx);
156
+ context.start = startIdx;
157
+ context.end = endIdx;
158
+ break;
159
+ }
160
+ // Execute the "onBeforeMutate" callback before mutation
161
+ onBeforeMutate?.(context);
162
+ // Execute the native array mutation
163
+ const value = Array.prototype[method].apply(target, args), patch = {
164
+ value,
165
+ key: method,
166
+ args,
167
+ context,
168
+ target,
169
+ ...props
170
+ };
171
+ // Construct and trigger the patch callback
172
+ onAfterMutate?.(patch);
173
+ return value;
174
+ };
175
+ }
176
+ return methods;
175
177
  };
176
178
 
177
179
  const requireTypes = (data, require, cb) => {
@@ -209,7 +211,7 @@ const utils = {
209
211
  //parseStr,
210
212
  deepClone,
211
213
  deepCloneToJSON,
212
- mutateArray,
214
+ wrapArrayMethods,
213
215
  mutableMethods
214
216
  };
215
217
 
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-19 9:4:44
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.6
4
+ * @version 0.0.7
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"],mutateArray=({target:e,method:t,args:r=[],onBeforeMutate:o=()=>{},onAfterMutate:a=()=>{},allowList:s,props:n={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");if(s&&!s?.length||(s=mutableMethods),!s?.includes(t))throw new Error(`Method "${t}" is not in the allowList or is not a mutation method.`);const i={},l=e.length;switch(t){case"push":case"unshift":i.addedItems=[...r];break;case"pop":i.poppedValue=e[l-1];break;case"shift":i.shiftedValue=e[0];break;case"splice":const[t,o]=r,a=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===o?l-a:o;i.deletedItems=e.slice(a,a+s);break;case"sort":case"reverse":i.oldSnapshot=[...e];break;case"fill":case"copyWithin":const n=r[1]||0,p=void 0===r[2]?l:r[2];i.oldItems=e.slice(n,p),i.start=n,i.end=p}o?.(i);const p=Array.prototype[t].apply(e,r),c={value:p,key:t,args:r,context:i,target:e,timestamp:Date.now(),...n};return a?.(c),p},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},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,mutateArray:mutateArray,mutableMethods:mutableMethods};module.exports=utils;
15
+ "use strict";const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=e=>{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:s={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");o&&!o?.length||(o=mutableMethods);const a={};for(let n of o)a[n]=function(...o){const a={},p=e.length;switch(n){case"push":case"unshift":a.addedItems=[...o];break;case"pop":a.poppedValue=e[p-1];break;case"shift":a.shiftedValue=e[0];break;case"splice":const[t,r]=o,s=t<0?Math.max(p+t,0):Math.min(t,p),n=void 0===r?p-s:r;a.deletedItems=e.slice(s,s+n);break;case"sort":case"reverse":a.oldSnapshot=[...e];break;case"fill":case"copyWithin":const l=o[1]||0,i=void 0===o[2]?p:o[2];a.oldItems=e.slice(l,i),a.start=l,a.end=i}t?.(a);const l=Array.prototype[n].apply(e,o),i={value:l,key:n,args:o,context:a,target:e,...s};return r?.(i),l};return a},requireTypes=(e,t,r)=>{let o=Array.isArray(t)?t:[t],s=getDataType(e),a=s.toLowerCase(),n=o.map(e=>e.toLowerCase()),p=a.includes("html")?"element":a;if(r)try{if(!n.includes(p))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${p}`)}catch(e){r(e,s)}else if(!n.includes(p))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${p}`);return s},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,mutableMethods:mutableMethods};module.exports=utils;
package/dist/utils.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-19 9:4:44
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.6
5
+ * @version 0.0.7
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}
@@ -105,7 +105,7 @@ const mutableMethods = [
105
105
  'sort', 'reverse', 'copyWithin', 'fill'
106
106
  ];
107
107
 
108
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
108
+ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
109
109
  // Validation: Ensure target is an array and method is allowed
110
110
  if (!Array.isArray(target)) {
111
111
  throw new TypeError("The 'target' parameter must be an array.");
@@ -114,62 +114,64 @@ const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, on
114
114
  if (!allowList || allowList?.length) {
115
115
  allowList = mutableMethods;
116
116
  }
117
- if (!allowList?.includes(method)) {
118
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
119
- }
120
- const context = {}, len = target.length;
121
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
122
- switch (method) {
123
- // 'push' and 'unshift' are add operations, in undo/redo,
124
- // we can determine the original data structure from result.length and args.length
125
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
126
- case 'push':
127
- case 'unshift':
128
- context.addedItems = [...args];
129
- break;
130
- case 'pop':
131
- context.poppedValue = target[len - 1];
132
- break;
133
- case 'shift':
134
- context.shiftedValue = target[0];
135
- break;
136
- case 'splice':
137
- const [s, d] = args,
138
- // Calculate actual start index (handling negative values)
139
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
140
- // Handle deleteCount defaults
141
- deleteCount = d === undefined ? len - start : d;
142
- context.deletedItems = target.slice(start, start + deleteCount);
143
- break;
144
- case 'sort':
145
- case 'reverse':
146
- // These methods reorder the whole array; requires a full shallow copy
147
- context.oldSnapshot = [...target];
148
- break;
149
- case 'fill':
150
- case 'copyWithin':
151
- const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
152
- // Overwritten values
153
- context.oldItems = target.slice(startIdx, endIdx);
154
- context.start = startIdx;
155
- context.end = endIdx;
156
- break;
157
- }
158
- // Execute the "onBeforeMutate" callback before mutation
159
- onBeforeMutate?.(context);
160
- // Execute the native array mutation
161
- const value = Array.prototype[method].apply(target, args), patch = {
162
- value,
163
- key: method,
164
- args,
165
- context,
166
- target,
167
- timestamp: Date.now(),
168
- ...props
169
- };
170
- // Construct and trigger the patch callback
171
- onAfterMutate?.(patch);
172
- return value;
117
+ const methods = {};
118
+ for (let method of allowList) {
119
+ methods[method] = function (...args) {
120
+ const context = {}, len = target.length;
121
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
122
+ switch (method) {
123
+ // 'push' and 'unshift' are add operations, in undo/redo,
124
+ // we can determine the original data structure from result.length and args.length
125
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
126
+ case 'push':
127
+ case 'unshift':
128
+ context.addedItems = [...args];
129
+ break;
130
+ case 'pop':
131
+ context.poppedValue = target[len - 1];
132
+ break;
133
+ case 'shift':
134
+ context.shiftedValue = target[0];
135
+ break;
136
+ case 'splice':
137
+ const [s, d] = args,
138
+ // Calculate actual start index (handling negative values)
139
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
140
+ // Handle deleteCount defaults
141
+ deleteCount = d === undefined ? len - start : d;
142
+ context.deletedItems = target.slice(start, start + deleteCount);
143
+ break;
144
+ case 'sort':
145
+ case 'reverse':
146
+ // These methods reorder the whole array; requires a full shallow copy
147
+ context.oldSnapshot = [...target];
148
+ break;
149
+ case 'fill':
150
+ case 'copyWithin':
151
+ const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
152
+ // Overwritten values
153
+ context.oldItems = target.slice(startIdx, endIdx);
154
+ context.start = startIdx;
155
+ context.end = endIdx;
156
+ break;
157
+ }
158
+ // Execute the "onBeforeMutate" callback before mutation
159
+ onBeforeMutate?.(context);
160
+ // Execute the native array mutation
161
+ const value = Array.prototype[method].apply(target, args), patch = {
162
+ value,
163
+ key: method,
164
+ args,
165
+ context,
166
+ target,
167
+ ...props
168
+ };
169
+ // Construct and trigger the patch callback
170
+ onAfterMutate?.(patch);
171
+ return value;
172
+ };
173
+ }
174
+ return methods;
173
175
  };
174
176
 
175
177
  const requireTypes = (data, require, cb) => {
@@ -207,7 +209,7 @@ const utils = {
207
209
  //parseStr,
208
210
  deepClone,
209
211
  deepCloneToJSON,
210
- mutateArray,
212
+ wrapArrayMethods,
211
213
  mutableMethods
212
214
  };
213
215
 
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-19 9:4:44
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.6
4
+ * @version 0.0.7
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=>{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"],mutateArray=({target:e,method:t,args:r=[],onBeforeMutate:o=()=>{},onAfterMutate:a=()=>{},allowList:s,props:n={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");if(s&&!s?.length||(s=mutableMethods),!s?.includes(t))throw new Error(`Method "${t}" is not in the allowList or is not a mutation method.`);const i={},l=e.length;switch(t){case"push":case"unshift":i.addedItems=[...r];break;case"pop":i.poppedValue=e[l-1];break;case"shift":i.shiftedValue=e[0];break;case"splice":const[t,o]=r,a=t<0?Math.max(l+t,0):Math.min(t,l),s=void 0===o?l-a:o;i.deletedItems=e.slice(a,a+s);break;case"sort":case"reverse":i.oldSnapshot=[...e];break;case"fill":case"copyWithin":const n=r[1]||0,p=void 0===r[2]?l:r[2];i.oldItems=e.slice(n,p),i.start=n,i.end=p}o?.(i);const p=Array.prototype[t].apply(e,r),c={value:p,key:t,args:r,context:i,target:e,timestamp:Date.now(),...n};return a?.(c),p},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},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,mutateArray:mutateArray,mutableMethods:mutableMethods};export{utils as default};
15
+ const getDataType=e=>{let t,r=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===r&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===r&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":r,t},deepClone=e=>{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={},p=e.length;switch(n){case"push":case"unshift":s.addedItems=[...o];break;case"pop":s.poppedValue=e[p-1];break;case"shift":s.shiftedValue=e[0];break;case"splice":const[t,r]=o,a=t<0?Math.max(p+t,0):Math.min(t,p),n=void 0===r?p-a:r;s.deletedItems=e.slice(a,a+n);break;case"sort":case"reverse":s.oldSnapshot=[...e];break;case"fill":case"copyWithin":const l=o[1]||0,i=void 0===o[2]?p:o[2];s.oldItems=e.slice(l,i),s.start=l,s.end=i}t?.(s);const l=Array.prototype[n].apply(e,o),i={value:l,key:n,args:o,context:s,target:e,...a};return r?.(i),l};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()),p=s.includes("html")?"element":s;if(r)try{if(!n.includes(p))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${p}`)}catch(e){r(e,a)}else if(!n.includes(p))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${p}`);return a},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,mutableMethods:mutableMethods};export{utils as default};
package/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-19 9:4:44
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.6
5
+ * @version 0.0.7
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}
@@ -111,7 +111,7 @@
111
111
  'sort', 'reverse', 'copyWithin', 'fill'
112
112
  ];
113
113
 
114
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
114
+ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
115
115
  // Validation: Ensure target is an array and method is allowed
116
116
  if (!Array.isArray(target)) {
117
117
  throw new TypeError("The 'target' parameter must be an array.");
@@ -120,62 +120,64 @@
120
120
  if (!allowList || allowList?.length) {
121
121
  allowList = mutableMethods;
122
122
  }
123
- if (!allowList?.includes(method)) {
124
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
125
- }
126
- const context = {}, len = target.length;
127
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
128
- switch (method) {
129
- // 'push' and 'unshift' are add operations, in undo/redo,
130
- // we can determine the original data structure from result.length and args.length
131
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
132
- case 'push':
133
- case 'unshift':
134
- context.addedItems = [...args];
135
- break;
136
- case 'pop':
137
- context.poppedValue = target[len - 1];
138
- break;
139
- case 'shift':
140
- context.shiftedValue = target[0];
141
- break;
142
- case 'splice':
143
- const [s, d] = args,
144
- // Calculate actual start index (handling negative values)
145
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
146
- // Handle deleteCount defaults
147
- deleteCount = d === undefined ? len - start : d;
148
- context.deletedItems = target.slice(start, start + deleteCount);
149
- break;
150
- case 'sort':
151
- case 'reverse':
152
- // These methods reorder the whole array; requires a full shallow copy
153
- context.oldSnapshot = [...target];
154
- break;
155
- case 'fill':
156
- case 'copyWithin':
157
- const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
158
- // Overwritten values
159
- context.oldItems = target.slice(startIdx, endIdx);
160
- context.start = startIdx;
161
- context.end = endIdx;
162
- break;
163
- }
164
- // Execute the "onBeforeMutate" callback before mutation
165
- onBeforeMutate?.(context);
166
- // Execute the native array mutation
167
- const value = Array.prototype[method].apply(target, args), patch = {
168
- value,
169
- key: method,
170
- args,
171
- context,
172
- target,
173
- timestamp: Date.now(),
174
- ...props
175
- };
176
- // Construct and trigger the patch callback
177
- onAfterMutate?.(patch);
178
- return value;
123
+ const methods = {};
124
+ for (let method of allowList) {
125
+ methods[method] = function (...args) {
126
+ const context = {}, len = target.length;
127
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
128
+ switch (method) {
129
+ // 'push' and 'unshift' are add operations, in undo/redo,
130
+ // we can determine the original data structure from result.length and args.length
131
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
132
+ case 'push':
133
+ case 'unshift':
134
+ context.addedItems = [...args];
135
+ break;
136
+ case 'pop':
137
+ context.poppedValue = target[len - 1];
138
+ break;
139
+ case 'shift':
140
+ context.shiftedValue = target[0];
141
+ break;
142
+ case 'splice':
143
+ const [s, d] = args,
144
+ // Calculate actual start index (handling negative values)
145
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
146
+ // Handle deleteCount defaults
147
+ deleteCount = d === undefined ? len - start : d;
148
+ context.deletedItems = target.slice(start, start + deleteCount);
149
+ break;
150
+ case 'sort':
151
+ case 'reverse':
152
+ // These methods reorder the whole array; requires a full shallow copy
153
+ context.oldSnapshot = [...target];
154
+ break;
155
+ case 'fill':
156
+ case 'copyWithin':
157
+ const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
158
+ // Overwritten values
159
+ context.oldItems = target.slice(startIdx, endIdx);
160
+ context.start = startIdx;
161
+ context.end = endIdx;
162
+ break;
163
+ }
164
+ // Execute the "onBeforeMutate" callback before mutation
165
+ onBeforeMutate?.(context);
166
+ // Execute the native array mutation
167
+ const value = Array.prototype[method].apply(target, args), patch = {
168
+ value,
169
+ key: method,
170
+ args,
171
+ context,
172
+ target,
173
+ ...props
174
+ };
175
+ // Construct and trigger the patch callback
176
+ onAfterMutate?.(patch);
177
+ return value;
178
+ };
179
+ }
180
+ return methods;
179
181
  };
180
182
 
181
183
  const requireTypes = (data, require, cb) => {
@@ -213,7 +215,7 @@
213
215
  //parseStr,
214
216
  deepClone,
215
217
  deepCloneToJSON,
216
- mutateArray,
218
+ wrapArrayMethods,
217
219
  mutableMethods
218
220
  };
219
221
 
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-19 9:4:44
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.6
4
+ * @version 0.0.7
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=>{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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"];return{getDataType:getDataType,requireTypes:(e,t,r)=>{let o=Array.isArray(t)?t:[t],s=getDataType(e),n=s.toLowerCase(),a=o.map(e=>e.toLowerCase()),i=n.includes("html")?"element":n;if(r)try{if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`)}catch(e){r(e,s)}else if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`);return s},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,mutateArray:({target:t,method:r,args:o=[],onBeforeMutate:s=()=>{},onAfterMutate:n=()=>{},allowList:a,props:i={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");if(a&&!a?.length||(a=e),!a?.includes(r))throw new Error(`Method "${r}" is not in the allowList or is not a mutation method.`);const c={},l=t.length;switch(r){case"push":case"unshift":c.addedItems=[...o];break;case"pop":c.poppedValue=t[l-1];break;case"shift":c.shiftedValue=t[0];break;case"splice":const[e,r]=o,s=e<0?Math.max(l+e,0):Math.min(e,l),n=void 0===r?l-s:r;c.deletedItems=t.slice(s,s+n);break;case"sort":case"reverse":c.oldSnapshot=[...t];break;case"fill":case"copyWithin":const a=o[1]||0,i=void 0===o[2]?l:o[2];c.oldItems=t.slice(a,i),c.start=a,c.end=i}s?.(c);const p=Array.prototype[r].apply(t,o),u={value:p,key:r,args:o,context:c,target:t,timestamp:Date.now(),...i};return n?.(u),p},mutableMethods:e}});
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=>{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},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"];return{getDataType:getDataType,requireTypes:(e,t,r)=>{let o=Array.isArray(t)?t:[t],s=getDataType(e),n=s.toLowerCase(),a=o.map(e=>e.toLowerCase()),i=n.includes("html")?"element":n;if(r)try{if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`)}catch(e){r(e,s)}else if(!a.includes(i))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${i}`);return s},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:s,props:n={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");s&&!s?.length||(s=e);const a={};for(let e of s)a[e]=function(...s){const a={},i=t.length;switch(e){case"push":case"unshift":a.addedItems=[...s];break;case"pop":a.poppedValue=t[i-1];break;case"shift":a.shiftedValue=t[0];break;case"splice":const[e,r]=s,o=e<0?Math.max(i+e,0):Math.min(e,i),n=void 0===r?i-o:r;a.deletedItems=t.slice(o,o+n);break;case"sort":case"reverse":a.oldSnapshot=[...t];break;case"fill":case"copyWithin":const c=s[1]||0,l=void 0===s[2]?i:s[2];a.oldItems=t.slice(c,l),a.start=c,a.end=l}r?.(a);const c=Array.prototype[e].apply(t,s),l={value:c,key:e,args:s,context:a,target:t,...n};return o?.(l),c};return a},mutableMethods:e}});
package/dist.zip CHANGED
Binary file
package/modules.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Last modified: 2025/12/19 10:03:23
3
+ */
4
+ 'use strict';
5
+ import deepClone from './src/deepClone';
6
+ import deepCloneToJSON from './src/deepCloneToJSON';
7
+ import getDataType from './src/getDataType';
8
+ import wrapArrayMethods from './src/wrapArrayMethods';
9
+ import mutableMethods from './src/mutableMethods';
10
+ import requireTypes from './src/requireTypes';
11
+ const utils = {
12
+ //executeStr,
13
+ getDataType,
14
+ requireTypes,
15
+ //renderTpl,
16
+ //parseStr,
17
+ deepClone,
18
+ deepCloneToJSON,
19
+ wrapArrayMethods,
20
+ mutableMethods
21
+ };
22
+ export default utils;
package/modules.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Last modified: 2025/12/19 10:03:23
3
+ */
4
+ 'use strict'
5
+ import deepClone from './src/deepClone';
6
+ import deepCloneToJSON from './src/deepCloneToJSON';
7
+ import executeStr from './src/executeStr';
8
+ import getDataType from './src/getDataType';
9
+ import wrapArrayMethods from './src/wrapArrayMethods';
10
+ import mutableMethods from './src/mutableMethods';
11
+ import parseStr from './src/parseStr';
12
+ import renderTpl from './src/renderTpl';
13
+ import requireTypes from './src/requireTypes';
14
+
15
+
16
+
17
+ const utils = {
18
+ //executeStr,
19
+ getDataType,
20
+ requireTypes,
21
+ //renderTpl,
22
+ //parseStr,
23
+ deepClone,
24
+ deepCloneToJSON,
25
+ wrapArrayMethods,
26
+ mutableMethods
27
+ };
28
+
29
+ export default utils;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
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.",
7
7
  "main": "./modules.js",
8
8
  "type": "module",
9
- "types": "./types/utils.d.ts",
9
+ "types": "./modules.ts",
10
10
  "directories": {
11
11
  "doc": "docs"
12
12
  },
@@ -18,6 +18,8 @@
18
18
  "dist",
19
19
  "src",
20
20
  "dist.zip",
21
+ "modules.ts",
22
+ "modules.js",
21
23
  "package.json",
22
24
  "rollup.config.js",
23
25
  "tsconfig.json",
@@ -70,4 +72,4 @@
70
72
  "dependencies": {
71
73
  "simple-git": "^3.27.0"
72
74
  }
73
- }
75
+ }
@@ -1,13 +1,13 @@
1
1
  /**
2
- * @since Last modified: 2025/12/19 08:59:38
2
+ * @since Last modified: 2025/12/19 10:06:07
3
3
  * A list of supported array mutation methods.
4
4
  * These methods are commonly used to modify the contents of an array.
5
5
  * These methods can be tracked and handled in various use cases, such as undo/redo functionality,
6
6
  * or when applying certain transformations to arrays.
7
7
  *
8
8
  */
9
- export type mutableMethods = ('push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'sort' | 'reverse' | 'copyWithin' | 'fill')[];
10
- const mutableMethods: mutableMethods = [
9
+ export type ArrayMutationNames = ('push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'sort' | 'reverse' | 'copyWithin' | 'fill')[];
10
+ const mutableMethods: ArrayMutationNames = [
11
11
  'push', 'pop', 'shift', 'unshift', 'splice',
12
12
  'sort', 'reverse', 'copyWithin', 'fill'
13
13
  ];
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @since Last modified: 2025/12/19 10:14:03
3
+ * Mutates an array by applying one of the allowed mutation methods such as push, pop, shift, unshift, splice, etc.
4
+ * Supports tracking of added, removed, and updated items for undo/redo or tracking purposes.
5
+ * The mutation methods that can be tracked include push, pop, shift, unshift, splice, sort, reverse, fill, and copyWithin.
6
+ *
7
+ * @template T - Array element type
8
+ * @param {MutationOptions<T>} options - Configuration object containing the target array and callbacks.
9
+ * @returns {ArrayMutationMethods<T>} - An object containing all mutable array methods bound to the target.
10
+ *
11
+ * @example
12
+ * // 获取方法对象后调用
13
+ * const arr = [1, 2, 3];
14
+ * const methods = mutateArray({
15
+ * target: arr,
16
+ * onAfterMutate: (patch) => { console.log(patch); }
17
+ * });
18
+ * methods.push(4); // arr is now [1, 2, 3, 4]
19
+ */
20
+ 'use strict';
21
+ import mutableMethods from "./mutableMethods";
22
+ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
23
+ // Validation: Ensure target is an array and method is allowed
24
+ if (!Array.isArray(target)) {
25
+ throw new TypeError("The 'target' parameter must be an array.");
26
+ }
27
+ //使用默认
28
+ if (!allowList || allowList?.length) {
29
+ allowList = mutableMethods;
30
+ }
31
+ const methods = {};
32
+ for (let method of allowList) {
33
+ methods[method] = function (...args) {
34
+ const context = {}, len = target.length;
35
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
36
+ switch (method) {
37
+ // 'push' and 'unshift' are add operations, in undo/redo,
38
+ // we can determine the original data structure from result.length and args.length
39
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
40
+ case 'push':
41
+ case 'unshift':
42
+ context.addedItems = [...args];
43
+ break;
44
+ case 'pop':
45
+ context.poppedValue = target[len - 1];
46
+ break;
47
+ case 'shift':
48
+ context.shiftedValue = target[0];
49
+ break;
50
+ case 'splice':
51
+ const [s, d] = args,
52
+ // Calculate actual start index (handling negative values)
53
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
54
+ // Handle deleteCount defaults
55
+ deleteCount = d === undefined ? len - start : d;
56
+ context.deletedItems = target.slice(start, start + deleteCount);
57
+ break;
58
+ case 'sort':
59
+ case 'reverse':
60
+ // These methods reorder the whole array; requires a full shallow copy
61
+ context.oldSnapshot = [...target];
62
+ break;
63
+ case 'fill':
64
+ case 'copyWithin':
65
+ const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
66
+ // Overwritten values
67
+ context.oldItems = target.slice(startIdx, endIdx);
68
+ context.start = startIdx;
69
+ context.end = endIdx;
70
+ break;
71
+ }
72
+ // Execute the "onBeforeMutate" callback before mutation
73
+ onBeforeMutate?.(context);
74
+ // Execute the native array mutation
75
+ const value = Array.prototype[method].apply(target, args), patch = {
76
+ value,
77
+ key: method,
78
+ args,
79
+ context,
80
+ target,
81
+ ...props
82
+ };
83
+ // Construct and trigger the patch callback
84
+ onAfterMutate?.(patch);
85
+ return value;
86
+ };
87
+ }
88
+ return methods;
89
+ };
90
+ export default wrapArrayMethods;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @since Last modified: 2025/12/19 10:14:03
3
+ * Mutates an array by applying one of the allowed mutation methods such as push, pop, shift, unshift, splice, etc.
4
+ * Supports tracking of added, removed, and updated items for undo/redo or tracking purposes.
5
+ * The mutation methods that can be tracked include push, pop, shift, unshift, splice, sort, reverse, fill, and copyWithin.
6
+ *
7
+ * @template T - Array element type
8
+ * @param {MutationOptions<T>} options - Configuration object containing the target array and callbacks.
9
+ * @returns {ArrayMutationMethods<T>} - An object containing all mutable array methods bound to the target.
10
+ *
11
+ * @example
12
+ * // 获取方法对象后调用
13
+ * const arr = [1, 2, 3];
14
+ * const methods = mutateArray({
15
+ * target: arr,
16
+ * onAfterMutate: (patch) => { console.log(patch); }
17
+ * });
18
+ * methods.push(4); // arr is now [1, 2, 3, 4]
19
+ */
20
+ 'use strict';
21
+
22
+ import mutableMethods, { ArrayMutationNames } from "./mutableMethods";
23
+
24
+
25
+ /**
26
+ * Defines the structure of the captured state before mutation.
27
+ */
28
+ export interface MutationContextt {
29
+ addedItems?: any[]; // Items added to the array
30
+ poppedValue?: any; // Value popped from the array
31
+ shiftedValue?: any; // Value shifted from the array
32
+ deletedItems?: any[]; // Items removed from the array
33
+ oldSnapshot?: any[]; // Snapshot of the array before methods like 'sort' or 'reverse'
34
+ oldItems?: any[]; // Items overwritten (for methods like 'fill' or 'copyWithin')
35
+ start?: number; // Starting index for mutations like 'fill' or 'splice'
36
+ end?: number; // Ending index for mutations like 'fill' or 'splice'
37
+ }
38
+
39
+ /**
40
+ * The data object passed to the callback after mutation.
41
+ */
42
+ export interface MutationPatch<T = any> {
43
+ key: string; // The mutation method (e.g., 'push', 'pop', 'splice', etc.)
44
+ value: any; // The result of the mutation (the modified array)
45
+ args: any[]; // Arguments passed to the mutation method
46
+ context: MutationContextt; // The state before mutation
47
+ target: T[]; // Reference to the mutated array
48
+ [key: string]: any; // Additional properties from props
49
+ }
50
+ /**
51
+ * The return type of wrapArrayMethods - an object containing all mutable array methods
52
+ */
53
+ export interface ArrayMutationMethods<T = any> {
54
+ push: (...args: any[]) => number;
55
+ pop: () => T | undefined;
56
+ shift: () => T | undefined;
57
+ unshift: (...args: T[]) => number;
58
+ splice: (start: number, deleteCount?: number, ...items: T[]) => T[];
59
+ sort: (compareFn?: (a: T, b: T) => number) => T[];
60
+ reverse: () => T[];
61
+ fill: (value: T, start?: number, end?: number) => T[];
62
+ copyWithin: (target: number, start: number, end?: number) => T[];
63
+ }
64
+ /**
65
+ * Configuration options for the wrapArrayMethods function.
66
+ */
67
+ export interface MutationOptions<T = any> {
68
+ target: T[]; // The array to mutate
69
+ onBeforeMutate?: (context: MutationContextt) => void; // Callback triggered before the mutation
70
+ onAfterMutate?: (patch: MutationPatch) => void; // Callback triggered after the mutation
71
+ allowList?: ArrayMutationNames; // Optional list of allowed mutation methods
72
+ props?: Record<string, any>; // Additional properties to attach to the patch
73
+ }
74
+
75
+
76
+ const wrapArrayMethods = <T = any>({
77
+ target,
78
+ onBeforeMutate = () => { },
79
+ onAfterMutate = () => { },
80
+ allowList,
81
+ props = {},
82
+ }: MutationOptions<T>): ArrayMutationMethods<T> => {
83
+
84
+ // Validation: Ensure target is an array and method is allowed
85
+ if (!Array.isArray(target)) {
86
+ throw new TypeError("The 'target' parameter must be an array.");
87
+ }
88
+ //使用默认
89
+ if (!allowList || allowList?.length) {
90
+ allowList = mutableMethods;
91
+ }
92
+
93
+ const methods: Partial<ArrayMutationMethods<T>> = {};
94
+
95
+ for (let method of allowList) {
96
+
97
+ methods[method as keyof ArrayMutationMethods<T>] = function (...args: any) {
98
+
99
+ const context: MutationContextt = {},
100
+ len = target.length;
101
+
102
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
103
+ switch (method) {
104
+ // 'push' and 'unshift' are add operations, in undo/redo,
105
+ // we can determine the original data structure from result.length and args.length
106
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
107
+ case 'push':
108
+ case 'unshift':
109
+ context.addedItems = [...args];
110
+ break;
111
+ case 'pop':
112
+ context.poppedValue = target[len - 1];
113
+ break;
114
+ case 'shift':
115
+ context.shiftedValue = target[0];
116
+ break;
117
+ case 'splice':
118
+ const [s, d] = args,
119
+ // Calculate actual start index (handling negative values)
120
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
121
+ // Handle deleteCount defaults
122
+ deleteCount = d === undefined ? len - start : d;
123
+ context.deletedItems = target.slice(start, start + deleteCount);
124
+ break;
125
+ case 'sort':
126
+ case 'reverse':
127
+ // These methods reorder the whole array; requires a full shallow copy
128
+ context.oldSnapshot = [...target];
129
+ break;
130
+ case 'fill':
131
+ case 'copyWithin':
132
+ const startIdx = args[1] || 0,
133
+ endIdx = args[2] === undefined ? len : args[2];
134
+ // Overwritten values
135
+ context.oldItems = target.slice(startIdx, endIdx);
136
+ context.start = startIdx;
137
+ context.end = endIdx;
138
+ break;
139
+ }
140
+
141
+ // Execute the "onBeforeMutate" callback before mutation
142
+ onBeforeMutate?.(context);
143
+
144
+ // Execute the native array mutation
145
+ const value = (Array.prototype as any)[method].apply(target, args),
146
+ patch: MutationPatch<T> = {
147
+ value,
148
+ key: method,
149
+ args,
150
+ context,
151
+ target,
152
+ ...props
153
+ };
154
+
155
+ // Construct and trigger the patch callback
156
+ onAfterMutate?.(patch);
157
+ return value;
158
+ }
159
+ }
160
+
161
+ return methods as ArrayMutationMethods<T>;
162
+ }
163
+
164
+ export default wrapArrayMethods;
@@ -1,100 +0,0 @@
1
- /**
2
- * @since Last modified: 2025/12/19 09:00:04
3
- * Mutates an array by applying one of the allowed mutation methods such as push, pop, shift, unshift, splice, etc.
4
- * Supports tracking of added, removed, and updated items for undo/redo or tracking purposes.
5
- * The mutation methods that can be tracked include push, pop, shift, unshift, splice, sort, reverse, fill, and copyWithin.
6
- *
7
- * @template T
8
- * @param {MutationOptions} options - Configuration object containing the target array, method to apply, arguments for the method, and an optional patch callback.
9
- * @returns {any} - The result of the array mutation.
10
- *
11
- * @example
12
- * const arr = [1, 2, 3];
13
- * mutateArray({
14
- * target: arr,
15
- * method: 'push',
16
- * args: [4],
17
- * onPatch: (patch) => { console.log(patch); }
18
- * });
19
- * // arr is now [1, 2, 3, 4]
20
- *
21
- * @example
22
- * const arr = [1, 2, 3];
23
- * mutateArray({
24
- * target: arr,
25
- * method: 'splice',
26
- * args: [1, 1, 4],
27
- * onPatch: (patch) => { console.log(patch); }
28
- * });
29
- * // arr is now [1, 4, 3]
30
- * // The patch callback logs the mutation details including deleted items and added items.
31
- */
32
- 'use strict';
33
- import mutableMethods from "./mutableMethods";
34
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList, props = {}, }) => {
35
- // Validation: Ensure target is an array and method is allowed
36
- if (!Array.isArray(target)) {
37
- throw new TypeError("The 'target' parameter must be an array.");
38
- }
39
- //使用默认
40
- if (!allowList || allowList?.length) {
41
- allowList = mutableMethods;
42
- }
43
- if (!allowList?.includes(method)) {
44
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
45
- }
46
- const context = {}, len = target.length;
47
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
48
- switch (method) {
49
- // 'push' and 'unshift' are add operations, in undo/redo,
50
- // we can determine the original data structure from result.length and args.length
51
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
52
- case 'push':
53
- case 'unshift':
54
- context.addedItems = [...args];
55
- break;
56
- case 'pop':
57
- context.poppedValue = target[len - 1];
58
- break;
59
- case 'shift':
60
- context.shiftedValue = target[0];
61
- break;
62
- case 'splice':
63
- const [s, d] = args,
64
- // Calculate actual start index (handling negative values)
65
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
66
- // Handle deleteCount defaults
67
- deleteCount = d === undefined ? len - start : d;
68
- context.deletedItems = target.slice(start, start + deleteCount);
69
- break;
70
- case 'sort':
71
- case 'reverse':
72
- // These methods reorder the whole array; requires a full shallow copy
73
- context.oldSnapshot = [...target];
74
- break;
75
- case 'fill':
76
- case 'copyWithin':
77
- const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
78
- // Overwritten values
79
- context.oldItems = target.slice(startIdx, endIdx);
80
- context.start = startIdx;
81
- context.end = endIdx;
82
- break;
83
- }
84
- // Execute the "onBeforeMutate" callback before mutation
85
- onBeforeMutate?.(context);
86
- // Execute the native array mutation
87
- const value = Array.prototype[method].apply(target, args), patch = {
88
- value,
89
- key: method,
90
- args,
91
- context,
92
- target,
93
- timestamp: Date.now(),
94
- ...props
95
- };
96
- // Construct and trigger the patch callback
97
- onAfterMutate?.(patch);
98
- return value;
99
- };
100
- export default mutateArray;
@@ -1,162 +0,0 @@
1
- /**
2
- * @since Last modified: 2025/12/19 09:00:04
3
- * Mutates an array by applying one of the allowed mutation methods such as push, pop, shift, unshift, splice, etc.
4
- * Supports tracking of added, removed, and updated items for undo/redo or tracking purposes.
5
- * The mutation methods that can be tracked include push, pop, shift, unshift, splice, sort, reverse, fill, and copyWithin.
6
- *
7
- * @template T
8
- * @param {MutationOptions} options - Configuration object containing the target array, method to apply, arguments for the method, and an optional patch callback.
9
- * @returns {any} - The result of the array mutation.
10
- *
11
- * @example
12
- * const arr = [1, 2, 3];
13
- * mutateArray({
14
- * target: arr,
15
- * method: 'push',
16
- * args: [4],
17
- * onPatch: (patch) => { console.log(patch); }
18
- * });
19
- * // arr is now [1, 2, 3, 4]
20
- *
21
- * @example
22
- * const arr = [1, 2, 3];
23
- * mutateArray({
24
- * target: arr,
25
- * method: 'splice',
26
- * args: [1, 1, 4],
27
- * onPatch: (patch) => { console.log(patch); }
28
- * });
29
- * // arr is now [1, 4, 3]
30
- * // The patch callback logs the mutation details including deleted items and added items.
31
- */
32
- 'use strict';
33
-
34
- import mutableMethods from "./mutableMethods";
35
-
36
-
37
- /**
38
- * Defines the structure of the captured state before mutation.
39
- */
40
- export interface MutationContextt {
41
- addedItems?: any[]; // Items added to the array
42
- poppedValue?: any; // Value popped from the array
43
- shiftedValue?: any; // Value shifted from the array
44
- deletedItems?: any[]; // Items removed from the array
45
- oldSnapshot?: any[]; // Snapshot of the array before methods like 'sort' or 'reverse'
46
- oldItems?: any[]; // Items overwritten (for methods like 'fill' or 'copyWithin')
47
- start?: number; // Starting index for mutations like 'fill' or 'splice'
48
- end?: number; // Ending index for mutations like 'fill' or 'splice'
49
- }
50
-
51
- /**
52
- * The data object passed to the callback after mutation.
53
- */
54
- export interface MutationPatch<T = any> {
55
- key: string; // The mutation method (e.g., 'push', 'pop', 'splice', etc.)
56
- value: any; // The result of the mutation (the modified array)
57
- args: any[]; // Arguments passed to the mutation method
58
- context: MutationContextt; // The state before mutation
59
- target: T[]; // Reference to the mutated array
60
- timestamp: number; // The timestamp of the mutation
61
- [key: string]: any; // Additional properties from props
62
- }
63
-
64
- /**
65
- * Configuration options for the mutateArray function.
66
- */
67
- export interface MutationOptions {
68
- target: any[]; // The array to mutate
69
- method: string; // The mutation method to apply (e.g., 'push', 'splice', etc.)
70
- args?: any[]; // Optional arguments to pass to the mutation method
71
- onBeforeMutate?: (context: MutationContextt) => void; // Callback triggered before the mutation
72
- onAfterMutate?: (patch: MutationPatch) => void; // Callback triggered after the mutation
73
- allowList?: string[]; // Optional list of allowed mutation methods
74
- props?: Record<string, any>; // Additional properties to attach to the patch
75
- }
76
-
77
- const mutateArray = ({
78
- target,
79
- method,
80
- args = [],
81
- onBeforeMutate = () => { },
82
- onAfterMutate = () => { },
83
- allowList,
84
- props = {},
85
- }: MutationOptions): any => {
86
-
87
- // Validation: Ensure target is an array and method is allowed
88
- if (!Array.isArray(target)) {
89
- throw new TypeError("The 'target' parameter must be an array.");
90
- }
91
- //使用默认
92
- if (!allowList || allowList?.length) {
93
- allowList = mutableMethods;
94
- }
95
- if (!allowList?.includes(method)) {
96
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
97
- }
98
-
99
- const context: MutationContextt = {},
100
- len = target.length;
101
-
102
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
103
- switch (method) {
104
- // 'push' and 'unshift' are add operations, in undo/redo,
105
- // we can determine the original data structure from result.length and args.length
106
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
107
- case 'push':
108
- case 'unshift':
109
- context.addedItems = [...args];
110
- break;
111
- case 'pop':
112
- context.poppedValue = target[len - 1];
113
- break;
114
- case 'shift':
115
- context.shiftedValue = target[0];
116
- break;
117
- case 'splice':
118
- const [s, d] = args,
119
- // Calculate actual start index (handling negative values)
120
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
121
- // Handle deleteCount defaults
122
- deleteCount = d === undefined ? len - start : d;
123
- context.deletedItems = target.slice(start, start + deleteCount);
124
- break;
125
- case 'sort':
126
- case 'reverse':
127
- // These methods reorder the whole array; requires a full shallow copy
128
- context.oldSnapshot = [...target];
129
- break;
130
- case 'fill':
131
- case 'copyWithin':
132
- const startIdx = args[1] || 0,
133
- endIdx = args[2] === undefined ? len : args[2];
134
- // Overwritten values
135
- context.oldItems = target.slice(startIdx, endIdx);
136
- context.start = startIdx;
137
- context.end = endIdx;
138
- break;
139
- }
140
-
141
- // Execute the "onBeforeMutate" callback before mutation
142
- onBeforeMutate?.(context);
143
-
144
- // Execute the native array mutation
145
- const value = (Array.prototype as any)[method].apply(target, args),
146
- patch: MutationPatch = {
147
- value,
148
- key: method,
149
- args,
150
- context,
151
- target,
152
- timestamp: Date.now(),
153
- ...props
154
- };
155
-
156
- // Construct and trigger the patch callback
157
- onAfterMutate?.(patch);
158
-
159
- return value;
160
- }
161
-
162
- export default mutateArray;