@libs-ui/utils 0.2.245 → 0.2.247
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/esm2022/format-date.mjs +12 -2
- package/esm2022/helpers.mjs +154 -8
- package/fesm2022/libs-ui-utils.mjs +163 -8
- package/fesm2022/libs-ui-utils.mjs.map +1 -1
- package/helpers.d.ts +139 -1
- package/package.json +2 -2
|
@@ -405,12 +405,44 @@ class UtilsHttpParamsRequest extends HttpParams {
|
|
|
405
405
|
|
|
406
406
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
407
407
|
/**Các hàm tương tự thư viện lodash */
|
|
408
|
+
/**
|
|
409
|
+
* Kiểm tra xem một giá trị có phải là null hoặc undefined hay không
|
|
410
|
+
* @param value Giá trị cần kiểm tra
|
|
411
|
+
* @returns true nếu giá trị là null hoặc undefined, false nếu không
|
|
412
|
+
* @example
|
|
413
|
+
* isNil(null); // true
|
|
414
|
+
* isNil(undefined); // true
|
|
415
|
+
* isNil(0); // false
|
|
416
|
+
* isNil('hello'); // false
|
|
417
|
+
*/
|
|
408
418
|
const isNil = (value) => {
|
|
409
419
|
return value === null || value === undefined;
|
|
410
420
|
};
|
|
421
|
+
/**
|
|
422
|
+
* Kiểm tra xem một giá trị có phải là rỗng hay không
|
|
423
|
+
* @param value Giá trị cần kiểm tra
|
|
424
|
+
* @returns true nếu giá trị là null, rỗng hoặc undefined, false nếu không
|
|
425
|
+
* @example
|
|
426
|
+
* isEmpty(null); // true
|
|
427
|
+
* isEmpty(''); // true
|
|
428
|
+
* isEmpty(undefined); // true
|
|
429
|
+
* isEmpty({}); // true
|
|
430
|
+
* isEmpty([]); // true
|
|
431
|
+
* isEmpty([1, 2, 3]); // false
|
|
432
|
+
* isEmpty({ a: 1 }); // false
|
|
433
|
+
*/
|
|
411
434
|
const isEmpty = (value) => {
|
|
412
435
|
return value === null || value === '' || value === undefined || (typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]'));
|
|
413
436
|
};
|
|
437
|
+
/**
|
|
438
|
+
* Loại bỏ các thuộc tính của đối tượng dựa trên một hàm điều kiện
|
|
439
|
+
* @param objData Đối tượng cần xử lý
|
|
440
|
+
* @param predicate Hàm điều kiện để kiểm tra giá trị của thuộc tính. Nếu hàm trả về true thì thuộc tính đó sẽ bị loại bỏ
|
|
441
|
+
* @returns Đối tượng mới sau khi đã loại bỏ các thuộc tính thỏa mãn điều kiện
|
|
442
|
+
* @example
|
|
443
|
+
* const obj = { a: 1, b: null, c: 3, d: undefined };
|
|
444
|
+
* omitBy(obj, isNil); // { a: 1, c: 3 }
|
|
445
|
+
*/
|
|
414
446
|
const omitBy = (objData, predicate) => {
|
|
415
447
|
if (!objData || typeof objData !== 'object' || Array.isArray(objData)) {
|
|
416
448
|
return objData;
|
|
@@ -459,6 +491,17 @@ const get = (obj, path, defaultValue = undefined, keepLastValueIfSignal) => {
|
|
|
459
491
|
}
|
|
460
492
|
return obj;
|
|
461
493
|
};
|
|
494
|
+
/**
|
|
495
|
+
* Thiết lập giá trị cho một thuộc tính trong đối tượng theo đường dẫn chỉ định
|
|
496
|
+
* @param obj Đối tượng cần thiết lập giá trị
|
|
497
|
+
* @param path Đường dẫn đến thuộc tính, có thể là chuỗi (vd: 'a.b.c') hoặc mảng (vd: ['a', 'b', 'c'])
|
|
498
|
+
* @param value Giá trị cần thiết lập
|
|
499
|
+
* @returns Đối tượng sau khi đã thiết lập giá trị
|
|
500
|
+
* @throws Error nếu tham số đầu tiên không phải là đối tượng
|
|
501
|
+
* @example
|
|
502
|
+
* const obj = { a: { b: 1 } };
|
|
503
|
+
* set(obj, 'a.b', 2); // { a: { b: 2 } }
|
|
504
|
+
*/
|
|
462
505
|
const set = (obj, path, value) => {
|
|
463
506
|
if (!obj || (typeof obj !== "object" && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== "object")) {
|
|
464
507
|
throw new Error("The first argument must be an object");
|
|
@@ -503,7 +546,23 @@ const set = (obj, path, value) => {
|
|
|
503
546
|
});
|
|
504
547
|
return obj;
|
|
505
548
|
};
|
|
506
|
-
|
|
549
|
+
/**
|
|
550
|
+
* Tạo một bản sao sâu của một đối tượng hoặc giá trị bất kỳ
|
|
551
|
+
* @param data Dữ liệu cần sao chép
|
|
552
|
+
* @param options Tùy chọn cấu hình
|
|
553
|
+
* @param options.ignoreSignal Nếu true, sẽ không sao chép các signal mà trả về signal gốc
|
|
554
|
+
* @param seen WeakMap để theo dõi các tham chiếu đã được sao chép, tránh lặp vô hạn với các tham chiếu vòng
|
|
555
|
+
* @returns Bản sao sâu của dữ liệu đầu vào
|
|
556
|
+
* @example
|
|
557
|
+
* const obj = {
|
|
558
|
+
* a: 1,
|
|
559
|
+
* b: { c: 2 },
|
|
560
|
+
* d: [1, 2, 3]
|
|
561
|
+
* };
|
|
562
|
+
* const clone = cloneDeep(obj);
|
|
563
|
+
* // clone là một bản sao hoàn toàn độc lập của obj
|
|
564
|
+
*/
|
|
565
|
+
const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()) => {
|
|
507
566
|
if (data === null || (typeof data !== 'object' && !isSignal(data))) {
|
|
508
567
|
return data;
|
|
509
568
|
}
|
|
@@ -523,7 +582,7 @@ const cloneDeep = (data, seen = new WeakMap()) => {
|
|
|
523
582
|
const mapCopy = new Map();
|
|
524
583
|
seen.set(data, mapCopy);
|
|
525
584
|
data.forEach((val, key) => {
|
|
526
|
-
mapCopy.set(cloneDeep(key, seen), cloneDeep(val, seen));
|
|
585
|
+
mapCopy.set(cloneDeep(key, options, seen), cloneDeep(val, options, seen));
|
|
527
586
|
});
|
|
528
587
|
return mapCopy;
|
|
529
588
|
}
|
|
@@ -531,12 +590,12 @@ const cloneDeep = (data, seen = new WeakMap()) => {
|
|
|
531
590
|
const setCopy = new Set();
|
|
532
591
|
seen.set(data, setCopy);
|
|
533
592
|
data.forEach(val => {
|
|
534
|
-
setCopy.add(cloneDeep(val, seen));
|
|
593
|
+
setCopy.add(cloneDeep(val, options, seen));
|
|
535
594
|
});
|
|
536
595
|
return setCopy;
|
|
537
596
|
}
|
|
538
597
|
if (Array.isArray(data)) {
|
|
539
|
-
seen.set(data, data.map(item => cloneDeep(item, seen)));
|
|
598
|
+
seen.set(data, data.map(item => cloneDeep(item, options, seen)));
|
|
540
599
|
return seen.get(data);
|
|
541
600
|
}
|
|
542
601
|
if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
|
|
@@ -546,7 +605,10 @@ const cloneDeep = (data, seen = new WeakMap()) => {
|
|
|
546
605
|
return data;
|
|
547
606
|
}
|
|
548
607
|
if (isSignal(data)) {
|
|
549
|
-
|
|
608
|
+
if (options?.ignoreSignal) {
|
|
609
|
+
return data;
|
|
610
|
+
}
|
|
611
|
+
seen.set(data, signal(cloneDeep(data(), options, seen)));
|
|
550
612
|
return seen.get(data);
|
|
551
613
|
}
|
|
552
614
|
const result = {};
|
|
@@ -562,11 +624,27 @@ const cloneDeep = (data, seen = new WeakMap()) => {
|
|
|
562
624
|
continue;
|
|
563
625
|
}
|
|
564
626
|
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
565
|
-
result[key] = cloneDeep(value, seen);
|
|
627
|
+
result[key] = cloneDeep(value, options, seen);
|
|
566
628
|
}
|
|
567
629
|
}
|
|
568
630
|
return result;
|
|
569
631
|
};
|
|
632
|
+
/**
|
|
633
|
+
* Chuyển đổi một mảng các đối tượng thành một đối tượng với khóa được chỉ định
|
|
634
|
+
* @param data Mảng các đối tượng cần chuyển đổi
|
|
635
|
+
* @param key Tên thuộc tính được sử dụng làm khóa trong đối tượng kết quả
|
|
636
|
+
* @returns Đối tượng với các giá trị từ mảng được đánh key theo thuộc tính đã chỉ định
|
|
637
|
+
* @example
|
|
638
|
+
* const data = [
|
|
639
|
+
* { id: 1, name: 'John' },
|
|
640
|
+
* { id: 2, name: 'Jane' }
|
|
641
|
+
* ];
|
|
642
|
+
* keyBy(data, 'id');
|
|
643
|
+
* // Kết quả: {
|
|
644
|
+
* // '1': { id: 1, name: 'John' },
|
|
645
|
+
* // '2': { id: 2, name: 'Jane' }
|
|
646
|
+
* // }
|
|
647
|
+
*/
|
|
570
648
|
const keyBy = (data, key) => {
|
|
571
649
|
if (!data || !data.length || !key) {
|
|
572
650
|
return {};
|
|
@@ -580,6 +658,27 @@ const keyBy = (data, key) => {
|
|
|
580
658
|
return dir;
|
|
581
659
|
}, {});
|
|
582
660
|
};
|
|
661
|
+
/**
|
|
662
|
+
* Nhóm các đối tượng trong một mảng thành các nhóm dựa trên một thuộc tính cụ thể
|
|
663
|
+
* @param data Mảng các đối tượng cần nhóm
|
|
664
|
+
* @param key Tên thuộc tính được sử dụng làm khóa nhóm
|
|
665
|
+
* @returns Đối tượng với các giá trị từ mảng được nhóm theo thuộc tính đã chỉ định
|
|
666
|
+
* @example
|
|
667
|
+
* const data = [
|
|
668
|
+
* { id: 1, name: 'John' },
|
|
669
|
+
* { id: 2, name: 'Jane' },
|
|
670
|
+
* { id: 1, name: 'John' }
|
|
671
|
+
* ];
|
|
672
|
+
* groupBy(data, 'id');
|
|
673
|
+
* // Kết quả: {
|
|
674
|
+
* // '1': [
|
|
675
|
+
* // { id: 1, name: 'John' },
|
|
676
|
+
* // { id: 1, name: 'John' }
|
|
677
|
+
* // ],
|
|
678
|
+
* // '2': [
|
|
679
|
+
* // { id: 2, name: 'Jane' }
|
|
680
|
+
* // }
|
|
681
|
+
*/
|
|
583
682
|
const groupBy = (data, key) => {
|
|
584
683
|
if (!data || !Object.keys(data).length || !key) {
|
|
585
684
|
return {};
|
|
@@ -596,6 +695,18 @@ const groupBy = (data, key) => {
|
|
|
596
695
|
return dir;
|
|
597
696
|
}, {});
|
|
598
697
|
};
|
|
698
|
+
/**
|
|
699
|
+
* Tạo một mảng các số từ giá trị bắt đầu đến giá trị kết thúc với bước nhảy tùy chọn
|
|
700
|
+
* @param start Giá trị bắt đầu của dãy số. Nếu chỉ có một tham số, đây sẽ là giá trị kết thúc và giá trị bắt đầu sẽ là 0
|
|
701
|
+
* @param end Giá trị kết thúc của dãy số (tùy chọn)
|
|
702
|
+
* @param step Bước nhảy giữa các số trong dãy (tùy chọn). Mặc định là 1 nếu end > start, -1 nếu end < start
|
|
703
|
+
* @returns Mảng các số từ start đến end với bước nhảy step
|
|
704
|
+
* @example
|
|
705
|
+
* range(4); // [0, 1, 2, 3]
|
|
706
|
+
* range(1, 5); // [1, 2, 3, 4]
|
|
707
|
+
* range(0, 20, 5); // [0, 5, 10, 15]
|
|
708
|
+
* range(5, 2); // [5, 4, 3]
|
|
709
|
+
*/
|
|
599
710
|
const range = (start, end, step) => {
|
|
600
711
|
if (end === undefined || end === null) {
|
|
601
712
|
end = start;
|
|
@@ -625,11 +736,30 @@ const range = (start, end, step) => {
|
|
|
625
736
|
}
|
|
626
737
|
return arr;
|
|
627
738
|
};
|
|
739
|
+
/**
|
|
740
|
+
* So sánh hai giá trị bất kỳ có bằng nhau hay không
|
|
741
|
+
* @param value1 Giá trị thứ nhất cần so sánh
|
|
742
|
+
* @param value2 Giá trị thứ hai cần so sánh
|
|
743
|
+
* @param exactlyPosition Có so sánh chính xác vị trí các phần tử trong mảng hay không
|
|
744
|
+
* @returns true nếu hai giá trị bằng nhau, false nếu không bằng nhau
|
|
745
|
+
* @example
|
|
746
|
+
* isEqual([1,2,3], [1,2,3]); // true
|
|
747
|
+
* isEqual([1,2,3], [3,2,1]); // true khi exactlyPosition = false
|
|
748
|
+
* isEqual([1,2,3], [3,2,1]); // false khi exactlyPosition = true
|
|
749
|
+
* isEqual({a:1}, {a:1}); // true
|
|
750
|
+
*/
|
|
628
751
|
const isEqual = (value1, value2, exactlyPosition = false) => {
|
|
629
752
|
if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
|
|
630
753
|
return true;
|
|
631
754
|
}
|
|
632
|
-
|
|
755
|
+
// Handle signals
|
|
756
|
+
while (isSignal(value1)) {
|
|
757
|
+
value1 = value1();
|
|
758
|
+
}
|
|
759
|
+
while (isSignal(value2)) {
|
|
760
|
+
value2 = value2();
|
|
761
|
+
}
|
|
762
|
+
if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2)) || (!Array.isArray(value1) && Array.isArray(value2))) {
|
|
633
763
|
return false;
|
|
634
764
|
}
|
|
635
765
|
if (Array.isArray(value1)) {
|
|
@@ -646,6 +776,22 @@ const isEqual = (value1, value2, exactlyPosition = false) => {
|
|
|
646
776
|
}
|
|
647
777
|
return !Object.keys(value1).some((key) => !isEqual(value1[key], value2[key]));
|
|
648
778
|
};
|
|
779
|
+
/**
|
|
780
|
+
* Loại bỏ các phần tử trùng lặp trong mảng dựa trên một thuộc tính chỉ định
|
|
781
|
+
* @param data Mảng dữ liệu cần xử lý
|
|
782
|
+
* @param key Tên thuộc tính dùng để so sánh trùng lặp. Nếu không có key thì so sánh trực tiếp giá trị
|
|
783
|
+
* @returns Mảng mới chứa các phần tử không trùng lặp
|
|
784
|
+
* @example
|
|
785
|
+
* const arr = [
|
|
786
|
+
* { id: 1, name: 'A' },
|
|
787
|
+
* { id: 2, name: 'B' },
|
|
788
|
+
* { id: 1, name: 'C' }
|
|
789
|
+
* ];
|
|
790
|
+
* uniqBy(arr, 'id'); // [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]
|
|
791
|
+
*
|
|
792
|
+
* const numbers = [1, 2, 2, 3, 3];
|
|
793
|
+
* uniqBy(numbers); // [1, 2, 3]
|
|
794
|
+
*/
|
|
649
795
|
const uniqBy = (data, key) => {
|
|
650
796
|
if (!key || !data || !data.length || typeof data[0] !== 'object') {
|
|
651
797
|
return Array.from(new Set(data));
|
|
@@ -1879,7 +2025,16 @@ const getDayjs = (config) => {
|
|
|
1879
2025
|
if (!config.date) {
|
|
1880
2026
|
return undefined;
|
|
1881
2027
|
}
|
|
1882
|
-
|
|
2028
|
+
let { date, utc, formatOfDate } = config;
|
|
2029
|
+
while (isSignal(date)) {
|
|
2030
|
+
date = date();
|
|
2031
|
+
}
|
|
2032
|
+
while (isSignal(utc)) {
|
|
2033
|
+
utc = utc();
|
|
2034
|
+
}
|
|
2035
|
+
while (isSignal(formatOfDate)) {
|
|
2036
|
+
formatOfDate = formatOfDate();
|
|
2037
|
+
}
|
|
1883
2038
|
if (utc) {
|
|
1884
2039
|
if (formatOfDate) {
|
|
1885
2040
|
return dayjs(date, formatOfDate).utc();
|