@codady/utils 0.0.1 → 0.0.3

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
+ ## [v0.0.3] - 2025-12-18
6
+
7
+ ### Distribution Files
8
+ - **JS**: https://unpkg.com/@codady/utils@0.0.3/dist/js/utils.js
9
+ - **Zip**: https://unpkg.com/@codady/utils@0.0.3/dist.zip
10
+
11
+ ### Changes
12
+
13
+ #### Fixed
14
+ - Some problems.
15
+
16
+ #### Added
17
+ - Added the `mutateMethods` variable and `mutateArray` function.新增了mutateMethods变量和mutateArray函数
18
+ - Added the `deepCloneToJSON` function.新增了deepCloneToJSON函数
19
+
20
+
21
+ #### Removed
22
+ - Null
23
+
24
+
25
+
26
+ ## [v0.0.2] - 2025-12-16
27
+
28
+ ### Distribution Files
29
+ - **JS**: https://unpkg.com/@codady/utils@0.0.2/dist/js/utils.js
30
+ - **Zip**: https://unpkg.com/@codady/utils@0.0.2/dist.zip
31
+
32
+ ### Changes
33
+
34
+ #### Fixed
35
+ - Some problems.
36
+
37
+ #### Added
38
+ - Null
39
+
40
+ #### Removed
41
+ - Null
42
+
43
+
44
+
5
45
  ## [v0.0.1] - 2025-12-15
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-16 9:8:6
3
+ * @since Last modified: 2025-12-18 21:8:4
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.1
5
+ * @version 0.0.2
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}
@@ -74,6 +74,34 @@ const deepClone = (data) => {
74
74
  }
75
75
  };
76
76
 
77
+ const deepCloneToJSON = (data) => {
78
+ const dataType = getDataType(data);
79
+ // Handle objects
80
+ if (dataType === 'Object') {
81
+ const newObj = {};
82
+ // Clone regular properties
83
+ for (const key in data) {
84
+ newObj[key] = deepCloneToJSON(data[key]);
85
+ }
86
+ for (const key in newObj) {
87
+ newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
88
+ }
89
+ return newObj;
90
+ // Handle arrays
91
+ }
92
+ else if (dataType === 'Array') {
93
+ let tmp = data.map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
94
+ return tmp;
95
+ // Handle Date objects
96
+ }
97
+ else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
98
+ return undefined;
99
+ }
100
+ else {
101
+ return data;
102
+ }
103
+ };
104
+
77
105
  const requireTypes = (data, require, cb) => {
78
106
  // Normalize the input types (convert to array if it's a single type)
79
107
  let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
@@ -108,6 +136,7 @@ const utils = {
108
136
  //renderTpl,
109
137
  //parseStr,
110
138
  deepClone,
139
+ deepCloneToJSON
111
140
  };
112
141
 
113
142
  module.exports = utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-11-15 11:0:34
2
+ * @since Last modified: 2025-12-18 21:8:4
3
3
  * @name Utils for web front-end.
4
- * @version 1.0.0
4
+ * @version 0.0.2
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},requireTypes=(e,t,r)=>{let s=getDataType(e).toLowerCase(),o="string"==typeof t?[t]:t;if(s.includes("html")&&(s="element"),o=o.map(e=>e.toLowerCase()),r)try{if(!o.includes(s))throw new Error(`Wrong data type,Require types: "${""+o}"!`)}catch(e){r(e)}else if(!o.includes(s))throw new Error(`Wrong data type,Require types: "${""+o}"!`)};exports.getDataType=getDataType,exports.requireTypes=requireTypes;
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;
package/dist/utils.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-16 9:8:6
3
+ * @since Last modified: 2025-12-18 21:8:4
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.1
5
+ * @version 0.0.2
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}
@@ -72,6 +72,34 @@ const deepClone = (data) => {
72
72
  }
73
73
  };
74
74
 
