@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/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  All changes to Utils including new features, updates, and removals are documented here.
4
4
 
5
+ ## [v0.0.11] - 2025-12-21
6
+
7
+ ### Distribution Files
8
+ * **JS**: https://unpkg.com/@codady/utils@0.0.11/dist/js/utils.js
9
+ * **Zip**:https://unpkg.com/@codady/utils@0.0.11/dist.zip
10
+
11
+ ### Changes
12
+
13
+ #### Fixed
14
+ * Null
15
+
16
+ #### Added
17
+ * 新增`deepEqual`、`deepMerge`、`deepMergeArrays`、`deepMergeObjects`、`deepMergeSets`、和`deepMegeMaps`函数。
18
+
19
+ #### Removed
20
+ * Null
21
+
22
+
23
+ ## [v0.0.10] - 2025-12-21
24
+
25
+ ### Distribution Files
26
+ * **JS**: https://unpkg.com/@codady/utils@0.0.10/dist/js/utils.js
27
+ * **Zip**:https://unpkg.com/@codady/utils@0.0.10/dist.zip
28
+
29
+ ### Changes
30
+
31
+ #### Fixed
32
+ * Modified the `getUniqueId` parameter structure, changing the `extra` parameter to `base10`, and adding a `base36` parameter.修改了`getUniqueId`的参数结构,extra参数改为base10,新增base36参数。
33
+ * Modified the `deepClone` function, adding an `options` parameter. By default, it does not copy reference types like `Date`, `Function`, `RegExp`, etc.修改了`deepClone`函数,增加options参数,默认不复制Date、Function、RegExp等引用类型数据。
34
+ * Changed `mutableMethods` to `arrayMutableMethods`.将`mutableMethods`改为`arrayMutableMethods`。
35
+
36
+ #### Added
37
+ * Added `setMutableMethods` and `mapMutableMethods` variables.新增`setMutableMethods`和`mapMutableMethods`变量。
38
+ * Added `wrapSetMethods` and `wrapMapMethods` functions.新增`wrapSetMethods`和`wrapMapMethods`函数。
39
+
40
+ #### Removed
41
+ * Null
42
+
5
43
 
6
44
  ## [v0.0.7] - 2025-12-19
7
45
 
package/dist/utils.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-19 15:23:38
3
+ * @since Last modified: 2025-12-24 17:50:8
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.9
5
+ * @version 0.0.11
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}
@@ -16,6 +16,8 @@
16
16
 
17
17
  'use strict';
18
18
 
