@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.
@@ -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
- const cloneDeep = (data, seen = new WeakMap()) => {
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
- seen.set(data, signal(cloneDeep(data(), seen)));
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
- if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2))) {
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
- const { date, utc, formatOfDate } = config;
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();