75
+ const deepCloneToJSON = (data) => {
76
+ const dataType = getDataType(data);
77
+ // Handle objects
78
+ if (dataType === 'Object') {
79
+ const newObj = {};
80
+ // Clone regular properties
81
+ for (const key in data) {
82
+ newObj[key] = deepCloneToJSON(data[key]);
83
+ }
84
+ for (const key in newObj) {
85
+ newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
86
+ }
87
+ return newObj;
88
+ // Handle arrays
89
+ }
90
+ else if (dataType === 'Array') {
91
+ let tmp = data.map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
92
+ return tmp;
93
+ // Handle Date objects
94
+ }
95
+ else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
96
+ return undefined;
97
+ }
98
+ else {
99
+ return data;
100
+ }
101
+ };
102
+
75
103
  const requireTypes = (data, require, cb) => {
76
104
  // Normalize the input types (convert to array if it's a single type)
77
105
  let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
@@ -106,6 +134,7 @@ const utils = {
106
134
  //renderTpl,
107
135
  //parseStr,
108
136
  deepClone,
137
+ deepCloneToJSON
109
138
  };
110
139
 
111
140
  export { utils as default };
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-11-15 11:0:34
2
+ * @since Last modified: 2025-12-18 21:8:4
3
3
  * @name Utils for web front-end.
4
- * @version 1.0.0
4
+ * @version 0.0.2
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},requireTypes=(e,t,r)=>{let o=getDataType(e).toLowerCase(),s="string"==typeof t?[t]:t;if(o.includes("html")&&(o="element"),s=s.map(e=>e.toLowerCase()),r)try{if(!s.includes(o))throw new Error(`Wrong data type,Require types: "${""+s}"!`)}catch(e){r(e)}else if(!s.includes(o))throw new Error(`Wrong data type,Require types: "${""+s}"!`)};export{getDataType,requireTypes};
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};
package/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-16 9:8:6
3
+ * @since Last modified: 2025-12-18 21:8:4
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.1
5
+ * @version 0.0.2
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}
@@ -78,6 +78,34 @@
78
78
  }
79
79
  };
80
80
 
81
+ const deepCloneToJSON = (data) => {
82
+ const dataType = getDataType(data);
83
+ // Handle objects
84
+ if (dataType === 'Object') {
85
+ const newObj = {};
86
+ // Clone regular properties
87
+ for (const key in data) {
88
+ newObj[key] = deepCloneToJSON(data[key]);
89
+ }
90
+ for (const key in newObj) {
91
+ newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
92
+ }
93
+ return newObj;
94
+ // Handle arrays
95
+ }
96
+ else if (dataType === 'Array') {
97
+ let tmp = data.map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
98
+ return tmp;
99
+ // Handle Date objects
100
+ }
101
+ else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
102
+ return undefined;
103
+ }
104
+ else {
105
+ return data;
106
+ }
107
+ };
108
+
81
109
  const requireTypes = (data, require, cb) => {
82
110
  // Normalize the input types (convert to array if it's a single type)
83
111
  let requiredTypes = Array.isArray(require) ? require : [require], dataType = getDataType(data), typeLower = dataType.toLowerCase(),
@@ -112,6 +140,7 @@
112
140
  //renderTpl,
113
141
  //parseStr,
114
142
  deepClone,
143
+ deepCloneToJSON
115
144
  };
116
145
 
117
146
  return utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-11-15 11:0:34
2
+ * @since Last modified: 2025-12-18 21:8:4
3
3
  * @name Utils for web front-end.
4
- * @version 1.0.0
4
+ * @version 0.0.2
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?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).utils={})}(this,function(e){"use strict";const getDataType=e=>{let t,o=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===o&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===o&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":o,t};e.getDataType=getDataType,e.requireTypes=(e,t,o)=>{let n=getDataType(e).toLowerCase(),s="string"==typeof t?[t]:t;if(n.includes("html")&&(n="element"),s=s.map(e=>e.toLowerCase()),o)try{if(!s.includes(n))throw new Error(`Wrong data type,Require types: "${""+s}"!`)}catch(e){o(e)}else if(!s.includes(n))throw new Error(`Wrong data type,Require types: "${""+s}"!`)}});
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}});
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.1",
3
+ "version": "0.0.3",
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/deepClone.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/16 09:02:07
2
+ * @since Last modified: 2025/12/16 13:33:46
3
3
  * Deep clone an array or object.
