@ntnyq/utils 0.10.0 → 0.11.1

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +585 -487
  2. package/dist/index.js +179 -147
  3. package/package.json +35 -37
package/dist/index.js CHANGED
@@ -7,7 +7,6 @@ function noop() {}
7
7
  * Alias of {@link noop}.
8
8
  */
9
9
  const NOOP = noop;
10
-
11
10
  //#endregion
12
11
  //#region src/fn/once.ts
13
12
  /**
@@ -35,7 +34,16 @@ function once(func) {
35
34
  return true;
36
35
  };
37
36
  }
38
-
37
+ //#endregion
38
+ //#region src/env/isBrowser.ts
39
+ /**
40
+ * Checks if the code is running in a browser
41
+ *
42
+ * @returns true if the code is running in a browser
43
+ */
44
+ function isBrowser() {
45
+ return typeof document !== "undefined" && typeof window !== "undefined" && typeof navigator !== "undefined" && window === self;
46
+ }
39
47
  //#endregion
40
48
  //#region src/is/dom.ts
41
49
  /**
@@ -47,9 +55,9 @@ function once(func) {
47
55
  * @returns True if the value is an HTMLElement, false otherwise
48
56
  */
49
57
  function isHTMLElement(value) {
58
+ if (!isBrowser()) return false;
50
59
  return typeof value === "object" && value !== null && "nodeType" in value && value.nodeType === Node.ELEMENT_NODE && value instanceof HTMLElement;
51
60
  }
52
-
53
61
  //#endregion
54
62
  //#region src/is/core.ts
