@codady/utils 0.0.10 → 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/dist/utils.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  /*!
3
- * @since Last modified: 2025-12-22 20:26:42
3
+ * @since Last modified: 2025-12-24 17:50:8
4
4
  * @name Utils for web front-end.
5
- * @version 0.0.10
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}
@@ -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(factory) :
20
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.utils = factory());
21
- })(this, (function () { 'use strict';
18
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('assert')) :
19
+ typeof define === 'function' && define.amd ? define(['assert'], factory) :
20
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.utils = factory(global.assert));
21
+ })(this, (function (assert) { 'use strict';
22
22
 
23
23
  const getDataType = (obj) => {
24
24
  let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
@@ -426,6 +426,251 @@
426
426
  return methods;
427
427
  };
428
428
 
429
+ const deepMergeObjects = (target, source, opts = {}) => {
430
+ let targetType = getDataType(target), sourceType = getDataType(source);
431
+ //target不是对象或者source为空则直接返回
432
+ if (targetType !== 'Object' || sourceType !== 'Object') {
433
+ return target;
434
+ }
435
+ const options = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, opts),
436
+ //如果是复制方法,则先复制target
437
+ result = options.targetClone ? deepClone(target) : target;
438
+ for (let k in source) {
439
+ if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
440
+ let resp = deepMergeHelper(result[k], source[k], opts);
441
+ //resp={result,flag,type}
442
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
443
+ if (!resp.flag) {
444
+ //类型不同则直接覆盖
445
+ if (options.useEnable && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
446
+ //部分替换,仅针对result={enable:true/false,a:''},source=false/true这种情况和相反的情况,因为这种情况再笨框架比较多见
447
+ if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
448
+ //result={enable:true,a:'',b:''},source[k]=false=>result={enable:false,a:'',b:''}
449
+ result[k].enable = source[k];
450
+ }
451
+ else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
452
+ //source={enable:true,a:'',b:''},(result as any)[k]=false=>result={enable:false,a:'',b:''}
453
+ result = Object.assign({ enable: result[k] }, source[k]);
454
+ }
455
+ else {
456
+ //完全替换
457
+ result[k] = source[k];
458
+ }
459
+ }
460
+ else {
461
+ //完全替换
462
+ result[k] = source[k];
463
+ }
464
+ }
465
+ else {
466
+ // If both target and source are objects, merge them recursively
467
+ if (resp.type === 'Object') {
468
+ result[k] = resp.result;
469
+ }
470
+ }
471
+ }
472
+ else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
473
+ //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
474
+ result[k] = source[k];
475
+ }
476
+ }
477
+ //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
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];
483
+ }
484
+ }
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);
507
+ return result;
508
+ }
509
+ else {
510
+ // Default "merge" mode: recursively merge items in the arrays
511
+ for (let i = 0; i < source.length; i++) {
512
+ let resp = deepMergeHelper(result[i], source[i], opts);
513
+ //resp={result,flag,type}
514
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
515
+ if (!resp.flag) {
516
+ result[i] = source[i];
517
+ }
518
+ }
519
+ return result;
520
+ }
521
+ };
522
+
523
+ const deepMergeMaps = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
524
+ // Ensure both target and source are Maps
525
+ if (!(target instanceof Map) || !(source instanceof Map))
526
+ return target;
527
+ // Merge options, with default values
528
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
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 {
544
+ // Default "merge" mode: recursively merge entries in the Maps
545
+ source.forEach((value, key) => {
546
+ // Check if the key already exists in the target Map
547
+ if (result.has(key)) {
548
+ const targetValue = result.get(key), sourceValue = value, resp = deepMergeHelper(targetValue, sourceValue, opts);
549
+ //resp={result,flag,type}
550
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
551
+ if (!resp.flag) {
552
+ // For simple values, overwrite the target value with the source value
553
+ result.set(key, sourceValue);
554
+ }
555
+ else {
556
+ // If both target and source are objects, merge them recursively
557
+ resp.type === 'Object' && result.set(key, resp.result);
558
+ }
559
+ }
560
+ else {
561
+ // If the key doesn't exist in the target, add the entry from the source Map
562
+ result.set(key, value);
563
+ }
564
+ });
565
+ return result;
566
+ }
567
+ };
568
+
569
+ const deepEqual = (a, b) => {
570
+ // If both are equal by reference
571
+ if (a === b)
572
+ return true;
573
+ // If both are arrays, check equality recursively
574
+ if (Array.isArray(a) && Array.isArray(b)) {
575
+ if (a.length !== b.length)
576
+ return false;
577
+ for (let i = 0; i < a.length; i++) {
578
+ if (!deepEqual(a[i], b[i]))
579
+ return false;
580
+ }
581
+ return true;
582
+ }
583
+ // If both are objects, check equality recursively
584
+ if (typeof a === 'object' && typeof b === 'object') {
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;
591
+ }
592
+ return true;
593
+ }
594
+ // For other types, direct comparison
595
+ return a === b;
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);
628
+ }
629
+ 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
+ };
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);
672
+ };
673
+
429
674
  const utils = {
430
675
  //executeStr,
431
676
  getDataType,
@@ -440,7 +685,13 @@
440
685
  mapMutableMethods,
441
686
  wrapSetMethods,
442
687
  wrapMapMethods,
443
- getUniqueId
688
+ getUniqueId,
689
+ deepEqual: assert.deepEqual,
690
+ deepMerge,
691
+ deepMergeArrays,
692
+ deepMergeMaps,
693
+ deepMergeObjects,
694
+ deepMergeSets,
444
695
  };
445
696
 
446
697
  return utils;
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @since Last modified: 2025-12-22 20:26:42
2
+ * @since Last modified: 2025-12-24 17:50:8
3
3
  * @name Utils for web front-end.
4
- * @version 0.0.10
4
+ * @version 0.0.11
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():"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,s=!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,s=!1;return o.onAfterClone?.({output:n,input:e,type:r,cloned:s}),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"];return{getDataType:getDataType,requireTypes:(e,t,r)=>{let o=Array.isArray(t)?t:[t],n=getDataType(e),s=n.toLowerCase(),a=o.map(e=>e.toLowerCase()),c=s.includes("html")?"element":s;if(r)try{if(!a.includes(c))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${c}`)}catch(e){r(e,n)}else if(!a.includes(c))throw new TypeError(`Expected data type(s): [${a.join(", ")}], but got: ${c}`);return n},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:t,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:n,props:s={}})=>{if(!Array.isArray(t))throw new TypeError("The 'target' parameter must be an array.");n&&!n?.length||(n=e);const a={};for(let e of n)a[e]=function(...n){const a={},c=t.length;switch(e){case"push":case"unshift":a.addedItems=[...n];break;case"pop":a.poppedItem=t[c-1];break;case"shift":a.shiftedItem=t[0];break;case"splice":const[e,r]=n,o=e<0?Math.max(c+e,0):Math.min(e,c),s=void 0===r?c-o:r;a.deletedItems=t.slice(o,o+s);break;case"sort":case"reverse":a.oldSnapshot=[...t];break;case"fill":case"copyWithin":const i=n[1]||0,l=void 0===n[2]?c:n[2];a.oldItems=t.slice(i,l),a.start=i,a.end=l}r?.(a);const i=Array.prototype[e].apply(t,n),l={value:i,key:e,args:n,context:a,target:t,...s};return o?.(l),i};return a},arrayMutableMethods:e,setMutableMethods:t,mapMutableMethods:r,wrapSetMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:n=t,props:s={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const a={},createWrappedMethod=t=>function(...n){const a={};switch(t){case"add":{const[t]=n;a.addedItem=t,a.existed=e.has(t);break}case"delete":{const[t]=n;a.existed=e.has(t),a.deletedItem=a.existed?t:void 0;break}case"clear":a.clearedItems=Array.from(e),a.previousSize=e.size}r(a);const c=e[t].apply(e,n),i={method:t,result:c,args:n,context:a,target:e,...s};return o(i),c};for(const e of n)t.includes(e)&&(a[e]=createWrappedMethod(e));return Object.defineProperty(a,"target",{get:()=>e,enumerable:!1,configurable:!1}),a},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:o=()=>{},allowList:n=r,props:s={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const a={},createWrappedMethod=r=>function(...n){const a={};switch(r){case"set":{const[t,r]=n;a.key=t,a.newValue=r,a.existed=e.has(t),a.oldValue=a.existed?e.get(t):void 0;break}case"delete":{const[t]=n;a.key=t,a.existed=e.has(t),a.value=a.existed?e.get(t):void 0;break}case"clear":a.clearedItems=Array.from(e.entries()),a.previousSize=e.size}t(a);const c=e[r].apply(e,n),i={method:r,result:c,args:n,context:a,target:e,...s};return o(i),c};for(const e of n)r.includes(e)&&(a[e]=createWrappedMethod(e));return Object.defineProperty(a,"target",{get:()=>e,enumerable:!1,configurable:!1}),a},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:""}`}}});
15
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("assert")):"function"==typeof define&&define.amd?define(["assert"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).utils=t(e.assert)}(this,function(e){"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},t=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],r=["add","delete","clear"],o=["set","delete","clear"],deepMergeObjects=(e,t,r={})=>{let o=getDataType(e),n=getDataType(t);if("Object"!==o||"Object"!==n)return e;const a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),s=a.targetClone?deepClone(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let o=deepMergeHelper(s[e],t[e],r);o.flag?"Object"===o.type&&(s[e]=o.result):a.useEnable&&s.hasOwnProperty(e)&&s[e]?.hasOwnProperty("enable")&&"boolean"==typeof t[e]?s[e]?.hasOwnProperty("enable")&&"boolean"==typeof t[e]?s[e].enable=t[e]:t[e]?.hasOwnProperty("enable")&&"boolean"==typeof s[e]?s=Object.assign({enable:s[e]},t[e]):s[e]=t[e]:s[e]=t[e]}else t.hasOwnProperty(e)&&!s.hasOwnProperty(e)&&a.propAppend&&(s[e]=t[e]);if(a.useSymbol){let e=Object.getOwnPropertySymbols(t);if(e.length>0)for(let r of e)s[r]=t[r]}return s},deepMergeArrays=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!Array.isArray(e)||!Array.isArray(t))return e;const o=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1},r),n=o.targetClone?[...e]:e;if("replace"===o.itemMode)return n.length=0,n.push(...t),n;if("concat"===o.itemMode)return n.push(...t),n;for(let e=0;e<t.length;e++){deepMergeHelper(n[e],t[e],o).flag||(n[e]=t[e])}return n},deepMergeMaps=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!(e instanceof Map&&t instanceof Map))return e;const o=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),n=o.targetClone?new Map(e):e;return"replace"===o.itemMode?(n.clear(),t.forEach((e,t)=>n.set(t,e)),n):"concat"===o.itemMode?(t.forEach((e,t)=>n.set(t,e)),n):(t.forEach((e,t)=>{if(n.has(t)){const r=n.get(t),a=e,s=deepMergeHelper(r,a,o);s.flag?"Object"===s.type&&n.set(t,s.result):n.set(t,a)}else n.set(t,e)}),n)},deepEqual=(e,t)=>{if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let r=0;r<e.length;r++)if(!deepEqual(e[r],t[r]))return!1;return!0}if("object"==typeof e&&"object"==typeof t){const r=Object.keys(e),o=Object.keys(t);if(r.length!==o.length)return!1;for(let n of r)if(!o.includes(n)||!deepEqual(e[n],t[n]))return!1;return!0}return e===t},deepMergeSets=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!(e instanceof Set&&t instanceof Set))return e;const o=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),n=o.targetClone?new Set(e):e;if("replace"===o.itemMode){n.clear();for(let e of t)n.add(e);return n}if("concat"===o.itemMode){for(let e of t)n.add(e);return n}for(let e of t){let t=[...n].find(t=>deepEqual(t,e));!deepMergeHelper(t,e,o).flag&&n.add(e)}return n},deepMergeHelper=(e,t,r)=>{let o,n,a=getDataType(e),s=getDataType(t),l=!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"):(l=!1,n=e),{result:n,flag:l,type:o}};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()),l=a.includes("html")?"element":a;if(r)try{if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`)}catch(e){r(e,n)}else if(!s.includes(l))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${l}`);return n},deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:({target:e,onBeforeMutate:r=()=>{},onAfterMutate:o=()=>{},allowList:n,props:a={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");n&&!n?.length||(n=t);const s={};for(let t of n)s[t]=function(...n){const s={},l=e.length;switch(t){case"push":case"unshift":s.addedItems=[...n];break;case"pop":s.poppedItem=e[l-1];break;case"shift":s.shiftedItem=e[0];break;case"splice":const[t,r]=n,o=t<0?Math.max(l+t,0):Math.min(t,l),a=void 0===r?l-o:r;s.deletedItems=e.slice(o,o+a);break;case"sort":case"reverse":s.oldSnapshot=[...e];break;case"fill":case"copyWithin":const c=n[1]||0,i=void 0===n[2]?l:n[2];s.oldItems=e.slice(c,i),s.start=c,s.end=i}r?.(s);const c=Array.prototype[t].apply(e,n),i={value:c,key:t,args:n,context:s,target:e,...a};return o?.(i),c};return s},arrayMutableMethods:t,setMutableMethods:r,mapMutableMethods:o,wrapSetMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:o=()=>{},allowList:n=r,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=r=>function(...n){const s={};switch(r){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}t(s);const l=e[r].apply(e,n),c={method:r,result:l,args:n,context:s,target:e,...a};return o(c),l};for(const e of n)r.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},wrapMapMethods:({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:n=o,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=o=>function(...n){const s={};switch(o){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 l=e[o].apply(e,n),c={method:o,result:l,args:n,context:s,target:e,...a};return r(c),l};for(const e of n)o.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:""}`},deepEqual:e.deepEqual,deepMerge:(e,t,r={})=>{let o=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r);return deepMergeHelper(e,t,o)},deepMergeArrays:deepMergeArrays,deepMergeMaps:deepMergeMaps,deepMergeObjects:deepMergeObjects,deepMergeSets:deepMergeSets}});
package/dist.zip CHANGED
Binary file
package/modules.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2025/12/22 17:21:44
2
+ * Last modified: 2025/12/24 17:05:40
3
3
  */
