@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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
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
+
5
22
 
6
23
  ## [v0.0.10] - 2025-12-21
7
24
 
package/dist/utils.cjs.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}
@@ -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())) {
@@ -422,6 +424,251 @@ const wrapMapMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = ()
422
424
  return methods;
423
425
  };
424
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);
670
+ };
671
+
425
672
  const utils = {
426
673
  //executeStr,
427
674
  getDataType,
@@ -436,7 +683,13 @@ const utils = {
436
683
  mapMutableMethods,
437
684
  wrapSetMethods,
438
685
  wrapMapMethods,
439
- getUniqueId
686
+ getUniqueId,
687
+ deepEqual: assert.deepEqual,
688
+ deepMerge,
689
+ deepMergeArrays,
690
+ deepMergeMaps,
691
+ deepMergeObjects,
692
+ deepMergeSets,
440
693
  };
441
694
 
442
695
  module.exports = 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
- "use strict";const getDataType=e=>{let t,o=Object.prototype.toString.call(e).slice(8,-1);return t="Function"===o&&/^\s*class\s+/.test(e.toString())?"Class":"Object"===o&&Object.getPrototypeOf(e)!==Object.prototype?"Instance":o,t},deepClone=(e,t={})=>{const o=getDataType(e),r=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(r.interceptor&&"function"==typeof r.interceptor){let t=r.interceptor(e,o);if(t)return r.onAfterClone?.({output:t,input:e,type:o,cloned:t!==e}),t}r.onBeforeClone?.(e,o);let a,s=!0;if("Object"===o&&r.cloneObject){const t={},o=Object.getOwnPropertySymbols(e);for(const o in e)t[o]=deepClone(e[o],r);if(o.length>0)for(const a of o)t[a]=deepClone(e[a],r);a=t}else if("Array"===o&&r.cloneArray)a=e.map(e=>deepClone(e,r));else if("Map"===o&&r.cloneMap){const t=new Map;for(const[o,a]of e)t.set(deepClone(o,r),deepClone(a,r));a=t}else if("Set"===o&&r.cloneSet){const t=new Set;for(const o of e)t.add(deepClone(o,r));a=t}else if("Date"===o&&r.cloneDate)a=new Date(e.getTime());else if("RegExp"===o&&r.cloneRegex){const t=e;a=new RegExp(t.source,t.flags)}else a=e,s=!1;return r.onAfterClone?.({output:a,input:e,type:o,cloned:s}),a},deepCloneToJSON=e=>{const t=getDataType(e);if("Object"===t){const t={};for(const o in e)t[o]=deepCloneToJSON(e[o]);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},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:o=()=>{},allowList:r,props:a={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");r&&!r?.length||(r=arrayMutableMethods);const s={};for(let n of r)s[n]=function(...r){const s={},l=e.length;switch(n){case"push":case"unshift":s.addedItems=[...r];break;case"pop":s.poppedItem=e[l-1];break;case"shift":s.shiftedItem=e[0];break;case"splice":const[t,o]=r,a=t<0?Math.max(l+t,0):Math.min(t,l),n=void 0===o?l-a:o;s.deletedItems=e.slice(a,a+n);break;case"sort":case"reverse":s.oldSnapshot=[...e];break;case"fill":case"copyWithin":const c=r[1]||0,p=void 0===r[2]?l:r[2];s.oldItems=e.slice(c,p),s.start=c,s.end=p}t?.(s);const c=Array.prototype[n].apply(e,r),p={value:c,key:n,args:r,context:s,target:e,...a};return o?.(p),c};return s},requireTypes=(e,t,o)=>{let r=Array.isArray(t)?t:[t],a=getDataType(e),s=a.toLowerCase(),n=r.map(e=>e.toLowerCase()),l=s.includes("html")?"element":s;if(o)try{if(!n.includes(l))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${l}`)}catch(e){o(e,a)}else if(!n.includes(l))throw new TypeError(`Expected data type(s): [${n.join(", ")}], but got: ${l}`);return a},getUniqueId=(e={})=>{const t=e.prefix,o=e.suffix,r=e.base10,a=e.base36;return`${t?t+"-":""}${Date.now()}${a?"-"+Math.random().toString(36).substring(2,11):""}${r?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${o?"-"+o:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:o=()=>{},allowList:r=setMutableMethods,props:a={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const s={},createWrappedMethod=r=>function(...s){const n={};switch(r){case"add":{const[t]=s;n.addedItem=t,n.existed=e.has(t);break}case"delete":{const[t]=s;n.existed=e.has(t),n.deletedItem=n.existed?t:void 0;break}case"clear":n.clearedItems=Array.from(e),n.previousSize=e.size}t(n);const l=e[r].apply(e,s),c={method:r,result:l,args:s,context:n,target:e,...a};return o(c),l};for(const e of r)setMutableMethods.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:r=mapMutableMethods,props:a={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const s={},createWrappedMethod=r=>function(...s){const n={};switch(r){case"set":{const[t,o]=s;n.key=t,n.newValue=o,n.existed=e.has(t),n.oldValue=n.existed?e.get(t):void 0;break}case"delete":{const[t]=s;n.key=t,n.existed=e.has(t),n.value=n.existed?e.get(t):void 0;break}case"clear":n.clearedItems=Array.from(e.entries()),n.previousSize=e.size}t(n);const l=e[r].apply(e,s),c={method:r,result:l,args:s,context:n,target:e,...a};return o(c),l};for(const e of r)mapMutableMethods.includes(e)&&(s[e]=createWrappedMethod(e));return Object.defineProperty(s,"target",{get:()=>e,enumerable:!1,configurable:!1}),s},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId};module.exports=utils;
15
+ "use strict";var assert=require("assert");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),a=Object.assign({cloneSet:!0,cloneMap:!0,cloneObject:!0,cloneArray:!0,cloneDate:!0,cloneRegex:!0},t);if(a.interceptor&&"function"==typeof a.interceptor){let t=a.interceptor(e,r);if(t)return a.onAfterClone?.({output:t,input:e,type:r,cloned:t!==e}),t}a.onBeforeClone?.(e,r);let o,n=!0;if("Object"===r&&a.cloneObject){const t={},r=Object.getOwnPropertySymbols(e);for(const r in e)t[r]=deepClone(e[r],a);if(r.length>0)for(const o of r)t[o]=deepClone(e[o],a);o=t}else if("Array"===r&&a.cloneArray)o=e.map(e=>deepClone(e,a));else if("Map"===r&&a.cloneMap){const t=new Map;for(const[r,o]of e)t.set(deepClone(r,a),deepClone(o,a));o=t}else if("Set"===r&&a.cloneSet){const t=new Set;for(const r of e)t.add(deepClone(r,a));o=t}else if("Date"===r&&a.cloneDate)o=new Date(e.getTime());else if("RegExp"===r&&a.cloneRegex){const t=e;o=new RegExp(t.source,t.flags)}else o=e,n=!1;return a.onAfterClone?.({output:o,input:e,type:r,cloned:n}),o},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},arrayMutableMethods=["push","pop","shift","unshift","splice","sort","reverse","copyWithin","fill"],wrapArrayMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a,props:o={}})=>{if(!Array.isArray(e))throw new TypeError("The 'target' parameter must be an array.");a&&!a?.length||(a=arrayMutableMethods);const n={};for(let s of a)n[s]=function(...a){const n={},p=e.length;switch(s){case"push":case"unshift":n.addedItems=[...a];break;case"pop":n.poppedItem=e[p-1];break;case"shift":n.shiftedItem=e[0];break;case"splice":const[t,r]=a,o=t<0?Math.max(p+t,0):Math.min(t,p),s=void 0===r?p-o:r;n.deletedItems=e.slice(o,o+s);break;case"sort":case"reverse":n.oldSnapshot=[...e];break;case"fill":case"copyWithin":const l=a[1]||0,c=void 0===a[2]?p:a[2];n.oldItems=e.slice(l,c),n.start=l,n.end=c}t?.(n);const l=Array.prototype[s].apply(e,a),c={value:l,key:s,args:a,context:n,target:e,...o};return r?.(c),l};return n},requireTypes=(e,t,r)=>{let a=Array.isArray(t)?t:[t],o=getDataType(e),n=o.toLowerCase(),s=a.map(e=>e.toLowerCase()),p=n.includes("html")?"element":n;if(r)try{if(!s.includes(p))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${p}`)}catch(e){r(e,o)}else if(!s.includes(p))throw new TypeError(`Expected data type(s): [${s.join(", ")}], but got: ${p}`);return o},getUniqueId=(e={})=>{const t=e.prefix,r=e.suffix,a=e.base10,o=e.base36;return`${t?t+"-":""}${Date.now()}${o?"-"+Math.random().toString(36).substring(2,11):""}${a?"-"+Math.floor(1e4*Math.random()).toString().padStart(4,"0"):""}${r?"-"+r:""}`},setMutableMethods=["add","delete","clear"],mapMutableMethods=["set","delete","clear"],wrapSetMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=setMutableMethods,props:o={}})=>{if(!(e instanceof Set))throw new TypeError("The 'target' parameter must be a Set.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){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 p=e[a].apply(e,n),l={method:a,result:p,args:n,context:s,target:e,...o};return r(l),p};for(const e of a)setMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},wrapMapMethods=({target:e,onBeforeMutate:t=()=>{},onAfterMutate:r=()=>{},allowList:a=mapMutableMethods,props:o={}})=>{if(!(e instanceof Map))throw new TypeError("The 'target' parameter must be a Map.");const n={},createWrappedMethod=a=>function(...n){const s={};switch(a){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 p=e[a].apply(e,n),l={method:a,result:p,args:n,context:s,target:e,...o};return r(l),p};for(const e of a)mapMutableMethods.includes(e)&&(n[e]=createWrappedMethod(e));return Object.defineProperty(n,"target",{get:()=>e,enumerable:!1,configurable:!1}),n},deepMergeObjects=(e,t,r={})=>{let a=getDataType(e),o=getDataType(t);if("Object"!==a||"Object"!==o)return e;const n=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),s=n.targetClone?deepClone(e):e;for(let e in t)if(t.hasOwnProperty(e)&&s.hasOwnProperty(e)){let a=deepMergeHelper(s[e],t[e],r);a.flag?"Object"===a.type&&(s[e]=a.result):n.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)&&n.propAppend&&(s[e]=t[e]);if(n.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 a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1},r),o=a.targetClone?[...e]:e;if("replace"===a.itemMode)return o.length=0,o.push(...t),o;if("concat"===a.itemMode)return o.push(...t),o;for(let e=0;e<t.length;e++){deepMergeHelper(o[e],t[e],a).flag||(o[e]=t[e])}return o},deepMergeMaps=(e,t,r={itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0})=>{if(!(e instanceof Map&&t instanceof Map))return e;const a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Map(e):e;return"replace"===a.itemMode?(o.clear(),t.forEach((e,t)=>o.set(t,e)),o):"concat"===a.itemMode?(t.forEach((e,t)=>o.set(t,e)),o):(t.forEach((e,t)=>{if(o.has(t)){const r=o.get(t),n=e,s=deepMergeHelper(r,n,a);s.flag?"Object"===s.type&&o.set(t,s.result):o.set(t,n)}else o.set(t,e)}),o)},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),a=Object.keys(t);if(r.length!==a.length)return!1;for(let o of r)if(!a.includes(o)||!deepEqual(e[o],t[o]))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 a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r),o=a.targetClone?new Set(e):e;if("replace"===a.itemMode){o.clear();for(let e of t)o.add(e);return o}if("concat"===a.itemMode){for(let e of t)o.add(e);return o}for(let e of t){let t=[...o].find(t=>deepEqual(t,e));!deepMergeHelper(t,e,a).flag&&o.add(e)}return o},deepMergeHelper=(e,t,r)=>{let a,o,n=getDataType(e),s=getDataType(t),p=!0;return"Object"===n&&"Object"===s?(o=deepMergeObjects(e,t,r),a="Object"):"Array"===n&&"Array"===s?(o=deepMergeArrays(e,t,r),a="Array"):"Set"===n&&"Set"===s?(o=deepMergeSets(e,t,r),a="Set"):"Map"===n&&"Map"===s?(o=deepMergeMaps(e,t,r),a="Map"):(p=!1,o=e),{result:o,flag:p,type:a}},deepMerge=(e,t,r={})=>{let a=Object.assign({itemMode:"merge",propAppend:!0,targetClone:!1,useEnable:!0},r);return deepMergeHelper(e,t,a)},utils={getDataType:getDataType,requireTypes:requireTypes,deepClone:deepClone,deepCloneToJSON:deepCloneToJSON,wrapArrayMethods:wrapArrayMethods,arrayMutableMethods:arrayMutableMethods,setMutableMethods:setMutableMethods,mapMutableMethods:mapMutableMethods,wrapSetMethods:wrapSetMethods,wrapMapMethods:wrapMapMethods,getUniqueId:getUniqueId,deepEqual:assert.deepEqual,deepMerge:deepMerge,deepMergeArrays:deepMergeArrays,deepMergeMaps:deepMergeMaps,deepMergeObjects:deepMergeObjects,deepMergeSets:deepMergeSets};module.exports=utils;
package/dist/utils.esm.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}
@@ -14,6 +14,8 @@
14
14
  * @license MIT license
15
15
  */
16
16
 
17
+ import { deepEqual as deepEqual$1 } from 'assert';
18
+
17
19
  const getDataType = (obj) => {
18
20
  let tmp = Object.prototype.toString.call(obj).slice(8, -1), result;
19
21
  if (tmp === 'Function' && /^\s*class\s+/.test(obj.toString())) {
@@ -420,6 +422,251 @@ const wrapMapMethods = ({ target, onBeforeMutate = () => { }, onAfterMutate = ()
420
422
  return methods;
421
423
  };
422
424
 
425
+ const deepMergeObjects = (target, source, opts = {}) => {
426
+ let targetType = getDataType(target), sourceType = getDataType(source);
427
+ //target不是对象或者source为空则直接返回
428
+ if (targetType !== 'Object' || sourceType !== 'Object') {
429
+ return target;
430
+ }
431
+ const options = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, opts),
432
+ //如果是复制方法,则先复制target
433
+ result = options.targetClone ? deepClone(target) : target;
434
+ for (let k in source) {
435
+ if (source.hasOwnProperty(k) && result.hasOwnProperty(k)) {
436
+ let resp = deepMergeHelper(result[k], source[k], opts);
437
+ //resp={result,flag,type}
438
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
439
+ if (!resp.flag) {
440
+ //类型不同则直接覆盖
441
+ if (options.useEnable && result.hasOwnProperty(k) && result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
442
+ //部分替换,仅针对result={enable:true/false,a:''},source=false/true这种情况和相反的情况,因为这种情况再笨框架比较多见
443
+ if (result[k]?.hasOwnProperty('enable') && typeof source[k] === 'boolean') {
444
+ //result={enable:true,a:'',b:''},source[k]=false=>result={enable:false,a:'',b:''}
445
+ result[k].enable = source[k];
446
+ }
447
+ else if (source[k]?.hasOwnProperty('enable') && typeof result[k] === 'boolean') {
448
+ //source={enable:true,a:'',b:''},(result as any)[k]=false=>result={enable:false,a:'',b:''}
449
+ result = Object.assign({ enable: result[k] }, source[k]);
450
+ }
451
+ else {
452
+ //完全替换
453
+ result[k] = source[k];
454
+ }
455
+ }
456
+ else {
457
+ //完全替换
458
+ result[k] = source[k];
459
+ }
460
+ }
461
+ else {
462
+ // If both target and source are objects, merge them recursively
463
+ if (resp.type === 'Object') {
464
+ result[k] = resp.result;
465
+ }
466
+ }
467
+ }
468
+ else if (source.hasOwnProperty(k) && !result.hasOwnProperty(k) && options.propAppend) {
469
+ //如果source有属性,result没有该属性,但是options允许追加属性则直接赋值
470
+ result[k] = source[k];
471
+ }
472
+ }
473
+ //Symbol键直接追加,因为Symbol是唯一,结果同Object.assign
474
+ if (options.useSymbol) {
475
+ let symbols = Object.getOwnPropertySymbols(source);
476
+ if (symbols.length > 0) {
477
+ for (let k of symbols) {
478
+ result[k] = source[k];
479
+ }
480
+ }
481
+ }
482
+ return result;
483
+ };
484
+
485
+ const deepMergeArrays = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
486
+ // Ensure both target and source are arrays
487
+ if (!Array.isArray(target) || !Array.isArray(source))
488
+ return target;
489
+ // Merge options, with default values
490
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false }, options),
491
+ // If cloning is enabled, create a deep copy of the target array
492
+ result = opts.targetClone ? [...target] : target;
493
+ // Handle different merge strategies based on itemMode
494
+ if (opts.itemMode === 'replace') {
495
+ // Replace mode: clear the target array and push all items from the source array
496
+ result.length = 0;
497
+ result.push(...source);
498
+ return result;
499
+ }
500
+ else if (opts.itemMode === 'concat') {
501
+ // Concatenate mode: append all items from the source array to the target array
502
+ result.push(...source);
503
+ return result;
504
+ }
505
+ else {
506
+ // Default "merge" mode: recursively merge items in the arrays
507
+ for (let i = 0; i < source.length; i++) {
508
+ let resp = deepMergeHelper(result[i], source[i], opts);
509
+ //resp={result,flag,type}
510
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
511
+ if (!resp.flag) {
512
+ result[i] = source[i];
513
+ }
514
+ }
515
+ return result;
516
+ }
517
+ };
518
+
519
+ const deepMergeMaps = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
520
+ // Ensure both target and source are Maps
521
+ if (!(target instanceof Map) || !(source instanceof Map))
522
+ return target;
523
+ // Merge options, with default values
524
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
525
+ // If cloning is enabled, create a deep copy of the target Map
526
+ result = opts.targetClone ? new Map(target) : target;
527
+ // Handle different merge strategies based on itemMode
528
+ if (opts.itemMode === 'replace') {
529
+ // Replace mode: clear the target Map and add all entries from the source Map
530
+ result.clear();
531
+ source.forEach((value, key) => result.set(key, value));
532
+ return result;
533
+ }
534
+ else if (opts.itemMode === 'concat') {
535
+ // Concatenate mode: add all entries from the source Map to the target Map
536
+ source.forEach((value, key) => result.set(key, value));
537
+ return result;
538
+ }
539
+ else {
540
+ // Default "merge" mode: recursively merge entries in the Maps
541
+ source.forEach((value, key) => {
542
+ // Check if the key already exists in the target Map
543
+ if (result.has(key)) {
544
+ const targetValue = result.get(key), sourceValue = value, resp = deepMergeHelper(targetValue, sourceValue, opts);
545
+ //resp={result,flag,type}
546
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
547
+ if (!resp.flag) {
548
+ // For simple values, overwrite the target value with the source value
549
+ result.set(key, sourceValue);
550
+ }
551
+ else {
552
+ // If both target and source are objects, merge them recursively
553
+ resp.type === 'Object' && result.set(key, resp.result);
554
+ }
555
+ }
556
+ else {
557
+ // If the key doesn't exist in the target, add the entry from the source Map
558
+ result.set(key, value);
559
+ }
560
+ });
561
+ return result;
562
+ }
563
+ };
564
+
565
+ const deepEqual = (a, b) => {
566
+ // If both are equal by reference
567
+ if (a === b)
568
+ return true;
569
+ // If both are arrays, check equality recursively
570
+ if (Array.isArray(a) && Array.isArray(b)) {
571
+ if (a.length !== b.length)
572
+ return false;
573
+ for (let i = 0; i < a.length; i++) {
574
+ if (!deepEqual(a[i], b[i]))
575
+ return false;
576
+ }
577
+ return true;
578
+ }
579
+ // If both are objects, check equality recursively
580
+ if (typeof a === 'object' && typeof b === 'object') {
581
+ const keysA = Object.keys(a), keysB = Object.keys(b);
582
+ if (keysA.length !== keysB.length)
583
+ return false;
584
+ for (let key of keysA) {
585
+ if (!keysB.includes(key) || !deepEqual(a[key], b[key]))
586
+ return false;
587
+ }
588
+ return true;
589
+ }
590
+ // For other types, direct comparison
591
+ return a === b;
592
+ };
593
+
594
+ const deepMergeSets = (target, source, options = { itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }) => {
595
+ // Ensure both target and source are Sets
596
+ if (!(target instanceof Set) || !(source instanceof Set))
597
+ return target;
598
+ // Merge options, with default values
599
+ const opts = Object.assign({ itemMode: 'merge', propAppend: true, targetClone: false, useEnable: true }, options),
600
+ // If cloning is enabled, create a deep copy of the target Set
601
+ result = opts.targetClone ? new Set(target) : target;
602
+ // Handle different merge strategies based on itemMode
603
+ if (opts.itemMode === 'replace') {
604
+ // Replace mode: clear the target Set and add all items from the source Set
605
+ result.clear();
606
+ for (let item of source)
607
+ result.add(item);
608
+ return result;
609
+ }
610
+ else if (opts.itemMode === 'concat') {
611
+ // Concatenate mode: add all items from the source Set to the target Set
612
+ for (let item of source)
613
+ result.add(item);
614
+ return result;
615
+ }
616
+ else {
617
+ // Default "merge" mode: recursively merge items in the Sets
618
+ for (let item of source) {
619
+ // Check the type of the target and source items
620
+ let _target = [...result].find(val => deepEqual(val, item)), resp = deepMergeHelper(_target, item, opts);
621
+ //resp={result,flag}
622
+ //flag=true表示类型一致并完成了合并,false表示并没有合并需要直接赋值
623
+ !resp.flag && result.add(item);
624
+ }
625
+ return result;
626
+ }
627
+ };
628
+
629
+ // deepMergeHelper.ts
630
+
631
+
632
+ const deepMergeHelper = (target, source, options) => {
633
+ let targetType = getDataType(target), sourceType = getDataType(source), flag = true, type, result;
634
+ if (targetType === 'Object' && sourceType === 'Object') {
635
+ result = deepMergeObjects(target, source, options);
636
+ type = 'Object';
637
+ }
638
+ else if (targetType === 'Array' && sourceType === 'Array') {
639
+ result = deepMergeArrays(target, source, options);
640
+ type = 'Array';
641
+ }
642
+ else if (targetType === 'Set' && sourceType === 'Set') {
643
+ result = deepMergeSets(target, source, options);
644
+ type = 'Set';
645
+ }
646
+ else if (targetType === 'Map' && sourceType === 'Map') {
647
+ result = deepMergeMaps(target, source, options);
648
+ type = 'Map';
649
+ }
650
+ else {
651
+ flag = false;
652
+ result = target; // Default case, replace primitive values
653
+ }
654
+ return {
655
+ result, flag, type
656
+ };
657
+ };
658
+
659
+ const deepMerge = (target, source, opts = {}) => {
660
+ // Get the data types of the target and source
661
+ let options = Object.assign({
662
+ itemMode: 'merge', // Default merge mode
663
+ propAppend: true, // Default to appending properties from source to target
664
+ targetClone: false, // Do not clone target by default
665
+ useEnable: true // Enable special handling for objects with an `enable` property
666
+ }, opts);
667
+ return deepMergeHelper(target, source, options);
668
+ };
669
+
423
670
  const utils = {
424
671
  //executeStr,
425
672
  getDataType,
@@ -434,7 +681,13 @@ const utils = {
434
681
  mapMutableMethods,
435
682
  wrapSetMethods,
436
683
  wrapMapMethods,
437
- getUniqueId
684
+ getUniqueId,
685
+ deepEqual: deepEqual$1,
686
+ deepMerge,
687
+ deepMergeArrays,
688
+ deepMergeMaps,
689
+ deepMergeObjects,
690
+ deepMergeSets,
438
691
  };
439
692
 
440
693
  export { utils as default };