55
63
  function getObjectType(value) {
@@ -116,24 +124,24 @@ function isEmptyArray(value) {
116
124
  function isNonEmptyArray(value) {
117
125
  return isArray(value) && value.length > 0;
118
126
  }
119
- function isObject(value) {
120
- return (typeof value === "object" || isFunction(value)) && !isNull(value);
121
- }
122
- function isEmptyObject(value) {
123
- return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
124
- }
125
127
  function isMap(value) {
126
128
  return getObjectType(value) === "Map";
127
129
  }
128
- function isEmptyMap(value) {
129
- return isMap(value) && value.size === 0;
130
- }
131
130
  function isSet(value) {
132
131
  return getObjectType(value) === "Set";
133
132
  }
134
133
  function isEmptySet(value) {
135
134
  return isSet(value) && value.size === 0;
136
135
  }
136
+ function isObject(value) {
137
+ return (typeof value === "object" || isFunction(value)) && !isNull(value);
138
+ }
139
+ function isEmptyObject(value) {
140
+ return isObject(value) && !isMap(value) && !isSet(value) && Object.keys(value).length === 0;
141
+ }
142
+ function isEmptyMap(value) {
143
+ return isMap(value) && value.size === 0;
144
+ }
137
145
  function isRegExp(value) {
138
146
  return getObjectType(value) === "RegExp";
139
147
  }
@@ -173,7 +181,6 @@ function isUrlString(value) {
173
181
  return false;
174
182
  }
175
183
  }
176
-
177
184
  //#endregion
178
185
  //#region src/is/isDeepEqual.ts
179
186
  /**
@@ -192,7 +199,6 @@ function isDeepEqual(value1, value2) {
192
199
  }
193
200
  return Object.is(value1, value2);
194
201
  }
195
-
196
202
  //#endregion
197
203
  //#region src/dom/scrollIntoView.ts
198
204
  /**
@@ -212,7 +218,6 @@ function scrollElementIntoView(element, options = {}) {
212
218
  const elementRect = element.getBoundingClientRect();
213
219
  if (parent.scrollWidth > parent.scrollHeight ? elementRect.left < parentRect.left || elementRect.right > parentRect.right : elementRect.top < parentRect.top || elementRect.bottom > parentRect.bottom) parent.scrollIntoView(scrollIntoViewOptions);
214
220
  }
215
-
216
221
  //#endregion
217
222
  //#region src/dom/openExternalURL.ts
218
223
  /**
@@ -225,7 +230,6 @@ function openExternalURL(url, options = {}) {
225
230
  const { target = "_blank" } = options;
226
231
  return window.open(url, target);
227
232
  }
228
-
229
233
  //#endregion
230
234
  //#region src/dom/isVisibleInViewport.ts
231
235
  /**
@@ -239,23 +243,8 @@ function isElementVisibleInViewport(element, targetWindow = window) {
239
243
  const { innerWidth, innerHeight } = targetWindow;
240
244
  return (top >= 0 && top <= innerHeight || bottom >= 0 && bottom <= innerHeight) && (left >= 0 && left <= innerWidth || right >= 0 && right <= innerWidth);
241
245
  }
242
-
243
- //#endregion
244
- //#region src/env/isBrowser.ts
245
- /**
246
- * @file env.ts
247
- */
248
- /**
249
- * Checks if the code is running in a browser
250
- *
251
- * @returns boolean - true if the code is running in a browser
252
- */
253
- function isBrowser() {
254
- return typeof document !== "undefined";
255
- }
256
-
257
246
  //#endregion
258
- //#region src/file/removeExtension.ts
247
+ //#region src/file/extension.ts
259
248
  /**
260
249
  * Removes the file extension from a filename.
261
250
  *
@@ -265,7 +254,15 @@ function isBrowser() {
265
254
  function removeFileExtension(filename) {
266
255
  return filename.replace(/\.[^/.]+$/, "");
267
256
  }
268
-
257
+ /**
258
+ * Gets the file extension from a filename.
259
+ * @param filePath - The filePath to get the extension from.
260
+ * @returns The file extension, or undefined if there is none.
261
+ */
262
+ function getFileExtension(filePath) {
263
+ if (!filePath) return;
264
+ return filePath.match(/\.([^.]+)$/)?.[1];
265
+ }
269
266
  //#endregion
270
267
  //#region src/html/escape.ts
271
268
  const htmlEscapeMap = {
@@ -301,7 +298,6 @@ const htmlUnescapeRegexp = /&(amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g;
301
298
  function unescapeHTML(str) {
302
299
  return str.replace(htmlUnescapeRegexp, (char) => htmlUnescapeMap[char]);
303
300
  }
304
-
305
301
  //#endregion
306
302
  //#region src/misc/raf.ts
307
303
  /**
@@ -334,7 +330,6 @@ function cAF(id) {
334
330
  const root = getRoot();
335
331
  return root.cancelAnimationFrame.call(root, id);
336
332
  }
337
-
338
333
  //#endregion
339
334
  //#region src/misc/clamp.ts
340
335
  /**
@@ -347,7 +342,6 @@ function cAF(id) {
347
342
  function clamp(value, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY) {
348
343
  return Math.min(Math.max(value, min), max);
349
344
  }
350
-
351
345
  //#endregion
352
346
  //#region src/misc/waitFor.ts
353
347
  /**
@@ -366,7 +360,6 @@ function clamp(value, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFI
366
360
  async function waitFor(ms) {
367
361
  return new Promise((resolve) => setTimeout(resolve, ms));
368
362
  }
369
-
370
363
  //#endregion
371
364
  //#region src/misc/throttle.ts
372
365
  /**
@@ -384,7 +377,7 @@ function throttle(delay, callback, options = {}) {
384
377
  */
385
378
  let lastExec = 0;
386
379
  let cancelled = false;
387
- let timeoutId;
380
+ let timeoutId = void 0;
388
381
  function clearExistingTimeout() {
389
382
  if (timeoutId) clearTimeout(timeoutId);
390
383
  }
@@ -418,7 +411,6 @@ function debounce(delay, callback, options = {}) {
418
411
  isDebounce: true
419
412
  });
420
413
  }
421
-
422
414
  //#endregion
423
415
  //#region src/misc/warnOnce.ts
424
416
  /**
@@ -435,7 +427,6 @@ function warnOnce(message) {
435
427
  warned.add(message);
436
428
  console.warn(message);
437
429
  }
438
-
439
430
  //#endregion
440
431
  //#region src/misc/convertTime.ts
441
432
  /**
@@ -499,7 +490,6 @@ function convertFromMilliseconds(milliseconds, toUnit = "SECOND") {
499
490
  function convertTimeUnit(value, fromUnit, toUnit) {
500
491
  return convertFromMilliseconds(convertToMilliseconds(value, fromUnit), toUnit);
501
492
  }
502
-
503
493
  //#endregion
504
494
  //#region src/misc/convertStorage.ts
505
495
  /**
@@ -562,7 +552,6 @@ function convertFromBytes(bytes, toUnit = "MB") {
562
552
  function convertStorageUnit(value, fromUnit, toUnit) {
563
553
  return convertFromBytes(convertToBytes(value, fromUnit), toUnit);
564
554
  }
565
-
566
555
  //#endregion
567
556
  //#region src/array/at.ts
568
557
  /**
@@ -585,7 +574,6 @@ function at(array, index) {
585
574
  function last(array) {
586
575
  return at(array, -1);
587
576
  }
588
-
589
577
  //#endregion
590
578
  //#region src/array/chunk.ts
591
579
  /**
@@ -599,7 +587,23 @@ function chunk(array, size) {
599
587
  for (let i = 0; i < array.length; i += size) result.push(array.slice(i, i + size));
600
588
  return result;
601
589
  }
602
-
590
+ //#endregion
591
+ //#region src/array/remove.ts
592
+ /**
593
+ * Remove given item from an array
594
+ * @param array - given array
595
+ * @param value - item to be removed
596
+ * @returns true if item was removed, otherwise false
597
+ */
598
+ function remove(array, value) {
599
+ if (!array) return false;
600
+ const index = array.indexOf(value);
601
+ if (index !== -1) {
602
+ array.splice(index, 1);
603
+ return true;
604
+ }
605
+ return false;
606
+ }
603
607
  //#endregion
604
608
  //#region src/array/unique.ts
605
609
  /**
@@ -622,7 +626,86 @@ function uniqueBy(array, equalFn) {
622
626
  return acc;
623
627
  }, []);
624
628
  }
625
-
629
+ //#endregion
630
+ //#region src/number/random.ts
631
+ /**
632
+ * random an integer by given range
633
+ *
634
+ * @param min - min value
635
+ * @param max - max value
636
+ * @returns random integer in range
637
+ */
638
+ function randomNumber(min, max = 0, options = {}) {
639
+ if (max === 0) {
640
+ max = min;
641
+ min = 0;
642
+ }
643
+ if (min > max) [min, max] = [max, min];
644
+ return Math.trunc(Math.random() * (max - min + (options.includeMax ? 1 : 0)) + min);
645
+ }
646
+ //#endregion
647
+ //#region src/number/toInteger.ts
648
+ /**
649
+ * Transforms a value to an integer.
650
+ * @param value - The value to convert to an integer.
651
+ * @param options - Options for the conversion.
652
+ * @returns The converted integer.
653
+ */
654
+ function toInteger(value, options = {}) {
655
+ const { defaultValue = 0, allowDecimal = false, allowNaN = false, onError = "useDefault", min, max, outOfRange = "clamp" } = options;
656
+ let numberValue;
657
+ let result;
658
+ if (isNumber(value)) numberValue = value;
659
+ else if (isString(value)) {
660
+ const trimmed = value.trim();
661
+ if (isEmptyString(trimmed)) {
662
+ if (onError === "throwError") throw new TypeError("Cannot convert empty string to an integer");
663
+ return onError === "returnOriginal" ? value : defaultValue;
664
+ }
665
+ numberValue = Number(trimmed);
666
+ } else if (isNullOrUndefined(value)) {
667
+ if (onError === "throwError") throw new TypeError(`Cannot convert ${value} to an integer`);
668
+ return onError === "useDefault" ? value : defaultValue;
669
+ } else numberValue = Number(value);
670
+ if (isNaN(numberValue)) {
671
+ if (allowNaN) return numberValue;
672
+ if (onError === "throwError") throw new TypeError(`Cannot convert NaN to an integer`);
673
+ return onError === "returnOriginal" ? value : defaultValue;
674
+ }
675
+ if (allowDecimal) result = numberValue > 0 ? Math.floor(numberValue) : Math.ceil(numberValue);
676
+ else {
677
+ if (numberValue % 1 !== 0) {
678
+ if (onError === "throwError") throw new Error("Decimal values are not allowed");
679
+ return onError === "returnOriginal" ? value : defaultValue;
680
+ }
681
+ result = numberValue;
682
+ }
683
+ if (!isUndefined(min) || !isUndefined(max)) {
684
+ const minVal = min ?? -Infinity;
685
+ const maxVal = max ?? Infinity;
686
+ if (result < minVal || result > maxVal) {
687
+ if (outOfRange === "throwError") throw new RangeError(`Value ${result} is out of range [${minVal}, ${maxVal}]`);
688
+ if (outOfRange === "useDefault") return defaultValue;
689
+ if (outOfRange === "clamp") result = Math.max(minVal, Math.min(maxVal, numberValue));
690
+ }
691
+ }
692
+ return result;
693
+ }
694
+ //#endregion
695
+ //#region src/array/shuffle.ts
696
+ /**
697
+ * Fisher–Yates shuffle
698
+ *
699
+ * @param array - array to shuffle
700
+ * @returns shuffled array
701
+ */
702
+ function shuffle(array) {
703
+ for (let i = array.length - 1; i > 0; i--) {
704
+ const j = randomNumber(0, i, { includeMax: true });
705
+ [array[i], array[j]] = [array[j], array[i]];
706
+ }
707
+ return array;
708
+ }
626
709
  //#endregion
627
710
  //#region src/array/toArray.ts
628
711
  /**
@@ -634,7 +717,6 @@ function toArray(array) {
634
717
  array = array ?? [];
635
718
  return Array.isArray(array) ? array : [array];
636
719
  }
637
-
638
720
  //#endregion
639
721
  //#region src/array/arrayable.ts
640
722
  /**
@@ -653,7 +735,6 @@ function flattenArrayable(array) {
653
735
  function mergeArrayable(...args) {
654
736
  return args.flatMap((i) => toArray(i));
655
737
  }
656
-
657
738
  //#endregion
658
739
  //#region src/array/intersect.ts
659
740
  /**
@@ -664,7 +745,6 @@ function mergeArrayable(...args) {
664
745
  function intersect(a, b) {
665
746
  return a.filter((item) => b.includes(item));
666
747
  }
667
-
668
748
  //#endregion
669
749
  //#region src/array/isArrayEqual.ts
670
750
  /**
@@ -677,14 +757,12 @@ function isArrayEqual(array1, array2) {
677
757
  if (array1.length !== array2.length) return false;
678
758
  return array1.every((item, idx) => item === array2[idx]);
679
759
  }
680
-
681
760
  //#endregion
682
761
  //#region src/string/pad.ts
683
762
  function createPadString(options) {
684
763
  const { length, char } = options;
685
764
  return (value) => (char.repeat(length) + value).slice(-length);
686
765
  }
687
-
688
766
  //#endregion
689
767
  //#region src/string/join.ts
690
768
  /**
@@ -696,85 +774,24 @@ function createPadString(options) {
696
774
  function join(array, options = {}) {
697
775
  const { separator = "" } = options;
698
776
  if (!Array.isArray(array) || !array.length) return "";
699
- return array.filter((v) => Boolean(v) || v === 0).join(separator);
777
+ return array.filter((i) => Boolean(i) || i === 0).join(separator);
700
778
  }
701
-
702
779
  //#endregion
703
780
  //#region src/string/slash.ts
704
781
  /**
705
782
  * Replace backslash to slash
706
783
  */
707
784
  function slash(input) {
708
- return input.replace(/\\/g, "/");
785
+ return input.replaceAll("\\", "/");
709
786
  }
710
-
711
787
  //#endregion
712
- //#region src/number/random.ts
788
+ //#region src/string/escape.ts
713
789
  /**
714
- * random an integer by given range
715
- *
716
- * @param min - min value
717
- * @param max - max value
718
- * @returns random integer in range
790
+ * @copyright {@link https://github.com/sindresorhus/escape-string-regexp}
719
791
  */
720
- function randomNumber(min, max = 0, options = {}) {
721
- if (max === 0) {
722
- max = min;
723
- min = 0;
724
- }
725
- if (min > max) [min, max] = [max, min];
726
- return Math.trunc(Math.random() * (max - min + (options.includeMax ? 1 : 0)) + min);
792
+ function escapeStringRegexp(value) {
793
+ return value.replaceAll(/[|\\{}()[\]^$+*?.]/g, "\\$&").replaceAll("-", "\\x2d");
727
794
  }
728
-
729
- //#endregion
730
- //#region src/number/toInteger.ts
731
- /**
732
- * Transforms a value to an integer.
733
- * @param value - The value to convert to an integer.
734
- * @param options - Options for the conversion.
735
- * @returns The converted integer.
736
- */
737
- function toInteger(value, options = {}) {
738
- const { defaultValue = 0, allowDecimal = false, allowNaN = false, onError = "useDefault", min, max, outOfRange = "clamp" } = options;
739
- let numberValue;
740
- let result;
741
- if (isNumber(value)) numberValue = value;
742
- else if (isString(value)) {
743
- const trimmed = value.trim();
744
- if (isEmptyString(trimmed)) {
745
- if (onError === "throwError") throw new TypeError("Cannot convert empty string to an integer");
746
- return onError === "returnOriginal" ? value : defaultValue;
747
- }
748
- numberValue = Number(trimmed);
749
- } else if (isNullOrUndefined(value)) {
750
- if (onError === "throwError") throw new TypeError(`Cannot convert ${value} to an integer`);
751
- return onError === "useDefault" ? value : defaultValue;
752
- } else numberValue = Number(value);
753
- if (isNaN(numberValue)) {
754
- if (allowNaN) return numberValue;
755
- if (onError === "throwError") throw new TypeError(`Cannot convert NaN to an integer`);
756
- return onError === "returnOriginal" ? value : defaultValue;
757
- }
758
- if (allowDecimal) result = numberValue > 0 ? Math.floor(numberValue) : Math.ceil(numberValue);
759
- else {
760
- if (numberValue % 1 !== 0) {
761
- if (onError === "throwError") throw new Error("Decimal values are not allowed");
762
- return onError === "returnOriginal" ? value : defaultValue;
763
- }
764
- result = numberValue;
765
- }
766
- if (!isUndefined(min) || !isUndefined(max)) {
767
- const minVal = min ?? -Infinity;
768
- const maxVal = max ?? Infinity;
769
- if (result < minVal || result > maxVal) {
770
- if (outOfRange === "throwError") throw new RangeError(`Value ${result} is out of range [${minVal}, ${maxVal}]`);
771
- if (outOfRange === "useDefault") return defaultValue;
772
- if (outOfRange === "clamp") result = Math.max(minVal, Math.min(maxVal, numberValue));
773
- }
774
- }
775
- return result;
776
- }
777
-
778
795
  //#endregion
779
796
  //#region src/string/random.ts
780
797
  /**
@@ -792,7 +809,6 @@ function randomString(length = 16, chars = "0123456789abcdefghijklmnopqrstuvwxyz
792
809
  }
793
810
  return result.join("");
794
811
  }
795
-
796
812
  //#endregion
797
813
  //#region src/string/slugify.ts
798
814
  const rControl = /[\u0000-\u001F]/g;
@@ -802,9 +818,8 @@ const rCombining = /[\u0300-\u036F]/g;
802
818
  * Default slugify function
803
819
  */
804
820
  function slugify(str) {
805
- return str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
821
+ return str.normalize("NFKD").replace(rCombining, "").replace(rControl, "").replace(rSpecial, "-").replaceAll(/-{2,}/g, "-").replaceAll(/^-+|-+$/g, "").replace(/^(\d)/, "_$1").toLowerCase();
806
822
  }
807
-
808
823
  //#endregion
809
824
  //#region src/string/unindent.ts
810
825
  const _RE_FULL_WS = /^\s*$/;
@@ -837,7 +852,6 @@ function unindent(input) {
837
852
  while (emptylinesTail < lines.length && whitespaceLines[lines.length - emptylinesTail - 1]) emptylinesTail++;
838
853
  return lines.slice(emptylinesHead, lines.length - emptylinesTail).map((line) => line.slice(commonIndent)).join("\n");
839
854
  }
840
-
841
855
  //#endregion
842
856
  //#region src/string/getLength.ts
843
857
  let segmenter;
@@ -854,19 +868,16 @@ function getStringLength(value) {
854
868
  segmenter ??= new Intl.Segmenter();
855
869
  return [...segmenter.segment(value)].length;
856
870
  }
857
-
858
871
  //#endregion
859
872
  //#region src/string/ensurePrefix.ts
860
873
  function ensurePrefix(input, prefix) {
861
874
  return input.startsWith(prefix) ? input : `${prefix}${input}`;
862
875
  }
863
-
864
876
  //#endregion
865
877
  //#region src/string/ensureSuffix.ts
866
878
  function ensureSuffix(input, suffix) {
867
879
  return input.endsWith(suffix) ? input : `${input}${suffix}`;
868
880
  }
869
-
870
881
  //#endregion
871
882
  //#region src/string/getSimilarity.ts
872
883
  function getStringSimilarity(str1, str2, options = {}) {
@@ -892,7 +903,6 @@ function getStringSimilarity(str1, str2, options = {}) {
892
903
  }
893
904
  return match * 2 / (str1.length + str2.length - (sliceLength - 1) * 2);
894
905
  }
895
-
896
906
  //#endregion
897
907
  //#region src/color/color.ts
898
908
  const RE_VALID_HEX_COLOR = /^#(?:[0-9a-f]{6}|[0-9a-f]{3})$/i;
@@ -902,7 +912,7 @@ function validateHexColor(hex) {
902
912
  return RE_VALID_HEX_COLOR.test(hex);
903
913
  }
904
914
  function normalizeHexString(hex) {
905
- return hex.length === 6 ? hex : hex.replace(/./g, "$&$&");
915
+ return hex.length === 6 ? hex : hex.replaceAll(/./g, "$&$&");
906
916
  }
907
917
  var Color = class Color {
908
918
  red = 0;
@@ -978,7 +988,6 @@ var Color = class Color {
978
988
  return new Color(Math.max(this.red - amount, 0), Math.max(this.green - amount, 0), Math.max(this.blue - amount, 0), this.alpha);
979
989
  }
980
990
  };
981
-
982
991
  //#endregion
983
992
  //#region src/color/random.ts
984
993
  /**
@@ -1006,7 +1015,6 @@ function randomRGBAColor() {
1006
1015
  function randomHexColor() {
1007
1016
  return `#${Math.random().toString(16).slice(2, 8)}`;
1008
1017
  }
1009
-
1010
1018
  //#endregion
1011
1019
  //#region src/proxy/enhance.ts
1012
1020
  /**
@@ -1024,7 +1032,28 @@ function enhance(module, extra) {
1024
1032
  }
1025
1033
  });
1026
1034
  }
1027
-
1035
+ //#endregion
1036
+ //#region src/tree/flatTree.ts
1037
+ function flatTree(roots, options = {}) {
1038
+ const { childrenKey = "children", includeSelf = true, map } = options;
1039
+ const out = [];
1040
+ function walk(nodes, parent, depth, path) {
1041
+ nodes.forEach((node, index) => {
1042
+ const nextPath = [...path, node];
1043
+ if (includeSelf) out.push(map ? map({
1044
+ node,
1045
+ parent,
1046
+ depth,
1047
+ index,
1048
+ path: nextPath
1049
+ }) : node);
1050
+ const children = node[childrenKey];
1051
+ if (Array.isArray(children) && children.length > 0) walk(children, node, depth + 1, nextPath);
1052
+ });
1053
+ }
1054
+ walk(roots, null, 0, []);
1055
+ return out;
1056
+ }
1028
1057
  //#endregion
1029
1058
  //#region src/module/interopDefault.ts
1030
1059
  /**
@@ -1045,7 +1074,6 @@ async function interopDefault(mod) {
1045
1074
  const resolved = await mod;
1046
1075
  return resolved.default || resolved;
1047
1076
  }
1048
-
1049
1077
  //#endregion
1050
1078
  //#region src/module/resolveSubOptions.ts
1051
1079
  /**
@@ -1078,14 +1106,12 @@ async function interopDefault(mod) {
1078
1106
  function resolveSubOptions(options, key) {
1079
1107
  return typeof options[key] === "boolean" ? {} : options[key] || {};
1080
1108
  }
1081
-
1082
1109
  //#endregion
1083
1110
  //#region src/object/omit.ts
1084
1111
  function omit(object, ...keys) {
1085
1112
  keys.forEach((key) => delete object[key]);
1086
1113
  return object;
1087
1114
  }
1088
-
1089
1115
  //#endregion
1090
1116
  //#region src/object/hasOwn.ts
1091
1117
  /**
@@ -1098,7 +1124,6 @@ function hasOwn(object, key) {
1098
1124
  if (object === null) return false;
1099
1125
  return Object.prototype.hasOwnProperty.call(object, key);
1100
1126
  }
1101
-
1102
1127
  //#endregion
1103
1128
  //#region src/object/pick.ts
1104
1129
  function pick(object, keys) {
@@ -1107,7 +1132,6 @@ function pick(object, keys) {
1107
1132
  return result;
1108
1133
  }, {});
1109
1134
  }
1110
-
1111
1135
  //#endregion
1112
1136
  //#region src/object/clean.ts
1113
1137
  /**
@@ -1123,7 +1147,7 @@ function cleanObject(obj, options = {}) {
1123
1147
  if (cleanUndefined && isUndefined(v)) delete obj[key];
1124
1148
  if (cleanNull && isNull(v)) delete obj[key];
1125
1149
  if (cleanZero && isZero(v)) delete obj[key];
1126
- if (cleanNaN && isZero(v)) delete obj[key];
1150
+ if (cleanNaN && isNaN(v)) delete obj[key];
1127
1151
  if (cleanEmptyString && isEmptyString(v)) delete obj[key];
1128
1152
  if (cleanEmptyArray && isEmptyArray(v)) delete obj[key];
1129
1153
  if (cleanEmptyObject && isEmptyObject(v)) delete obj[key];
@@ -1131,7 +1155,19 @@ function cleanObject(obj, options = {}) {
1131
1155
  });
1132
1156
  return obj;
1133
1157
  }
1134
-
1158
+ //#endregion
1159
+ //#region src/object/isKeyOf.ts
1160
+ /**
1161
+ * Type guard for any key, `k`
1162
+ * marks `k` as a key of `T` if `k` is a key of `T`
1163
+ *
1164
+ * @param obj - object to query for key
1165
+ * @param k - key to check for
1166
+ * @returns true if `k` is a key of `T`
1167
+ */
1168
+ function isKeyOf(obj, k) {
1169
+ return k in obj;
1170
+ }
1135
1171
  //#endregion
1136
1172
  //#region src/object/isPlainObject.ts
1137
1173
  /**
@@ -1145,32 +1181,30 @@ function isPlainObject(value) {
1145
1181
  const prototype = Object.getPrototypeOf(value);
1146
1182
  return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
1147
1183
  }
1148
-
1149
1184
  //#endregion
1150
1185
  //#region src/object/sortObject.ts
1151
1186
  /**
1152
1187
  * Sort object properties
1153
1188
  */
1154
- function sortObject(obj, options = {}) {
1189
+ function sortObject(object, options = {}) {
1155
1190
  const { compareFn = (a, b) => a.localeCompare(b) } = options;
1156
- function sortKeys(obj$1) {
1157
- const sortedKeys = Object.keys(obj$1).sort(compareFn);
1191
+ function sortKeys(obj) {
1192
+ const sortedKeys = Object.keys(obj).sort(compareFn);
1158
1193
  const result = {};
1159
1194
  for (const key of sortedKeys) {
1160
- const value = obj$1[key];
1195
+ const value = obj[key];
1161
1196
  let newValue;
1162
1197
  if (options.deep && isPlainObject(value)) newValue = sortKeys(value);
1163
1198
  else newValue = value;
1164
1199
  Object.defineProperty(result, key, {
1165
- ...Object.getOwnPropertyDescriptor(obj$1, key),
1200
+ ...Object.getOwnPropertyDescriptor(obj, key),
1166
1201
  value: newValue
1167
1202
  });
1168
1203
  }
1169
1204
  return result;
1170
1205
  }
1171
- return sortKeys(obj);
1206
+ return sortKeys(object);
1172
1207
  }
1173
-
1174
1208
  //#endregion
1175
1209
  //#region src/constants/char.ts
1176
1210
  /**
@@ -1184,7 +1218,6 @@ const SPECIAL_CHAR = {
1184
1218
  newline: "\n",
1185
1219
  whitespace: " "
1186
1220
  };
1187
-
1188
1221
  //#endregion
1189
1222
  //#region src/constants/regexp.ts
1190
1223
  /**
@@ -1201,6 +1234,5 @@ const RE_LINE_COMMENT = /\/\/.*/;
1201
1234
  * JavaScript block comment
1202
1235
  */
1203
1236
  const RE_BLOCK_COMMENT = /\/\*[\s\S]*?\*\//g;
1204
-
1205
1237
  //#endregion
1206
- export { Color, NOOP, RE_BLOCK_COMMENT, RE_COMMENTS, RE_LINE_COMMENT, SPECIAL_CHAR, STORAGE_UNITS, TIME_UNITS, at, cAF, chunk, clamp, cleanObject, convertFromBytes, convertFromMilliseconds, convertStorageUnit, convertTimeUnit, convertToBytes, convertToMilliseconds, createPadString, debounce, enhance, ensurePrefix, ensureSuffix, escapeHTML, flattenArrayable, getObjectType, getRoot, getStringLength, getStringSimilarity, hasOwn, interopDefault, intersect, isArray, isArrayEqual, isBigInt, isBlob, isBoolean, isBrowser, isDeepEqual, isElementVisibleInViewport, isEmptyArray, isEmptyMap, isEmptyObject, isEmptySet, isEmptyString, isEmptyStringOrWhitespace, isError, isFile, isFormData, isFunction, isHTMLElement, isInteger, isIterable, isMap, isNaN, isNativePromise, isNil, isNonEmptyArray, isNonEmptyString, isNull, isNullOrUndefined, isNumber, isNumbericString, isObject, isPromise, isRegExp, isSet, isString, isTruthy, isUndefined, isUrlString, isWhitespaceString, isZero, join, last, mergeArrayable, noop, omit, once, openExternalURL, pick, rAF, randomHexColor, randomNumber, randomRGBAColor, randomRGBColor, randomString, removeFileExtension, resolveSubOptions, scrollElementIntoView, slash, slugify, sortObject, throttle, toArray, toInteger, unescapeHTML, unindent, unique, uniqueBy, waitFor, warnOnce };
1238
+ export { Color, NOOP, RE_BLOCK_COMMENT, RE_COMMENTS, RE_LINE_COMMENT, SPECIAL_CHAR, STORAGE_UNITS, TIME_UNITS, at, cAF, chunk, clamp, cleanObject, convertFromBytes, convertFromMilliseconds, convertStorageUnit, convertTimeUnit, convertToBytes, convertToMilliseconds, createPadString, debounce, enhance, ensurePrefix, ensureSuffix, escapeHTML, escapeStringRegexp, flatTree, flattenArrayable, getFileExtension, getObjectType, getRoot, getStringLength, getStringSimilarity, hasOwn, interopDefault, intersect, isArray, isArrayEqual, isBigInt, isBlob, isBoolean, isBrowser, isDeepEqual, isElementVisibleInViewport, isEmptyArray, isEmptyMap, isEmptyObject, isEmptySet, isEmptyString, isEmptyStringOrWhitespace, isError, isFile, isFormData, isFunction, isHTMLElement, isInteger, isIterable, isKeyOf, isMap, isNaN, isNativePromise, isNil, isNonEmptyArray, isNonEmptyString, isNull, isNullOrUndefined, isNumber, isNumbericString, isObject, isPlainObject, isPromise, isRegExp, isSet, isString, isTruthy, isUndefined, isUrlString, isWhitespaceString, isZero, join, last, mergeArrayable, noop, omit, once, openExternalURL, pick, rAF, randomHexColor, randomNumber, randomRGBAColor, randomRGBColor, randomString, remove, removeFileExtension, resolveSubOptions, scrollElementIntoView, shuffle, slash, slugify, sortObject, throttle, toArray, toInteger, unescapeHTML, unindent, unique, uniqueBy, waitFor, warnOnce };