4
4
  'use strict';
5
5
  import deepClone from './src/deepClone';
@@ -13,6 +13,12 @@ import setMutableMethods from './src/setMutableMethods';
13
13
  import mapMutableMethods from './src/mapMutableMethods';
14
14
  import wrapSetMethods from './src/wrapSetMethods';
15
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';
16
22
  const utils = {
17
23
  //executeStr,
18
24
  getDataType,
@@ -27,6 +33,12 @@ const utils = {
27
33
  mapMutableMethods,
28
34
  wrapSetMethods,
29
35
  wrapMapMethods,
30
- getUniqueId
36
+ getUniqueId,
37
+ deepEqual,
38
+ deepMerge,
39
+ deepMergeArrays,
40
+ deepMergeMaps,
41
+ deepMergeObjects,
42
+ deepMergeSets,
31
43
  };
32
44
  export default utils;
package/modules.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Last modified: 2025/12/22 17:21:44
2
+ * Last modified: 2025/12/24 17:05:40
3
3
  */
4
4
  'use strict'
5
5
  import deepClone from './src/deepClone';
@@ -16,6 +16,12 @@ import setMutableMethods from './src/setMutableMethods';
16
16
  import mapMutableMethods from './src/mapMutableMethods';
17
17
  import wrapSetMethods from './src/wrapSetMethods';
18
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';
19
25
 
20
26
 
21
27
 
@@ -33,7 +39,13 @@ const utils = {
33
39
  mapMutableMethods,
34
40
  wrapSetMethods,
35
41
  wrapMapMethods,
36
- getUniqueId
42
+ getUniqueId,
43
+ deepEqual,
44
+ deepMerge,
45
+ deepMergeArrays,
46
+ deepMergeMaps,
47
+ deepMergeObjects,
48
+ deepMergeSets,
37
49
  };
38
50
 
39
51
  export default utils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codady/utils",
3
- "version": "0.0.10",
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.",
package/src/deepClone.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/22 20:20:47
2
+ * @since Last modified: 2025/12/24 17:05:29
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
package/src/deepClone.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @since Last modified: 2025/12/22 20:20:47
2
+ * @since Last modified: 2025/12/24 17:05:29
3
3
  * Deep clone an array, object, or other cloneable data types.
4
4
  *
5
5
  * Features:
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @since Last modified: 2025/12/24 17:11:15
3
+ * @function deepEqual
4
+ * @description Compares two values for deep equality. This function checks whether the values are deeply equal, meaning that if the values are objects or arrays, their properties or items are recursively compared. If they are primitive types, a direct comparison is performed.
5
+ * It supports comparison for arrays, objects, and primitive types (like numbers, strings, booleans, etc.). The comparison is done by value, not by reference.
6
+ *
7
+ * @param a The first value to compare.
8
+ * @param b The second value to compare.
9
+ * @returns {boolean} `true` if the values are deeply equal, otherwise `false`.
10
+ *
11
+ * @example
12
+ * deepEqual([1, 2, 3], [1, 2, 3]); // returns true
13
+ * deepEqual([1, 2, 3], [3, 2, 1]); // returns false
14
+ * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // returns true
15
+ * deepEqual({ a: 1, b: 2 }, { a: 1, b: 3 }); // returns false
16
+ * deepEqual(5, 5); // returns true
17
+ * deepEqual('hello', 'hello'); // returns true
18
+ * deepEqual(5, '5'); // returns false
19
+ */
20
+ const deepEqual = (a, b) => {
21
+ // If both are equal by reference
22
+ if (a === b)
23
+ return true;
24
+ // If both are arrays, check equality recursively
25
+ if (Array.isArray(a) && Array.isArray(b)) {
26
+ if (a.length !== b.length)
27
+ return false;
28
+ for (let i = 0; i < a.length; i++) {
29
+ if (!deepEqual(a[i], b[i]))
30
+ return false;
31
+ }
32
+ return true;
33
+ }
34
+ // If both are objects, check equality recursively
35
+ if (typeof a === 'object' && typeof b === 'object') {
36
+ const keysA = Object.keys(a), keysB = Object.keys(b);
37
+ if (keysA.length !== keysB.length)
38
+ return false;
39
+ for (let key of keysA) {
40
+ if (!keysB.includes(key) || !deepEqual(a[key], b[key]))
41
+ return false;
42
+ }
43
+ return true;
44
+ }
45
+ // For other types, direct comparison
46
+ return a === b;
47
+ };
48
+ export default deepEqual;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @since Last modified: 2025/12/24 17:11:15
3
+ * @function deepEqual
4
+ * @description Compares two values for deep equality. This function checks whether the values are deeply equal, meaning that if the values are objects or arrays, their properties or items are recursively compared. If they are primitive types, a direct comparison is performed.
5
+ * It supports comparison for arrays, objects, and primitive types (like numbers, strings, booleans, etc.). The comparison is done by value, not by reference.
6
+ *
7
+ * @param a The first value to compare.
8
+ * @param b The second value to compare.
9
+ * @returns {boolean} `true` if the values are deeply equal, otherwise `false`.
10
+ *
11
+ * @example
12
+ * deepEqual([1, 2, 3], [1, 2, 3]); // returns true
13
+ * deepEqual([1, 2, 3], [3, 2, 1]); // returns false
14
+ * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // returns true
15
+ * deepEqual({ a: 1, b: 2 }, { a: 1, b: 3 }); // returns false
16
+ * deepEqual(5, 5); // returns true
17
+ * deepEqual('hello', 'hello'); // returns true
18
+ * deepEqual(5, '5'); // returns false
19
+ */
20
+ const deepEqual = (a: any, b: any): boolean => {
21
+ // If both are equal by reference
22
+ if (a === b) return true;
23
+
24
+ // If both are arrays, check equality recursively
25
+ if (Array.isArray(a) && Array.isArray(b)) {
26
+ if (a.length !== b.length) return false;
27
+ for (let i = 0; i < a.length; i++) {
28
+ if (!deepEqual(a[i], b[i])) return false;
29
+ }
30
+ return true;
31
+ }
32
+
33
+ // If both are objects, check equality recursively
34
+ if (typeof a === 'object' && typeof b === 'object') {
35
+ const keysA = Object.keys(a), keysB = Object.keys(b);
36
+ if (keysA.length !== keysB.length) return false;
37
+ for (let key of keysA) {
38
+ if (!keysB.includes(key) || !deepEqual(a[key], b[key])) return false;
39
+ }
40
+ return true;
41
+ }
42
+
43
+ // For other types, direct comparison
44
+ return a === b;
45
+ }
46
+ export default deepEqual;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @since Last modified: 2025/12/24 17:21:45
3
+ * @function deepMerge
4
+ * @description Deeply merges two data structures (Object, Array, Map, or Set) based on their types.
5
+ * This function recursively merges the properties or items of the target and source, depending on their types.
6
+ * If the types of target and source do not match, the target will be returned unchanged.
7
+ * @param target The target data structure to merge into (can be Object, Array, Map, or Set).
8
+ * @param source The source data structure to merge from (can be Object, Array, Map, or Set).
9
+ * @param opts Configuration options for merging. The default options include:
10
+ * - `itemMode`: Specifies the merging mode (`'merge'`, `'replace'`, or `'concat'`).
11
+ * - `propAppend`: Whether to append properties from the source if they do not exist in the target.
12
+ * - `targetClone`: Whether to clone the target before merging (if true, the target is not modified).
13
+ * - `useEnable`: Some special handling for specific objects that have `enable` properties.
14
+ * - `useSymbol`: Whether to merge symbol properties.
15
+ * @returns The deeply merged target data structure.
16
+ * @example
17
+ * let x = { a: 'man', b: 0, c: [] };
18
+ * let y = { a: 'woman', b: 2, d: 'new' };
19
+ * const merged = deepMerge(x, y, { itemMode: 'merge', propAppend: true });
20
+ * // Returns { a: 'woman', b: 2, c: [], d: 'new' }
21
+ */
22
+ 'use strict';
23
+ import deepMergeHelper from './deepMergeHelper';
24
+ const deepMerge = (target, source, opts = {}) => {
25
+ // Get the data types of the target and source
26
+ let options = Object.assign({
27
+ itemMode: 'merge', // Default merge mode
28
+ propAppend: true, // Default to appending properties from source to target
29
+ targetClone: false, // Do not clone target by default
30
+ useEnable: true // Enable special handling for objects with an `enable` property
31
+ }, opts);
32
+ return deepMergeHelper(target, source, options);
33
+ };
34
+ export default deepMerge;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @since Last modified: 2025/12/24 17:21:45
3
+ * @function deepMerge
4
+ * @description Deeply merges two data structures (Object, Array, Map, or Set) based on their types.
5
+ * This function recursively merges the properties or items of the target and source, depending on their types.
6
+ * If the types of target and source do not match, the target will be returned unchanged.
7
+ * @param target The target data structure to merge into (can be Object, Array, Map, or Set).
8
+ * @param source The source data structure to merge from (can be Object, Array, Map, or Set).
9
+ * @param opts Configuration options for merging. The default options include:
10
+ * - `itemMode`: Specifies the merging mode (`'merge'`, `'replace'`, or `'concat'`).
11
+ * - `propAppend`: Whether to append properties from the source if they do not exist in the target.
12
+ * - `targetClone`: Whether to clone the target before merging (if true, the target is not modified).
13
+ * - `useEnable`: Some special handling for specific objects that have `enable` properties.
14
+ * - `useSymbol`: Whether to merge symbol properties.
15
+ * @returns The deeply merged target data structure.
16
+ * @example
17
+ * let x = { a: 'man', b: 0, c: [] };
18
+ * let y = { a: 'woman', b: 2, d: 'new' };
19
+ * const merged = deepMerge(x, y, { itemMode: 'merge', propAppend: true });
20
+ * // Returns { a: 'woman', b: 2, c: [], d: 'new' }
21
+ */
22
+ 'use strict';
23
+ import getDataType from './getDataType';
24
+ import deepMergeObjects from './deepMergeObjects';
25
+ import deepMergeArrays, { DeepMergeOptions } from './deepMergeArrays';
26
+ import deepMergeMaps from './deepMergeMaps';
27
+ import deepMergeSets from './deepMergeSets';
28
+ import deepMergeHelper from './deepMergeHelper';
29
+ const deepMerge = (target: Object | Array<any> | Map<any, any> | Set<any>, source: any, opts: DeepMergeOptions = {}): Object | Array<any> | Map<any, any> | Set<any> => {
30
+ // Get the data types of the target and source
31
+ let options = Object.assign({
32
+ itemMode: 'merge', // Default merge mode
33
+ propAppend: true, // Default to appending properties from source to target
34
+ targetClone: false, // Do not clone target by default
35
+ useEnable: true // Enable special handling for objects with an `enable` property
36
+ }, opts);
37
+
38
+ return deepMergeHelper(target,source,options);
39
+ }
40
+ export default deepMerge;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @since Last modified: 2025/12/24 17:49:40
3
+ * @function deepMergeArrays
4
+ * Deeply merges two arrays, with flexible options to replace, concatenate, or merge items.
5
+ * @param target The target array to merge into
6
+ * @param source The source array to merge from
7
+ * @param options Configuration options for merging
8
+ * @returns The deeply merged array
9
+ */
10
+ 'use strict';
11
+ import deepMergeHelper from './deepMergeHelper';
12
+ const deepMergeArrays = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
13
+ // Ensure both target and source are arrays
14
+ if (!Array.isArray(target) || !Array.isArray(source))
15
+ return target;
16
+ // Merge options, with default values
17
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false }, options),
18
+ // If cloning is enabled, create a deep copy of the target array
19
+ result = opts.targetClone ? [...target] : target;
20
+ // Handle different merge strategies based on itemMode
21
+ if (opts.itemMode === 'replace') {
22
+ // Replace mode: clear the target array and push all items from the source array
23
+ result.length = 0;
24
+ result.push(...source);
25
+ return result;
26
+ }
27
+ else if (opts.itemMode === 'concat') {
28
+ // Concatenate mode: append all items from the source array to the target array
29
+ result.push(...source);
30
+ return result;
31
+ }
32
+ else {
33
+ // Default "merge" mode: recursively merge items in the arrays
34
+ for (let i = 0; i < source.length; i++) {
35
+ let resp = deepMergeHelper(result[i], source[i], opts);
36
+ //resp={result,flag,type}
37
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
38
+ if (!resp.flag) {
39
+ result[i] = source[i];
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+ };
45
+ export default deepMergeArrays;