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