@codady/utils 0.0.5 → 0.0.7

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,46 @@
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
+
24
+ ## [v0.0.6] - 2025-12-19
25
+
26
+ ### Distribution Files
27
+ - **JS**: https://unpkg.com/@codady/utils@0.0.6/dist/js/utils.js
28
+ - **Zip**: https://unpkg.com/@codady/utils@0.0.6/dist.zip
29
+
30
+ ### Changes
31
+
32
+ #### Fixed
33
+ - Some problems.
34
+
35
+ #### Added
36
+ - The `mutateMethods` variable has been renamed to `mutableMethods`.`mutateMethods`变量改名为`mutableMethods`。
37
+ - Added `props` parameter to `mutateArray`.mutateArray新增参数props。
38
+ - The `method` parameter in `onAfterMutate` callback of `mutateArray` has been renamed to `key`, and `result` renamed to `value`.mutateArray的onAfterMutate的参数method改名为key,result改名为value。
39
+
40
+
41
+ #### Removed
42
+ - Null
43
+
44
+
5
45
  ## [v0.0.3] - 2025-12-18
6
46
 
7
47
  ### Distribution Files
package/dist/utils.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-18 21:39:9
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.4
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}
@@ -102,74 +102,78 @@ const deepCloneToJSON = (data) => {
102
102
  }
103
103
  };
104
104
 
105
- const mutateMethods = [
105
+ const mutableMethods = [
106
106
  'push', 'pop', 'shift', 'unshift', 'splice',
107
107
  'sort', 'reverse', 'copyWithin', 'fill'
108
108
  ];
109
109
 
110
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList }) => {
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.");
114
114
  }
115
115
  //使用默认
116
116
  if (!allowList || allowList?.length) {
117
- allowList = mutateMethods;
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 && onBeforeMutate(context);
162
- // Execute the native array mutation
163
- const result = Array.prototype[method].apply(target, args);
164
- // Construct and trigger the patch callback
165
- onAfterMutate && onAfterMutate({
166
- method,
167
- args,
168
- context,
169
- result,
170
- timestamp: Date.now()
171
- });
172
- return result;
117
+ allowList = mutableMethods;
118
+ }
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;
173
177
  };
174
178
 
175
179
  const requireTypes = (data, require, cb) => {
@@ -207,8 +211,8 @@ const utils = {
207
211
  //parseStr,
208
212
  deepClone,
209
213
  deepCloneToJSON,
210
- mutateArray,
211
- mutateMethods
214
+ wrapArrayMethods,
215
+ mutableMethods
212
216
  };
213
217
 
214
218
  module.exports = utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-18 21:8:4
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.2
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},requireTypes=(e,t,r)=>{let o=Array.isArray(t)?t:[t],n=getDataType(e),s=n.toLowerCase(),p=o.map(e=>e.toLowerCase()),l=s.includes("html")?"element":s;if(r)try{if(!p.includes(l))throw new TypeError(`Expected data type(s): [${p.join(", ")}], but got: ${l}`)}catch(e){r(e,n)}else if(!p.includes(l))throw new TypeError(`Expected data type(s): [${p.join(", ")}], but got: ${l}`);return n},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON};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-18 21:39:9
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.4
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}
@@ -100,74 +100,78 @@ const deepCloneToJSON = (data) => {
100
100
  }
101
101
  };
102
102
 
103
- const mutateMethods = [
103
+ const mutableMethods = [
104
104
  'push', 'pop', 'shift', 'unshift', 'splice',
105
105
  'sort', 'reverse', 'copyWithin', 'fill'
106
106
  ];
107
107
 
108
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList }) => {
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.");
112
112
  }
113
113
  //使用默认
114
114
  if (!allowList || allowList?.length) {
115
- allowList = mutateMethods;
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 && onBeforeMutate(context);
160
- // Execute the native array mutation
161
- const result = Array.prototype[method].apply(target, args);
162
- // Construct and trigger the patch callback
163
- onAfterMutate && onAfterMutate({
164
- method,
165
- args,
166
- context,
167
- result,
168
- timestamp: Date.now()
169
- });
170
- return result;
115
+ allowList = mutableMethods;
116
+ }
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;
171
175
  };
