@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.
- package/CHANGELOG.md +38 -0
- package/dist/utils.cjs.js +488 -28
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +488 -28
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd - /345/211/257/346/234/254.js" +749 -0
- package/dist/utils.umd.js +490 -32
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/modules.js +24 -4
- package/modules.ts +24 -4
- package/package.json +1 -1
- package/src/arrayMutableMethods - /345/211/257/346/234/254.js" +5 -0
- package/src/arrayMutableMethods.js +5 -0
- package/src/{mutableMethods.ts → arrayMutableMethods.ts} +3 -3
- package/src/deepClone.js +151 -26
- package/src/deepClone.ts +194 -35
- package/src/deepCloneToJSON - /345/211/257/346/234/254.js" +47 -0
- package/src/deepEqual.js +48 -0
- package/src/deepEqual.ts +46 -0
- package/src/deepMerge.js +34 -0
- package/src/deepMerge.ts +40 -0
- package/src/deepMergeArrays.js +45 -0
- package/src/deepMergeArrays.ts +62 -0
- package/src/deepMergeHelper.js +40 -0
- package/src/deepMergeHelper.ts +45 -0
- package/src/deepMergeMaps - /345/211/257/346/234/254.js" +78 -0
- package/src/deepMergeMaps.js +57 -0
- package/src/deepMergeMaps.ts +67 -0
- package/src/deepMergeObjects.js +82 -0
- package/src/deepMergeObjects.ts +85 -0
- package/src/deepMergeSets.js +48 -0
- package/src/deepMergeSets.ts +55 -0
- package/src/getUniqueId.js +11 -7
- package/src/getUniqueId.ts +16 -9
- package/src/mapMutableMethods.js +5 -0
- package/src/mapMutableMethods.ts +15 -0
- package/src/mutableMethods.js +2 -2
- package/src/setMutableMethods - /345/211/257/346/234/254.js" +5 -0
- package/src/setMutableMethods.js +5 -0
- package/src/setMutableMethods.ts +14 -0
- package/src/wrapArrayMethods.js +5 -5
- package/src/wrapArrayMethods.ts +7 -7
- package/src/wrapMap - /345/211/257/346/234/254.js" +119 -0
- package/src/wrapMapMethods.js +118 -0
- package/src/wrapMapMethods.ts +226 -0
- package/src/wrapSetMethods.js +112 -0
- package/src/wrapSetMethods.ts +215 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since Last modified: 2025/12/22 17:19:32
|
|
3
|
+
* Wraps Map objects with mutation tracking capabilities.
|
|
4
|
+
* Provides hooks for before/after mutation events and captures detailed context
|
|
5
|
+
* for undo/redo or change tracking purposes.
|
|
6
|
+
*
|
|
7
|
+
* @template K - Map key type
|
|
8
|
+
* @template V - Map value type
|
|
9
|
+
* @param {MapMutationOptions<K, V>} options - Configuration object containing target Map and callbacks
|
|
10
|
+
* @returns {MapMutationMethods<K, V>} - Object containing wrapped Map mutation methods
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Basic usage with tracking
|
|
14
|
+
* const map = new Map([['key1', 'value1']]);
|
|
15
|
+
* const methods = wrapMap({
|
|
16
|
+
* target: map,
|
|
17
|
+
* onAfterMutate: (patch) => {
|
|
18
|
+
* console.log(`Map ${patch.method} called`, patch.context);
|
|
19
|
+
* }
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* methods.set('key2', 'value2'); // Tracked
|
|
23
|
+
* methods.delete('key1'); // Tracked
|
|
24
|
+
* methods.clear(); // Tracked
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // With undo/redo support
|
|
28
|
+
* const history: MapMutationPatch<any, any>[] = [];
|
|
29
|
+
* const map = new Map<string, number>();
|
|
30
|
+
*
|
|
31
|
+
* const methods = wrapMap({
|
|
32
|
+
* target: map,
|
|
33
|
+
* onBeforeMutate: (context) => {
|
|
34
|
+
* console.log('Before mutation:', context);
|
|
35
|
+
* },
|
|
36
|
+
* onAfterMutate: (patch) => {
|
|
37
|
+
* history.push(patch);
|
|
38
|
+
* console.log('Mutation recorded:', patch.method, 'History size:', history.length);
|
|
39
|
+
* }
|
|
40
|
+
* });
|
|
41
|
+
*/
|
|
42
|
+
'use strict';
|
|
43
|
+
|
|
44
|
+
import mapMutableMethods, { MapMutationNames } from "./mapMutableMethods";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Context captured before Map mutation for tracking purposes
|
|
48
|
+
*/
|
|
49
|
+
export interface MapMutationContext<K = any, V = any> {
|
|
50
|
+
/** For set method: the key being set */
|
|
51
|
+
key?: K;
|
|
52
|
+
/** For delete method: the deleted value */
|
|
53
|
+
value?: V;
|
|
54
|
+
/** For set method: the new value being set */
|
|
55
|
+
newValue?: V;
|
|
56
|
+
/** For set method: the old value if key existed */
|
|
57
|
+
oldValue?: V;
|
|
58
|
+
/** For set / delete method: whether the key existed */
|
|
59
|
+
existed?: boolean;
|
|
60
|
+
/** For clear method: snapshot of all entries before clearing */
|
|
61
|
+
clearedItems?: [K, V][];
|
|
62
|
+
/** For clear method: size of the Map before clearing */
|
|
63
|
+
previousSize?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Data object passed to callback after Map mutation
|
|
68
|
+
*/
|
|
69
|
+
export interface MapMutationPatch<K = any, V = any> {
|
|
70
|
+
/** The mutation method called */
|
|
71
|
+
method: MapMutationNames;
|
|
72
|
+
/** The result returned by the mutation method */
|
|
73
|
+
result: any;
|
|
74
|
+
/** Arguments passed to the mutation method */
|
|
75
|
+
args: any[];
|
|
76
|
+
/** Context captured before mutation */
|
|
77
|
+
context: MapMutationContext<K, V>;
|
|
78
|
+
/** Reference to the mutated Map */
|
|
79
|
+
target: Map<K, V>;
|
|
80
|
+
/** Additional custom properties */
|
|
81
|
+
[key: string]: any;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Configuration options for wrapMap function
|
|
86
|
+
*/
|
|
87
|
+
export interface MapMutationOptions<K = any, V = any> {
|
|
88
|
+
/** The Map to wrap with mutation tracking */
|
|
89
|
+
target: Map<K, V>;
|
|
90
|
+
/** Callback triggered before mutation */
|
|
91
|
+
onBeforeMutate?: (context: MapMutationContext<K, V>) => void;
|
|
92
|
+
/** Callback triggered after mutation */
|
|
93
|
+
onAfterMutate?: (patch: MapMutationPatch<K, V>) => void;
|
|
94
|
+
/** Optional list of allowed mutation methods (default: all Map methods) */
|
|
95
|
+
allowList?: MapMutationNames[];
|
|
96
|
+
/** Additional properties to attach to the patch */
|
|
97
|
+
props?: Record<string, any>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Wrapped mutation methods for Map
|
|
102
|
+
*/
|
|
103
|
+
export interface MapMutationMethods<K = any, V = any> {
|
|
104
|
+
/**
|
|
105
|
+
* Sets the value for the key in the Map.
|
|
106
|
+
* @param key The key to set
|
|
107
|
+
* @param value The value to set
|
|
108
|
+
* @returns The Map object
|
|
109
|
+
*/
|
|
110
|
+
set: (key: K, value: V) => Map<K, V>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Deletes the key from the Map.
|
|
114
|
+
* @param key The key to delete
|
|
115
|
+
* @returns true if the key existed and has been removed, false otherwise
|
|
116
|
+
*/
|
|
117
|
+
delete: (key: K) => boolean;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Clears all entries from the Map.
|
|
121
|
+
* @returns void
|
|
122
|
+
*/
|
|
123
|
+
clear: () => void;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Gets the original Map instance for direct access
|
|
127
|
+
*/
|
|
128
|
+
readonly target: Map<K, V>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Creates wrapped mutation methods for Map with tracking capabilities
|
|
133
|
+
*
|
|
134
|
+
* @param options Configuration options
|
|
135
|
+
* @returns Object containing wrapped Map mutation methods
|
|
136
|
+
* @throws TypeError if target is not a Map
|
|
137
|
+
*/
|
|
138
|
+
const wrapMapMethods = <K = any, V = any>({
|
|
139
|
+
target,
|
|
140
|
+
onBeforeMutate = () => { },
|
|
141
|
+
onAfterMutate = () => { },
|
|
142
|
+
allowList = mapMutableMethods,
|
|
143
|
+
props = {},
|
|
144
|
+
}: MapMutationOptions<K, V>): MapMutationMethods<K, V> => {
|
|
145
|
+
|
|
146
|
+
// Validation: Ensure target is a Map
|
|
147
|
+
if (!(target instanceof Map)) {
|
|
148
|
+
throw new TypeError("The 'target' parameter must be a Map.");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Create method wrappers
|
|
152
|
+
const methods: Partial<MapMutationMethods<K, V>> = {};
|
|
153
|
+
|
|
154
|
+
// Helper to create wrapped method
|
|
155
|
+
const createWrappedMethod = (method: MapMutationNames) => {
|
|
156
|
+
return function (...args: any[]) {
|
|
157
|
+
const context: MapMutationContext<K, V> = {};
|
|
158
|
+
|
|
159
|
+
// Capture pre-mutation context based on method
|
|
160
|
+
switch (method) {
|
|
161
|
+
case 'set': {
|
|
162
|
+
const [key, newValue] = args as [K, V];
|
|
163
|
+
context.key = key;
|
|
164
|
+
context.newValue = newValue;
|
|
165
|
+
context.existed = target.has(key);
|
|
166
|
+
context.oldValue = context.existed ? target.get(key) : undefined;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
case 'delete': {
|
|
171
|
+
const [key] = args as [K];
|
|
172
|
+
context.key = key;
|
|
173
|
+
context.existed = target.has(key);
|
|
174
|
+
context.value = context.existed ? target.get(key) : undefined;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
case 'clear': {
|
|
179
|
+
context.clearedItems = Array.from(target.entries());
|
|
180
|
+
//用来做验证
|
|
181
|
+
context.previousSize = target.size;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Execute before mutation callback
|
|
187
|
+
onBeforeMutate(context);
|
|
188
|
+
|
|
189
|
+
// Execute the native Map method
|
|
190
|
+
const result = (target as any)[method].apply(target, args);
|
|
191
|
+
|
|
192
|
+
// Construct patch object
|
|
193
|
+
const patch: MapMutationPatch<K, V> = {
|
|
194
|
+
method,
|
|
195
|
+
result,
|
|
196
|
+
args,
|
|
197
|
+
context,
|
|
198
|
+
target,
|
|
199
|
+
...props
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Execute after mutation callback
|
|
203
|
+
onAfterMutate(patch);
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Wrap allowed methods
|
|
210
|
+
for (const method of allowList) {
|
|
211
|
+
if (mapMutableMethods.includes(method)) {
|
|
212
|
+
(methods as any)[method] = createWrappedMethod(method);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Add target reference
|
|
217
|
+
Object.defineProperty(methods, 'target', {
|
|
218
|
+
get: () => target,
|
|
219
|
+
enumerable: false,
|
|
220
|
+
configurable: false
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return methods as MapMutationMethods<K, V>;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
export default wrapMapMethods;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since Last modified: 2025/12/22 17:19:21
|
|
3
|
+
* Wraps Set objects with mutation tracking capabilities.
|
|
4
|
+
* Provides hooks for before/after mutation events and captures detailed context
|
|
5
|
+
* for undo/redo or change tracking purposes.
|
|
6
|
+
*
|
|
7
|
+
* @template T - Set element type
|
|
8
|
+
* @param {SetMutationOptions<T>} options - Configuration object containing target Set and callbacks
|
|
9
|
+
* @returns {SetMutationMethods<T>} - Object containing wrapped Set mutation methods
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Basic usage with tracking
|
|
13
|
+
* const set = new Set([1, 2, 3]);
|
|
14
|
+
* const methods = wrapSet({
|
|
15
|
+
* target: set,
|
|
16
|
+
* onAfterMutate: (patch) => {
|
|
17
|
+
* console.log(`Set ${patch.method} called`, patch.context);
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* methods.add(4); // Tracked
|
|
22
|
+
* methods.delete(2); // Tracked
|
|
23
|
+
* methods.clear(); // Tracked
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // With change detection for UI updates
|
|
27
|
+
* const set = new Set<string>();
|
|
28
|
+
* const methods = wrapSet({
|
|
29
|
+
* target: set,
|
|
30
|
+
* onAfterMutate: (patch) => {
|
|
31
|
+
* // Trigger UI update when Set changes
|
|
32
|
+
* if (patch.method === 'add' || patch.method === 'delete') {
|
|
33
|
+
* updateUI(Array.from(patch.target));
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* });
|
|
37
|
+
*/
|
|
38
|
+
'use strict';
|
|
39
|
+
import setMutableMethods from "./setMutableMethods";
|
|
40
|
+
/**
|
|
41
|
+
* Creates wrapped mutation methods for Set with tracking capabilities
|
|
42
|
+
*
|
|
43
|
+
* @param options Configuration options
|
|
44
|
+
* @returns Object containing wrapped Set mutation methods
|
|
45
|
+
* @throws TypeError if target is not a Set
|
|
46
|
+
*/
|
|
47
|
+
const wrapSetMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList = setMutableMethods, props = {}, }) => {
|
|
48
|
+
// Validation: Ensure target is a Set
|
|
49
|
+
if (!(target instanceof Set)) {
|
|
50
|
+
throw new TypeError("The 'target' parameter must be a Set.");
|
|
51
|
+
}
|
|
52
|
+
// Create method wrappers
|
|
53
|
+
const methods = {};
|
|
54
|
+
// Helper to create wrapped method
|
|
55
|
+
const createWrappedMethod = (method) => {
|
|
56
|
+
return function (...args) {
|
|
57
|
+
const context = {};
|
|
58
|
+
// Capture pre-mutation context based on method
|
|
59
|
+
switch (method) {
|
|
60
|
+
case 'add': {
|
|
61
|
+
const [value] = args;
|
|
62
|
+
context.addedItem = value;
|
|
63
|
+
//context.existed=true,说明值重复
|
|
64
|
+
context.existed = target.has(value);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'delete': {
|
|
68
|
+
const [value] = args;
|
|
69
|
+
context.existed = target.has(value);
|
|
70
|
+
context.deletedItem = context.existed ? value : undefined;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case 'clear': {
|
|
74
|
+
context.clearedItems = Array.from(target);
|
|
75
|
+
//用来做验证
|
|
76
|
+
context.previousSize = target.size;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Execute before mutation callback
|
|
81
|
+
onBeforeMutate(context);
|
|
82
|
+
// Execute the native Set method
|
|
83
|
+
const result = target[method].apply(target, args);
|
|
84
|
+
// Construct patch object
|
|
85
|
+
const patch = {
|
|
86
|
+
method,
|
|
87
|
+
result,
|
|
88
|
+
args,
|
|
89
|
+
context,
|
|
90
|
+
target,
|
|
91
|
+
...props
|
|
92
|
+
};
|
|
93
|
+
// Execute after mutation callback
|
|
94
|
+
onAfterMutate(patch);
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
// Wrap allowed methods
|
|
99
|
+
for (const method of allowList) {
|
|
100
|
+
if (setMutableMethods.includes(method)) {
|
|
101
|
+
methods[method] = createWrappedMethod(method);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Add target reference
|
|
105
|
+
Object.defineProperty(methods, 'target', {
|
|
106
|
+
get: () => target,
|
|
107
|
+
enumerable: false,
|
|
108
|
+
configurable: false
|
|
109
|
+
});
|
|
110
|
+
return methods;
|
|
111
|
+
};
|
|
112
|
+
export default wrapSetMethods;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since Last modified: 2025/12/22 17:19:21
|
|
3
|
+
* Wraps Set objects with mutation tracking capabilities.
|
|
4
|
+
* Provides hooks for before/after mutation events and captures detailed context
|
|
5
|
+
* for undo/redo or change tracking purposes.
|
|
6
|
+
*
|
|
7
|
+
* @template T - Set element type
|
|
8
|
+
* @param {SetMutationOptions<T>} options - Configuration object containing target Set and callbacks
|
|
9
|
+
* @returns {SetMutationMethods<T>} - Object containing wrapped Set mutation methods
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Basic usage with tracking
|
|
13
|
+
* const set = new Set([1, 2, 3]);
|
|
14
|
+
* const methods = wrapSet({
|
|
15
|
+
* target: set,
|
|
16
|
+
* onAfterMutate: (patch) => {
|
|
17
|
+
* console.log(`Set ${patch.method} called`, patch.context);
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* methods.add(4); // Tracked
|
|
22
|
+
* methods.delete(2); // Tracked
|
|
23
|
+
* methods.clear(); // Tracked
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // With change detection for UI updates
|
|
27
|
+
* const set = new Set<string>();
|
|
28
|
+
* const methods = wrapSet({
|
|
29
|
+
* target: set,
|
|
30
|
+
* onAfterMutate: (patch) => {
|
|
31
|
+
* // Trigger UI update when Set changes
|
|
32
|
+
* if (patch.method === 'add' || patch.method === 'delete') {
|
|
33
|
+
* updateUI(Array.from(patch.target));
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* });
|
|
37
|
+
*/
|
|
38
|
+
'use strict';
|
|
39
|
+
|
|
40
|
+
import setMutableMethods, { SetMutationNames } from "./setMutableMethods";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Context captured before Set mutation for tracking purposes
|
|
44
|
+
*/
|
|
45
|
+
export interface SetMutationContext<T = any> {
|
|
46
|
+
/** For add method: the value being added */
|
|
47
|
+
addedItem?: T;
|
|
48
|
+
/** For add / delete method: whether the value already existed */
|
|
49
|
+
existed?: boolean;
|
|
50
|
+
/** For delete method: the value being deleted */
|
|
51
|
+
deletedItem?: T;
|
|
52
|
+
/** For clear method: snapshot of all values before clearing */
|
|
53
|
+
clearedItems?: T[];
|
|
54
|
+
/** For clear method: size of the Set before clearing */
|
|
55
|
+
previousSize?: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Data object passed to callback after Set mutation
|
|
60
|
+
*/
|
|
61
|
+
export interface SetMutationPatch<T = any> {
|
|
62
|
+
/** The mutation method called */
|
|
63
|
+
method: SetMutationNames;
|
|
64
|
+
/** The result returned by the mutation method */
|
|
65
|
+
result: any;
|
|
66
|
+
/** Arguments passed to the mutation method */
|
|
67
|
+
args: any[];
|
|
68
|
+
/** Context captured before mutation */
|
|
69
|
+
context: SetMutationContext<T>;
|
|
70
|
+
/** Reference to the mutated Set */
|
|
71
|
+
target: Set<T>;
|
|
72
|
+
/** Additional custom properties */
|
|
73
|
+
[key: string]: any;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Configuration options for wrapSet function
|
|
78
|
+
*/
|
|
79
|
+
export interface SetMutationOptions<T = any> {
|
|
80
|
+
/** The Set to wrap with mutation tracking */
|
|
81
|
+
target: Set<T>;
|
|
82
|
+
/** Callback triggered before mutation */
|
|
83
|
+
onBeforeMutate?: (context: SetMutationContext<T>) => void;
|
|
84
|
+
/** Callback triggered after mutation */
|
|
85
|
+
onAfterMutate?: (patch: SetMutationPatch<T>) => void;
|
|
86
|
+
/** Optional list of allowed mutation methods (default: all Set methods) */
|
|
87
|
+
allowList?: SetMutationNames[];
|
|
88
|
+
/** Additional properties to attach to the patch */
|
|
89
|
+
props?: Record<string, any>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Wrapped mutation methods for Set
|
|
94
|
+
*/
|
|
95
|
+
export interface SetMutationMethods<T = any> {
|
|
96
|
+
/**
|
|
97
|
+
* Adds a value to the Set.
|
|
98
|
+
* @param value The value to add
|
|
99
|
+
* @returns The Set object
|
|
100
|
+
*/
|
|
101
|
+
add: (value: T) => Set<T>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Deletes a value from the Set.
|
|
105
|
+
* @param value The value to delete
|
|
106
|
+
* @returns true if the value existed and has been removed, false otherwise
|
|
107
|
+
*/
|
|
108
|
+
delete: (value: T) => boolean;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Clears all values from the Set.
|
|
112
|
+
* @returns void
|
|
113
|
+
*/
|
|
114
|
+
clear: () => void;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Gets the original Set instance for direct access
|
|
118
|
+
*/
|
|
119
|
+
readonly target: Set<T>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Creates wrapped mutation methods for Set with tracking capabilities
|
|
124
|
+
*
|
|
125
|
+
* @param options Configuration options
|
|
126
|
+
* @returns Object containing wrapped Set mutation methods
|
|
127
|
+
* @throws TypeError if target is not a Set
|
|
128
|
+
*/
|
|
129
|
+
const wrapSetMethods = <T = any>({
|
|
130
|
+
target,
|
|
131
|
+
onBeforeMutate = () => { },
|
|
132
|
+
onAfterMutate = () => { },
|
|
133
|
+
allowList = setMutableMethods,
|
|
134
|
+
props = {},
|
|
135
|
+
}: SetMutationOptions<T>): SetMutationMethods<T> => {
|
|
136
|
+
|
|
137
|
+
// Validation: Ensure target is a Set
|
|
138
|
+
if (!(target instanceof Set)) {
|
|
139
|
+
throw new TypeError("The 'target' parameter must be a Set.");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Create method wrappers
|
|
143
|
+
const methods: Partial<SetMutationMethods<T>> = {};
|
|
144
|
+
|
|
145
|
+
// Helper to create wrapped method
|
|
146
|
+
const createWrappedMethod = (method: SetMutationNames) => {
|
|
147
|
+
return function (...args: any[]) {
|
|
148
|
+
const context: SetMutationContext<T> = {};
|
|
149
|
+
|
|
150
|
+
// Capture pre-mutation context based on method
|
|
151
|
+
switch (method) {
|
|
152
|
+
case 'add': {
|
|
153
|
+
const [value] = args as [T];
|
|
154
|
+
context.addedItem = value;
|
|
155
|
+
//context.existed=true,说明值重复
|
|
156
|
+
context.existed = target.has(value);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
case 'delete': {
|
|
161
|
+
const [value] = args as [T];
|
|
162
|
+
context.existed = target.has(value);
|
|
163
|
+
context.deletedItem = context.existed ? value : undefined;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
case 'clear': {
|
|
168
|
+
context.clearedItems = Array.from(target);
|
|
169
|
+
//用来做验证
|
|
170
|
+
context.previousSize = target.size;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Execute before mutation callback
|
|
176
|
+
onBeforeMutate(context);
|
|
177
|
+
|
|
178
|
+
// Execute the native Set method
|
|
179
|
+
const result = (target as any)[method].apply(target, args);
|
|
180
|
+
|
|
181
|
+
// Construct patch object
|
|
182
|
+
const patch: SetMutationPatch<T> = {
|
|
183
|
+
method,
|
|
184
|
+
result,
|
|
185
|
+
args,
|
|
186
|
+
context,
|
|
187
|
+
target,
|
|
188
|
+
...props
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Execute after mutation callback
|
|
192
|
+
onAfterMutate(patch);
|
|
193
|
+
|
|
194
|
+
return result;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Wrap allowed methods
|
|
199
|
+
for (const method of allowList) {
|
|
200
|
+
if (setMutableMethods.includes(method)) {
|
|
201
|
+
(methods as any)[method] = createWrappedMethod(method);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Add target reference
|
|
206
|
+
Object.defineProperty(methods, 'target', {
|
|
207
|
+
get: () => target,
|
|
208
|
+
enumerable: false,
|
|
209
|
+
configurable: false
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return methods as SetMutationMethods<T>;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export default wrapSetMethods;
|