@catbee/utils 0.0.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.
- package/LICENSE +201 -0
- package/README.md +295 -0
- package/build/esm/config.d.ts +22 -0
- package/build/esm/config.js +21 -0
- package/build/esm/config.js.map +1 -0
- package/build/esm/index.d.ts +19 -0
- package/build/esm/index.js +19 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/types/api-response.d.ts +44 -0
- package/build/esm/types/api-response.js +2 -0
- package/build/esm/types/api-response.js.map +1 -0
- package/build/esm/utils/array.utils.d.ts +105 -0
- package/build/esm/utils/array.utils.js +232 -0
- package/build/esm/utils/array.utils.js.map +1 -0
- package/build/esm/utils/async.utils.d.ts +119 -0
- package/build/esm/utils/async.utils.js +474 -0
- package/build/esm/utils/async.utils.js.map +1 -0
- package/build/esm/utils/cache.utils.d.ts +90 -0
- package/build/esm/utils/cache.utils.js +294 -0
- package/build/esm/utils/cache.utils.js.map +1 -0
- package/build/esm/utils/context-store.utils.d.ts +85 -0
- package/build/esm/utils/context-store.utils.js +99 -0
- package/build/esm/utils/context-store.utils.js.map +1 -0
- package/build/esm/utils/crypto.utils.d.ts +58 -0
- package/build/esm/utils/crypto.utils.js +76 -0
- package/build/esm/utils/crypto.utils.js.map +1 -0
- package/build/esm/utils/dir.utils.d.ts +75 -0
- package/build/esm/utils/dir.utils.js +400 -0
- package/build/esm/utils/dir.utils.js.map +1 -0
- package/build/esm/utils/env.utils.d.ts +131 -0
- package/build/esm/utils/env.utils.js +218 -0
- package/build/esm/utils/env.utils.js.map +1 -0
- package/build/esm/utils/exception.utils.d.ts +114 -0
- package/build/esm/utils/exception.utils.js +217 -0
- package/build/esm/utils/exception.utils.js.map +1 -0
- package/build/esm/utils/fs.utils.d.ts +32 -0
- package/build/esm/utils/fs.utils.js +140 -0
- package/build/esm/utils/fs.utils.js.map +1 -0
- package/build/esm/utils/http-status-codes.d.ts +357 -0
- package/build/esm/utils/http-status-codes.js +358 -0
- package/build/esm/utils/http-status-codes.js.map +1 -0
- package/build/esm/utils/id.utils.d.ts +35 -0
- package/build/esm/utils/id.utils.js +55 -0
- package/build/esm/utils/id.utils.js.map +1 -0
- package/build/esm/utils/logger.utils.d.ts +15 -0
- package/build/esm/utils/logger.utils.js +59 -0
- package/build/esm/utils/logger.utils.js.map +1 -0
- package/build/esm/utils/obj.utils.d.ts +55 -0
- package/build/esm/utils/obj.utils.js +121 -0
- package/build/esm/utils/obj.utils.js.map +1 -0
- package/build/esm/utils/response.utils.d.ts +48 -0
- package/build/esm/utils/response.utils.js +80 -0
- package/build/esm/utils/response.utils.js.map +1 -0
- package/build/esm/utils/string.utils.d.ts +37 -0
- package/build/esm/utils/string.utils.js +56 -0
- package/build/esm/utils/string.utils.js.map +1 -0
- package/build/esm/utils/url.utils.d.ts +24 -0
- package/build/esm/utils/url.utils.js +73 -0
- package/build/esm/utils/url.utils.js.map +1 -0
- package/build/esm/utils/validate.utils.d.ts +60 -0
- package/build/esm/utils/validate.utils.js +121 -0
- package/build/esm/utils/validate.utils.js.map +1 -0
- package/build/esnext/config.d.ts +22 -0
- package/build/esnext/config.js +21 -0
- package/build/esnext/config.js.map +1 -0
- package/build/esnext/index.d.ts +19 -0
- package/build/esnext/index.js +19 -0
- package/build/esnext/index.js.map +1 -0
- package/build/esnext/types/api-response.d.ts +44 -0
- package/build/esnext/types/api-response.js +2 -0
- package/build/esnext/types/api-response.js.map +1 -0
- package/build/esnext/utils/array.utils.d.ts +105 -0
- package/build/esnext/utils/array.utils.js +203 -0
- package/build/esnext/utils/array.utils.js.map +1 -0
- package/build/esnext/utils/async.utils.d.ts +119 -0
- package/build/esnext/utils/async.utils.js +291 -0
- package/build/esnext/utils/async.utils.js.map +1 -0
- package/build/esnext/utils/cache.utils.d.ts +90 -0
- package/build/esnext/utils/cache.utils.js +142 -0
- package/build/esnext/utils/cache.utils.js.map +1 -0
- package/build/esnext/utils/context-store.utils.d.ts +85 -0
- package/build/esnext/utils/context-store.utils.js +95 -0
- package/build/esnext/utils/context-store.utils.js.map +1 -0
- package/build/esnext/utils/crypto.utils.d.ts +58 -0
- package/build/esnext/utils/crypto.utils.js +72 -0
- package/build/esnext/utils/crypto.utils.js.map +1 -0
- package/build/esnext/utils/dir.utils.d.ts +75 -0
- package/build/esnext/utils/dir.utils.js +150 -0
- package/build/esnext/utils/dir.utils.js.map +1 -0
- package/build/esnext/utils/env.utils.d.ts +131 -0
- package/build/esnext/utils/env.utils.js +211 -0
- package/build/esnext/utils/env.utils.js.map +1 -0
- package/build/esnext/utils/exception.utils.d.ts +114 -0
- package/build/esnext/utils/exception.utils.js +148 -0
- package/build/esnext/utils/exception.utils.js.map +1 -0
- package/build/esnext/utils/fs.utils.d.ts +32 -0
- package/build/esnext/utils/fs.utils.js +62 -0
- package/build/esnext/utils/fs.utils.js.map +1 -0
- package/build/esnext/utils/http-status-codes.d.ts +357 -0
- package/build/esnext/utils/http-status-codes.js +358 -0
- package/build/esnext/utils/http-status-codes.js.map +1 -0
- package/build/esnext/utils/id.utils.d.ts +35 -0
- package/build/esnext/utils/id.utils.js +53 -0
- package/build/esnext/utils/id.utils.js.map +1 -0
- package/build/esnext/utils/logger.utils.d.ts +15 -0
- package/build/esnext/utils/logger.utils.js +59 -0
- package/build/esnext/utils/logger.utils.js.map +1 -0
- package/build/esnext/utils/obj.utils.d.ts +55 -0
- package/build/esnext/utils/obj.utils.js +94 -0
- package/build/esnext/utils/obj.utils.js.map +1 -0
- package/build/esnext/utils/response.utils.d.ts +48 -0
- package/build/esnext/utils/response.utils.js +58 -0
- package/build/esnext/utils/response.utils.js.map +1 -0
- package/build/esnext/utils/string.utils.d.ts +37 -0
- package/build/esnext/utils/string.utils.js +46 -0
- package/build/esnext/utils/string.utils.js.map +1 -0
- package/build/esnext/utils/url.utils.d.ts +24 -0
- package/build/esnext/utils/url.utils.js +35 -0
- package/build/esnext/utils/url.utils.js.map +1 -0
- package/build/esnext/utils/validate.utils.d.ts +60 -0
- package/build/esnext/utils/validate.utils.js +105 -0
- package/build/esnext/utils/validate.utils.js.map +1 -0
- package/build/src/config.d.ts +22 -0
- package/build/src/config.js +24 -0
- package/build/src/config.js.map +1 -0
- package/build/src/index.d.ts +19 -0
- package/build/src/index.js +35 -0
- package/build/src/index.js.map +1 -0
- package/build/src/types/api-response.d.ts +44 -0
- package/build/src/types/api-response.js +3 -0
- package/build/src/types/api-response.js.map +1 -0
- package/build/src/utils/array.utils.d.ts +105 -0
- package/build/src/utils/array.utils.js +216 -0
- package/build/src/utils/array.utils.js.map +1 -0
- package/build/src/utils/async.utils.d.ts +119 -0
- package/build/src/utils/async.utils.js +304 -0
- package/build/src/utils/async.utils.js.map +1 -0
- package/build/src/utils/cache.utils.d.ts +90 -0
- package/build/src/utils/cache.utils.js +146 -0
- package/build/src/utils/cache.utils.js.map +1 -0
- package/build/src/utils/context-store.utils.d.ts +85 -0
- package/build/src/utils/context-store.utils.js +100 -0
- package/build/src/utils/context-store.utils.js.map +1 -0
- package/build/src/utils/crypto.utils.d.ts +58 -0
- package/build/src/utils/crypto.utils.js +82 -0
- package/build/src/utils/crypto.utils.js.map +1 -0
- package/build/src/utils/dir.utils.d.ts +75 -0
- package/build/src/utils/dir.utils.js +164 -0
- package/build/src/utils/dir.utils.js.map +1 -0
- package/build/src/utils/env.utils.d.ts +131 -0
- package/build/src/utils/env.utils.js +215 -0
- package/build/src/utils/env.utils.js.map +1 -0
- package/build/src/utils/exception.utils.d.ts +114 -0
- package/build/src/utils/exception.utils.js +162 -0
- package/build/src/utils/exception.utils.js.map +1 -0
- package/build/src/utils/fs.utils.d.ts +32 -0
- package/build/src/utils/fs.utils.js +71 -0
- package/build/src/utils/fs.utils.js.map +1 -0
- package/build/src/utils/http-status-codes.d.ts +357 -0
- package/build/src/utils/http-status-codes.js +361 -0
- package/build/src/utils/http-status-codes.js.map +1 -0
- package/build/src/utils/id.utils.d.ts +35 -0
- package/build/src/utils/id.utils.js +60 -0
- package/build/src/utils/id.utils.js.map +1 -0
- package/build/src/utils/logger.utils.d.ts +15 -0
- package/build/src/utils/logger.utils.js +96 -0
- package/build/src/utils/logger.utils.js.map +1 -0
- package/build/src/utils/obj.utils.d.ts +55 -0
- package/build/src/utils/obj.utils.js +103 -0
- package/build/src/utils/obj.utils.js.map +1 -0
- package/build/src/utils/response.utils.d.ts +48 -0
- package/build/src/utils/response.utils.js +63 -0
- package/build/src/utils/response.utils.js.map +1 -0
- package/build/src/utils/string.utils.d.ts +37 -0
- package/build/src/utils/string.utils.js +54 -0
- package/build/src/utils/string.utils.js.map +1 -0
- package/build/src/utils/url.utils.d.ts +24 -0
- package/build/src/utils/url.utils.js +39 -0
- package/build/src/utils/url.utils.js.map +1 -0
- package/build/src/utils/validate.utils.d.ts +60 -0
- package/build/src/utils/validate.utils.js +115 -0
- package/build/src/utils/validate.utils.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection of common validation helpers for strings, numbers, email, UUID, etc.
|
|
3
|
+
*/
|
|
4
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
5
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
6
|
+
if (!m) return o;
|
|
7
|
+
var i = m.call(o), r, ar = [], e;
|
|
8
|
+
try {
|
|
9
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
10
|
+
}
|
|
11
|
+
catch (error) { e = { error: error }; }
|
|
12
|
+
finally {
|
|
13
|
+
try {
|
|
14
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
15
|
+
}
|
|
16
|
+
finally { if (e) throw e.error; }
|
|
17
|
+
}
|
|
18
|
+
return ar;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a string is a valid email address.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} str - The input string.
|
|
24
|
+
* @returns {boolean} True if valid email, else false.
|
|
25
|
+
*/
|
|
26
|
+
export function isEmail(str) {
|
|
27
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str))
|
|
28
|
+
return false;
|
|
29
|
+
// Additional checks
|
|
30
|
+
var _a = __read(str.split("@"), 2), local = _a[0], domain = _a[1];
|
|
31
|
+
if (!local || !domain)
|
|
32
|
+
return false;
|
|
33
|
+
// Disallow consecutive dots in local or domain part
|
|
34
|
+
if (local.includes("..") || domain.includes(".."))
|
|
35
|
+
return false;
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a string is a valid UUID (versions 1-5).
|
|
40
|
+
*
|
|
41
|
+
* @param {string} str - The input string.
|
|
42
|
+
* @returns {boolean} True if valid UUID, else false.
|
|
43
|
+
*/
|
|
44
|
+
export function isUUID(str) {
|
|
45
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a string is a valid URL.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} str - The input string.
|
|
51
|
+
* @returns {boolean} True if valid URL, else false.
|
|
52
|
+
*/
|
|
53
|
+
export function isURL(str) {
|
|
54
|
+
try {
|
|
55
|
+
new URL(str);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
catch (_a) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Checks if a string is a valid international phone number (E.164 or common patterns).
|
|
64
|
+
*
|
|
65
|
+
* @param {string} str - The input string.
|
|
66
|
+
* @returns {boolean} True if looks like a phone number.
|
|
67
|
+
*/
|
|
68
|
+
export function isPhone(str) {
|
|
69
|
+
if (typeof str !== "string")
|
|
70
|
+
return false;
|
|
71
|
+
// Strip non-digit characters to count total digits
|
|
72
|
+
var digitsOnly = str.replace(/\D/g, "");
|
|
73
|
+
if (digitsOnly.length < 6 || digitsOnly.length > 15)
|
|
74
|
+
return false;
|
|
75
|
+
// Accept typical phone characters: +, digits, space, -, (, )
|
|
76
|
+
return /^[+]?[\d\s().-]+$/.test(str);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Checks if a string is strictly alphanumeric (letters/numbers only).
|
|
80
|
+
*
|
|
81
|
+
* @param {string} str - The input string.
|
|
82
|
+
* @returns {boolean} True if alphanumeric.
|
|
83
|
+
*/
|
|
84
|
+
export function isAlphanumeric(str) {
|
|
85
|
+
return /^[a-z0-9]+$/i.test(str);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Checks if a string or number can be safely parsed to a number.
|
|
89
|
+
*
|
|
90
|
+
* @param {string | number} value - The value to check.
|
|
91
|
+
* @returns {boolean} True if the value is numeric.
|
|
92
|
+
*/
|
|
93
|
+
export function isNumeric(value) {
|
|
94
|
+
if (typeof value === "string" && value.trim() === "")
|
|
95
|
+
return false;
|
|
96
|
+
var num = typeof value === "number" ? value : Number(value);
|
|
97
|
+
return typeof num === "number" && isFinite(num);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Checks if a string is a valid hex color code (e.g. #FFF or #FFFFFF).
|
|
101
|
+
*
|
|
102
|
+
* @param {string} str - Input string.
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
export function isHexColor(str) {
|
|
106
|
+
return /^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(str);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Checks if a string is a valid date string.
|
|
110
|
+
*
|
|
111
|
+
* @param {string} str - Input string.
|
|
112
|
+
* @returns {boolean}
|
|
113
|
+
*/
|
|
114
|
+
export function isISODate(str) {
|
|
115
|
+
var isoRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
|
116
|
+
if (!isoRegex.test(str))
|
|
117
|
+
return false;
|
|
118
|
+
var date = new Date(str);
|
|
119
|
+
return (!isNaN(date.getTime()) && date.toISOString().startsWith(str.slice(0, 10)));
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=validate.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.utils.js","sourceRoot":"","sources":["../../../src/utils/validate.utils.ts"],"names":[],"mappings":"AAAA;;GAEG;;;;;;;;;;;;;;;;;AAEH;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAE1D,oBAAoB;IACd,IAAA,KAAA,OAAkB,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAA,EAA/B,KAAK,QAAA,EAAE,MAAM,QAAkB,CAAC;IACvC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAEpC,oDAAoD;IACpD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAEhE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO,4EAA4E,CAAC,IAAI,CACtF,GAAG,CACJ,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE1C,mDAAmD;IACnD,IAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC;IAElE,6DAA6D;IAC7D,OAAO,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,KAAsB;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACnE,IAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9D,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,+BAA+B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAM,QAAQ,GACZ,sEAAsE,CAAC;IAEzE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,IAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,CACL,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Collection of common validation helpers for strings, numbers, email, UUID, etc.\n */\n\n/**\n * Checks if a string is a valid email address.\n *\n * @param {string} str - The input string.\n * @returns {boolean} True if valid email, else false.\n */\nexport function isEmail(str: string): boolean {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(str)) return false;\n\n // Additional checks\n const [local, domain] = str.split(\"@\");\n if (!local || !domain) return false;\n\n // Disallow consecutive dots in local or domain part\n if (local.includes(\"..\") || domain.includes(\"..\")) return false;\n\n return true;\n}\n\n/**\n * Checks if a string is a valid UUID (versions 1-5).\n *\n * @param {string} str - The input string.\n * @returns {boolean} True if valid UUID, else false.\n */\nexport function isUUID(str: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(\n str,\n );\n}\n\n/**\n * Checks if a string is a valid URL.\n *\n * @param {string} str - The input string.\n * @returns {boolean} True if valid URL, else false.\n */\nexport function isURL(str: string): boolean {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a string is a valid international phone number (E.164 or common patterns).\n *\n * @param {string} str - The input string.\n * @returns {boolean} True if looks like a phone number.\n */\nexport function isPhone(str: string): boolean {\n if (typeof str !== \"string\") return false;\n\n // Strip non-digit characters to count total digits\n const digitsOnly = str.replace(/\\D/g, \"\");\n if (digitsOnly.length < 6 || digitsOnly.length > 15) return false;\n\n // Accept typical phone characters: +, digits, space, -, (, )\n return /^[+]?[\\d\\s().-]+$/.test(str);\n}\n\n/**\n * Checks if a string is strictly alphanumeric (letters/numbers only).\n *\n * @param {string} str - The input string.\n * @returns {boolean} True if alphanumeric.\n */\nexport function isAlphanumeric(str: string): boolean {\n return /^[a-z0-9]+$/i.test(str);\n}\n\n/**\n * Checks if a string or number can be safely parsed to a number.\n *\n * @param {string | number} value - The value to check.\n * @returns {boolean} True if the value is numeric.\n */\nexport function isNumeric(value: string | number): boolean {\n if (typeof value === \"string\" && value.trim() === \"\") return false;\n const num = typeof value === \"number\" ? value : Number(value);\n return typeof num === \"number\" && isFinite(num);\n}\n\n/**\n * Checks if a string is a valid hex color code (e.g. #FFF or #FFFFFF).\n *\n * @param {string} str - Input string.\n * @returns {boolean}\n */\nexport function isHexColor(str: string): boolean {\n return /^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(str);\n}\n\n/**\n * Checks if a string is a valid date string.\n *\n * @param {string} str - Input string.\n * @returns {boolean}\n */\nexport function isISODate(str: string): boolean {\n const isoRegex =\n /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})?)?$/;\n\n if (!isoRegex.test(str)) return false;\n\n const date = new Date(str);\n return (\n !isNaN(date.getTime()) && date.toISOString().startsWith(str.slice(0, 10))\n );\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type LogLevel = "fatal" | "error" | "warn" | "info" | "debug" | "trace" | "silent";
|
|
2
|
+
/**
|
|
3
|
+
* Application runtime configuration loaded from environment variables.
|
|
4
|
+
*/
|
|
5
|
+
export declare const Config: {
|
|
6
|
+
Logger: {
|
|
7
|
+
/**
|
|
8
|
+
* Logging level (e.g., 'info', 'debug', 'warn', 'error').
|
|
9
|
+
*/
|
|
10
|
+
level: LogLevel;
|
|
11
|
+
/**
|
|
12
|
+
* Name of the logger instance (defaults to npm package name).
|
|
13
|
+
*/
|
|
14
|
+
name: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Whether to use ISO 8601 timestamps in logs.
|
|
17
|
+
*/
|
|
18
|
+
isoTimestamp: boolean;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Env } from "./utils/env.utils";
|
|
2
|
+
/**
|
|
3
|
+
* Application runtime configuration loaded from environment variables.
|
|
4
|
+
*/
|
|
5
|
+
export const Config = {
|
|
6
|
+
Logger: {
|
|
7
|
+
/**
|
|
8
|
+
* Logging level (e.g., 'info', 'debug', 'warn', 'error').
|
|
9
|
+
*/
|
|
10
|
+
level: Env.get("LOGGER_LEVEL", "info"),
|
|
11
|
+
/**
|
|
12
|
+
* Name of the logger instance (defaults to npm package name).
|
|
13
|
+
*/
|
|
14
|
+
name: Env.get("LOGGER_NAME", Env.get("npm_package_name", "@catbee/utils")),
|
|
15
|
+
/**
|
|
16
|
+
* Whether to use ISO 8601 timestamps in logs.
|
|
17
|
+
*/
|
|
18
|
+
isoTimestamp: Env.getBoolean("LOGGER_ISO_TIMESTAMP", false),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAWxC;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,MAAM,EAAE;QACN;;WAEG;QACH,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAa;QAElD;;WAEG;QACH,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;QAE1E;;WAEG;QACH,YAAY,EAAE,GAAG,CAAC,UAAU,CAAC,sBAAsB,EAAE,KAAK,CAAC;KAC5D;CACF,CAAC","sourcesContent":["import { Env } from \"./utils/env.utils\";\n\ntype LogLevel =\n | \"fatal\"\n | \"error\"\n | \"warn\"\n | \"info\"\n | \"debug\"\n | \"trace\"\n | \"silent\";\n\n/**\n * Application runtime configuration loaded from environment variables.\n */\nexport const Config = {\n Logger: {\n /**\n * Logging level (e.g., 'info', 'debug', 'warn', 'error').\n */\n level: Env.get(\"LOGGER_LEVEL\", \"info\") as LogLevel,\n\n /**\n * Name of the logger instance (defaults to npm package name).\n */\n name: Env.get(\"LOGGER_NAME\", Env.get(\"npm_package_name\", \"@catbee/utils\")),\n\n /**\n * Whether to use ISO 8601 timestamps in logs.\n */\n isoTimestamp: Env.getBoolean(\"LOGGER_ISO_TIMESTAMP\", false),\n },\n};\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from "./utils/array.utils";
|
|
2
|
+
export * from "./utils/async.utils";
|
|
3
|
+
export * from "./utils/cache.utils";
|
|
4
|
+
export * from "./utils/context-store.utils";
|
|
5
|
+
export * from "./utils/crypto.utils";
|
|
6
|
+
export * from "./utils/dir.utils";
|
|
7
|
+
export * from "./utils/env.utils";
|
|
8
|
+
export * from "./utils/exception.utils";
|
|
9
|
+
export * from "./utils/fs.utils";
|
|
10
|
+
export * from "./utils/http-status-codes";
|
|
11
|
+
export * from "./utils/id.utils";
|
|
12
|
+
export * from "./utils/logger.utils";
|
|
13
|
+
export * from "./utils/obj.utils";
|
|
14
|
+
export * from "./utils/response.utils";
|
|
15
|
+
export * from "./utils/string.utils";
|
|
16
|
+
export * from "./utils/url.utils";
|
|
17
|
+
export * from "./utils/validate.utils";
|
|
18
|
+
export * from "./types/api-response";
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from "./utils/array.utils";
|
|
2
|
+
export * from "./utils/async.utils";
|
|
3
|
+
export * from "./utils/cache.utils";
|
|
4
|
+
export * from "./utils/context-store.utils";
|
|
5
|
+
export * from "./utils/crypto.utils";
|
|
6
|
+
export * from "./utils/dir.utils";
|
|
7
|
+
export * from "./utils/env.utils";
|
|
8
|
+
export * from "./utils/exception.utils";
|
|
9
|
+
export * from "./utils/fs.utils";
|
|
10
|
+
export * from "./utils/http-status-codes";
|
|
11
|
+
export * from "./utils/id.utils";
|
|
12
|
+
export * from "./utils/logger.utils";
|
|
13
|
+
export * from "./utils/obj.utils";
|
|
14
|
+
export * from "./utils/response.utils";
|
|
15
|
+
export * from "./utils/string.utils";
|
|
16
|
+
export * from "./utils/url.utils";
|
|
17
|
+
export * from "./utils/validate.utils";
|
|
18
|
+
export * from "./types/api-response";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,sBAAsB,CAAC","sourcesContent":["export * from \"./utils/array.utils\";\nexport * from \"./utils/async.utils\";\nexport * from \"./utils/cache.utils\";\nexport * from \"./utils/context-store.utils\";\nexport * from \"./utils/crypto.utils\";\nexport * from \"./utils/dir.utils\";\nexport * from \"./utils/env.utils\";\nexport * from \"./utils/exception.utils\";\nexport * from \"./utils/fs.utils\";\nexport * from \"./utils/http-status-codes\";\nexport * from \"./utils/id.utils\";\nexport * from \"./utils/logger.utils\";\nexport * from \"./utils/obj.utils\";\nexport * from \"./utils/response.utils\";\nexport * from \"./utils/string.utils\";\nexport * from \"./utils/url.utils\";\nexport * from \"./utils/validate.utils\";\n\nexport * from \"./types/api-response\";\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic API response format.
|
|
3
|
+
* Used to wrap any successful or failed response from the server.
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiResponse<T = any> {
|
|
6
|
+
/** Payload returned from the API. Can be any shape depending on the endpoint. */
|
|
7
|
+
data: T | null;
|
|
8
|
+
/** Indicates whether an error occurred (true = error, false = success). */
|
|
9
|
+
error: boolean;
|
|
10
|
+
/** Human-readable message to describe the result or error. */
|
|
11
|
+
message: string;
|
|
12
|
+
/** Unique request ID for traceability in logs (e.g., from a middleware). */
|
|
13
|
+
requestId: string;
|
|
14
|
+
/** ISO timestamp when the response was generated. */
|
|
15
|
+
timestamp: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generic pagination structure used for paged lists (e.g., /users?page=1).
|
|
19
|
+
*/
|
|
20
|
+
export interface Pagination<T = any> {
|
|
21
|
+
/** List of records for the current page. */
|
|
22
|
+
content: T[];
|
|
23
|
+
/** Metadata about the pagination state. */
|
|
24
|
+
pagination: {
|
|
25
|
+
/** Total number of records across all pages. */
|
|
26
|
+
totalRecords: number;
|
|
27
|
+
/** Total number of pages available. */
|
|
28
|
+
totalPages: number;
|
|
29
|
+
/** Current page number (1-based index). */
|
|
30
|
+
page: number;
|
|
31
|
+
/** Number of records per page. */
|
|
32
|
+
limit: number;
|
|
33
|
+
/** Field by which the data is sorted. */
|
|
34
|
+
sortBy: string;
|
|
35
|
+
/** Sort order: ascending or descending. */
|
|
36
|
+
sortOrder: "asc" | "desc";
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Alias for paginated API response.
|
|
41
|
+
* Allows semantic naming like `PaginationResponse<User>` or `PaginationResponse<Post>`.
|
|
42
|
+
*/
|
|
43
|
+
export type PaginationResponse<T = any> = Pagination<T>;
|
|
44
|
+
//# sourceMappingURL=api-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-response.js","sourceRoot":"","sources":["../../../src/types/api-response.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Generic API response format.\n * Used to wrap any successful or failed response from the server.\n */\nexport interface ApiResponse<T = any> {\n /** Payload returned from the API. Can be any shape depending on the endpoint. */\n data: T | null;\n\n /** Indicates whether an error occurred (true = error, false = success). */\n error: boolean;\n\n /** Human-readable message to describe the result or error. */\n message: string;\n\n /** Unique request ID for traceability in logs (e.g., from a middleware). */\n requestId: string;\n\n /** ISO timestamp when the response was generated. */\n timestamp: string;\n}\n\n/**\n * Generic pagination structure used for paged lists (e.g., /users?page=1).\n */\nexport interface Pagination<T = any> {\n /** List of records for the current page. */\n content: T[];\n\n /** Metadata about the pagination state. */\n pagination: {\n /** Total number of records across all pages. */\n totalRecords: number;\n\n /** Total number of pages available. */\n totalPages: number;\n\n /** Current page number (1-based index). */\n page: number;\n\n /** Number of records per page. */\n limit: number;\n\n /** Field by which the data is sorted. */\n sortBy: string;\n\n /** Sort order: ascending or descending. */\n sortOrder: \"asc\" | \"desc\";\n };\n}\n\n/**\n * Alias for paginated API response.\n * Allows semantic naming like `PaginationResponse<User>` or `PaginationResponse<Post>`.\n */\nexport type PaginationResponse<T = any> = Pagination<T>;\n"]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits an array into chunks of the specified size.
|
|
3
|
+
*
|
|
4
|
+
* @template T The type of array elements.
|
|
5
|
+
* @param {T[]} array - The array to split into chunks.
|
|
6
|
+
* @param {number} size - The number of elements per chunk.
|
|
7
|
+
* @returns {T[][]} A new array containing chunked arrays.
|
|
8
|
+
* @throws {TypeError} If array is not an array.
|
|
9
|
+
* @throws {Error} If chunk size is not a positive integer.
|
|
10
|
+
*/
|
|
11
|
+
export declare const chunk: <T>(array: T[], size: number) => T[][];
|
|
12
|
+
/**
|
|
13
|
+
* Removes duplicate values from an array.
|
|
14
|
+
* Optionally enforces uniqueness by a key function.
|
|
15
|
+
*
|
|
16
|
+
* @template T The type of array elements.
|
|
17
|
+
* @param {T[]} array - The input array.
|
|
18
|
+
* @param {(item: T) => unknown} [keyFn] - Optional function to determine uniqueness by key.
|
|
19
|
+
* @returns {T[]} A new array with unique values.
|
|
20
|
+
*/
|
|
21
|
+
export declare function unique<T>(array: T[], keyFn?: (item: T) => unknown): T[];
|
|
22
|
+
/**
|
|
23
|
+
* Deeply flattens a nested array to a single-level array.
|
|
24
|
+
*
|
|
25
|
+
* @template T The leaf type of array elements.
|
|
26
|
+
* @param {any[]} array - The (possibly deeply nested) input array.
|
|
27
|
+
* @returns {T[]} A deeply flattened array.
|
|
28
|
+
*/
|
|
29
|
+
export declare function flattenDeep<T>(array: any[]): T[];
|
|
30
|
+
/**
|
|
31
|
+
* Returns a random element from an array, or undefined if empty.
|
|
32
|
+
*
|
|
33
|
+
* @template T The type of array elements.
|
|
34
|
+
* @param {T[]} array - The input array.
|
|
35
|
+
* @returns {T | undefined} A randomly selected item, or undefined if array is empty or not an array.
|
|
36
|
+
*/
|
|
37
|
+
export declare function random<T>(array: T[]): T | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Groups items in an array by a key or key function.
|
|
40
|
+
*
|
|
41
|
+
* @template T The type of array elements.
|
|
42
|
+
* @overload
|
|
43
|
+
* @param {T[]} array - The array to group.
|
|
44
|
+
* @param {keyof T} key - Property key to group by.
|
|
45
|
+
* @returns {Record<string, T[]>}
|
|
46
|
+
* @overload
|
|
47
|
+
* @param {T[]} array - The array to group.
|
|
48
|
+
* @param {(item: T) => string | number | symbol} keyFn - Function to generate group key from item.
|
|
49
|
+
* @returns {Record<K, T[]>}
|
|
50
|
+
* @param {T[]} array - The array to group.
|
|
51
|
+
* @param {keyof T | ((item: T) => string | number | symbol)} keyOrFn - Property key or key-generating function.
|
|
52
|
+
* @returns {Record<string | number | symbol, T[]>} An object mapping group keys to item arrays.
|
|
53
|
+
*/
|
|
54
|
+
export declare function groupBy<T>(array: T[], key: keyof T): Record<string, T[]>;
|
|
55
|
+
export declare function groupBy<T, K extends string | number | symbol>(array: T[], keyFn: (item: T) => K): Record<K, T[]>;
|
|
56
|
+
/**
|
|
57
|
+
* Shuffles an array using the Fisher-Yates algorithm.
|
|
58
|
+
*
|
|
59
|
+
* @template T The type of array elements.
|
|
60
|
+
* @param {T[]} array - The input array.
|
|
61
|
+
* @returns {T[]} A new shuffled array.
|
|
62
|
+
* @throws {TypeError} If array is not an array.
|
|
63
|
+
*/
|
|
64
|
+
export declare function shuffle<T>(array: T[]): T[];
|
|
65
|
+
/**
|
|
66
|
+
* Returns an array of property values from an array of objects.
|
|
67
|
+
*
|
|
68
|
+
* @template T The type of array elements.
|
|
69
|
+
* @template K The object property to pluck.
|
|
70
|
+
* @param {T[]} array - The input array.
|
|
71
|
+
* @param {K} key - The property name to pluck.
|
|
72
|
+
* @returns {T[K][]} Array of property values.
|
|
73
|
+
*/
|
|
74
|
+
export declare function pluck<T, K extends keyof T>(array: T[], key: K): T[K][];
|
|
75
|
+
/**
|
|
76
|
+
* Returns values in array A that are not in array B.
|
|
77
|
+
*
|
|
78
|
+
* @template T The type of array elements.
|
|
79
|
+
* @param {T[]} a - First array.
|
|
80
|
+
* @param {T[]} b - Second array.
|
|
81
|
+
* @returns {T[]} Elements in A that are not in B.
|
|
82
|
+
*/
|
|
83
|
+
export declare function difference<T>(a: T[], b: T[]): T[];
|
|
84
|
+
/**
|
|
85
|
+
* Returns common values between arrays A and B.
|
|
86
|
+
*
|
|
87
|
+
* @template T The type of array elements.
|
|
88
|
+
* @param {T[]} a - First array.
|
|
89
|
+
* @param {T[]} b - Second array.
|
|
90
|
+
* @returns {T[]} Elements that exist in both arrays.
|
|
91
|
+
*/
|
|
92
|
+
export declare function intersect<T>(a: T[], b: T[]): T[];
|
|
93
|
+
/**
|
|
94
|
+
* Sorts an array of objects by a nested key using Merge Sort (O(n log n)).
|
|
95
|
+
* Missing/undefined keys are sorted to the "end" (asc) or "start" (desc).
|
|
96
|
+
*
|
|
97
|
+
* @template T The type of array elements (objects).
|
|
98
|
+
* @param {T[]} array - Array of objects to sort.
|
|
99
|
+
* @param {string | ((item: T) => any)} key - Dot-notated key (e.g., "profile.age") or function.
|
|
100
|
+
* @param {"asc" | "desc"} [direction="asc"] - Sort direction: 'asc' or 'desc'.
|
|
101
|
+
* @returns {T[]} A new sorted array.
|
|
102
|
+
* @throws {TypeError} If array is not an array.
|
|
103
|
+
*/
|
|
104
|
+
export declare function mergeSort<T>(array: T[], key: string | ((item: T) => any), direction?: "asc" | "desc"): T[];
|
|
105
|
+
//# sourceMappingURL=array.utils.d.ts.map
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { getValueByPath } from "./obj.utils";
|
|
2
|
+
/**
|
|
3
|
+
* Splits an array into chunks of the specified size.
|
|
4
|
+
*
|
|
5
|
+
* @template T The type of array elements.
|
|
6
|
+
* @param {T[]} array - The array to split into chunks.
|
|
7
|
+
* @param {number} size - The number of elements per chunk.
|
|
8
|
+
* @returns {T[][]} A new array containing chunked arrays.
|
|
9
|
+
* @throws {TypeError} If array is not an array.
|
|
10
|
+
* @throws {Error} If chunk size is not a positive integer.
|
|
11
|
+
*/
|
|
12
|
+
export const chunk = (array, size) => {
|
|
13
|
+
if (!Array.isArray(array))
|
|
14
|
+
throw new TypeError("Expected an array");
|
|
15
|
+
if (!array.length)
|
|
16
|
+
return [];
|
|
17
|
+
if (!Number.isInteger(size) || size <= 0)
|
|
18
|
+
throw new Error("Chunk size must be a positive integer");
|
|
19
|
+
return Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size));
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Removes duplicate values from an array.
|
|
23
|
+
* Optionally enforces uniqueness by a key function.
|
|
24
|
+
*
|
|
25
|
+
* @template T The type of array elements.
|
|
26
|
+
* @param {T[]} array - The input array.
|
|
27
|
+
* @param {(item: T) => unknown} [keyFn] - Optional function to determine uniqueness by key.
|
|
28
|
+
* @returns {T[]} A new array with unique values.
|
|
29
|
+
*/
|
|
30
|
+
export function unique(array, keyFn) {
|
|
31
|
+
if (!Array.isArray(array) || array.length === 0)
|
|
32
|
+
return [];
|
|
33
|
+
if (!keyFn)
|
|
34
|
+
return Array.from(new Set(array));
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
return array.filter((item) => {
|
|
37
|
+
const key = keyFn(item);
|
|
38
|
+
if (seen.has(key))
|
|
39
|
+
return false;
|
|
40
|
+
seen.add(key);
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Deeply flattens a nested array to a single-level array.
|
|
46
|
+
*
|
|
47
|
+
* @template T The leaf type of array elements.
|
|
48
|
+
* @param {any[]} array - The (possibly deeply nested) input array.
|
|
49
|
+
* @returns {T[]} A deeply flattened array.
|
|
50
|
+
*/
|
|
51
|
+
export function flattenDeep(array) {
|
|
52
|
+
if (!Array.isArray(array))
|
|
53
|
+
return [];
|
|
54
|
+
return array.reduce((acc, val) => {
|
|
55
|
+
if (Array.isArray(val)) {
|
|
56
|
+
acc.push(...flattenDeep(val));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
acc.push(val);
|
|
60
|
+
}
|
|
61
|
+
return acc;
|
|
62
|
+
}, []);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns a random element from an array, or undefined if empty.
|
|
66
|
+
*
|
|
67
|
+
* @template T The type of array elements.
|
|
68
|
+
* @param {T[]} array - The input array.
|
|
69
|
+
* @returns {T | undefined} A randomly selected item, or undefined if array is empty or not an array.
|
|
70
|
+
*/
|
|
71
|
+
export function random(array) {
|
|
72
|
+
if (!Array.isArray(array) || array.length === 0)
|
|
73
|
+
return undefined;
|
|
74
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
75
|
+
}
|
|
76
|
+
export function groupBy(array, keyOrFn) {
|
|
77
|
+
if (!Array.isArray(array) || array.length === 0)
|
|
78
|
+
return {};
|
|
79
|
+
const keyFn = typeof keyOrFn === "function"
|
|
80
|
+
? keyOrFn
|
|
81
|
+
: (item) => item[keyOrFn];
|
|
82
|
+
return array.reduce((acc, item) => {
|
|
83
|
+
const key = keyFn(item);
|
|
84
|
+
if (!acc[key])
|
|
85
|
+
acc[key] = [];
|
|
86
|
+
acc[key].push(item);
|
|
87
|
+
return acc;
|
|
88
|
+
}, {});
|
|
89
|
+
}
|
|
90
|
+
/* eslint-enable no-redeclare */
|
|
91
|
+
/**
|
|
92
|
+
* Shuffles an array using the Fisher-Yates algorithm.
|
|
93
|
+
*
|
|
94
|
+
* @template T The type of array elements.
|
|
95
|
+
* @param {T[]} array - The input array.
|
|
96
|
+
* @returns {T[]} A new shuffled array.
|
|
97
|
+
* @throws {TypeError} If array is not an array.
|
|
98
|
+
*/
|
|
99
|
+
export function shuffle(array) {
|
|
100
|
+
if (!Array.isArray(array))
|
|
101
|
+
throw new TypeError("Expected an array");
|
|
102
|
+
const copy = array.slice();
|
|
103
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
104
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
105
|
+
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
106
|
+
}
|
|
107
|
+
return copy;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns an array of property values from an array of objects.
|
|
111
|
+
*
|
|
112
|
+
* @template T The type of array elements.
|
|
113
|
+
* @template K The object property to pluck.
|
|
114
|
+
* @param {T[]} array - The input array.
|
|
115
|
+
* @param {K} key - The property name to pluck.
|
|
116
|
+
* @returns {T[K][]} Array of property values.
|
|
117
|
+
*/
|
|
118
|
+
export function pluck(array, key) {
|
|
119
|
+
if (!Array.isArray(array))
|
|
120
|
+
return [];
|
|
121
|
+
return array.map((item) => item[key]);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns values in array A that are not in array B.
|
|
125
|
+
*
|
|
126
|
+
* @template T The type of array elements.
|
|
127
|
+
* @param {T[]} a - First array.
|
|
128
|
+
* @param {T[]} b - Second array.
|
|
129
|
+
* @returns {T[]} Elements in A that are not in B.
|
|
130
|
+
*/
|
|
131
|
+
export function difference(a, b) {
|
|
132
|
+
if (!Array.isArray(a) || !Array.isArray(b))
|
|
133
|
+
return [];
|
|
134
|
+
const setB = new Set(b);
|
|
135
|
+
return a.filter((item) => !setB.has(item));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns common values between arrays A and B.
|
|
139
|
+
*
|
|
140
|
+
* @template T The type of array elements.
|
|
141
|
+
* @param {T[]} a - First array.
|
|
142
|
+
* @param {T[]} b - Second array.
|
|
143
|
+
* @returns {T[]} Elements that exist in both arrays.
|
|
144
|
+
*/
|
|
145
|
+
export function intersect(a, b) {
|
|
146
|
+
if (!Array.isArray(a) || !Array.isArray(b))
|
|
147
|
+
return [];
|
|
148
|
+
const setB = new Set(b);
|
|
149
|
+
return a.filter((item) => setB.has(item));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Sorts an array of objects by a nested key using Merge Sort (O(n log n)).
|
|
153
|
+
* Missing/undefined keys are sorted to the "end" (asc) or "start" (desc).
|
|
154
|
+
*
|
|
155
|
+
* @template T The type of array elements (objects).
|
|
156
|
+
* @param {T[]} array - Array of objects to sort.
|
|
157
|
+
* @param {string | ((item: T) => any)} key - Dot-notated key (e.g., "profile.age") or function.
|
|
158
|
+
* @param {"asc" | "desc"} [direction="asc"] - Sort direction: 'asc' or 'desc'.
|
|
159
|
+
* @returns {T[]} A new sorted array.
|
|
160
|
+
* @throws {TypeError} If array is not an array.
|
|
161
|
+
*/
|
|
162
|
+
export function mergeSort(array, key, direction = "asc") {
|
|
163
|
+
if (!Array.isArray(array))
|
|
164
|
+
throw new TypeError("Expected array");
|
|
165
|
+
if (array.length <= 1)
|
|
166
|
+
return array.slice();
|
|
167
|
+
const keyFn = typeof key === "function"
|
|
168
|
+
? key
|
|
169
|
+
: (item) => getValueByPath(item, key);
|
|
170
|
+
const compare = (a, b) => {
|
|
171
|
+
const aVal = keyFn(a);
|
|
172
|
+
const bVal = keyFn(b);
|
|
173
|
+
// Sorts undefined/null last for "asc", first for "desc"
|
|
174
|
+
if (aVal === bVal)
|
|
175
|
+
return 0;
|
|
176
|
+
if (aVal == null)
|
|
177
|
+
return direction === "asc" ? 1 : -1;
|
|
178
|
+
if (bVal == null)
|
|
179
|
+
return direction === "asc" ? -1 : 1;
|
|
180
|
+
return direction === "asc" ? (aVal < bVal ? -1 : 1) : aVal > bVal ? -1 : 1;
|
|
181
|
+
};
|
|
182
|
+
const merge = (left, right) => {
|
|
183
|
+
const result = [];
|
|
184
|
+
let i = 0, j = 0;
|
|
185
|
+
while (i < left.length && j < right.length) {
|
|
186
|
+
if (compare(left[i], right[j]) <= 0)
|
|
187
|
+
result.push(left[i++]);
|
|
188
|
+
else
|
|
189
|
+
result.push(right[j++]);
|
|
190
|
+
}
|
|
191
|
+
return result.concat(left.slice(i)).concat(right.slice(j));
|
|
192
|
+
};
|
|
193
|
+
const sort = (arr) => {
|
|
194
|
+
if (arr.length <= 1)
|
|
195
|
+
return arr;
|
|
196
|
+
const mid = Math.floor(arr.length / 2);
|
|
197
|
+
const left = sort(arr.slice(0, mid));
|
|
198
|
+
const right = sort(arr.slice(mid));
|
|
199
|
+
return merge(left, right);
|
|
200
|
+
};
|
|
201
|
+
return sort(array);
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=array.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.utils.js","sourceRoot":"","sources":["../../../src/utils/array.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { getValueByPath } from \"./obj.utils\";\n\n/**\n * Splits an array into chunks of the specified size.\n *\n * @template T The type of array elements.\n * @param {T[]} array - The array to split into chunks.\n * @param {number} size - The number of elements per chunk.\n * @returns {T[][]} A new array containing chunked arrays.\n * @throws {TypeError} If array is not an array.\n * @throws {Error} If chunk size is not a positive integer.\n */\nexport const chunk = <T>(array: T[], size: number): T[][] => {\n if (!Array.isArray(array)) throw new TypeError(\"Expected an array\");\n if (!array.length) return [];\n if (!Number.isInteger(size) || size <= 0)\n throw new Error(\"Chunk size must be a positive integer\");\n return Array.from({ length: Math.ceil(array.length / size) }, (_, i) =>\n array.slice(i * size, i * size + size),\n );\n};\n\n/**\n * Removes duplicate values from an array.\n * Optionally enforces uniqueness by a key function.\n *\n * @template T The type of array elements.\n * @param {T[]} array - The input array.\n * @param {(item: T) => unknown} [keyFn] - Optional function to determine uniqueness by key.\n * @returns {T[]} A new array with unique values.\n */\nexport function unique<T>(array: T[], keyFn?: (item: T) => unknown): T[] {\n if (!Array.isArray(array) || array.length === 0) return [];\n if (!keyFn) return Array.from(new Set(array));\n const seen = new Set<unknown>();\n return array.filter((item) => {\n const key = keyFn(item);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/**\n * Deeply flattens a nested array to a single-level array.\n *\n * @template T The leaf type of array elements.\n * @param {any[]} array - The (possibly deeply nested) input array.\n * @returns {T[]} A deeply flattened array.\n */\nexport function flattenDeep<T>(array: any[]): T[] {\n if (!Array.isArray(array)) return [];\n return array.reduce<T[]>((acc, val) => {\n if (Array.isArray(val)) {\n acc.push(...flattenDeep<T>(val));\n } else {\n acc.push(val);\n }\n return acc;\n }, []);\n}\n\n/**\n * Returns a random element from an array, or undefined if empty.\n *\n * @template T The type of array elements.\n * @param {T[]} array - The input array.\n * @returns {T | undefined} A randomly selected item, or undefined if array is empty or not an array.\n */\nexport function random<T>(array: T[]): T | undefined {\n if (!Array.isArray(array) || array.length === 0) return undefined;\n return array[Math.floor(Math.random() * array.length)];\n}\n\n/* eslint-disable no-redeclare */\n/**\n * Groups items in an array by a key or key function.\n *\n * @template T The type of array elements.\n * @overload\n * @param {T[]} array - The array to group.\n * @param {keyof T} key - Property key to group by.\n * @returns {Record<string, T[]>}\n * @overload\n * @param {T[]} array - The array to group.\n * @param {(item: T) => string | number | symbol} keyFn - Function to generate group key from item.\n * @returns {Record<K, T[]>}\n * @param {T[]} array - The array to group.\n * @param {keyof T | ((item: T) => string | number | symbol)} keyOrFn - Property key or key-generating function.\n * @returns {Record<string | number | symbol, T[]>} An object mapping group keys to item arrays.\n */\nexport function groupBy<T>(array: T[], key: keyof T): Record<string, T[]>;\nexport function groupBy<T, K extends string | number | symbol>(\n array: T[],\n keyFn: (item: T) => K,\n): Record<K, T[]>;\nexport function groupBy<T>(\n array: T[],\n keyOrFn: keyof T | ((item: T) => string | number | symbol),\n): Record<string | number | symbol, T[]> {\n if (!Array.isArray(array) || array.length === 0) return {};\n const keyFn =\n typeof keyOrFn === \"function\"\n ? keyOrFn\n : (item: T) => item[keyOrFn as keyof T];\n return array.reduce(\n (acc, item) => {\n const key = keyFn(item) as string | number | symbol;\n if (!acc[key]) acc[key] = [];\n acc[key].push(item);\n return acc;\n },\n {} as Record<string | number | symbol, T[]>,\n );\n}\n/* eslint-enable no-redeclare */\n\n/**\n * Shuffles an array using the Fisher-Yates algorithm.\n *\n * @template T The type of array elements.\n * @param {T[]} array - The input array.\n * @returns {T[]} A new shuffled array.\n * @throws {TypeError} If array is not an array.\n */\nexport function shuffle<T>(array: T[]): T[] {\n if (!Array.isArray(array)) throw new TypeError(\"Expected an array\");\n const copy = array.slice();\n for (let i = copy.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [copy[i], copy[j]] = [copy[j], copy[i]];\n }\n return copy;\n}\n\n/**\n * Returns an array of property values from an array of objects.\n *\n * @template T The type of array elements.\n * @template K The object property to pluck.\n * @param {T[]} array - The input array.\n * @param {K} key - The property name to pluck.\n * @returns {T[K][]} Array of property values.\n */\nexport function pluck<T, K extends keyof T>(array: T[], key: K): T[K][] {\n if (!Array.isArray(array)) return [];\n return array.map((item) => item[key]);\n}\n\n/**\n * Returns values in array A that are not in array B.\n *\n * @template T The type of array elements.\n * @param {T[]} a - First array.\n * @param {T[]} b - Second array.\n * @returns {T[]} Elements in A that are not in B.\n */\nexport function difference<T>(a: T[], b: T[]): T[] {\n if (!Array.isArray(a) || !Array.isArray(b)) return [];\n const setB = new Set(b);\n return a.filter((item) => !setB.has(item));\n}\n\n/**\n * Returns common values between arrays A and B.\n *\n * @template T The type of array elements.\n * @param {T[]} a - First array.\n * @param {T[]} b - Second array.\n * @returns {T[]} Elements that exist in both arrays.\n */\nexport function intersect<T>(a: T[], b: T[]): T[] {\n if (!Array.isArray(a) || !Array.isArray(b)) return [];\n const setB = new Set(b);\n return a.filter((item) => setB.has(item));\n}\n\n/**\n * Sorts an array of objects by a nested key using Merge Sort (O(n log n)).\n * Missing/undefined keys are sorted to the \"end\" (asc) or \"start\" (desc).\n *\n * @template T The type of array elements (objects).\n * @param {T[]} array - Array of objects to sort.\n * @param {string | ((item: T) => any)} key - Dot-notated key (e.g., \"profile.age\") or function.\n * @param {\"asc\" | \"desc\"} [direction=\"asc\"] - Sort direction: 'asc' or 'desc'.\n * @returns {T[]} A new sorted array.\n * @throws {TypeError} If array is not an array.\n */\nexport function mergeSort<T>(\n array: T[],\n key: string | ((item: T) => any),\n direction: \"asc\" | \"desc\" = \"asc\",\n): T[] {\n if (!Array.isArray(array)) throw new TypeError(\"Expected array\");\n if (array.length <= 1) return array.slice();\n\n const keyFn =\n typeof key === \"function\"\n ? key\n : (item: T) => getValueByPath(item as object, key);\n\n const compare = (a: T, b: T) => {\n const aVal = keyFn(a);\n const bVal = keyFn(b);\n // Sorts undefined/null last for \"asc\", first for \"desc\"\n if (aVal === bVal) return 0;\n if (aVal == null) return direction === \"asc\" ? 1 : -1;\n if (bVal == null) return direction === \"asc\" ? -1 : 1;\n return direction === \"asc\" ? (aVal < bVal ? -1 : 1) : aVal > bVal ? -1 : 1;\n };\n\n const merge = (left: T[], right: T[]): T[] => {\n const result: T[] = [];\n let i = 0,\n j = 0;\n while (i < left.length && j < right.length) {\n if (compare(left[i], right[j]) <= 0) result.push(left[i++]);\n else result.push(right[j++]);\n }\n return result.concat(left.slice(i)).concat(right.slice(j));\n };\n\n const sort = (arr: T[]): T[] => {\n if (arr.length <= 1) return arr;\n const mid = Math.floor(arr.length / 2);\n const left = sort(arr.slice(0, mid));\n const right = sort(arr.slice(mid));\n return merge(left, right);\n };\n return sort(array);\n}\n"]}
|