172
176
 
173
177
  const requireTypes = (data, require, cb) => {
@@ -205,8 +209,8 @@ const utils = {
205
209
  //parseStr,
206
210
  deepClone,
207
211
  deepCloneToJSON,
208
- mutateArray,
209
- mutateMethods
212
+ wrapArrayMethods,
213
+ mutableMethods
210
214
  };
211
215
 
212
216
  export { utils as default };
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-18 21:8:4
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.2
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},requireTypes=(e,t,r)=>{let o=Array.isArray(t)?t:[t],n=getDataType(e),p=n.toLowerCase(),s=o.map(e=>e.toLowerCase()),l=p.includes("html")?"element":p;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,n)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return n},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON};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-18 21:39:9
3
+ * @since Last modified: 2025-12-19 10:14:9
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.4
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}
@@ -106,74 +106,78 @@
106
106
  }
107
107
  };
108
108
 
109
- const mutateMethods = [
109
+ const mutableMethods = [
110
110
  'push', 'pop', 'shift', 'unshift', 'splice',
111
111
  'sort', 'reverse', 'copyWithin', 'fill'
112
112
  ];
113
113
 
114
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList }) => {
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.");
118
118
  }
119
119
  //使用默认
120
120
  if (!allowList || allowList?.length) {
121
- allowList = mutateMethods;
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 && onBeforeMutate(context);
166
- // Execute the native array mutation
167
- const result = Array.prototype[method].apply(target, args);
168
- // Construct and trigger the patch callback
169
- onAfterMutate && onAfterMutate({
170
- method,
171
- args,
172
- context,
173
- result,
174
- timestamp: Date.now()
175
- });
176
- return result;
121
+ allowList = mutableMethods;
122
+ }
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;
177
181
  };
178
182
 
179
183
  const requireTypes = (data, require, cb) => {
@@ -211,8 +215,8 @@
211
215
  //parseStr,
212
216
  deepClone,
213
217
  deepCloneToJSON,
214
- mutateArray,
215
- mutateMethods
218
+ wrapArrayMethods,
219
+ mutableMethods
216
220
  };
217
221
 
218
222
  return utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-18 21:8:4
