@codady/utils 0.0.9 → 0.0.11

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/utils.cjs.js +488 -28
  3. package/dist/utils.cjs.min.js +3 -3
  4. package/dist/utils.esm.js +488 -28
  5. package/dist/utils.esm.min.js +3 -3
  6. package/dist/utils.umd - /345/211/257/346/234/254.js" +749 -0
  7. package/dist/utils.umd.js +490 -32
  8. package/dist/utils.umd.min.js +3 -3
  9. package/dist.zip +0 -0
  10. package/modules.js +24 -4
  11. package/modules.ts +24 -4
  12. package/package.json +1 -1
  13. package/src/arrayMutableMethods - /345/211/257/346/234/254.js" +5 -0
  14. package/src/arrayMutableMethods.js +5 -0
  15. package/src/{mutableMethods.ts → arrayMutableMethods.ts} +3 -3
  16. package/src/deepClone.js +151 -26
  17. package/src/deepClone.ts +194 -35
  18. package/src/deepCloneToJSON - /345/211/257/346/234/254.js" +47 -0
  19. package/src/deepEqual.js +48 -0
  20. package/src/deepEqual.ts +46 -0
  21. package/src/deepMerge.js +34 -0
  22. package/src/deepMerge.ts +40 -0
  23. package/src/deepMergeArrays.js +45 -0
  24. package/src/deepMergeArrays.ts +62 -0
  25. package/src/deepMergeHelper.js +40 -0
  26. package/src/deepMergeHelper.ts +45 -0
  27. package/src/deepMergeMaps - /345/211/257/346/234/254.js" +78 -0
  28. package/src/deepMergeMaps.js +57 -0
  29. package/src/deepMergeMaps.ts +67 -0
  30. package/src/deepMergeObjects.js +82 -0
  31. package/src/deepMergeObjects.ts +85 -0
  32. package/src/deepMergeSets.js +48 -0
  33. package/src/deepMergeSets.ts +55 -0
  34. package/src/getUniqueId.js +11 -7
  35. package/src/getUniqueId.ts +16 -9
  36. package/src/mapMutableMethods.js +5 -0
  37. package/src/mapMutableMethods.ts +15 -0
  38. package/src/mutableMethods.js +2 -2
  39. package/src/setMutableMethods - /345/211/257/346/234/254.js" +5 -0
  40. package/src/setMutableMethods.js +5 -0
  41. package/src/setMutableMethods.ts +14 -0
  42. package/src/wrapArrayMethods.js +5 -5
  43. package/src/wrapArrayMethods.ts +7 -7
  44. package/src/wrapMap - /345/211/257/346/234/254.js" +119 -0
  45. package/src/wrapMapMethods.js +118 -0
  46. package/src/wrapMapMethods.ts +226 -0
  47. package/src/wrapSetMethods.js +112 -0
  48. package/src/wrapSetMethods.ts +215 -0
package/modules.js CHANGED
@@ -1,14 +1,24 @@
1
1
  /**
2
- * Last modified: 2025/12/19 15:23:21
2
+ * Last modified: 2025/12/24 17:05:40
3
3
  */
4
4
  'use strict';
5
5
  import deepClone from './src/deepClone';
6
6
  import deepCloneToJSON from './src/deepCloneToJSON';
7
7
  import getDataType from './src/getDataType';
8
8
  import wrapArrayMethods from './src/wrapArrayMethods';
9
- import mutableMethods from './src/mutableMethods';
10
9
  import requireTypes from './src/requireTypes';
11
10
  import getUniqueId from './src/getUniqueId';
