@codady/utils 0.0.11 → 0.0.12
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 +22 -2
- package/dist/utils.cjs.js +231 -213
- package/dist/utils.cjs.min.js +3 -3
- package/dist/utils.esm.js +231 -213
- package/dist/utils.esm.min.js +3 -3
- package/dist/utils.umd.js +235 -215
- package/dist/utils.umd.min.js +3 -3
- package/dist.zip +0 -0
- package/examples/deepMerge.html +1049 -0
- package/modules.js +3 -11
- package/modules.ts +5 -7
- package/package.json +1 -1
- package/src/deepEqual.js +1 -1
- package/src/deepEqual.ts +1 -1
- package/src/deepMerge.js +253 -13
- package/src/deepMerge.ts +306 -18
- package/src/deepMergeHelper.js +1 -3
- package/src/deepMergeHelper.ts +1 -3
- package/src/deepMergeMaps.js +4 -4
- package/src/deepMergeMaps.ts +6 -6
- package/src/deepMergeObjects.js +11 -4
- package/src/deepMergeObjects.ts +10 -4
- package/src/deepMergeSets.js +5 -10
- package/src/deepMergeSets.ts +6 -9
- package/src/mapMutableMethods - /345/211/257/346/234/254.js" +5 -0
- package/src/shallowCopy.js +46 -0
- package/src/shallowCopy.ts +55 -0
package/dist/utils.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* @since Last modified: 2025-12-
|
|
3
|
+
* @since Last modified: 2025-12-25 12:10:38
|
|
4
4
|
* @name Utils for web front-end.
|
|
5
|
-
* @version 0.0.
|
|
5
|
+
* @version 0.0.12
|
|
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}
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
(function (global, factory) {
|
|
18
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(
|
|
19
|
-
typeof define === 'function' && define.amd ? define(
|
|
20
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.utils = factory(
|
|
21
|
-
})(this, (function (
|
|
18
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
19
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
20
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.utils = factory());
|
|
21
|
+
})(this, (function () { 'use strict';
|
|
22
22
|
|
|
23
23
|
const getDataType = (obj) => {
|
|
24
24
|
let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
|
|
@@ -426,31 +426,139 @@
|
|
|
426
426
|
return methods;
|
|
427
427
|
};
|
|
428
428
|
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
//
|
|
432
|
-
if (
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
429
|
+
const shallowCopy = (data) => {
|
|
430
|
+
const dataType = getDataType(data);
|
|
431
|
+
// Check if data is a Set
|
|
432
|
+
if (dataType === 'Set') {
|
|
433
|
+
// Shallow copy Set
|
|
434
|
+
return new Set([...data]);
|
|
435
|
+
}
|
|
436
|
+
// Check if data is a Map
|
|
437
|
+
if (dataType === 'Map') {
|
|
438
|
+
// Shallow copy Map
|
|
439
|
+
return new Map([...data]);
|
|
440
|
+
}
|
|
441
|
+
// Check if data is an Array
|
|
442
|
+
if (Array.isArray(data)) {
|
|
443
|
+
// Shallow copy Array
|
|
444
|
+
return [...data];
|
|
445
|
+
}
|
|
446
|
+
// Check if data is a Plain Object (including Symbol keys)
|
|
447
|
+
if (dataType === 'object') {
|
|
448
|
+
const obj = data; // Ensure the object type includes string and symbol keys
|
|
449
|
+
const symbolProperties = Object.getOwnPropertySymbols(obj).reduce((acc, sym) => {
|
|
450
|
+
acc[sym] = obj[sym];
|
|
451
|
+
return acc;
|
|
452
|
+
}, {});
|
|
453
|
+
// Shallow copy the object and include the Symbol properties
|
|
454
|
+
return { ...obj, ...symbolProperties };
|
|
455
|
+
}
|
|
456
|
+
// For other types (such as numbers, strings, booleans, etc.), return the original value
|
|
457
|
+
return data;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const deepMerge = (target, source, opts = {}) => {
|
|
461
|
+
// Set default options
|
|
462
|
+
// 设置默认选项
|
|
463
|
+
const options = Object.assign({
|
|
464
|
+
// Merging mode for array and set collections:
|
|
465
|
+
// 'clear' means clear first then append; 'concat' means append directly at the end;
|
|
466
|
+
// 'replace' means merge sequentially (deep merging)
|
|
467
|
+
// 对于array和set合集的合并方式:'clear'表示先清空再追加;'concat'表示直接在尾部追加;
|
|
468
|
+
// 'replace'表示按顺序进行合并(深度合并)
|
|
469
|
+
dataMode: 'clear',
|
|
470
|
+
// Whether to directly append properties/items from source that target doesn't have.
|
|
471
|
+
// true: append; false: discard
|
|
472
|
+
// source对象如果有target对象没有的item或prop属性,是否直接新追加。true则追加;false则丢弃
|
|
473
|
+
inheritMissing: true,
|
|
474
|
+
// Whether to clone the target object, generating a brand new object. Default false.
|
|
475
|
+
// 是否克隆target对象,生成全新对象,默认false。
|
|
476
|
+
targetClone: false,
|
|
477
|
+
// How to merge when target or source has enable property and boolean value into {enable:boolean}
|
|
478
|
+
// 当target或source有enable属性(prop)和boolean值时,如何合并为{enable:boolean}
|
|
479
|
+
useEnable: true,
|
|
480
|
+
// Whether to allow merging key=symbol key-value pairs when target is {} type.
|
|
481
|
+
// target是{}类型时,是否允许合并key=symbol的键值对。
|
|
482
|
+
useSymbol: true,
|
|
483
|
+
// Options passed to the deepClone function when targetClone is true
|
|
484
|
+
// 当targetClone为true时传递给deepClone函数的选项
|
|
485
|
+
deepClone: {},
|
|
486
|
+
// Callback function executed before merging each data structure
|
|
487
|
+
// 在每个数据结构合并前执行的回调函数
|
|
488
|
+
onBeforeMerge: undefined,
|
|
489
|
+
// Callback function executed after merging each data structure
|
|
490
|
+
// 在每个数据结构合并后执行的回调函数
|
|
491
|
+
onAfterMerge: undefined,
|
|
492
|
+
}, opts),
|
|
493
|
+
// Main helper function for recursive merging
|
|
494
|
+
// 递归合并的主辅助函数
|
|
495
|
+
deepMergeHelper = (target, source, options) => {
|
|
496
|
+
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
|
|
497
|
+
// Determine the type and perform appropriate merging
|
|
498
|
+
// 确定类型并执行相应的合并
|
|
499
|
+
if (targetType === 'Object' && sourceType === 'Object') {
|
|
500
|
+
result = deepMergeObjects(target, source, options);
|
|
501
|
+
type = 'Object';
|
|
502
|
+
}
|
|
503
|
+
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
504
|
+
result = deepMergeArrays(target, source, options);
|
|
505
|
+
type = 'Array';
|
|
506
|
+
}
|
|
507
|
+
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
508
|
+
result = deepMergeSets(target, source, options);
|
|
509
|
+
type = 'Set';
|
|
510
|
+
}
|
|
511
|
+
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
512
|
+
result = deepMergeMaps(target, source, options);
|
|
513
|
+
type = 'Map';
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
flag = false;
|
|
517
|
+
result = target;
|
|
518
|
+
}
|
|
519
|
+
return { result, flag, type };
|
|
520
|
+
},
|
|
521
|
+
// Special handling for objects with enable property
|
|
522
|
+
// 对具有enable属性的对象进行特殊处理
|
|
523
|
+
mergeEnableObject = (target, source) => {
|
|
524
|
+
if (target?.hasOwnProperty('enable') && typeof source === 'boolean') {
|
|
525
|
+
//result={enable:true,a:'',b:''},source[k]=false=>result={enable:false,a:'',b:''}
|
|
526
|
+
//仅设置enable属性
|
|
527
|
+
target.enable = source;
|
|
528
|
+
//返回target原对象
|
|
529
|
+
return target;
|
|
530
|
+
}
|
|
531
|
+
else if (source?.hasOwnProperty('enable') && typeof target === 'boolean') {
|
|
532
|
+
//source={enable:true,a:'',b:''},(result as any)[k]=false=>result={enable:false,a:'',b:''}
|
|
533
|
+
//返回新值,新值包含enable属性
|
|
534
|
+
return Object.assign({ enable: target }, source);
|
|
535
|
+
}
|
|
536
|
+
return source;
|
|
537
|
+
},
|
|
538
|
+
// Deep merge for objects
|
|
539
|
+
// 对象的深度合并
|
|
540
|
+
deepMergeObjects = (target, source, opts = {}) => {
|
|
541
|
+
let targetType = getDataType(target), sourceType = getDataType(source);
|
|
542
|
+
// If target is not an object or source is empty, return target directly
|
|
543
|
+
// 如果target不是对象或者source为空则直接返回
|
|
544
|
+
if (targetType !== 'Object' || sourceType !== 'Object') {
|
|
545
|
+
return target;
|
|
546
|
+
}
|
|
547
|
+
opts?.onBeforeMerge?.(target, source);
|
|
548
|
+
const options = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, opts);
|
|
549
|
+
let result = {};
|
|
550
|
+
// If cloning is enabled, clone the target first
|
|
551
|
+
// 如果是复制方法,则先复制target
|
|
552
|
+
result = options.targetClone ? shallowCopy(target) : target;
|
|
553
|
+
for (let k in source) {
|
|
554
|
+
if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
|
|
555
|
+
let resp = deepMergeHelper(result[k], source[k], opts);
|
|
556
|
+
//resp={result,flag,type}
|
|
557
|
+
//flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
|
|
558
|
+
if (!resp.flag) {
|
|
559
|
+
//类型不同则直接覆盖
|
|
560
|
+
if (options.useEnable) {
|
|
561
|
+
result[k] = mergeEnableObject(result[k], source[k]);
|
|
454
562
|
}
|
|
455
563
|
else {
|
|
456
564
|
//完全替换
|
|
@@ -458,99 +566,89 @@
|
|
|
458
566
|
}
|
|
459
567
|
}
|
|
460
568
|
else {
|
|
461
|
-
|
|
462
|
-
|
|
569
|
+
//类型相同
|
|
570
|
+
if (resp.type) {
|
|
571
|
+
if (resp.type === 'Object') {
|
|
572
|
+
//如果遇上对象则深度复制
|
|
573
|
+
result[k] = resp.result;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
//其他类型则直接覆盖
|
|
578
|
+
result[k] = source[k];
|
|
579
|
+
}
|
|
463
580
|
}
|
|
464
581
|
}
|
|
465
|
-
else {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
result[k] = resp.result;
|
|
469
|
-
}
|
|
582
|
+
else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.inheritMissing) {
|
|
583
|
+
//如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
|
|
584
|
+
result[k] = source[k];
|
|
470
585
|
}
|
|
471
586
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (options.useSymbol) {
|
|
479
|
-
let symbols = Object.getOwnPropertySymbols(source);
|
|
480
|
-
if (symbols.length > 0) {
|
|
481
|
-
for (let k of symbols) {
|
|
482
|
-
result[k] = source[k];
|
|
587
|
+
//Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
|
|
588
|
+
if (options.useSymbol) {
|
|
589
|
+
let symbols = Object.getOwnPropertySymbols(source);
|
|
590
|
+
if (symbols.length) {
|
|
591
|
+
for (let k of symbols)
|
|
592
|
+
result[k] = source[k];
|
|
483
593
|
}
|
|
484
594
|
}
|
|
485
|
-
|
|
486
|
-
return result;
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
const deepMergeArrays = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
|
|
490
|
-
// Ensure both target and source are arrays
|
|
491
|
-
if (!Array.isArray(target) || !Array.isArray(source))
|
|
492
|
-
return target;
|
|
493
|
-
// Merge options, with default values
|
|
494
|
-
const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false }, options),
|
|
495
|
-
// If cloning is enabled, create a deep copy of the target array
|
|
496
|
-
result = opts.targetClone ? [...target] : target;
|
|
497
|
-
// Handle different merge strategies based on itemMode
|
|
498
|
-
if (opts.itemMode === 'replace') {
|
|
499
|
-
// Replace mode: clear the target array and push all items from the source array
|
|
500
|
-
result.length = 0;
|
|
501
|
-
result.push(...source);
|
|
502
|
-
return result;
|
|
503
|
-
}
|
|
504
|
-
else if (opts.itemMode === 'concat') {
|
|
505
|
-
// Concatenate mode: append all items from the source array to the target array
|
|
506
|
-
result.push(...source);
|
|
595
|
+
options?.onAfterMerge?.(result, target, source);
|
|
507
596
|
return result;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
597
|
+
}, deepMergeArrays = (target, source, options = {}) => {
|
|
598
|
+
// Ensure both target and source are arrays
|
|
599
|
+
if (!Array.isArray(target) || !Array.isArray(source))
|
|
600
|
+
return target;
|
|
601
|
+
options?.onBeforeMerge?.(target, source);
|
|
602
|
+
// Merge options, with default values
|
|
603
|
+
const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false }, options),
|
|
604
|
+
// If cloning is enabled, create a deep copy of the target array
|
|
605
|
+
result = opts.targetClone ? [...target] : target;
|
|
606
|
+
// Handle different merge strategies based on dataMode
|
|
607
|
+
if (opts.dataMode === 'replace') {
|
|
608
|
+
// "replace" mode: recursively merge items in the arrays
|
|
609
|
+
for (let i = 0; i < source.length; i++) {
|
|
610
|
+
// If not allowed to add beyond length
|
|
611
|
+
// 如果不允许添加超过长度
|
|
612
|
+
if (!opts.inheritMissing && i >= result.length)
|
|
613
|
+
break;
|
|
614
|
+
let resp = deepMergeHelper(result[i], source[i], opts);
|
|
615
|
+
//resp={result,flag,type}
|
|
616
|
+
//flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
|
|
617
|
+
if (!resp.flag) {
|
|
618
|
+
result[i] = source[i];
|
|
619
|
+
}
|
|
517
620
|
}
|
|
518
621
|
}
|
|
622
|
+
else if (opts.dataMode === 'concat') {
|
|
623
|
+
// Concatenate mode: append all items from the source array to the target array
|
|
624
|
+
result.push(...source);
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
//Default replace mode: clear the target array and push all items from the source array
|
|
628
|
+
result.length = 0;
|
|
629
|
+
result.push(...source);
|
|
630
|
+
}
|
|
631
|
+
options?.onAfterMerge?.(result, target, source);
|
|
519
632
|
return result;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
// If cloning is enabled, create a deep copy of the target Map
|
|
530
|
-
result = opts.targetClone ? new Map(target) : target;
|
|
531
|
-
// Handle different merge strategies based on itemMode
|
|
532
|
-
if (opts.itemMode === 'replace') {
|
|
533
|
-
// Replace mode: clear the target Map and add all entries from the source Map
|
|
534
|
-
result.clear();
|
|
535
|
-
source.forEach((value, key) => result.set(key, value));
|
|
536
|
-
return result;
|
|
537
|
-
}
|
|
538
|
-
else if (opts.itemMode === 'concat') {
|
|
539
|
-
// Concatenate mode: add all entries from the source Map to the target Map
|
|
540
|
-
source.forEach((value, key) => result.set(key, value));
|
|
541
|
-
return result;
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
633
|
+
}, deepMergeMaps = (target, source, options = {}) => {
|
|
634
|
+
// Ensure both target and source are Maps
|
|
635
|
+
if (!(target instanceof Map) || !(source instanceof Map))
|
|
636
|
+
return target;
|
|
637
|
+
options?.onBeforeMerge?.(target, source);
|
|
638
|
+
// Merge options, with default values
|
|
639
|
+
const opts = Object.assign({ inheritMissing: true, targetClone: false, useEnable: true }, options),
|
|
640
|
+
// If cloning is enabled, create a deep copy of the target Map
|
|
641
|
+
result = opts.targetClone ? new Map([...target]) : target;
|
|
544
642
|
// Default "merge" mode: recursively merge entries in the Maps
|
|
545
|
-
|
|
643
|
+
for (const [key, value] of source.entries())
|
|
546
644
|
// Check if the key already exists in the target Map
|
|
547
645
|
if (result.has(key)) {
|
|
548
|
-
const
|
|
646
|
+
const _target = result.get(key), _source = value, resp = deepMergeHelper(_target, _source, opts);
|
|
549
647
|
//resp={result,flag,type}
|
|
550
648
|
//flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
|
|
551
649
|
if (!resp.flag) {
|
|
552
650
|
// For simple values, overwrite the target value with the source value
|
|
553
|
-
result.set(key,
|
|
651
|
+
result.set(key, _source);
|
|
554
652
|
}
|
|
555
653
|
else {
|
|
556
654
|
// If both target and source are objects, merge them recursively
|
|
@@ -559,116 +657,42 @@
|
|
|
559
657
|
}
|
|
560
658
|
else {
|
|
561
659
|
// If the key doesn't exist in the target, add the entry from the source Map
|
|
562
|
-
result.set(key, value);
|
|
660
|
+
options.inheritMissing && result.set(key, value);
|
|
563
661
|
}
|
|
564
|
-
|
|
662
|
+
options?.onAfterMerge?.(result, target, source);
|
|
565
663
|
return result;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
664
|
+
}, deepMergeSets = (target, source, options = {}) => {
|
|
665
|
+
// Ensure both target and source are Sets
|
|
666
|
+
if (!(target instanceof Set) || !(source instanceof Set))
|
|
667
|
+
return target;
|
|
668
|
+
options?.onBeforeMerge?.(target, source);
|
|
669
|
+
// Merge options, with default values
|
|
670
|
+
const opts = Object.assign({ dataMode: 'clear', inheritMissing: true, targetClone: false, useEnable: true }, options),
|
|
671
|
+
// If cloning is enabled, create a deep copy of the target Set
|
|
672
|
+
result = opts.targetClone ? new Set(...target) : target;
|
|
673
|
+
// Handle different merge strategies based on dataMode
|
|
674
|
+
if (opts.dataMode === 'replace') {
|
|
675
|
+
// Replace mode: recursively merge items in the Sets
|
|
676
|
+
const _result = [...result], _source = [...source], resp = deepMergeHelper(_result, _source, opts);
|
|
677
|
+
result.clear();
|
|
678
|
+
for (let item of resp.result)
|
|
679
|
+
result.add(item);
|
|
580
680
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const keysA = Object.keys(a), keysB = Object.keys(b);
|
|
586
|
-
if (keysA.length !== keysB.length)
|
|
587
|
-
return false;
|
|
588
|
-
for (let key of keysA) {
|
|
589
|
-
if (!keysB.includes(key) || !deepEqual(a[key], b[key]))
|
|
590
|
-
return false;
|
|
681
|
+
else if (opts.dataMode === 'concat') {
|
|
682
|
+
// Concatenate mode: add all items from the source Set to the target Set
|
|
683
|
+
for (let item of source)
|
|
684
|
+
result.add(item);
|
|
591
685
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const deepMergeSets = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
|
|
599
|
-
// Ensure both target and source are Sets
|
|
600
|
-
if (!(target instanceof Set) || !(source instanceof Set))
|
|
601
|
-
return target;
|
|
602
|
-
// Merge options, with default values
|
|
603
|
-
const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
|
|
604
|
-
// If cloning is enabled, create a deep copy of the target Set
|
|
605
|
-
result = opts.targetClone ? new Set(target) : target;
|
|
606
|
-
// Handle different merge strategies based on itemMode
|
|
607
|
-
if (opts.itemMode === 'replace') {
|
|
608
|
-
// Replace mode: clear the target Set and add all items from the source Set
|
|
609
|
-
result.clear();
|
|
610
|
-
for (let item of source)
|
|
611
|
-
result.add(item);
|
|
612
|
-
return result;
|
|
613
|
-
}
|
|
614
|
-
else if (opts.itemMode === 'concat') {
|
|
615
|
-
// Concatenate mode: add all items from the source Set to the target Set
|
|
616
|
-
for (let item of source)
|
|
617
|
-
result.add(item);
|
|
618
|
-
return result;
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
// Default "merge" mode: recursively merge items in the Sets
|
|
622
|
-
for (let item of source) {
|
|
623
|
-
// Check the type of the target and source items
|
|
624
|
-
let _target = [...result].find(val => deepEqual(val, item)), resp = deepMergeHelper(_target, item, opts);
|
|
625
|
-
//resp={result,flag}
|
|
626
|
-
//flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
|
|
627
|
-
!resp.flag && result.add(item);
|
|
686
|
+
else {
|
|
687
|
+
//Default "clear" mode: clear the target Set and add all items from the source Set
|
|
688
|
+
result.clear();
|
|
689
|
+
for (let item of source)
|
|
690
|
+
result.add(item);
|
|
628
691
|
}
|
|
692
|
+
options?.onAfterMerge?.(result, target, source);
|
|
629
693
|
return result;
|
|
630
|
-
}
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
// deepMergeHelper.ts
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
const deepMergeHelper = (target, source, options) => {
|
|
637
|
-
let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
|
|
638
|
-
if (targetType === 'Object' && sourceType === 'Object') {
|
|
639
|
-
result = deepMergeObjects(target, source, options);
|
|
640
|
-
type = 'Object';
|
|
641
|
-
}
|
|
642
|
-
else if (targetType === 'Array' && sourceType === 'Array') {
|
|
643
|
-
result = deepMergeArrays(target, source, options);
|
|
644
|
-
type = 'Array';
|
|
645
|
-
}
|
|
646
|
-
else if (targetType === 'Set' && sourceType === 'Set') {
|
|
647
|
-
result = deepMergeSets(target, source, options);
|
|
648
|
-
type = 'Set';
|
|
649
|
-
}
|
|
650
|
-
else if (targetType === 'Map' && sourceType === 'Map') {
|
|
651
|
-
result = deepMergeMaps(target, source, options);
|
|
652
|
-
type = 'Map';
|
|
653
|
-
}
|
|
654
|
-
else {
|
|
655
|
-
flag = false;
|
|
656
|
-
result = target; // Default case, replace primitive values
|
|
657
|
-
}
|
|
658
|
-
return {
|
|
659
|
-
result, flag, type
|
|
660
694
|
};
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
const deepMerge = (target, source, opts = {}) => {
|
|
664
|
-
// Get the data types of the target and source
|
|
665
|
-
let options = Object.assign({
|
|
666
|
-
itemMode: 'merge', // Default merge mode
|
|
667
|
-
propAppend: true, // Default to appending properties from source to target
|
|
668
|
-
targetClone: false, // Do not clone target by default
|
|
669
|
-
useEnable: true // Enable special handling for objects with an `enable` property
|
|
670
|
-
}, opts);
|
|
671
|
-
return deepMergeHelper(target, source, options);
|
|
695
|
+
return deepMergeHelper(target, source, options).result;
|
|
672
696
|
};
|
|
673
697
|
|
|
674
698
|
const utils = {
|
|
@@ -686,12 +710,8 @@
|
|
|
686
710
|
wrapSetMethods,
|
|
687
711
|
wrapMapMethods,
|
|
688
712
|
getUniqueId,
|
|
689
|
-
deepEqual: assert.deepEqual,
|
|
690
713
|
deepMerge,
|
|
691
|
-
|
|
692
|
-
deepMergeMaps,
|
|
693
|
-
deepMergeObjects,
|
|
694
|
-
deepMergeSets,
|
|
714
|
+
shallowCopy,
|
|
695
715
|
};
|
|
696
716
|
|
|
697
717
|
return utils;
|
package/dist/utils.umd.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @since Last modified: 2025-12-
|
|
2
|
+
* @since Last modified: 2025-12-25 12:10:38
|
|
3
3
|
* @name Utils for web front-end.
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.12
|
|
5
5
|
* @author AXUI development team <3217728223@qq.com>
|
|
6
6
|
* @description This is a set of general-purpose JavaScript utility functions developed by the AXUI team. All functions are pure and do not involve CSS or other third-party libraries. They are suitable for any web front-end environment.
|
|
7
7
|
* @see {@link https://www.axui.cn|Official website}
|
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* @copyright This software supports the MIT License, allowing free learning and commercial use, but please retain the terms 'ax,' 'axui,' 'AX,' and 'AXUI' within the software.
|
|
13
13
|
* @license MIT license
|
|
14
14
|
*/
|
|
15
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(
|
|
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,t={})=>{const r=getDataType(e),o=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(o.interceptor&&"function"==typeof o.interceptor){let t=o.interceptor(e,r);if(t)return o.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e}),t}o.onBeforeClone?.(e,r);let n,a=!0;if("Object"===r&&o.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],o);if(r.length>0)for(const n of r)t[n]=deepClone(e[n],o);n=t}else if("Array"===r&&o.cloneArray)n=e.map(e=>deepClone(e,o));else if("Map"===r&&o.cloneMap){const t=new Map;for(const[r,n]of e)t.set(deepClone(r,o),deepClone(n,o));n=t}else if("Set"===r&&o.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,o));n=t}else if("Date"===r&&o.cloneDate)n=new Date(e.getTime());else if("RegExp"===r&&o.cloneRegex){const t=e;n=new RegExp(t.source,t.flags)}else n=e,a=!1;return o.onAfterClone?.({output:n,input:e,type:r,cloned:a}),n},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const r in e)t[r]=deepCloneToJSON(e[r]);for(const e in t)void 0===t[e]&&Reflect.deleteProperty(t,e);return t}if("Array"===t){return e.map((e,t)=>deepCloneToJSON(e)).filter(e=>void 0!==e)}return["Number","String","Boolean","Null"].includes(t)?e:void 0},e=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],t=["add","delete","clear"],r=["set","delete","clear"],shallowCopy=e=>{const t=getDataType(e);if("Set"===t)return new Set([...e]);if("Map"===t)return new Map([...e]);if(Array.isArray(e))return[...e];if("object"===t){const t=e,r=Object.getOwnPropertySymbols(t).reduce((e,r)=>(e[r]=t[r],e),{});return{...t,...r}}return e};return{getDataType:getDataType,requireTypes:(e,t,r)=>{let o=Array.isArray(t)?t:[t],n=getDataType(e),a=n.toLowerCase(),s=o.map(e=>e.toLowerCase()),i=a.includes("html")?"element":a;if(r)try{if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`)}catch(e){r(e,n)}else if(!s.includes(i))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${i}`);return n},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:n,props:a={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");n&&!n?.length||(n=e);const s={};for(let e of n)s[e]=function(...n){const s={},i=t.length;switch(e){case"push":case"unshift":s.addedItems=[...n];break;case"pop":s.poppedItem=t[i-1];break;case"shift":s.shiftedItem=t[0];break;case"splice":const[e,r]=n,o=e<0?Math.max(i+e,0):Math.min(e,i),a=void 0===r?i-o:r;s.deletedItems=t.slice(o,o+a);break;case"sort":case"reverse":s.oldSnapshot=[...t];break;case"fill":case"copyWithin":const l=n[1]||0,c=void 0===n[2]?i:n[2];s.oldItems=t.slice(l,c),s.start=l,s.end=c}r?.(s);const l=Array.prototype[e].apply(t,n),c={value:l,key:e,args:n,context:s,target:t,...a};return o?.(c),l};return s},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:n=t,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=t=>function(...n){const s={};switch(t){case"add":{const[t]=n;s.addedItem=t,s.existed=e.has(t);break}case"delete":{const[t]=n;s.existed=e.has(t),s.deletedItem=s.existed?t:void 0;break}case"clear":s.clearedItems=Array.from(e),s.previousSize=e.size}r(s);const i=e[t].apply(e,n),l={method:t,result:i,args:n,context:s,target:e,...a};return o(l),i};for(const e of n)t.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:o=()=>{},allowList:n=r,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...n){const s={};switch(r){case"set":{const[t,r]=n;s.key=t,s.newValue=r,s.existed=e.has(t),s.oldValue=s.existed?e.get(t):void 0;break}case"delete":{const[t]=n;s.key=t,s.existed=e.has(t),s.value=s.existed?e.get(t):void 0;break}case"clear":s.clearedItems=Array.from(e.entries()),s.previousSize=e.size}t(s);const i=e[r].apply(e,n),l={method:r,result:i,args:n,context:s,target:e,...a};return o(l),i};for(const e of n)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},getUniqueId:(e={})=>{const t=e.prefix,r=e.suffix,o=e.base10,n=e.base36;return`${t?t+"-":""}${Date.now()}${n?"-"+Math.random().toString(36).substring(2,11):""}${o?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},deepMerge:(e,t,r={})=>{const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0,useSymbol:!0,deepClone:{},onBeforeMerge:void 0,onAfterMerge:void 0},r),deepMergeHelper=(e,t,r)=>{let o,n,a=getDataType(e),s=getDataType(t),i=!0;return"Object"===a&&"Object"===s?(n=deepMergeObjects(e,t,r),o="Object"):"Array"===a&&"Array"===s?(n=deepMergeArrays(e,t,r),o="Array"):"Set"===a&&"Set"===s?(n=deepMergeSets(e,t,r),o="Set"):"Map"===a&&"Map"===s?(n=deepMergeMaps(e,t,r),o="Map"):(i=!1,n=e),{result:n,flag:i,type:o}},mergeEnableObject=(e,t)=>e?.hasOwnProperty("enable")&&"boolean"==typeof t?(e.enable=t,e):t?.hasOwnProperty("enable")&&"boolean"==typeof e?Object.assign({enable:e},t):t,deepMergeObjects=(e,t,r={})=>{let o=getDataType(e),n=getDataType(t);if("Object"!==o||"Object"!==n)return e;r?.onBeforeMerge?.(e,t);const a=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r);let s={};s=a.targetClone?shallowCopy(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let o=deepMergeHelper(s[e],t[e],r);o.flag?o.type?"Object"===o.type&&(s[e]=o.result):s[e]=t[e]:a.useEnable?s[e]=mergeEnableObject(s[e],t[e]):s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.inheritMissing&&(s[e]=t[e]);if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length)for(let r of e)s[r]=t[r]}return a?.onAfterMerge?.(s,e,t),s},deepMergeArrays=(e,t,r={})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1},r),n=o.targetClone?[...e]:e;if("replace"===o.dataMode)for(let e=0;e<t.length&&(o.inheritMissing||!(e>=n.length));e++){deepMergeHelper(n[e],t[e],o).flag||(n[e]=t[e])}else"concat"===o.dataMode||(n.length=0),n.push(...t);return r?.onAfterMerge?.(n,e,t),n},deepMergeMaps=(e,t,r={})=>{if(!(e instanceof Map&&t instanceof Map))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({inheritMissing:!0,targetClone:!1,useEnable:!0},r),n=o.targetClone?new Map([...e]):e;for(const[e,a]of t.entries())if(n.has(e)){const t=n.get(e),r=a,s=deepMergeHelper(t,r,o);s.flag?"Object"===s.type&&n.set(e,s.result):n.set(e,r)}else r.inheritMissing&&n.set(e,a);return r?.onAfterMerge?.(n,e,t),n},deepMergeSets=(e,t,r={})=>{if(!(e instanceof Set&&t instanceof Set))return e;r?.onBeforeMerge?.(e,t);const o=Object.assign({dataMode:"clear",inheritMissing:!0,targetClone:!1,useEnable:!0},r),n=o.targetClone?new Set(...e):e;if("replace"===o.dataMode){const e=[...n],r=[...t],a=deepMergeHelper(e,r,o);n.clear();for(let e of a.result)n.add(e)}else if("concat"===o.dataMode)for(let e of t)n.add(e);else{n.clear();for(let e of t)n.add(e)}return r?.onAfterMerge?.(n,e,t),n};return deepMergeHelper(e,t,o).result},shallowCopy:shallowCopy}});
|
package/dist.zip
CHANGED
|
Binary file
|