2
+ * @since Last modified: 2025-12-19 10:14:9
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.2
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};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let o=Array.isArray(t)?t:[t],n=getDataType(e),i=n.toLowerCase(),s=o.map(e=>e.toLowerCase()),c=i.includes("html")?"element":i;if(r)try{if(!s.includes(c))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${c}`)}catch(e){r(e,n)}else if(!s.includes(c))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${c}`);return n},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON}});
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
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.",
@@ -1,5 +1,5 @@
1
- const mutateMethods = [
1
+ const mutableMethods = [
2
2
  'push', 'pop', 'shift', 'unshift', 'splice',
3
3
  'sort', 'reverse', 'copyWithin', 'fill'
4
4
  ];
5
- export default mutateMethods;
5
+ export default mutableMethods;
@@ -1,15 +1,15 @@
1
1
  /**
2
- * @since Last modified: 2025/12/18 21:04:34
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 mutateMethods = ('push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'sort' | 'reverse' | 'copyWithin' | 'fill')[];
10
- const mutateMethods: mutateMethods = [
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
  ];
14
14
 
15
- export default mutateMethods;
15
+ export default mutableMethods;
@@ -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,98 +0,0 @@
1
- /**
2
- * @since Last modified: 2025/12/18 21:20:26
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 {MutateOptions} 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 mutateMethods from "./mutateMethods";
34
- const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList }) => {
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 = mutateMethods;
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 && onBeforeMutate(context);
86
- // Execute the native array mutation
87
- const result = Array.prototype[method].apply(target, args);
88
- // Construct and trigger the patch callback
89
- onAfterMutate && onAfterMutate({
90
- method,
91
- args,
92
- context,
93
- result,
94
- timestamp: Date.now()
95
- });
96
- return result;
97
- };
98
- export default mutateArray;
@@ -1,155 +0,0 @@
1
- /**
2
- * @since Last modified: 2025/12/18 21:20:26
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 {MutateOptions} 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 mutateMethods from "./mutateMethods";
35
-
36
-
37
- /**
38
- * Defines the structure of the captured state before mutation.
39
- */
40
- export interface MutateContext {
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 MutatePatch {
55
- method: string; // The mutation method (e.g., 'push', 'pop', 'splice', etc.)
56
- args: any[]; // Arguments passed to the mutation method
57
- context: MutateContext; // The state before mutation
58
- result: any; // The result of the mutation (the modified array)
59
- timestamp: number; // The timestamp of the mutation
60
- }
61
-
62
- /**
63
- * Configuration options for the mutateArray function.
64
- */
65
- export interface MutateOptions {
66
- target: any[]; // The array to mutate
67
- method: string; // The mutation method to apply (e.g., 'push', 'splice', etc.)
68
- args?: any[]; // Optional arguments to pass to the mutation method
69
- onBeforeMutate?: (context: MutateContext) => void; // Callback triggered before the mutation
70
- onAfterMutate?: (patch: MutatePatch) => void; // Callback triggered after the mutation
71
- allowList?: string[]; // Optional list of allowed mutation methods
72
- }
73
-
74
- const mutateArray = ({
75
- target,
76
- method,
77
- args = [],
78
- onBeforeMutate = () => { },
79
- onAfterMutate = () => { },
80
- allowList
81
- }: MutateOptions): any => {
82
-
83
- // Validation: Ensure target is an array and method is allowed
84
- if (!Array.isArray(target)) {
85
- throw new TypeError("The 'target' parameter must be an array.");
86
- }
87
- //使用默认
88
- if (!allowList || allowList?.length) {
89
- allowList = mutateMethods;
90
- }
91
- if (!allowList?.includes(method)) {
92
- throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
93
- }
94
-
95
- const context: MutateContext = {},
96
- len = target.length;
97
-
98
- // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
99
- switch (method) {
100
- // 'push' and 'unshift' are add operations, in undo/redo,
101
- // we can determine the original data structure from result.length and args.length
102
- // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
103
- case 'push':
104
- case 'unshift':
105
- context.addedItems = [...args];
106
- break;
107
- case 'pop':
108
- context.poppedValue = target[len - 1];
109
- break;
110
- case 'shift':
111
- context.shiftedValue = target[0];
112
- break;
113
- case 'splice':
114
- const [s, d] = args,
115
- // Calculate actual start index (handling negative values)
116
- start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
117
- // Handle deleteCount defaults
118
- deleteCount = d === undefined ? len - start : d;
119
- context.deletedItems = target.slice(start, start + deleteCount);
120
- break;
121
- case 'sort':
122
- case 'reverse':
123
- // These methods reorder the whole array; requires a full shallow copy
124
- context.oldSnapshot = [...target];
125
- break;
126
- case 'fill':
127
- case 'copyWithin':
128
- const startIdx = args[1] || 0,
129
- endIdx = args[2] === undefined ? len : args[2];
130
- // Overwritten values
131
- context.oldItems = target.slice(startIdx, endIdx);
132
- context.start = startIdx;
133
- context.end = endIdx;
134
- break;
135
- }
136
-
137
- // Execute the "onBeforeMutate" callback before mutation
138
- onBeforeMutate && onBeforeMutate(context);
139
-
140
- // Execute the native array mutation
141
- const result = (Array.prototype as any)[method].apply(target, args);
142
-
143
- // Construct and trigger the patch callback
144
- onAfterMutate && onAfterMutate({
145
- method,
146
- args,
147
- context,
148
- result,
149
- timestamp: Date.now()
150
- });
151
-
152
- return result;
153
- }
154
-
155
- export default mutateArray;