11
+ import arrayMutableMethods from './src/arrayMutableMethods';
12
+ import setMutableMethods from './src/setMutableMethods';
13
+ import mapMutableMethods from './src/mapMutableMethods';
14
+ import wrapSetMethods from './src/wrapSetMethods';
15
+ import wrapMapMethods from './src/wrapMapMethods';
16
+ import { deepEqual } from 'assert';
17
+ import deepMerge from './src/deepMerge';
18
+ import deepMergeArrays from './src/deepMergeArrays';
19
+ import deepMergeMaps from './src/deepMergeMaps';
20
+ import deepMergeObjects from './src/deepMergeObjects';
21
+ import deepMergeSets from './src/deepMergeSets';
12
22
  const utils = {
13
23
  //executeStr,
14
24
  getDataType,
@@ -18,7 +28,17 @@ const utils = {
18
28
  deepClone,
19
29
  deepCloneToJSON,
20
30
  wrapArrayMethods,
21
- mutableMethods,
22
- getUniqueId
31
+ arrayMutableMethods,
32
+ setMutableMethods,
33
+ mapMutableMethods,
34
+ wrapSetMethods,
35
+ wrapMapMethods,
36
+ getUniqueId,
37
+ deepEqual,
38
+ deepMerge,
39
+ deepMergeArrays,
40
+ deepMergeMaps,
41
+ deepMergeObjects,
42
+ deepMergeSets,
23
43
  };
24
44
  export default utils;
package/modules.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2025/12/19 15:23:21
2
+ * Last modified: 2025/12/24 17:05:40
3
3
  */
4
4
  'use strict'
5
5
  import deepClone from './src/deepClone';
@@ -7,11 +7,21 @@ import deepCloneToJSON from './src/deepCloneToJSON';
7
7
  import executeStr from './src/executeStr';
8
8
  import getDataType from './src/getDataType';
9
9
  import wrapArrayMethods from './src/wrapArrayMethods';
10
- import mutableMethods from './src/mutableMethods';
11
10
  import parseStr from './src/parseStr';
12
11
  import renderTpl from './src/renderTpl';
13
12
  import requireTypes from './src/requireTypes';
14
13
  import getUniqueId from './src/getUniqueId';
14
+ import arrayMutableMethods from './src/arrayMutableMethods';
15
+ import setMutableMethods from './src/setMutableMethods';
16
+ import mapMutableMethods from './src/mapMutableMethods';
17
+ import wrapSetMethods from './src/wrapSetMethods';
18
+ import wrapMapMethods from './src/wrapMapMethods';
19
+ import { deepEqual } from 'assert';
20
+ import deepMerge from './src/deepMerge';
21
+ import deepMergeArrays from './src/deepMergeArrays';
22
+ import deepMergeMaps from './src/deepMergeMaps';
23
+ import deepMergeObjects from './src/deepMergeObjects';
24
+ import deepMergeSets from './src/deepMergeSets';
15
25
 
16
26
 
17
27
 
@@ -24,8 +34,18 @@ const utils = {
24
34
  deepClone,
25
35
  deepCloneToJSON,
26
36
  wrapArrayMethods,
27
- mutableMethods,
28
- getUniqueId
37
+ arrayMutableMethods,
38
+ setMutableMethods,
39
+ mapMutableMethods,
40
+ wrapSetMethods,
41
+ wrapMapMethods,
42
+ getUniqueId,
43
+ deepEqual,
44
+ deepMerge,
45
+ deepMergeArrays,
46
+ deepMergeMaps,
47
+ deepMergeObjects,
48
+ deepMergeSets,
29
49
  };
30
50
 
31
51
  export default utils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
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.",
@@ -0,0 +1,5 @@
1
+ const arrayMutableMethods = [
2
+ 'push', 'pop', 'shift', 'unshift', 'splice',
3
+ 'sort', 'reverse', 'copyWithin', 'fill'
4
+ ];
5
+ export default arrayMutableMethods;
@@ -0,0 +1,5 @@
1
+ const arrayMutableMethods = [
2
+ 'push', 'pop', 'shift', 'unshift', 'splice',
3
+ 'sort', 'reverse', 'copyWithin', 'fill'
4
+ ];
5
+ export default arrayMutableMethods;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/19 10:06:07
2
+ * @since Last modified: 2025/12/22 17:20:46
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,
@@ -7,9 +7,9 @@
7
7
  *
8
8
  */
9
9
  export type ArrayMutationNames = ('push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'sort' | 'reverse' | 'copyWithin' | 'fill')[];
10
- const mutableMethods: ArrayMutationNames = [
10
+ const arrayMutableMethods: ArrayMutationNames = [
11
11
  'push', 'pop', 'shift', 'unshift', 'splice',
12
12
  'sort', 'reverse', 'copyWithin', 'fill'
13
13
  ];
14
14
 
15
- export default mutableMethods;
15
+ export default arrayMutableMethods;
package/src/deepClone.js CHANGED
@@ -1,53 +1,178 @@
1
1
  /**
2
- * @since Last modified: 2025/12/16 13:33:46
3
- * Deep clone an array or object.
4
- * Supports Symbol keys. These types are returned directly:
5
- * Number, String, Boolean, Symbol, HTML*Element, Function, Date, RegExp.
2
+ * @since Last modified: 2025/12/24 17:05:29
3
+ * Deep clone an array, object, or other cloneable data types.
6
4
  *
7
- * @template T
8
- * @param {T} data - Array or object to clone
9
- * @returns {T} - New object with different memory address
5
+ * Features:
6
+ * - Handles nested objects and arrays recursively
7
+ * - Preserves Symbol properties
8
+ * - Customizable cloning behavior via options
9
+ * - Interceptor for custom cloning logic
10
+ * - Lifecycle callbacks for monitoring
11
+ *
12
+ * Default cloning behavior:
13
+ * - Objects and arrays: Deep cloned (enabled by default)
14
+ * - Maps and Sets: Deep cloned (enabled by default)
15
+ * - Dates: Returned directly (disabled by default, set cloneDate: true to clone)
16
+ * - RegExp: Returned directly (disabled by default, set cloneRegex: true to clone)
17
+ * - DOM elements: Returned directly (disabled by default, set cloneElement: true to clone)
18
+ * - DocumentFragment: Returned directly (disabled by default, set cloneFragment: true to clone)
19
+ *
20
+ * Types always returned directly (no cloning):
21
+ * - Primitive types: Number, String, Boolean, BigInt, undefined, null
22
+ * - Functions and Classes
23
+ * - Symbol instances
24
+ * - Errors and Promises
25
+ * - ArrayBuffer, Blob, File
26
+ * - WeakMap and WeakSet
27
+ *
28
+ * @template T - Type of the data to clone
29
+ * @param {T} data - The data to deep clone
30
+ * @param {DeepCloneOptions} [options={}] - Configuration options for cloning behavior
31
+ * @returns {T} - A deep clone of the input data (new memory reference)
10
32
  *
11
33
  * @example
12
- * const obj = { a: '', b: 0, c: [] };
34
+ * // Basic usage - clones objects and arrays
35
+ * const obj = { a: '', b: 0, c: [], d: new Map([['key', 'value']]) };
13
36
  * const cloned = deepClone(obj);
37
+ * console.log(cloned !== obj); // true
38
+ * console.log(cloned.c !== obj.c); // true
39
+ *
40
+ * @example
41
+ * // With Symbol properties
42
+ * const sym = Symbol('id');
43
+ * const objWithSymbol = { [sym]: 'value', normal: 'property' };
44
+ * const clonedWithSymbol = deepClone(objWithSymbol);
45
+ *
46
+ * @example
47
+ * // Custom options - clone Dates and RegExp
48
+ * const data = { date: new Date(), regex: /test/gi };
49
+ * const cloned = deepClone(data, {
50
+ * cloneDate: true,
51
+ * cloneRegex: true
52
+ * });
53
+ *
54
+ * @example
55
+ * // Using interceptor for custom types
56
+ * class CustomClass {
57
+ * constructor(public value: number) {}
58
+ * }
59
+ *
60
+ * const customData = new CustomClass(42);
61
+ * const cloned = deepClone(customData, {
62
+ * interceptor: (data, type) => {
63
+ * if (data instanceof CustomClass) {
64
+ * return new CustomClass(data.value);
65
+ * }
66
+ * return null;
67
+ * }
68
+ * });
14
69
  *
15
70
  * @example
16
- * const arr = [{}, {}, {}];
17
- * const cloned = deepClone(arr);
71
+ * // With lifecycle callbacks
72
+ * const trackedClone = deepClone(someData, {
73
+ * onBeforeClone: (data, type) => {
74
+ * console.log(`Starting to clone ${type}`);
75
+ * },
76
+ * onAfterClone: (result) => {
77
+ * console.log(`Cloned ${result.type}, success: ${result.cloned}`);
78
+ * }
79
+ * });
18
80
  */
19
81
  'use strict';
20
82
  import getDataType from './getDataType';
21
- const deepClone = (data) => {
22
- const dataType = getDataType(data);
23
- if (dataType === 'Object') {
24
- const newObj = {};
25
- const symbols = Object.getOwnPropertySymbols(data);
83
+ //支持原始值的复制,包括Number、String、Boolean、Null
84
+ //支持Date和Regex对象值复制(值转换)
85
+ //支持{},[],Set和Map的遍历
86
+ const deepClone = (data, options = {}) => {
87
+ const dataType = getDataType(data),
88
+ // Default options
89
+ opts = Object.assign({
90
+ cloneSet: true,
91
+ cloneMap: true,
92
+ cloneObject: true,
93
+ cloneArray: true,
94
+ //可重新构建
95
+ cloneDate: true,
96
+ cloneRegex: true,
97
+ //节点默认不复制
98
+ //cloneElement: false,
99
+ //cloneFragment: false,
100
+ }, options);
101
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
102
+ if (opts.interceptor && typeof opts.interceptor === 'function') {
103
+ let result = opts.interceptor(data, dataType);
104
+ if ((result ?? false)) {
105
+ // Call onAfterClone if set
106
+ opts.onAfterClone?.({
107
+ output: result,
108
+ input: data,
109
+ type: dataType,
110
+ cloned: result !== data,
111
+ });
112
+ return result;
113
+ }
114
+ // If interceptor returns null/undefined, continue with normal cloning process
115
+ }
116
+ // Callback before cloning
117
+ opts.onBeforeClone?.(data, dataType);
118
+ let newData, cloned = true;
119
+ if (dataType === 'Object' && opts.cloneObject) {
120
+ const newObj = {}, symbols = Object.getOwnPropertySymbols(data);
26
121
  // Clone regular properties
27
122
  for (const key in data) {
28
- newObj[key] = deepClone(data[key]);
123
+ newObj[key] = deepClone(data[key], opts);
29
124
  }
30
125
  // Clone Symbol properties
31
126
  if (symbols.length > 0) {
32
127
  for (const symbol of symbols) {
33
- newObj[symbol] = deepClone(data[symbol]);
128
+ newObj[symbol] = deepClone(data[symbol], opts);
34
129
  }
35
130
  }
36
- return newObj;
131
+ newData = newObj;
37
132
  }
38
- else if (dataType === 'Array') {
39
- return data.map(item => deepClone(item));
133
+ else if (dataType === 'Array' && opts.cloneArray) {
134
+ newData = data.map(item => deepClone(item, opts));
135
+ }
136
+ else if (dataType === 'Map' && opts.cloneMap) {
137
+ const newMap = new Map();
138
+ for (const [key, value] of data) {
139
+ // Both Map keys and values need deep cloning
140
+ newMap.set(deepClone(key, opts), deepClone(value, opts));
141
+ }
142
+ newData = newMap;
143
+ }
144
+ else if (dataType === 'Set' && opts.cloneSet) {
145
+ const newSet = new Set();
146
+ for (const value of data) {
147
+ // Set values need deep cloning
148
+ newSet.add(deepClone(value, opts));
149
+ }
150
+ newData = newSet;
40
151
  }
41
- else if (dataType === 'Date') {
42
- return new Date(data.getTime());
152
+ else if (dataType === 'Date' && opts.cloneDate) {
153
+ newData = new Date(data.getTime());
43
154
  }
44
- else if (dataType === 'RegExp') {
155
+ else if (dataType === 'RegExp' && opts.cloneRegex) {
45
156
  const regex = data;
46
- return new RegExp(regex.source, regex.flags);
157
+ newData = new RegExp(regex.source, regex.flags);
158
+ // } else if ((dataType.includes('HTML') && opts.cloneElement) ||
159
+ // (dataType === 'DocumentFragment' && opts.cloneFragment)
160
+ //) {
161
+ //Text,Comment,HTML*Element,DocumentFragment,Attr
162
+ // newData = (data as any).cloneNode(true) as T;
47
163
  }
48
164
  else {
49
- // Number, String, Boolean, Symbol,Text,Comment,Set,Map, HTML*Element, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
50
- return data;
165
+ // Number, String, Boolean, Symbol, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
166
+ newData = data;
167
+ cloned = false;
51
168
  }
169
+ // Callback after cloning
170
+ opts.onAfterClone?.({
171
+ output: newData,
172
+ input: data,
173
+ type: dataType,
174
+ cloned,
175
+ });
176
+ return newData;
52
177
  };
53
178
  export default deepClone;
package/src/deepClone.ts CHANGED
@@ -1,59 +1,218 @@
1
1
  /**
2
- * @since Last modified: 2025/12/16 13:33:46
3
- * Deep clone an array or object.
4
- * Supports Symbol keys. These types are returned directly:
5
- * Number, String, Boolean, Symbol, HTML*Element, Function, Date, RegExp.
2
+ * @since Last modified: 2025/12/24 17:05:29
3
+ * Deep clone an array, object, or other cloneable data types.
6
4
  *
7
- * @template T
8
- * @param {T} data - Array or object to clone
9
- * @returns {T} - New object with different memory address
5
+ * Features:
6
+ * - Handles nested objects and arrays recursively
7
+ * - Preserves Symbol properties
8
+ * - Customizable cloning behavior via options
9
+ * - Interceptor for custom cloning logic
10
+ * - Lifecycle callbacks for monitoring
11
+ *
12
+ * Default cloning behavior:
13
+ * - Objects and arrays: Deep cloned (enabled by default)
14
+ * - Maps and Sets: Deep cloned (enabled by default)
15
+ * - Dates: Returned directly (disabled by default, set cloneDate: true to clone)
16
+ * - RegExp: Returned directly (disabled by default, set cloneRegex: true to clone)
17
+ * - DOM elements: Returned directly (disabled by default, set cloneElement: true to clone)
18
+ * - DocumentFragment: Returned directly (disabled by default, set cloneFragment: true to clone)
19
+ *
20
+ * Types always returned directly (no cloning):
21
+ * - Primitive types: Number, String, Boolean, BigInt, undefined, null
22
+ * - Functions and Classes
23
+ * - Symbol instances
24
+ * - Errors and Promises
25
+ * - ArrayBuffer, Blob, File
26
+ * - WeakMap and WeakSet
27
+ *
28
+ * @template T - Type of the data to clone
29
+ * @param {T} data - The data to deep clone
30
+ * @param {DeepCloneOptions} [options={}] - Configuration options for cloning behavior
31
+ * @returns {T} - A deep clone of the input data (new memory reference)
10
32
  *
11
33
  * @example
12
- * const obj = { a: '', b: 0, c: [] };
34
+ * // Basic usage - clones objects and arrays
35
+ * const obj = { a: '', b: 0, c: [], d: new Map([['key', 'value']]) };
13
36
  * const cloned = deepClone(obj);
37
+ * console.log(cloned !== obj); // true
38
+ * console.log(cloned.c !== obj.c); // true
39
+ *
40
+ * @example
41
+ * // With Symbol properties
42
+ * const sym = Symbol('id');
43
+ * const objWithSymbol = { [sym]: 'value', normal: 'property' };
44
+ * const clonedWithSymbol = deepClone(objWithSymbol);
45
+ *
46
+ * @example
47
+ * // Custom options - clone Dates and RegExp
48
+ * const data = { date: new Date(), regex: /test/gi };
49
+ * const cloned = deepClone(data, {
50
+ * cloneDate: true,
51
+ * cloneRegex: true
52
+ * });
53
+ *
54
+ * @example
55
+ * // Using interceptor for custom types
56
+ * class CustomClass {
57
+ * constructor(public value: number) {}
58
+ * }
14
59
  *
15
- * @example
16
- * const arr = [{}, {}, {}];
17
- * const cloned = deepClone(arr);
60
+ * const customData = new CustomClass(42);
61
+ * const cloned = deepClone(customData, {
62
+ * interceptor: (data, type) => {
63
+ * if (data instanceof CustomClass) {
64
+ * return new CustomClass(data.value);
65
+ * }
66
+ * return null;
67
+ * }
68
+ * });
69
+ *
70
+ * @example
71
+ * // With lifecycle callbacks
72
+ * const trackedClone = deepClone(someData, {
73
+ * onBeforeClone: (data, type) => {
74
+ * console.log(`Starting to clone ${type}`);
75
+ * },
76
+ * onAfterClone: (result) => {
77
+ * console.log(`Cloned ${result.type}, success: ${result.cloned}`);
78
+ * }
79
+ * });
18
80
  */
19
81
  'use strict';
20
82
  import getDataType from './getDataType';
21
83
 
22
- const deepClone = <T>(data: T): T => {
23
- const dataType = getDataType(data);
24
-
25
- if (dataType === 'Object') {
26
- const newObj: Record<string | symbol, any> = {};
27
- const symbols = Object.getOwnPropertySymbols(data);
28
-
84
+ export interface DeepCloneOptions {
85
+ cloneDate?: boolean;
86
+ cloneRegex?: boolean;
87
+ cloneSet?: boolean;
88
+ cloneMap?: boolean;
89
+ cloneObject?: boolean;
90
+ cloneArray?: boolean;
91
+ cloneElement?: boolean;
92
+ cloneFragment?: boolean;
93
+
94
+ /**
95
+ * Interceptor function. If returns a non-null value, use it as the cloning result.
96
+ */
97
+ interceptor?: <T>(data: T, dataType: string) => T | null | undefined;
98
+
99
+ /**
100
+ * Callback before cloning.
101
+ */
102
+ onBeforeClone?: (data: any, dataType: string) => void;
103
+
104
+ /**
105
+ * Callback after cloning.
106
+ * @param result Object containing cloning result.
107
+ */
108
+ onAfterClone?: (result: AfterCloneResult) => void;
109
+ }
110
+ export interface AfterCloneResult<T = any> {
111
+ // Cloned data
112
+ output: T;
113
+ // Original data
114
+ input: any;
115
+ // Data type
116
+ type: string;
117
+ // Whether cloning was performed
118
+ cloned: boolean;
119
+ }
120
+ //支持原始值的复制,包括Number、String、Boolean、Null
121
+ //支持Date和Regex对象值复制(值转换)
122
+ //支持{},[],Set和Map的遍历
123
+ const deepClone = <T>(data: T, options: DeepCloneOptions = {}): T => {
124
+ const dataType = getDataType(data),
125
+ // Default options
126
+ opts = Object.assign({
127
+ cloneSet: true,
128
+ cloneMap: true,
129
+ cloneObject: true,
130
+ cloneArray: true,
131
+ //可重新构建
132
+ cloneDate: true,
133
+ cloneRegex: true,
134
+ //节点默认不复制
135
+ //cloneElement: false,
136
+ //cloneFragment: false,
137
+ }, options);
138
+
139
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
140
+ if (opts.interceptor && typeof opts.interceptor === 'function') {
141
+ let result = opts.interceptor(data, dataType);
142
+ if ((result ?? false)) {
143
+ // Call onAfterClone if set
144
+ opts.onAfterClone?.({
145
+ output: result,
146
+ input: data,
147
+ type: dataType,
148
+ cloned: result !== data,
149
+ });
150
+ return result as T;
151
+ }
152
+ // If interceptor returns null/undefined, continue with normal cloning process
153
+ }
154
+
155
+ // Callback before cloning
156
+ opts.onBeforeClone?.(data, dataType);
157
+
158
+ let newData,
159
+ cloned = true;
160
+
161
+ if (dataType === 'Object' && opts.cloneObject) {
162
+ const newObj: Record<string | symbol, any> = {},
163
+ symbols = Object.getOwnPropertySymbols(data);
164
+
29
165
  // Clone regular properties
30
166
  for (const key in data) {
31
- newObj[key] = deepClone((data as any)[key]);
167
+ newObj[key] = deepClone((data as any)[key],opts);
32
168
  }
33
-
169
+
34
170
  // Clone Symbol properties
35
171
  if (symbols.length > 0) {
36
172
  for (const symbol of symbols) {
37
- newObj[symbol] = deepClone((data as any)[symbol]);
173
+ newObj[symbol] = deepClone((data as any)[symbol],opts);
38
174
  }
39
175
  }
40
-
41
- return newObj as T;
42
-
43
- } else if (dataType === 'Array') {
44
- return (data as any[]).map(item => deepClone(item)) as T;
45
-
46
- } else if (dataType === 'Date') {
47
- return new Date((data as Date).getTime()) as T;
48
-
49
- } else if (dataType === 'RegExp') {
176
+ newData = newObj as T;
177
+ } else if (dataType === 'Array' && opts.cloneArray) {
178
+ newData = (data as any[]).map(item => deepClone(item,opts)) as T;
179
+ } else if (dataType === 'Map' && opts.cloneMap) {
180
+ const newMap = new Map();
181
+ for (const [key, value] of data as Map<any, any>) {
182
+ // Both Map keys and values need deep cloning
183
+ newMap.set(deepClone(key,opts), deepClone(value,opts));
184
+ }
185
+ newData = newMap as T;
186
+ } else if (dataType === 'Set' && opts.cloneSet) {
187
+ const newSet = new Set();
188
+ for (const value of data as Set<any>) {
189
+ // Set values need deep cloning
190
+ newSet.add(deepClone(value,opts));
191
+ }
192
+ newData = newSet as T;
193
+ } else if (dataType === 'Date' && opts.cloneDate) {
194
+ newData = new Date((data as Date).getTime()) as T;
195
+ } else if (dataType === 'RegExp' && opts.cloneRegex) {
50
196
  const regex = data as RegExp;
51
- return new RegExp(regex.source, regex.flags) as T;
52
-
197
+ newData = new RegExp(regex.source, regex.flags) as T;
198
+ // } else if ((dataType.includes('HTML') && opts.cloneElement) ||
199
+ // (dataType === 'DocumentFragment' && opts.cloneFragment)
200
+ //) {
201
+ //Text,Comment,HTML*Element,DocumentFragment,Attr
202
+ // newData = (data as any).cloneNode(true) as T;
53
203
  } else {
54
- // Number, String, Boolean, Symbol,Text,Comment,Set,Map, HTML*Element, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
55
- return data;
204
+ // Number, String, Boolean, Symbol, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
205
+ newData = data;
206
+ cloned = false;
56
207
  }
208
+ // Callback after cloning
209
+ opts.onAfterClone?.({
210
+ output: newData,
211
+ input: data,
212
+ type: dataType,
213
+ cloned,
214
+ });
215
+ return newData;
57
216
  };
58
217
 
59
218
  export default deepClone;
@@ -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;