4
4
  * Supports Symbol keys. These types are returned directly:
5
5
  * Number, String, Boolean, Symbol, HTML*Element, Function, Date, RegExp.
package/src/deepClone.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/16 09:02:07
2
+ * @since Last modified: 2025/12/16 13:33:46
3
3
  * Deep clone an array or object.
4
4
  * Supports Symbol keys. These types are returned directly:
5
5
  * Number, String, Boolean, Symbol, HTML*Element, Function, Date, RegExp.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @since Last modified: 2025/12/16 14:43:51
3
+ * Deep clone an array or object to a JSON-compatible structure.
4
+ * Converts non-serializable types like functions, symbols, Date, RegExp to plain values.
5
+ *
6
+ * @template T
7
+ * @param {T} data - Array or object to clone
8
+ * @returns {T} - New object with different memory address, in a JSON-compatible structure
9
+ *
10
+ * @example
11
+ * const obj = { a: '', b: 0, c: [] };
12
+ * const cloned = deepCloneToJSON(obj);
13
+ *
14
+ * @example
15
+ * const arr = [{}, {}, {}];
16
+ * const cloned = deepCloneToJSON(arr);
17
+ */
18
+ 'use strict';
19
+ import getDataType from './getDataType';
20
+ const deepCloneToJSON = (data) => {
21
+ const dataType = getDataType(data);
22
+ // Handle objects
23
+ if (dataType === 'Object') {
24
+ const newObj = {};
25
+ // Clone regular properties
26
+ for (const key in data) {
27
+ newObj[key] = deepCloneToJSON(data[key]);
28
+ }
29
+ for (const key in newObj) {
30
+ newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
31
+ }
32
+ return newObj;
33
+ // Handle arrays
34
+ }
35
+ else if (dataType === 'Array') {
36
+ let tmp = data.map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
37
+ return tmp;
38
+ // Handle Date objects
39
+ }
40
+ else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
41
+ return undefined;
42
+ }
43
+ else {
44
+ return data;
45
+ }
46
+ };
47
+ export default deepCloneToJSON;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @since Last modified: 2025/12/16 14:43:51
3
+ * Deep clone an array or object to a JSON-compatible structure.
4
+ * Converts non-serializable types like functions, symbols, Date, RegExp to plain values.
5
+ *
6
+ * @template T
7
+ * @param {T} data - Array or object to clone
8
+ * @returns {T} - New object with different memory address, in a JSON-compatible structure
9
+ *
10
+ * @example
11
+ * const obj = { a: '', b: 0, c: [] };
12
+ * const cloned = deepCloneToJSON(obj);
13
+ *
14
+ * @example
15
+ * const arr = [{}, {}, {}];
16
+ * const cloned = deepCloneToJSON(arr);
17
+ */
18
+ 'use strict';
19
+ import getDataType from './getDataType';
20
+
21
+ const deepCloneToJSON = (data: Record<string, any>|Record<string, any>[]): any => {
22
+ const dataType = getDataType(data);
23
+
24
+ // Handle objects
25
+ if (dataType === 'Object') {
26
+ const newObj: Record<string, any> = {};
27
+
28
+ // Clone regular properties
29
+ for (const key in data) {
30
+ newObj[key] = deepCloneToJSON((data as any)[key]);
31
+ }
32
+ for(const key in newObj){
33
+ newObj[key] === undefined && Reflect.deleteProperty(newObj, key);
34
+ }
35
+
36
+ return newObj ;
37
+
38
+ // Handle arrays
39
+ } else if (dataType === 'Array') {
40
+ let tmp = (data as any[]).map((item, index) => deepCloneToJSON(item)).filter(item => item !== undefined);
41
+ return tmp;
42
+ // Handle Date objects
43
+ } else if (!['Number', 'String', 'Boolean', 'Null'].includes(dataType)) {
44
+ return undefined ;
45
+ } else {
46
+ return data;
47
+ }
48
+
49
+ };
50
+
51
+ export default deepCloneToJSON;
52
+
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @since Last modified: 2025/12/18 20:54:23
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
+ const mutateArray = ({ target, method, args = [], onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList }) => {
34
+ // Validation: Ensure target is an array and method is allowed
35
+ if (!Array.isArray(target)) {
36
+ throw new TypeError("The 'target' parameter must be an array.");
37
+ }
38
+ //使用默认
39
+ if (!allowList || allowList?.length) {
40
+ allowList = [
41
+ 'push', 'pop', 'shift', 'unshift', 'splice',
42
+ 'sort', 'reverse', 'copyWithin', 'fill'
43
+ ];
44
+ }
45
+ if (!allowList?.includes(method)) {
46
+ throw new Error(`Method "${method}" is not in the allowList or is not a mutation method.`);
47
+ }
48
+ const context = {}, len = target.length;
49
+ // Capture "Pre-mutation" context for Undo/Redo/Tracking purposes
50
+ switch (method) {
51
+ // 'push' and 'unshift' are add operations, in undo/redo,
52
+ // we can determine the original data structure from result.length and args.length
53
+ // but methods that involve deletion need to record the deleted items to ensure the patch can restore the data structure during undo
54
+ case 'push':
55
+ case 'unshift':
56
+ context.addedItems = [...args];
57
+ break;
58
+ case 'pop':
59
+ context.poppedValue = target[len - 1];
60
+ break;
61
+ case 'shift':
62
+ context.shiftedValue = target[0];
63
+ break;
64
+ case 'splice':
65
+ const [s, d] = args,
66
+ // Calculate actual start index (handling negative values)
67
+ start = s < 0 ? Math.max(len + s, 0) : Math.min(s, len),
68
+ // Handle deleteCount defaults
69
+ deleteCount = d === undefined ? len - start : d;
70
+ context.deletedItems = target.slice(start, start + deleteCount);
71
+ break;
72
+ case 'sort':
73
+ case 'reverse':
74
+ // These methods reorder the whole array; requires a full shallow copy
75
+ context.oldSnapshot = [...target];
76
+ break;
77
+ case 'fill':
78
+ case 'copyWithin':
79
+ const startIdx = args[1] || 0, endIdx = args[2] === undefined ? len : args[2];
80
+ // Overwritten values
81
+ context.oldItems = target.slice(startIdx, endIdx);
82
+ context.start = startIdx;
83
+ context.end = endIdx;
84
+ break;
85
+ }
86
+ // Execute the "onBeforeMutate" callback before mutation
87
+ onBeforeMutate && onBeforeMutate(context);
88
+ // Execute the native array mutation
89
+ const result = Array.prototype[method].apply(target, args);
90
+ // Construct and trigger the patch callback
91
+ onAfterMutate && onAfterMutate({
92
+ method,
93
+ args,
94
+ context,
95
+ result,
96
+ timestamp: Date.now()
97
+ });
98
+ return result;
99
+ };
100
+ export default mutateArray;
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @since Last modified: 2025/12/18 21:04:39
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;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @since Last modified: 2025/12/18 21:04:34
3
+ * A list of supported array mutation methods.
4
+ * These methods are commonly used to modify the contents of an array.
5
+ * These methods can be tracked and handled in various use cases, such as undo/redo functionality,
6
+ * or when applying certain transformations to arrays.
7
+ *
8
+ */
9
+ export type mutateMethods = ('push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'sort' | 'reverse' | 'copyWithin' | 'fill')[];
10
+ const mutateMethods: mutateMethods = [
11
+ 'push', 'pop', 'shift', 'unshift', 'splice',
12
+ 'sort', 'reverse', 'copyWithin', 'fill'
13
+ ];
14
+
15
+ export default mutateMethods;