19
+ var assert = require('assert');
20
+
19
21
  const getDataType = (obj) => {
20
22
  let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
21
23
  if (tmp === 'Function' && /^\s*class\s+/.test(obj.toString())) {
@@ -41,37 +43,100 @@ const getDataType = (obj) => {
41
43
  //document.createElementNS('http://www.w3.org/1998/Math/MathML', 'math'); -> MathMLElement
42
44
  };
43
45
 
44
- const deepClone = (data) => {
45
- const dataType = getDataType(data);
46
- if (dataType === 'Object') {
47
- const newObj = {};
48
- const symbols = Object.getOwnPropertySymbols(data);
46
+ //支持原始值的复制,包括Number、String、Boolean、Null
47
+ //支持Date和Regex对象值复制(值转换)
48
+ //支持{},[],Set和Map的遍历
49
+ const deepClone = (data, options = {}) => {
50
+ const dataType = getDataType(data),
51
+ // Default options
52
+ opts = Object.assign({
53
+ cloneSet: true,
54
+ cloneMap: true,
55
+ cloneObject: true,
56
+ cloneArray: true,
57
+ //可重新构建
58
+ cloneDate: true,
59
+ cloneRegex: true,
60
+ //节点默认不复制
61
+ //cloneElement: false,
62
+ //cloneFragment: false,
63
+ }, options);
64
+ // Check interceptor - if it returns a value (not null/undefined), use it directly
65
+ if (opts.interceptor && typeof opts.interceptor === 'function') {
66
+ let result = opts.interceptor(data, dataType);
67
+ if ((result ?? false)) {
68
+ // Call onAfterClone if set
69
+ opts.onAfterClone?.({
70
+ output: result,
71
+ input: data,
72
+ type: dataType,
73
+ cloned: result !== data,
74
+ });
75
+ return result;
76
+ }
77
+ // If interceptor returns null/undefined, continue with normal cloning process
78
+ }
79
+ // Callback before cloning
80
+ opts.onBeforeClone?.(data, dataType);
81
+ let newData, cloned = true;
82
+ if (dataType === 'Object' && opts.cloneObject) {
83
+ const newObj = {}, symbols = Object.getOwnPropertySymbols(data);
49
84
  // Clone regular properties
50
85
  for (const key in data) {
51
- newObj[key] = deepClone(data[key]);
86
+ newObj[key] = deepClone(data[key], opts);
52
87
  }
53
88
  // Clone Symbol properties
54
89
  if (symbols.length > 0) {
55
90
  for (const symbol of symbols) {
56
- newObj[symbol] = deepClone(data[symbol]);
91
+ newObj[symbol] = deepClone(data[symbol], opts);
57
92
  }
58
93
  }
59
- return newObj;
94
+ newData = newObj;
60
95
  }
61
- else if (dataType === 'Array') {
62
- return data.map(item => deepClone(item));
96
+ else if (dataType === 'Array' && opts.cloneArray) {
97
+ newData = data.map(item => deepClone(item, opts));
98
+ }
99
+ else if (dataType === 'Map' && opts.cloneMap) {
100
+ const newMap = new Map();
101
+ for (const [key, value] of data) {
102
+ // Both Map keys and values need deep cloning
103
+ newMap.set(deepClone(key, opts), deepClone(value, opts));
104
+ }
105
+ newData = newMap;
63
106
  }
64
- else if (dataType === 'Date') {
65
- return new Date(data.getTime());
107
+ else if (dataType === 'Set' && opts.cloneSet) {
108
+ const newSet = new Set();
109
+ for (const value of data) {
110
+ // Set values need deep cloning
111
+ newSet.add(deepClone(value, opts));
112
+ }
113
+ newData = newSet;
66
114
  }
67
- else if (dataType === 'RegExp') {
115
+ else if (dataType === 'Date' && opts.cloneDate) {
116
+ newData = new Date(data.getTime());
117
+ }
118
+ else if (dataType === 'RegExp' && opts.cloneRegex) {
68
119
  const regex = data;
69
- return new RegExp(regex.source, regex.flags);
120
+ newData = new RegExp(regex.source, regex.flags);
121
+ // } else if ((dataType.includes('HTML') && opts.cloneElement) ||
122
+ // (dataType === 'DocumentFragment' && opts.cloneFragment)
123
+ //) {
124
+ //Text,Comment,HTML*Element,DocumentFragment,Attr
125
+ // newData = (data as any).cloneNode(true) as T;
70
126
  }
71
127
  else {
72
- // Number, String, Boolean, Symbol,Text,Comment,Set,Map, HTML*Element, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
73
- return data;
128
+ // Number, String, Boolean, Symbol, Function,Error,Promise,ArrayBuffer,Blob,File, return directly
129
+ newData = data;
130
+ cloned = false;
74
131
  }
132
+ // Callback after cloning
133
+ opts.onAfterClone?.({
134
+ output: newData,
135
+ input: data,
136
+ type: dataType,
137
+ cloned,
138
+ });
139
+ return newData;
75
140
  };
76
141
 
77
142
  const deepCloneToJSON = (data) => {
@@ -102,7 +167,7 @@ const deepCloneToJSON = (data) => {
102
167
  }
103
168
  };
104
169
 
105
- const mutableMethods = [
170
+ const arrayMutableMethods = [
106
171
  'push', 'pop', 'shift', 'unshift', 'splice',
107
172
  'sort', 'reverse', 'copyWithin', 'fill'
108
173
  ];
@@ -114,7 +179,7 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
114
179
  }
115
180
  //使用默认
116
181
  if (!allowList || allowList?.length) {
117
- allowList = mutableMethods;
182
+ allowList = arrayMutableMethods;
118
183
  }
119
184
  const methods = {};
120
185
  for (let method of allowList) {
@@ -130,10 +195,10 @@ const wrapArrayMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate =
130
195
  context.addedItems = [...args];
131
196
  break;
132
197
  case 'pop':
133
- context.poppedValue = target[len - 1];
198
+ context.poppedItem = target[len - 1];
134
199
  break;
135
200
  case 'shift':
136
- context.shiftedValue = target[0];
201
+ context.shiftedItem = target[0];
137
202
  break;
138
203
  case 'splice':
139
204
  const [s, d] = args,
@@ -203,20 +268,405 @@ const requireTypes = (data, require, cb) => {
203
268
  return dataType;
204
269
  };
205
270
 
206
- const getUniqueId = (prefix, extra = true) => {
271
+ const getUniqueId = (options = {}) => {
272
+ const prefix = options.prefix, suffix = options.suffix, base10 = options.base10, base36 = options.base36;
207
273
  // Current timestamp in milliseconds (since Unix epoch)
208
274
  // This provides the primary uniqueness guarantee
209
275
  const timestamp = Date.now(),
210
276
  // Generate a base-36 random string (0-9, a-z)
211
277
  // Math.random() returns a number in [0, 1), converting to base-36 gives a compact representation
212
278
  // substring(2, 11) extracts 9 characters starting from index 2
213
- random = Math.random().toString(36).substring(2, 11),
279
+ //0.259854635->0.9crs03e8v2
280
+ base36Random = base36 ? '-' + Math.random().toString(36).substring(2, 11) : '',
214
281
  // Additional 4-digit random number for extra randomness
215
282
  // This helps avoid collisions in high-frequency generation scenarios
216
- extraRandom = extra ? '_' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '_' : '';
283
+ base10Random = base10 ? '-' + Math.floor(Math.random() * 10000).toString().padStart(4, '0') : '', prefixString = prefix ? prefix + '-' : '', suffixString = suffix ? '-' + suffix : '';
217
284
  // Construct the final ID string
218
285
  // Format: [prefix_]timestamp_randomBase36_extraRandom
219
- return `${prefixString}${timestamp}_${random}${extraRandom}`;
286
+ return `${prefixString}${timestamp}${base36Random}${base10Random}${suffixString}`;
287
+ };
288
+
289
+ const setMutableMethods = ['add', 'delete', 'clear'];
290
+
291
+ const mapMutableMethods = ['set', 'delete', 'clear'];
292
+
293
+ const wrapSetMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList = setMutableMethods, props = {}, }) => {
294
+ // Validation: Ensure target is a Set
295
+ if (!(target instanceof Set)) {
296
+ throw new TypeError("The 'target' parameter must be a Set.");
297
+ }
298
+ // Create method wrappers
299
+ const methods = {};
300
+ // Helper to create wrapped method
301
+ const createWrappedMethod = (method) => {
302
+ return function (...args) {
303
+ const context = {};
304
+ // Capture pre-mutation context based on method
305
+ switch (method) {
306
+ case 'add': {
307
+ const [value] = args;
308
+ context.addedItem = value;
309
+ //context.existed=true,说明值重复
310
+ context.existed = target.has(value);
311
+ break;
312
+ }
313
+ case 'delete': {
314
+ const [value] = args;
315
+ context.existed = target.has(value);
316
+ context.deletedItem = context.existed ? value : undefined;
317
+ break;
318
+ }
319
+ case 'clear': {
320
+ context.clearedItems = Array.from(target);
321
+ //用来做验证
322
+ context.previousSize = target.size;
323
+ break;
324
+ }
325
+ }
326
+ // Execute before mutation callback
327
+ onBeforeMutate(context);
328
+ // Execute the native Set method
329
+ const result = target[method].apply(target, args);
330
+ // Construct patch object
331
+ const patch = {
332
+ method,
333
+ result,
334
+ args,
335
+ context,
336
+ target,
337
+ ...props
338
+ };
339
+ // Execute after mutation callback
340
+ onAfterMutate(patch);
341
+ return result;
342
+ };
343
+ };
344
+ // Wrap allowed methods
345
+ for (const method of allowList) {
346
+ if (setMutableMethods.includes(method)) {
347
+ methods[method] = createWrappedMethod(method);
348
+ }
349
+ }
350
+ // Add target reference
351
+ Object.defineProperty(methods, 'target', {
352
+ get: () => target,
353
+ enumerable: false,
354
+ configurable: false
355
+ });
356
+ return methods;
357
+ };
358
+
359
+ const wrapMapMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = () => { }, allowList = mapMutableMethods, props = {}, }) => {
360
+ // Validation: Ensure target is a Map
361
+ if (!(target instanceof Map)) {
362
+ throw new TypeError("The 'target' parameter must be a Map.");
363
+ }
364
+ // Create method wrappers
365
+ const methods = {};
366
+ // Helper to create wrapped method
367
+ const createWrappedMethod = (method) => {
368
+ return function (...args) {
369
+ const context = {};
370
+ // Capture pre-mutation context based on method
371
+ switch (method) {
372
+ case 'set': {
373
+ const [key, newValue] = args;
374
+ context.key = key;
375
+ context.newValue = newValue;
376
+ context.existed = target.has(key);
377
+ context.oldValue = context.existed ? target.get(key) : undefined;
378
+ break;
379
+ }
380
+ case 'delete': {
381
+ const [key] = args;
382
+ context.key = key;
383
+ context.existed = target.has(key);
384
+ context.value = context.existed ? target.get(key) : undefined;
385
+ break;
386
+ }
387
+ case 'clear': {
388
+ context.clearedItems = Array.from(target.entries());
389
+ //用来做验证
390
+ context.previousSize = target.size;
391
+ break;
392
+ }
393
+ }
394
+ // Execute before mutation callback
395
+ onBeforeMutate(context);
396
+ // Execute the native Map method
397
+ const result = target[method].apply(target, args);
398
+ // Construct patch object
399
+ const patch = {
400
+ method,
401
+ result,
402
+ args,
403
+ context,
404
+ target,
405
+ ...props
406
+ };
407
+ // Execute after mutation callback
408
+ onAfterMutate(patch);
409
+ return result;
410
+ };
411
+ };
412
+ // Wrap allowed methods
413
+ for (const method of allowList) {
414
+ if (mapMutableMethods.includes(method)) {
415
+ methods[method] = createWrappedMethod(method);
416
+ }
417
+ }
418
+ // Add target reference
419
+ Object.defineProperty(methods, 'target', {
420
+ get: () => target,
421
+ enumerable: false,
422
+ configurable: false
423
+ });
424
+ return methods;
425
+ };
426
+
427
+ const deepMergeObjects = (target, source, opts = {}) => {
428
+ let targetType = getDataType(target), sourceType = getDataType(source);
429
+ //target不是对象或者source为空则直接返回
430
+ if (targetType !== 'Object' || sourceType !== 'Object') {
431
+ return target;
432
+ }
433
+ const options = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, opts),
434
+ //如果是复制方法,则先复制target
435
+ result = options.targetClone ? deepClone(target) : target;
436
+ for (let k in source) {
437
+ if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
438
+ let resp = deepMergeHelper(result[k], source[k], opts);
439
+ //resp={result,flag,type}
440
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
441
+ if (!resp.flag) {
442
+ //类型不同则直接覆盖
443
+ if (options.useEnable && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
444
+ //部分替换,仅针对result={enable:true/false,a:''},source=false/true这种情况和相反的情况,因为这种情况再笨框架比较多见
445
+ if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
446
+ //result={enable:true,a:'',b:''},source[k]=false=>result={enable:false,a:'',b:''}
447
+ result[k].enable = source[k];
448
+ }
449
+ else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
450
+ //source={enable:true,a:'',b:''},(result as any)[k]=false=>result={enable:false,a:'',b:''}
451
+ result = Object.assign({ enable: result[k] }, source[k]);
452
+ }
453
+ else {
454
+ //完全替换
455
+ result[k] = source[k];
456
+ }
457
+ }
458
+ else {
459
+ //完全替换
460
+ result[k] = source[k];
461
+ }
462
+ }
463
+ else {
464
+ // If both target and source are objects, merge them recursively
465
+ if (resp.type === 'Object') {
466
+ result[k] = resp.result;
467
+ }
468
+ }
469
+ }
470
+ else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
471
+ //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
472
+ result[k] = source[k];
473
+ }
474
+ }
475
+ //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
476
+ if (options.useSymbol) {
477
+ let symbols = Object.getOwnPropertySymbols(source);
478
+ if (symbols.length > 0) {
479
+ for (let k of symbols) {
480
+ result[k] = source[k];
481
+ }
482
+ }
483
+ }
484
+ return result;
485
+ };
486
+
487
+ const deepMergeArrays = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
488
+ // Ensure both target and source are arrays
489
+ if (!Array.isArray(target) || !Array.isArray(source))
490
+ return target;
491
+ // Merge options, with default values
492
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false }, options),
493
+ // If cloning is enabled, create a deep copy of the target array
494
+ result = opts.targetClone ? [...target] : target;
495
+ // Handle different merge strategies based on itemMode
496
+ if (opts.itemMode === 'replace') {
497
+ // Replace mode: clear the target array and push all items from the source array
498
+ result.length = 0;
499
+ result.push(...source);
500
+ return result;
501
+ }
502
+ else if (opts.itemMode === 'concat') {
503
+ // Concatenate mode: append all items from the source array to the target array
504
+ result.push(...source);
505
+ return result;
506
+ }
507
+ else {
508
+ // Default "merge" mode: recursively merge items in the arrays
509
+ for (let i = 0; i < source.length; i++) {
510
+ let resp = deepMergeHelper(result[i], source[i], opts);
511
+ //resp={result,flag,type}
512
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
513
+ if (!resp.flag) {
514
+ result[i] = source[i];
515
+ }
516
+ }
517
+ return result;
518
+ }
519
+ };
520
+
521
+ const deepMergeMaps = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
522
+ // Ensure both target and source are Maps
523
+ if (!(target instanceof Map) || !(source instanceof Map))
524
+ return target;
525
+ // Merge options, with default values
526
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
527
+ // If cloning is enabled, create a deep copy of the target Map
528
+ result = opts.targetClone ? new Map(target) : target;
529
+ // Handle different merge strategies based on itemMode
530
+ if (opts.itemMode === 'replace') {
531
+ // Replace mode: clear the target Map and add all entries from the source Map
532
+ result.clear();
533
+ source.forEach((value, key) => result.set(key, value));
534
+ return result;
535
+ }
536
+ else if (opts.itemMode === 'concat') {
537
+ // Concatenate mode: add all entries from the source Map to the target Map
538
+ source.forEach((value, key) => result.set(key, value));
539
+ return result;
540
+ }
541
+ else {
542
+ // Default "merge" mode: recursively merge entries in the Maps
543
+ source.forEach((value, key) => {
544
+ // Check if the key already exists in the target Map
545
+ if (result.has(key)) {
546
+ const targetValue = result.get(key), sourceValue = value, resp = deepMergeHelper(targetValue, sourceValue, opts);
547
+ //resp={result,flag,type}
548
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
549
+ if (!resp.flag) {
550
+ // For simple values, overwrite the target value with the source value
551
+ result.set(key, sourceValue);
552
+ }
553
+ else {
554
+ // If both target and source are objects, merge them recursively
555
+ resp.type === 'Object' && result.set(key, resp.result);
556
+ }
557
+ }
558
+ else {
559
+ // If the key doesn't exist in the target, add the entry from the source Map
560
+ result.set(key, value);
561
+ }
562
+ });
563
+ return result;
564
+ }
565
+ };
566
+
567
+ const deepEqual = (a, b) => {
568
+ // If both are equal by reference
569
+ if (a === b)
570
+ return true;
571
+ // If both are arrays, check equality recursively
572
+ if (Array.isArray(a) && Array.isArray(b)) {
573
+ if (a.length !== b.length)
574
+ return false;
575
+ for (let i = 0; i < a.length; i++) {
576
+ if (!deepEqual(a[i], b[i]))
577
+ return false;
578
+ }
579
+ return true;
580
+ }
581
+ // If both are objects, check equality recursively
582
+ if (typeof a === 'object' && typeof b === 'object') {
583
+ const keysA = Object.keys(a), keysB = Object.keys(b);
584
+ if (keysA.length !== keysB.length)
585
+ return false;
586
+ for (let key of keysA) {
587
+ if (!keysB.includes(key) || !deepEqual(a[key], b[key]))
588
+ return false;
589
+ }
590
+ return true;
591
+ }
592
+ // For other types, direct comparison
593
+ return a === b;
594
+ };
595
+
596
+ const deepMergeSets = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
597
+ // Ensure both target and source are Sets
598
+ if (!(target instanceof Set) || !(source instanceof Set))
599
+ return target;
600
+ // Merge options, with default values
601
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
602
+ // If cloning is enabled, create a deep copy of the target Set
603
+ result = opts.targetClone ? new Set(target) : target;
604
+ // Handle different merge strategies based on itemMode
605
+ if (opts.itemMode === 'replace') {
606
+ // Replace mode: clear the target Set and add all items from the source Set
607
+ result.clear();
608
+ for (let item of source)
609
+ result.add(item);
610
+ return result;
611
+ }
612
+ else if (opts.itemMode === 'concat') {
613
+ // Concatenate mode: add all items from the source Set to the target Set
614
+ for (let item of source)
615
+ result.add(item);
616
+ return result;
617
+ }
618
+ else {
619
+ // Default "merge" mode: recursively merge items in the Sets
620
+ for (let item of source) {
621
+ // Check the type of the target and source items
622
+ let _target = [...result].find(val => deepEqual(val, item)), resp = deepMergeHelper(_target, item, opts);
623
+ //resp={result,flag}
624
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
625
+ !resp.flag && result.add(item);
626
+ }
627
+ return result;
628
+ }
629
+ };
630
+
631
+ // deepMergeHelper.ts
632
+
633
+
634
+ const deepMergeHelper = (target, source, options) => {
635
+ let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
636
+ if (targetType === 'Object' && sourceType === 'Object') {
637
+ result = deepMergeObjects(target, source, options);
638
+ type = 'Object';
639
+ }
640
+ else if (targetType === 'Array' && sourceType === 'Array') {
641
+ result = deepMergeArrays(target, source, options);
642
+ type = 'Array';
643
+ }
644
+ else if (targetType === 'Set' && sourceType === 'Set') {
645
+ result = deepMergeSets(target, source, options);
646
+ type = 'Set';
647
+ }
648
+ else if (targetType === 'Map' && sourceType === 'Map') {
649
+ result = deepMergeMaps(target, source, options);
650
+ type = 'Map';
651
+ }
652
+ else {
653
+ flag = false;
654
+ result = target; // Default case, replace primitive values
655
+ }
656
+ return {
657
+ result, flag, type
658
+ };
659
+ };
660
+
661
+ const deepMerge = (target, source, opts = {}) => {
662
+ // Get the data types of the target and source
663
+ let options = Object.assign({
664
+ itemMode: 'merge', // Default merge mode
665
+ propAppend: true, // Default to appending properties from source to target
666
+ targetClone: false, // Do not clone target by default
667
+ useEnable: true // Enable special handling for objects with an `enable` property
668
+ }, opts);
669
+ return deepMergeHelper(target, source, options);
220
670
  };
221
671
 
222
672
  const utils = {
@@ -228,8 +678,18 @@ const utils = {
228
678
  deepClone,
229
679
  deepCloneToJSON,
230
680
  wrapArrayMethods,
231
- mutableMethods,
232
- getUniqueId
681
+ arrayMutableMethods,
682
+ setMutableMethods,
683
+ mapMutableMethods,
684
+ wrapSetMethods,
685
+ wrapMapMethods,
686
+ getUniqueId,
687
+ deepEqual: assert.deepEqual,
688
+ deepMerge,
689
+ deepMergeArrays,
690
+ deepMergeMaps,
691
+ deepMergeObjects,
692
+ deepMergeSets,
233
693
  };
234
694
 
235
695
  module.exports = utils;