@codady/utils 0.0.6 → 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 +19 -0
- package/dist/utils.cjs.js +62 -60
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +62 -60
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd.js +62 -60
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/package.json +1 -1
- package/src/mutableMethods.ts +3 -3
- package/src/wrapArrayMethods.js +90 -0
- package/src/wrapArrayMethods.ts +164 -0
- package/src/mutateArray.js +0 -100
- package/src/mutateArray.ts +0 -162
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
|
|
3
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
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
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
214
|
+
wrapArrayMethods,
|
|
213
215
|
mutableMethods
|
|
214
216
|
};
|
|
215
217
|
|
package/dist/utils.cjs.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-19
|
|
2
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
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"],
|
|
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
|
|
3
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
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
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
212
|
+
wrapArrayMethods,
|
|
211
213
|
mutableMethods
|
|
212
214
|
};
|
|
213
215
|
|
package/dist/utils.esm.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-19
|
|
2
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
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"],
|
|
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
|
|
3
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
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
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
218
|
+
wrapArrayMethods,
|
|
217
219
|
mutableMethods
|
|
218
220
|
};
|
|
219
221
|
|
package/dist/utils.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-19
|
|
2
|
+
* @since Last modified: 2025-12-19 10:14:9
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
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,
|
|
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.
|
|
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.",
|
package/src/mutableMethods.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @since Last modified: 2025/12/19
|
|
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
|
|
10
|
-
const 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;
|
package/src/mutateArray.js
DELETED
|
@@ -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;
|
package/src/mutateArray.ts
DELETED
|
@@ -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;
|