toolbox-x 2.2.4 → 2.3.0

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 (62) hide show
  1. package/CHANGELOG.md +23 -4
  2. package/dist/{guards-Dc9MB9on.mjs → basics-B7Sqf33u.mjs} +233 -233
  3. package/dist/{guards-BSwFQX1M.cjs → basics-Cif013VV.cjs} +233 -233
  4. package/dist/{colors.cjs → colors/index.cjs} +6 -6
  5. package/dist/{colors.d.mts → colors/index.d.cts} +2 -2
  6. package/dist/{colors.d.cts → colors/index.d.mts} +2 -2
  7. package/dist/{colors.mjs → colors/index.mjs} +6 -6
  8. package/dist/constants.cjs +13 -13
  9. package/dist/constants.mjs +3 -3
  10. package/dist/{converter.cjs → converter/index.cjs} +1 -1
  11. package/dist/{converter.d.cts → converter/index.d.cts} +2 -2
  12. package/dist/{converter.d.mts → converter/index.d.mts} +2 -2
  13. package/dist/{converter.mjs → converter/index.mjs} +1 -1
  14. package/dist/{date.cjs → date/index.cjs} +7 -7
  15. package/dist/{date.d.cts → date/index.d.cts} +1 -1
  16. package/dist/{date.d.mts → date/index.d.mts} +1 -1
  17. package/dist/{date.mjs → date/index.mjs} +7 -7
  18. package/dist/{dom.cjs → dom/index.cjs} +8 -8
  19. package/dist/{dom.d.cts → dom/index.d.cts} +3 -3
  20. package/dist/{dom.d.mts → dom/index.d.mts} +3 -3
  21. package/dist/{dom.mjs → dom/index.mjs} +5 -5
  22. package/dist/{guards.cjs → guards/index.cjs} +38 -38
  23. package/dist/{guards.d.mts → guards/index.d.cts} +4 -4
  24. package/dist/{guards.d.cts → guards/index.d.mts} +4 -4
  25. package/dist/{guards.mjs → guards/index.mjs} +6 -6
  26. package/dist/{guards-CqbVT4L5.cjs → guards-BD2Fkugj.cjs} +2 -2
  27. package/dist/{guards-DKGBsd6x.mjs → guards-DBunDnng.mjs} +2 -2
  28. package/dist/{hash.cjs → hash/index.cjs} +69 -66
  29. package/dist/{hash.d.cts → hash/index.d.cts} +77 -5
  30. package/dist/{hash.d.mts → hash/index.d.mts} +77 -5
  31. package/dist/{hash.mjs → hash/index.mjs} +5 -5
  32. package/dist/{http-status.cjs → http-status/index.cjs} +1 -1
  33. package/dist/{http-status.d.mts → http-status/index.d.cts} +2 -2
  34. package/dist/{http-status.d.cts → http-status/index.d.mts} +2 -2
  35. package/dist/{http-status.mjs → http-status/index.mjs} +1 -1
  36. package/dist/index.cjs +84 -84
  37. package/dist/index.mjs +5 -5
  38. package/dist/{parse-TuFyLeVH.mjs → parse-CILDG7TG.mjs} +3 -3
  39. package/dist/{parse-jh637S25.cjs → parse-CffWYCuy.cjs} +3 -3
  40. package/dist/{query-sWSi-d7u.cjs → query-Blm7AiEZ.cjs} +9 -9
  41. package/dist/{query-BomnyWh3.mjs → query-PGFEup3p.mjs} +2 -2
  42. package/dist/{stylog.cjs → stylog/index.cjs} +5 -5
  43. package/dist/{stylog.d.cts → stylog/index.d.cts} +2 -2
  44. package/dist/{stylog.d.mts → stylog/index.d.mts} +2 -2
  45. package/dist/{stylog.mjs → stylog/index.mjs} +5 -5
  46. package/dist/types/pluralizer.d.cts +25 -1
  47. package/dist/types/pluralizer.d.mts +25 -1
  48. package/dist/{utilities-BSv8VbnM.mjs → utilities-CmPwOkdy.mjs} +1 -1
  49. package/dist/{utilities-BVpk3LKy.cjs → utilities-_COSGq1U.cjs} +1 -1
  50. package/dist/{basics-20lm69yy.mjs → utils-BO5CcsjK.mjs} +631 -548
  51. package/dist/{basics-byj0VH1c.cjs → utils-DR9g0Sef.cjs} +580 -479
  52. package/dist/{verbalizer.cjs → verbalizer/index.cjs} +1 -1
  53. package/dist/{verbalizer.mjs → verbalizer/index.mjs} +1 -1
  54. package/package.json +22 -25
  55. package/dist/pluralizer-DXMuPUAK.d.mts +0 -42
  56. package/dist/pluralizer-DYsDqq9c.d.cts +0 -42
  57. package/dist/pluralizer.cjs +0 -678
  58. package/dist/pluralizer.d.cts +0 -152
  59. package/dist/pluralizer.d.mts +0 -152
  60. package/dist/pluralizer.mjs +0 -676
  61. /package/dist/{verbalizer.d.cts → verbalizer/index.d.cts} +0 -0
  62. /package/dist/{verbalizer.d.mts → verbalizer/index.d.mts} +0 -0
@@ -16,532 +16,289 @@
16
16
 
17
17
  import { a as isNonEmptyString, c as isNumber, d as isString, m as isUndefined, n as isBoolean, u as isPrimitive } from "./primitives-Djsevc69.mjs";
18
18
  import { C as isMethodDescriptor, E as isObjectWithKeys, T as isObject, b as isFunction, c as isHexString, d as isNumericString, g as isArrayOfType, h as isArray, j as isValidArray, m as isUUID, w as isNotEmptyObject } from "./specials-krf7zsqI.mjs";
19
- import { a as normalizeNumber } from "./utilities-BSv8VbnM.mjs";
20
- import { t as isDateLike } from "./guards-DKGBsd6x.mjs";
19
+ import { a as normalizeNumber } from "./utilities-CmPwOkdy.mjs";
20
+ import { t as isDateLike } from "./guards-DBunDnng.mjs";
21
21
 
22
- //#region src/array/helpers.ts
22
+ //#region src/string/basics.ts
23
23
  /**
24
- * Safely resolves value of nested key (dot-notation key like `"user.city"`).
24
+ * * Utility to truncate a string to a specified length.
25
25
  *
26
- * @param obj - The source object
27
- * @param path - The nested path string (e.g. `"user.city"`)
28
- * @returns The resolved value or `undefined`
26
+ * @param str The string to truncate.
27
+ * @param maxLength The maximum length of the truncated string.
28
+ * @returns Truncated string with ellipsis (`...`) (only if it has more length than `maxLength`).
29
29
  */
30
- function _resolveNestedKey(obj, path) {
31
- if (isNotEmptyObject(obj)) return path?.split(".").reduce((acc, key) => {
32
- if (isNotEmptyObject(acc)) return acc[key];
33
- }, obj);
30
+ function truncateString(str, maxLength) {
31
+ if (!isNonEmptyString(str)) return "";
32
+ const trimmedString = str.trim();
33
+ if (!trimmedString) return "";
34
+ if (trimmedString.length <= maxLength) return trimmedString;
35
+ return trimmedString.slice(0, maxLength).concat("...");
34
36
  }
35
37
  /**
36
- * Retrieves a numeric value from a nested property (dot-notation key like 'user.income.tax').
37
- * Falls back to 0 if value is not a number or numeric string.
38
+ * * Generates a random alphanumeric (16 characters long, this length is customizable in the options) ID string composed of an optional `prefix`, `suffix`, a `timestamp`, `caseOption` and a customizable `separator`.
38
39
  *
39
- * @param obj - The source object to read from.
40
- * @param path - The dot-notation path string like 'user.income.tax'.
41
- * @returns The numeric value at that path, or 0 if not valid.
42
- */
43
- function _getNumericProp(obj, path) {
44
- return normalizeNumber(_resolveNestedKey(obj, path)) ?? 0;
45
- }
46
-
47
- //#endregion
48
- //#region src/array/sort.ts
49
- /**
50
- * Compare two strings using natural sorting (e.g., `"file2"` < `"file10"`).
51
- * - Optionally supports case-insensitive and locale-aware string chunk comparisons.
40
+ * @param options Configuration options for random ID generation.
41
+ * @returns The generated ID string composed of the random alphanumeric string of specified length with optional `timeStamp`, `prefix`, and `suffix`, `caseOption` and `separator`.
52
42
  *
53
- * @param a - The first string to compare.
54
- * @param b - The second string to compare.
55
- * @param options - Optional settings to configure comparison behavior.
56
- * @returns A negative number if `a` comes before `b`, a positive number if `a` comes after `b`, or 0 if equal.
43
+ * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/hash/uuid uuid} for `uuid` generation
44
+ * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/hash/random-hex randomHex} for random hexadecimal string generation
45
+ *
46
+ * @example
47
+ * // Generate an ID with all default options
48
+ * const id = generateRandomID();
49
+ * // Example output: "swo8ckxwsc13w7xw"
50
+ *
51
+ * @example
52
+ * // Generate an ID with a custom prefix and separator
53
+ * const id = generateRandomID({ prefix: 'ID', separator: '-' });
54
+ * // Example output: "ID-eh1ymwfxzwas9jte"
55
+ *
56
+ * @example
57
+ * // Generate an ID with a timestamp
58
+ * const id = generateRandomID({ timeStamp: false });
59
+ * // Example output: "1764610287501pd3r4w85qwkuulgf"
60
+ *
61
+ * @example
62
+ * // Generate an ID with a custom length for the random string
63
+ * const id = generateRandomID({ length: 8 });
64
+ * // Example output: "i623uiev"
65
+ *
66
+ * @example
67
+ * // Generate an ID with a custom suffix
68
+ * const id = generateRandomID({ suffix: 'END' });
69
+ * // Example output: "3csf27a4800rbli9END"
70
+ *
71
+ * @example
72
+ * // Generate an ID with a uppercase random string
73
+ * const id = generateRandomID({ caseOption: "upper" });
74
+ * // Example output: "H0VNU6O8XV1Y30HG"
75
+ *
76
+ * @example
77
+ * // Generate an ID with all options customized
78
+ * const id = generateRandomID({
79
+ * prefix: 'ID',
80
+ * suffix: 'END',
81
+ * timeStamp: true,
82
+ * length: 10,
83
+ * separator: '-',
84
+ * caseOption: "upper"
85
+ * });
86
+ * // Example output: "ID-1764610471474-4KSL51IB91-END"
57
87
  */
58
- function naturalSort(a, b, options) {
59
- const { caseInsensitive = true, localeAware = false } = options || {};
60
- /**
61
- * * Splits a string into an array of number and non-number chunks.
62
- * @param str - The string to split.
63
- * @returns An array of string and number parts.
64
- */
65
- const _createChunks = (str) => {
66
- const chunks = [];
67
- let current = "";
68
- let isNumeric = false;
69
- for (const char of str) {
70
- const charIsNum = !Number.isNaN(Number(char));
71
- if (current?.length === 0) {
72
- current = char;
73
- isNumeric = charIsNum;
74
- continue;
75
- }
76
- if (charIsNum === isNumeric) current += char;
77
- else {
78
- chunks?.push(isNumeric ? Number(current) : current);
79
- current = char;
80
- isNumeric = charIsNum;
81
- }
82
- }
83
- if (current?.length > 0) chunks?.push(isNumeric ? Number(current) : current);
84
- return chunks;
85
- };
86
- const aChunks = _createChunks(a);
87
- const bChunks = _createChunks(b);
88
- for (let i = 0; i < Math.min(aChunks?.length, bChunks?.length); i++) {
89
- let aChunk = aChunks[i];
90
- let bChunk = bChunks[i];
91
- if (caseInsensitive && isString(aChunk) && isString(bChunk)) {
92
- aChunk = aChunk?.toLowerCase();
93
- bChunk = bChunk?.toLowerCase();
94
- }
95
- if (typeof aChunk !== typeof bChunk) return isString(aChunk) ? 1 : -1;
96
- if (aChunk !== bChunk) {
97
- if (isNumber(aChunk) && isNumber(bChunk)) return aChunk - bChunk;
98
- if (isString(aChunk) && isString(bChunk)) {
99
- if (localeAware) {
100
- const cmp = aChunk.localeCompare(bChunk, void 0, { sensitivity: caseInsensitive ? "accent" : "variant" });
101
- if (cmp !== 0) return cmp;
102
- }
103
- return aChunk < bChunk ? -1 : 1;
104
- }
105
- }
88
+ function generateRandomID(options) {
89
+ const { prefix = "", suffix = "", timeStamp = false, length = 16, separator = "", caseOption = null } = options || {};
90
+ const date = timeStamp ? Date.now() : "";
91
+ const randomString = Array.from({ length }, () => Math.random().toString(36).slice(2, 3)).join("");
92
+ const ID = [
93
+ prefix?.trim(),
94
+ date,
95
+ randomString,
96
+ suffix?.trim()
97
+ ].filter(Boolean).join(separator);
98
+ switch (caseOption) {
99
+ case "upper": return ID.toUpperCase();
100
+ case "lower": return ID.toLowerCase();
101
+ default: return ID;
106
102
  }
107
- return aChunks?.length - bChunks?.length;
108
103
  }
109
104
  /**
110
- * * Sorts an array of strings, numbers, booleans, or objects based on the provided options.
105
+ * * Trims all whitespaces in a string or an array of strings.
111
106
  *
112
- * @param array - The array to sort.
113
- * @param options - Sorting options.
114
- * @returns The sorted array.
107
+ * @param input String or array of strings.
108
+ * @returns Trimmed string or array of strings.
115
109
  */
116
- function sortAnArray(array, options) {
117
- if (!isValidArray(array)) return array;
118
- if (isArrayOfType(array, isString)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? naturalSort(b, a) : naturalSort(a, b));
119
- if (isArrayOfType(array, isNumber)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? b - a : a - b);
120
- if (isArrayOfType(array, isBoolean)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? Number(b) - Number(a) : Number(a) - Number(b));
121
- if (isArrayOfType(array, isObject) && options && "sortByField" in options) return [...array].sort((a, b) => {
122
- const _getKeyValue = (obj, path) => {
123
- return path.split(".").reduce((acc, key) => acc?.[key], obj);
124
- };
125
- const keyA = _getKeyValue(a, options?.sortByField);
126
- const keyB = _getKeyValue(b, options?.sortByField);
127
- if (keyA == null || keyB == null) return keyA == null ? 1 : -1;
128
- if (isString(keyA) && isString(keyB)) return options?.sortOrder === "desc" ? naturalSort(keyB, keyA) : naturalSort(keyA, keyB);
129
- if (isNumber(keyA) && isNumber(keyB)) return options?.sortOrder === "desc" ? keyB - keyA : keyA - keyB;
130
- if (isBoolean(keyA) && isBoolean(keyB)) return options?.sortOrder === "desc" ? Number(keyB) - Number(keyA) : Number(keyA) - Number(keyB);
131
- return 0;
132
- });
133
- return [...array];
110
+ function trimString(input) {
111
+ if (!input) return "";
112
+ if (isNonEmptyString(input)) return input.trim().replace(/\s+/g, " ");
113
+ if (Array.isArray(input)) return input.map((str) => isNonEmptyString(str) ? str.trim().replace(/\s+/g, " ") : str);
114
+ throw new TypeError("Expected string or array of strings!", { cause: "Invalid Input Type" });
134
115
  }
135
116
 
136
117
  //#endregion
137
- //#region src/utils/index.ts
118
+ //#region src/hash/utils.ts
138
119
  /**
139
- * * Deeply compare two values (arrays, objects, or primitive values).
120
+ * * Generates random bytes in the {@link Uint8Array} format.
140
121
  *
141
- * @param a First value to compare.
142
- * @param b Second value to compare.
143
- * @returns Whether the values are deeply equal.
144
- */
145
- const isDeepEqual = (a, b) => {
146
- if (a === b) return true;
147
- if (typeof a !== typeof b) return false;
148
- if (a === null || b === null) return a === b;
149
- if (isArray(a) && isArray(b)) {
150
- if (a?.length !== b?.length) return false;
151
- return a?.every((element, index) => isDeepEqual(element, b?.[index]));
152
- }
153
- if (isObject(a) && isObject(b)) {
154
- const aKeys = Object.keys(a);
155
- const bKeys = Object.keys(b);
156
- if (aKeys?.length !== bKeys?.length) return false;
157
- return aKeys?.every((key) => isDeepEqual(a?.[key], b?.[key]));
158
- }
159
- return false;
160
- };
161
- /**
162
- * * Converts an array of primitive values or objects to a string using a separator or target key.
122
+ * @param size - The length of the byte array to generate. Defaults to `8`.
123
+ * @returns A random array of bytes.
163
124
  *
164
- * @param array Array to convert.
165
- * @param options Options for separator or key extraction from objects.
166
- * @returns String representation of array values.
167
- */
168
- function convertArrayToString(array, options) {
169
- if (!isValidArray(array)) return "";
170
- const { separator = ", " } = options ?? {};
171
- if (isArrayOfType(array, isPrimitive)) return array?.join(separator);
172
- else if (isArrayOfType(array, isNotEmptyObject)) if (options && "target" in options) return array?.map((el) => _resolveNestedKey(el, options?.target))?.join(separator);
173
- else return "";
174
- return "";
175
- }
176
- /**
177
- * * A generic debounce function that delays the execution of a callback.
125
+ * @example
126
+ * ```typescript
127
+ * const bytes = randomBytes(16);
128
+ * // Returns something like: Uint8Array(16) [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 224, 166, 170, 224, 167, 131]
178
129
  *
179
- * @param callback - The function to debounce.
180
- * @param delay - The delay in milliseconds. Default is `300ms`.
181
- * @returns A debounced version of the callback function.
130
+ * // Empty array
131
+ * const empty = randomBytes(0);
132
+ * // Returns: Uint8Array(0) []
182
133
  *
183
- * @example
184
- * const debouncedSearch = debounceAction((query: string) => {
185
- * console.log(`Searching for: ${query}`);
186
- * }, 300);
134
+ * // Zero or negative values are treated as 0
135
+ * const zero = randomBytes(-5);
136
+ * // Returns: Uint8Array(0) []
137
+ * ```
187
138
  *
188
- * debouncedSearch('laptop'); // Executes after 300ms of inactivity.
139
+ * @remarks
140
+ * - It uses {@link crypto.getRandomValues} when available for secure randomness, and falls back to {@link Math.random} if not.
141
+ * - If {@link crypto.getRandomValues} is available (supported environments include browser and Node.js), it is used for cryptographically secure random number generation.
142
+ * - In environments where {@link crypto.getRandomValues} is not available, the function falls back to {@link Math.random}, which is **not** cryptographically secure.
143
+ * - {@link crypto.getRandomValues} fills the array with random values in the range [0, 255] (inclusive).
144
+ * - {@link Math.random} returns values in the range [0, 1) (exclusive of 1), so the values are scaled to [0, 255].
145
+ * - If `size` is 0 or negative, an empty `Uint8Array` is returned.
189
146
  */
190
- function debounceAction(callback, delay = 300) {
191
- let timeoutId;
192
- return (...args) => {
193
- clearTimeout(timeoutId);
194
- timeoutId = setTimeout(() => {
195
- callback(...args);
196
- }, delay);
197
- };
147
+ function randomBytes(size = 8) {
148
+ if (size <= 0) return new Uint8Array(0);
149
+ return _fillWithRandomValues(new Uint8Array(size));
198
150
  }
199
151
  /**
200
- * * A generic throttle function that ensures a callback is executed at most once per specified interval.
152
+ * * Generates a random hexadecimal string of the specified length.
201
153
  *
202
- * @param callback - The function to throttle.
203
- * @param delay - The delay in milliseconds. Default is `150ms`.
204
- * @returns A throttled version of the callback function.
154
+ * @param length - Number of hex characters to generate.
155
+ * @param uppercase - Whether to return uppercase `A–F` characters. Defaults to `false` (lowercase).
205
156
  *
206
- * @example
207
- * const throttledResize = throttleAction(() => {
208
- * console.log('Resized');
209
- * }, 300);
157
+ * @returns A randomly generated hexadecimal string.
210
158
  *
211
- * window.addEventListener('resize', throttledResize);
212
- */
213
- function throttleAction(callback, delay = 150) {
214
- let lastCall = 0;
215
- return (...args) => {
216
- const now = Date.now();
217
- if (now - lastCall >= delay) {
218
- lastCall = now;
219
- callback(...args);
220
- }
221
- };
222
- }
223
- /**
224
- * * Retrieves the names of all instance methods defined directly on a class prototype.
159
+ * @remarks
160
+ * - This function generates a random hexadecimal string of the specified length.
161
+ * - It uses {@link crypto.getRandomValues} when available for secure randomness, and falls back to {@link Math.random} if not.
162
+ * - The output is a string of hex characters (`0–9`, `a–f` or `A–F`) with no prefixes or separators.
163
+ * - If `length` is `0` or negative, an empty string is returned.
225
164
  *
226
- * @param cls - The class constructor (not an instance).
227
- * @returns A sorted array of instance method names.
228
- */
229
- function getInstanceMethodNames(cls) {
230
- const prototype = cls.prototype;
231
- return sortAnArray(Object.getOwnPropertyNames(prototype).filter((method) => {
232
- if (method === "constructor") return false;
233
- return isMethodDescriptor(Object.getOwnPropertyDescriptor(prototype, method));
234
- }));
235
- }
236
- /**
237
- * * Retrieves the names of all static methods defined directly on a class constructor.
165
+ * @example
166
+ * // 16-character lowercase hex
167
+ * const id = randomHex(16);
238
168
  *
239
- * @param cls - The class constructor (not an instance).
240
- * @returns A sorted array of static method names.
169
+ * @example
170
+ * // 8-character uppercase hex
171
+ * const token = randomHex(8, true);
241
172
  */
242
- function getStaticMethodNames(cls) {
243
- return sortAnArray(Object.getOwnPropertyNames(cls).filter((method) => {
244
- return method !== "prototype" && method !== "name" && method !== "length";
245
- }));
173
+ function randomHex(length, uppercase = false) {
174
+ if (length <= 0) return "";
175
+ const expected = _bytesToRandomHex(new Uint8Array(Math.ceil(length / 2))).slice(0, length);
176
+ return uppercase ? expected.toUpperCase() : expected;
246
177
  }
247
178
  /**
248
- * * Counts the number of instance methods defined directly on a class prototype.
179
+ * * Generates a random numeric string of the specified length.
249
180
  *
250
- * @param cls - The class constructor (not an instance).
251
- * @returns The number of instance methods defined on the class prototype.
252
- */
253
- function countInstanceMethods(cls) {
254
- return getInstanceMethodNames(cls)?.length;
255
- }
256
- /**
257
- * * Counts the number of static methods defined directly on a class constructor.
181
+ * @param length - Length of the numeric string. Defaults to `6`.
182
+ * @returns A randomly generated numeric string.
258
183
  *
259
- * @param cls - The class constructor (not an instance).
260
- * @returns The number of static methods defined on the class constructor.
261
- */
262
- function countStaticMethods(cls) {
263
- return getStaticMethodNames(cls)?.length;
264
- }
265
- /**
266
- * * Retrieves the names of all instance getters defined directly on a class prototype.
184
+ * @example
185
+ * ```typescript
186
+ * const otp = randomNumeric(6);
187
+ * // Returns something like: '123456'
188
+ * ```
267
189
  *
268
- * @param cls - The class constructor (not an instance).
269
- * @returns A sorted array of instance getter names.
190
+ * @remarks
191
+ * - If `length` is `0` or negative, an empty string is returned.
270
192
  */
271
- function getInstanceGetterNames(cls) {
272
- const descriptors = Object.getOwnPropertyDescriptors(cls.prototype);
273
- return sortAnArray(Object.entries(descriptors).filter(([key, desc]) => isFunction(desc.get) && key !== "constructor").map(([key]) => key));
193
+ function randomNumeric(length = 6) {
194
+ return randomBytes(length).map((byte) => byte & 10).join("");
274
195
  }
275
196
  /**
276
- * * Retrieves the names of all static getters defined directly on a class constructor.
197
+ * * Generates a random alphanumeric string (letters and numbers) of the specified length.
277
198
  *
278
- * @param cls - The class constructor (not an instance).
279
- * @returns A sorted array of static getter names.
280
- */
281
- function getStaticGetterNames(cls) {
282
- return sortAnArray(Object.entries(Object.getOwnPropertyDescriptors(cls)).filter(([key, desc]) => typeof desc.get === "function" && key !== "prototype").map(([key]) => key));
283
- }
284
- /**
285
- * * Gathers detailed information about the instance and static methods of a class.
199
+ * @param length - The desired length of the random string. Defaults to `8`.
200
+ * @param uppercase - If `true`, the string will contain uppercase letters (A-Z). Defaults to `false` (lowercase).
286
201
  *
287
- * @param cls - The class constructor (not an instance).
288
- * @returns An object containing names and counts of instance and static methods.
289
- */
290
- function getClassDetails(cls) {
291
- const instanceNames = getInstanceMethodNames(cls);
292
- const staticNames = getStaticMethodNames(cls);
293
- const instanceGetters = getInstanceGetterNames(cls);
294
- const staticGetters = getStaticGetterNames(cls);
295
- return {
296
- instanceMethods: instanceNames,
297
- staticMethods: staticNames,
298
- instanceGetters,
299
- staticGetters,
300
- instanceCount: instanceNames?.length,
301
- staticCount: staticNames?.length,
302
- totalGetters: instanceGetters?.length + staticGetters?.length,
303
- totalMethods: instanceNames?.length + staticNames?.length
304
- };
305
- }
306
- /**
307
- * * Create a deterministic JSON string representation of any value.
308
- * - The output format matches standard JSON but with guaranteed sorted keys.
202
+ * @returns A random string composed of alphanumeric characters.
309
203
  *
310
- * @remarks
311
- * - This function guarantees **stable, repeatable output** by:
312
- * - Sorting all object keys alphabetically.
313
- * - Recursively stabilizing nested objects and arrays.
314
- * - Converting all `undefined` values into `null` so the output remains valid JSON.
315
- * - Converting date-like objects (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) **in the same way that {@link JSON.stringify} would serialize them**, ensuring predictable and JSON-compliant output.
316
- * - Falling back to native JSON serialization for primitives.
204
+ * @example
205
+ * ```typescript
206
+ * // Generate a random 8-character alphanumeric string (default: lowercase)
207
+ * const randomStr = randomAlphaNumeric(8);
208
+ * // Example output: "a7b2f9d1"
317
209
  *
318
- * - **Useful for:**
319
- * - Hash generation (e.g., signatures, cache keys)
320
- * - Deep equality checks
321
- * - Producing predictable output across environments
210
+ * // Generate a 12-character uppercase alphanumeric string
211
+ * const randomUpper = randomAlphaNumeric(12, true);
212
+ * // Example output: "X5K9P2M7H4L3"
322
213
  *
323
- * @param obj - The value to stringify into a deterministic JSON string.
324
- * @returns A stable, deterministic string representation of the input.
325
- */
326
- function stableStringify(obj) {
327
- const _replacer = (_, v) => v === void 0 ? null : v;
328
- if (isNotEmptyObject(obj)) return "{" + Object.keys(obj).sort().map((k) => JSON.stringify(k, _replacer) + ":" + (isDateLike(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k]))).join(",") + "}";
329
- if (isValidArray(obj)) return "[" + obj.map((v) => stableStringify(v)).join(",") + "]";
330
- return JSON.stringify(obj, _replacer);
331
- }
332
- /**
333
- * * Remove trailing or leading garbage characters **after/before JSON object or array**.
334
- * @param str String to sanitize/strip.
335
- * @returns Sanitized/stripped JSON string.
214
+ * // Generate a 6-character string
215
+ * const shortStr = randomAlphaNumeric(6);
216
+ * ```
217
+ *
218
+ * @remarks
219
+ * - The function generates random bytes and converts them to base-36 (0-9, a-z) characters.
220
+ * - If `length` is `0` or negative, an empty string is returned.
336
221
  */
337
- function stripJsonEdgeGarbage(str) {
338
- if (!isNonEmptyString(str)) return "";
339
- const lastIdx = Math.max(str.lastIndexOf("}"), str.lastIndexOf("]"));
340
- const _idxOf = (sym) => str.indexOf(sym) !== -1 ? str.indexOf(sym) : Infinity;
341
- const firstIdx = Math.min(_idxOf("{"), _idxOf("["));
342
- if (lastIdx === -1 || firstIdx === Infinity) return str;
343
- return str.slice(firstIdx, lastIdx + 1);
222
+ function randomAlphaNumeric(length = 8, uppercase = false) {
223
+ const bytes = randomBytes(Math.ceil(length / 2));
224
+ let ran = "";
225
+ for (const byte of bytes) ran += byte.toString(36).padStart(2, "0");
226
+ const result = ran.slice(0, length);
227
+ return uppercase ? result.toUpperCase() : result;
344
228
  }
345
229
  /**
346
- * * Parses any valid JSON string, optionally converting stringified primitives inside (nested) arrays or objects.
230
+ * * Converts a UTF-8 string to a byte array (`Uint8Array`).
347
231
  *
348
- * @typeParam T - Expected return type (default is unknown).
349
- * @param value - The JSON string to parse.
350
- * @param parsePrimitives - Whether to convert stringified primitives (default: `true`).
351
- * @returns The parsed JSON value typed as `T`, or the original parsed value with optional primitive conversion.
352
- * - Returns `{}` if parsing fails, such as when the input is malformed or invalid JSON or passing single quoted string.
232
+ * This function encodes a JavaScript string into UTF-8 bytes, handling all Unicode code points including supplementary characters (surrogate pairs).
353
233
  *
354
- * - *Unlike {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/object/parse-json-to-object parseJsonToObject}, which ensures the root value is an object,
355
- * this function returns any valid JSON structure such as arrays, strings, numbers, or objects.*
234
+ * @example
235
+ * ```typescript
236
+ * // Basic ASCII
237
+ * const asciiBytes = utf8ToBytes('hello');
238
+ * // Returns:
239
+ * Uint8Array(5) [104, 101, 108, 108, 111]
356
240
  *
357
- * This is useful when you're not sure of the root structure of the JSON, or when you expect something other than an object.
241
+ * // Unicode characters
242
+ * const unicodeBytes = utf8ToBytes('Hello পৃথিবী!');
243
+ * // Returns:
244
+ * Uint8Array(25) [
245
+ * 72, 101, 108, 108, 111, 32,
246
+ * 224, 166, 170, 224, 167, 131,
247
+ * 224, 166, 165, 224, 166, 191,
248
+ * 224, 166, 172, 224, 167, 128,
249
+ * 33
250
+ * ]
251
+ * ```
358
252
  *
359
- * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/object/parse-json-to-object parseJsonToObject} for strict object-only parsing.
360
- */
361
- const parseJSON = (value, parsePrimitives = true) => {
362
- try {
363
- const parsed = JSON.parse(value);
364
- return parsePrimitives ? deepParsePrimitives(parsed) : parsed;
365
- } catch {
366
- return {};
367
- }
368
- };
369
- /**
370
- * * Recursively parses primitive values inside objects and arrays.
253
+ * @param str - The input string to encode as UTF-8 bytes.
254
+ * @returns A `Uint8Array` containing the UTF-8 encoded bytes.
371
255
  *
372
- * @typeParam T - Expected return type after parsing (default is unknown).
373
- * @param input - Any input value to parse recursively.
374
- * @returns Input with primitives (strings like "true", "123") converted, typed as `T`.
256
+ * @remarks
257
+ * - The encoding follows the UTF-8 specification:
258
+ * - 1-byte sequence for code points U+0000 to U+007F (ASCII)
259
+ * - 2-byte sequence for code points U+0080 to U+07FF
260
+ * - 3-byte sequence for code points U+0800 to U+FFFF
261
+ * - 4-byte sequence for code points U+10000 to U+10FFFF (surrogate pairs)
262
+ *
263
+ * **Note:** Invalid surrogate pairs in the input string are silently ignored.
264
+ *
265
+ * @see {@link bytesToUtf8} for the inverse operation
375
266
  */
376
- function deepParsePrimitives(input) {
377
- if (Array.isArray(input)) return input?.map(deepParsePrimitives);
378
- if (isObject(input)) {
379
- const result = {};
380
- for (const [key, value] of Object.entries(input)) result[key] = deepParsePrimitives(value);
381
- return result;
382
- }
383
- if (isString(input)) {
384
- if (/^(true|false)$/i.test(input)) return input?.toLowerCase() === "true";
385
- if (isNumericString(input)) return Number(input);
386
- if (input === "null") return null;
387
- if (input === "undefined") return;
388
- return input;
267
+ function utf8ToBytes(str) {
268
+ const out = [];
269
+ for (let i = 0; i < str.length; i++) {
270
+ const code = str.charCodeAt(i);
271
+ if (code < 128) out.push(code);
272
+ else if (code < 2048) out.push(192 | code >> 6, 128 | code & 63);
273
+ else if (code >= 55296 && code <= 57343) {
274
+ if (code < 56320 && i + 1 < str.length) {
275
+ const hi = code;
276
+ const lo = str.charCodeAt(++i);
277
+ const codePoint = 65536 + (hi - 55296 << 10) + (lo - 56320);
278
+ out.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
279
+ }
280
+ } else out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
389
281
  }
390
- return input;
282
+ return new Uint8Array(out);
391
283
  }
392
284
  /**
393
- * * Defines a method on any prototype — including built-in prototypes — in a safe, idempotent manner.
394
- * - The method is non-enumerable by default and will not overwrite an existing method unless explicitly allowed.
285
+ * * Converts `UTF-8` encoded bytes back to a string.
395
286
  *
396
- * @param proto The target prototype object (e.g., String.prototype).
397
- * @param name The method name to define on the prototype.
398
- * @param impl The function implementation for the method.
399
- * @param options Optional property-descriptor settings and overwrite rules.
287
+ * This function decodes a `Uint8Array` containing `UTF-8` bytes into a JavaScript string.
400
288
  *
401
289
  * @example
402
- * // Safely augment prototype methods by extending the global interface:
403
- * declare global {
404
- * interface String {
405
- * toBang(): string;
406
- * }
407
- * }
290
+ * ```typescript
291
+ * // Decode UTF-8 bytes
292
+ * const bytes = new Uint8Array([104, 101, 108, 108, 111]);
293
+ * const str = bytesToUtf8(bytes);
294
+ * // Returns: 'hello'
408
295
  *
409
- * // Define a custom method on String.prototype
410
- * definePrototypeMethod(String.prototype, 'toBang', function (this: String) {
411
- * return this.toString().concat('!');
412
- * // or
413
- * // return this.concat('!');
414
- * });
415
- *
416
- * "Hi".toBang(); // "Hi!"
417
- *
418
- * // Attempting to redefine without overwrite option is ignored
419
- * definePrototypeMethod(String.prototype, 'toBang', () => 'x'); // ignored
420
- *
421
- * // Overwrite intentionally using the overwrite option
422
- * definePrototypeMethod(
423
- * String.prototype,
424
- * 'toBang',
425
- * function (this: String) { return this.concat('!!!'); },
426
- * { overwrite: true }
427
- * );
428
- *
429
- * "Hi".toBang(); // "Hi!!!"
430
- */
431
- function definePrototypeMethod(proto, name, impl, options) {
432
- if (Object.hasOwn(proto, name) && !options?.overwrite) return;
433
- Object.defineProperty(proto, name, {
434
- value: function(...args) {
435
- return impl.apply(this, args);
436
- },
437
- enumerable: options?.enumerable ?? false,
438
- configurable: options?.configurable ?? false,
439
- writable: options?.writable ?? true
440
- });
441
- }
442
-
443
- //#endregion
444
- //#region src/hash/utils.ts
445
- /**
446
- * * Generates a random hexadecimal string of the specified length.
447
- *
448
- * @param length - Number of hex characters to generate.
449
- * @param uppercase - Whether to return uppercase `A–F` characters. Defaults to `false` (lowercase).
450
- *
451
- * @returns A randomly generated hexadecimal string.
452
- *
453
- * @remarks
454
- * - This function generates a random hexadecimal string of the specified length.
455
- * - It uses {@link crypto.getRandomValues} when available for secure randomness, and falls back to {@link Math.random} if not.
456
- * - The output is a string of hex characters (`0–9`, `a–f` or `A–F`) with no prefixes or separators.
457
- * - If `length` is `0` or negative, an empty string is returned.
458
- *
459
- * @example
460
- * // 16-character lowercase hex
461
- * const id = randomHex(16);
462
- *
463
- * @example
464
- * // 8-character uppercase hex
465
- * const token = randomHex(8, true);
466
- */
467
- function randomHex(length, uppercase = false) {
468
- if (length <= 0) return "";
469
- const expected = _bytesToRandomHex(new Uint8Array(Math.ceil(length / 2))).slice(0, length);
470
- return uppercase ? expected.toUpperCase() : expected;
471
- }
472
- /**
473
- * * Converts a UTF-8 string to a byte array (`Uint8Array`).
474
- *
475
- * This function encodes a JavaScript string into UTF-8 bytes, handling all Unicode code points including supplementary characters (surrogate pairs).
476
- *
477
- * @example
478
- * ```typescript
479
- * // Basic ASCII
480
- * const asciiBytes = utf8ToBytes('hello');
481
- * // Returns:
482
- * Uint8Array(5) [104, 101, 108, 108, 111]
483
- *
484
- * // Unicode characters
485
- * const unicodeBytes = utf8ToBytes('Hello পৃথিবী!');
486
- * // Returns:
487
- * Uint8Array(25) [
488
- * 72, 101, 108, 108, 111, 32,
489
- * 224, 166, 170, 224, 167, 131,
490
- * 224, 166, 165, 224, 166, 191,
491
- * 224, 166, 172, 224, 167, 128,
492
- * 33
493
- * ]
494
- * ```
495
- *
496
- * @param str - The input string to encode as UTF-8 bytes.
497
- * @returns A `Uint8Array` containing the UTF-8 encoded bytes.
498
- *
499
- * @remarks
500
- * - The encoding follows the UTF-8 specification:
501
- * - 1-byte sequence for code points U+0000 to U+007F (ASCII)
502
- * - 2-byte sequence for code points U+0080 to U+07FF
503
- * - 3-byte sequence for code points U+0800 to U+FFFF
504
- * - 4-byte sequence for code points U+10000 to U+10FFFF (surrogate pairs)
505
- *
506
- * **Note:** Invalid surrogate pairs in the input string are silently ignored.
507
- *
508
- * @see {@link bytesToUtf8} for the inverse operation
509
- */
510
- function utf8ToBytes(str) {
511
- const out = [];
512
- for (let i = 0; i < str.length; i++) {
513
- const code = str.charCodeAt(i);
514
- if (code < 128) out.push(code);
515
- else if (code < 2048) out.push(192 | code >> 6, 128 | code & 63);
516
- else if (code >= 55296 && code <= 57343) {
517
- if (code < 56320 && i + 1 < str.length) {
518
- const hi = code;
519
- const lo = str.charCodeAt(++i);
520
- const codePoint = 65536 + (hi - 55296 << 10) + (lo - 56320);
521
- out.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
522
- }
523
- } else out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
524
- }
525
- return new Uint8Array(out);
526
- }
527
- /**
528
- * * Converts `UTF-8` encoded bytes back to a string.
529
- *
530
- * This function decodes a `Uint8Array` containing `UTF-8` bytes into a JavaScript string.
531
- *
532
- * @example
533
- * ```typescript
534
- * // Decode UTF-8 bytes
535
- * const bytes = new Uint8Array([104, 101, 108, 108, 111]);
536
- * const str = bytesToUtf8(bytes);
537
- * // Returns: 'hello'
538
- *
539
- * // Round-trip conversion
540
- * const original = 'Hello 🌍';
541
- * const bytes = utf8ToBytes(original);
542
- * const decoded = bytesToUtf8(bytes);
543
- * console.log(original === decoded); // true
544
- * ```
296
+ * // Round-trip conversion
297
+ * const original = 'Hello 🌍';
298
+ * const bytes = utf8ToBytes(original);
299
+ * const decoded = bytesToUtf8(bytes);
300
+ * console.log(original === decoded); // true
301
+ * ```
545
302
  *
546
303
  * @param bytes - A `Uint8Array` containing `UTF-8` encoded bytes.
547
304
  * @returns The decoded string.
@@ -1654,100 +1411,426 @@ function isUUIDv8(value) {
1654
1411
  }
1655
1412
 
1656
1413
  //#endregion
1657
- //#region src/string/basics.ts
1414
+ //#region src/array/helpers.ts
1658
1415
  /**
1659
- * * Utility to truncate a string to a specified length.
1416
+ * Safely resolves value of nested key (dot-notation key like `"user.city"`).
1660
1417
  *
1661
- * @param str The string to truncate.
1662
- * @param maxLength The maximum length of the truncated string.
1663
- * @returns Truncated string with ellipsis (`...`) (only if it has more length than `maxLength`).
1418
+ * @param obj - The source object
1419
+ * @param path - The nested path string (e.g. `"user.city"`)
1420
+ * @returns The resolved value or `undefined`
1664
1421
  */
1665
- function truncateString(str, maxLength) {
1666
- if (!isNonEmptyString(str)) return "";
1667
- const trimmedString = str.trim();
1668
- if (!trimmedString) return "";
1669
- if (trimmedString.length <= maxLength) return trimmedString;
1670
- return trimmedString.slice(0, maxLength).concat("...");
1422
+ function _resolveNestedKey(obj, path) {
1423
+ if (isNotEmptyObject(obj)) return path?.split(".").reduce((acc, key) => {
1424
+ if (isNotEmptyObject(acc)) return acc[key];
1425
+ }, obj);
1671
1426
  }
1672
1427
  /**
1673
- * * Generates a random alphanumeric (16 characters long, this length is customizable in the options) ID string composed of an optional `prefix`, `suffix`, a `timestamp`, `caseOption` and a customizable `separator`.
1674
- *
1675
- * @param options Configuration options for random ID generation.
1676
- * @returns The generated ID string composed of the random alphanumeric string of specified length with optional `timeStamp`, `prefix`, and `suffix`, `caseOption` and `separator`.
1677
- *
1678
- * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/hash/uuid uuid} for `uuid` generation
1679
- * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/hash/random-hex randomHex} for random hexadecimal string generation
1680
- *
1681
- * @example
1682
- * // Generate an ID with all default options
1683
- * const id = generateRandomID();
1684
- * // Example output: "swo8ckxwsc13w7xw"
1685
- *
1686
- * @example
1687
- * // Generate an ID with a custom prefix and separator
1688
- * const id = generateRandomID({ prefix: 'ID', separator: '-' });
1689
- * // Example output: "ID-eh1ymwfxzwas9jte"
1690
- *
1691
- * @example
1692
- * // Generate an ID with a timestamp
1693
- * const id = generateRandomID({ timeStamp: false });
1694
- * // Example output: "1764610287501pd3r4w85qwkuulgf"
1695
- *
1696
- * @example
1697
- * // Generate an ID with a custom length for the random string
1698
- * const id = generateRandomID({ length: 8 });
1699
- * // Example output: "i623uiev"
1700
- *
1701
- * @example
1702
- * // Generate an ID with a custom suffix
1703
- * const id = generateRandomID({ suffix: 'END' });
1704
- * // Example output: "3csf27a4800rbli9END"
1705
- *
1706
- * @example
1707
- * // Generate an ID with a uppercase random string
1708
- * const id = generateRandomID({ caseOption: "upper" });
1709
- * // Example output: "H0VNU6O8XV1Y30HG"
1428
+ * Retrieves a numeric value from a nested property (dot-notation key like 'user.income.tax').
1429
+ * Falls back to 0 if value is not a number or numeric string.
1710
1430
  *
1711
- * @example
1712
- * // Generate an ID with all options customized
1713
- * const id = generateRandomID({
1714
- * prefix: 'ID',
1715
- * suffix: 'END',
1716
- * timeStamp: true,
1717
- * length: 10,
1718
- * separator: '-',
1719
- * caseOption: "upper"
1720
- * });
1721
- * // Example output: "ID-1764610471474-4KSL51IB91-END"
1431
+ * @param obj - The source object to read from.
1432
+ * @param path - The dot-notation path string like 'user.income.tax'.
1433
+ * @returns The numeric value at that path, or 0 if not valid.
1722
1434
  */
1723
- function generateRandomID(options) {
1724
- const { prefix = "", suffix = "", timeStamp = false, length = 16, separator = "", caseOption = null } = options || {};
1725
- const date = timeStamp ? Date.now() : "";
1726
- const randomString = Array.from({ length }, () => Math.random().toString(36).slice(2, 3)).join("");
1727
- const ID = [
1728
- prefix?.trim(),
1729
- date,
1730
- randomString,
1731
- suffix?.trim()
1732
- ].filter(Boolean).join(separator);
1733
- switch (caseOption) {
1734
- case "upper": return ID.toUpperCase();
1735
- case "lower": return ID.toLowerCase();
1736
- default: return ID;
1737
- }
1435
+ function _getNumericProp(obj, path) {
1436
+ return normalizeNumber(_resolveNestedKey(obj, path)) ?? 0;
1738
1437
  }
1438
+
1439
+ //#endregion
1440
+ //#region src/array/sort.ts
1739
1441
  /**
1740
- * * Trims all whitespaces in a string or an array of strings.
1442
+ * Compare two strings using natural sorting (e.g., `"file2"` < `"file10"`).
1443
+ * - Optionally supports case-insensitive and locale-aware string chunk comparisons.
1741
1444
  *
1742
- * @param input String or array of strings.
1743
- * @returns Trimmed string or array of strings.
1445
+ * @param a - The first string to compare.
1446
+ * @param b - The second string to compare.
1447
+ * @param options - Optional settings to configure comparison behavior.
1448
+ * @returns A negative number if `a` comes before `b`, a positive number if `a` comes after `b`, or 0 if equal.
1744
1449
  */
1745
- function trimString(input) {
1746
- if (!input) return "";
1747
- if (isNonEmptyString(input)) return input.trim().replace(/\s+/g, " ");
1748
- if (Array.isArray(input)) return input.map((str) => isNonEmptyString(str) ? str.trim().replace(/\s+/g, " ") : str);
1749
- throw new TypeError("Expected string or array of strings!", { cause: "Invalid Input Type" });
1450
+ function naturalSort(a, b, options) {
1451
+ const { caseInsensitive = true, localeAware = false } = options || {};
1452
+ /**
1453
+ * * Splits a string into an array of number and non-number chunks.
1454
+ * @param str - The string to split.
1455
+ * @returns An array of string and number parts.
1456
+ */
1457
+ const _createChunks = (str) => {
1458
+ const chunks = [];
1459
+ let current = "";
1460
+ let isNumeric = false;
1461
+ for (const char of str) {
1462
+ const charIsNum = !Number.isNaN(Number(char));
1463
+ if (current?.length === 0) {
1464
+ current = char;
1465
+ isNumeric = charIsNum;
1466
+ continue;
1467
+ }
1468
+ if (charIsNum === isNumeric) current += char;
1469
+ else {
1470
+ chunks?.push(isNumeric ? Number(current) : current);
1471
+ current = char;
1472
+ isNumeric = charIsNum;
1473
+ }
1474
+ }
1475
+ if (current?.length > 0) chunks?.push(isNumeric ? Number(current) : current);
1476
+ return chunks;
1477
+ };
1478
+ const aChunks = _createChunks(a);
1479
+ const bChunks = _createChunks(b);
1480
+ for (let i = 0; i < Math.min(aChunks?.length, bChunks?.length); i++) {
1481
+ let aChunk = aChunks[i];
1482
+ let bChunk = bChunks[i];
1483
+ if (caseInsensitive && isString(aChunk) && isString(bChunk)) {
1484
+ aChunk = aChunk?.toLowerCase();
1485
+ bChunk = bChunk?.toLowerCase();
1486
+ }
1487
+ if (typeof aChunk !== typeof bChunk) return isString(aChunk) ? 1 : -1;
1488
+ if (aChunk !== bChunk) {
1489
+ if (isNumber(aChunk) && isNumber(bChunk)) return aChunk - bChunk;
1490
+ if (isString(aChunk) && isString(bChunk)) {
1491
+ if (localeAware) {
1492
+ const cmp = aChunk.localeCompare(bChunk, void 0, { sensitivity: caseInsensitive ? "accent" : "variant" });
1493
+ if (cmp !== 0) return cmp;
1494
+ }
1495
+ return aChunk < bChunk ? -1 : 1;
1496
+ }
1497
+ }
1498
+ }
1499
+ return aChunks?.length - bChunks?.length;
1500
+ }
1501
+ /**
1502
+ * * Sorts an array of strings, numbers, booleans, or objects based on the provided options.
1503
+ *
1504
+ * @param array - The array to sort.
1505
+ * @param options - Sorting options.
1506
+ * @returns The sorted array.
1507
+ */
1508
+ function sortAnArray(array, options) {
1509
+ if (!isValidArray(array)) return array;
1510
+ if (isArrayOfType(array, isString)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? naturalSort(b, a) : naturalSort(a, b));
1511
+ if (isArrayOfType(array, isNumber)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? b - a : a - b);
1512
+ if (isArrayOfType(array, isBoolean)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? Number(b) - Number(a) : Number(a) - Number(b));
1513
+ if (isArrayOfType(array, isObject) && options && "sortByField" in options) return [...array].sort((a, b) => {
1514
+ const _getKeyValue = (obj, path) => {
1515
+ return path.split(".").reduce((acc, key) => acc?.[key], obj);
1516
+ };
1517
+ const keyA = _getKeyValue(a, options?.sortByField);
1518
+ const keyB = _getKeyValue(b, options?.sortByField);
1519
+ if (keyA == null || keyB == null) return keyA == null ? 1 : -1;
1520
+ if (isString(keyA) && isString(keyB)) return options?.sortOrder === "desc" ? naturalSort(keyB, keyA) : naturalSort(keyA, keyB);
1521
+ if (isNumber(keyA) && isNumber(keyB)) return options?.sortOrder === "desc" ? keyB - keyA : keyA - keyB;
1522
+ if (isBoolean(keyA) && isBoolean(keyB)) return options?.sortOrder === "desc" ? Number(keyB) - Number(keyA) : Number(keyA) - Number(keyB);
1523
+ return 0;
1524
+ });
1525
+ return [...array];
1526
+ }
1527
+
1528
+ //#endregion
1529
+ //#region src/utils/index.ts
1530
+ /**
1531
+ * * Deeply compare two values (arrays, objects, or primitive values).
1532
+ *
1533
+ * @param a First value to compare.
1534
+ * @param b Second value to compare.
1535
+ * @returns Whether the values are deeply equal.
1536
+ */
1537
+ const isDeepEqual = (a, b) => {
1538
+ if (a === b) return true;
1539
+ if (typeof a !== typeof b) return false;
1540
+ if (a === null || b === null) return a === b;
1541
+ if (isArray(a) && isArray(b)) {
1542
+ if (a?.length !== b?.length) return false;
1543
+ return a?.every((element, index) => isDeepEqual(element, b?.[index]));
1544
+ }
1545
+ if (isObject(a) && isObject(b)) {
1546
+ const aKeys = Object.keys(a);
1547
+ const bKeys = Object.keys(b);
1548
+ if (aKeys?.length !== bKeys?.length) return false;
1549
+ return aKeys?.every((key) => isDeepEqual(a?.[key], b?.[key]));
1550
+ }
1551
+ return false;
1552
+ };
1553
+ /**
1554
+ * * Converts an array of primitive values or objects to a string using a separator or target key.
1555
+ *
1556
+ * @param array Array to convert.
1557
+ * @param options Options for separator or key extraction from objects.
1558
+ * @returns String representation of array values.
1559
+ */
1560
+ function convertArrayToString(array, options) {
1561
+ if (!isValidArray(array)) return "";
1562
+ const { separator = ", " } = options ?? {};
1563
+ if (isArrayOfType(array, isPrimitive)) return array?.join(separator);
1564
+ else if (isArrayOfType(array, isNotEmptyObject)) if (options && "target" in options) return array?.map((el) => _resolveNestedKey(el, options?.target))?.join(separator);
1565
+ else return "";
1566
+ return "";
1567
+ }
1568
+ /**
1569
+ * * A generic debounce function that delays the execution of a callback.
1570
+ *
1571
+ * @param callback - The function to debounce.
1572
+ * @param delay - The delay in milliseconds. Default is `300ms`.
1573
+ * @returns A debounced version of the callback function.
1574
+ *
1575
+ * @example
1576
+ * const debouncedSearch = debounceAction((query: string) => {
1577
+ * console.log(`Searching for: ${query}`);
1578
+ * }, 300);
1579
+ *
1580
+ * debouncedSearch('laptop'); // Executes after 300ms of inactivity.
1581
+ */
1582
+ function debounceAction(callback, delay = 300) {
1583
+ let timeoutId;
1584
+ return (...args) => {
1585
+ clearTimeout(timeoutId);
1586
+ timeoutId = setTimeout(() => {
1587
+ callback(...args);
1588
+ }, delay);
1589
+ };
1590
+ }
1591
+ /**
1592
+ * * A generic throttle function that ensures a callback is executed at most once per specified interval.
1593
+ *
1594
+ * @param callback - The function to throttle.
1595
+ * @param delay - The delay in milliseconds. Default is `150ms`.
1596
+ * @returns A throttled version of the callback function.
1597
+ *
1598
+ * @example
1599
+ * const throttledResize = throttleAction(() => {
1600
+ * console.log('Resized');
1601
+ * }, 300);
1602
+ *
1603
+ * window.addEventListener('resize', throttledResize);
1604
+ */
1605
+ function throttleAction(callback, delay = 150) {
1606
+ let lastCall = 0;
1607
+ return (...args) => {
1608
+ const now = Date.now();
1609
+ if (now - lastCall >= delay) {
1610
+ lastCall = now;
1611
+ callback(...args);
1612
+ }
1613
+ };
1614
+ }
1615
+ /**
1616
+ * * Retrieves the names of all instance methods defined directly on a class prototype.
1617
+ *
1618
+ * @param cls - The class constructor (not an instance).
1619
+ * @returns A sorted array of instance method names.
1620
+ */
1621
+ function getInstanceMethodNames(cls) {
1622
+ const prototype = cls.prototype;
1623
+ return sortAnArray(Object.getOwnPropertyNames(prototype).filter((method) => {
1624
+ if (method === "constructor") return false;
1625
+ return isMethodDescriptor(Object.getOwnPropertyDescriptor(prototype, method));
1626
+ }));
1627
+ }
1628
+ /**
1629
+ * * Retrieves the names of all static methods defined directly on a class constructor.
1630
+ *
1631
+ * @param cls - The class constructor (not an instance).
1632
+ * @returns A sorted array of static method names.
1633
+ */
1634
+ function getStaticMethodNames(cls) {
1635
+ return sortAnArray(Object.getOwnPropertyNames(cls).filter((method) => {
1636
+ return method !== "prototype" && method !== "name" && method !== "length";
1637
+ }));
1638
+ }
1639
+ /**
1640
+ * * Counts the number of instance methods defined directly on a class prototype.
1641
+ *
1642
+ * @param cls - The class constructor (not an instance).
1643
+ * @returns The number of instance methods defined on the class prototype.
1644
+ */
1645
+ function countInstanceMethods(cls) {
1646
+ return getInstanceMethodNames(cls)?.length;
1647
+ }
1648
+ /**
1649
+ * * Counts the number of static methods defined directly on a class constructor.
1650
+ *
1651
+ * @param cls - The class constructor (not an instance).
1652
+ * @returns The number of static methods defined on the class constructor.
1653
+ */
1654
+ function countStaticMethods(cls) {
1655
+ return getStaticMethodNames(cls)?.length;
1656
+ }
1657
+ /**
1658
+ * * Retrieves the names of all instance getters defined directly on a class prototype.
1659
+ *
1660
+ * @param cls - The class constructor (not an instance).
1661
+ * @returns A sorted array of instance getter names.
1662
+ */
1663
+ function getInstanceGetterNames(cls) {
1664
+ const descriptors = Object.getOwnPropertyDescriptors(cls.prototype);
1665
+ return sortAnArray(Object.entries(descriptors).filter(([key, desc]) => isFunction(desc.get) && key !== "constructor").map(([key]) => key));
1666
+ }
1667
+ /**
1668
+ * * Retrieves the names of all static getters defined directly on a class constructor.
1669
+ *
1670
+ * @param cls - The class constructor (not an instance).
1671
+ * @returns A sorted array of static getter names.
1672
+ */
1673
+ function getStaticGetterNames(cls) {
1674
+ return sortAnArray(Object.entries(Object.getOwnPropertyDescriptors(cls)).filter(([key, desc]) => typeof desc.get === "function" && key !== "prototype").map(([key]) => key));
1675
+ }
1676
+ /**
1677
+ * * Gathers detailed information about the instance and static methods of a class.
1678
+ *
1679
+ * @param cls - The class constructor (not an instance).
1680
+ * @returns An object containing names and counts of instance and static methods.
1681
+ */
1682
+ function getClassDetails(cls) {
1683
+ const instanceNames = getInstanceMethodNames(cls);
1684
+ const staticNames = getStaticMethodNames(cls);
1685
+ const instanceGetters = getInstanceGetterNames(cls);
1686
+ const staticGetters = getStaticGetterNames(cls);
1687
+ return {
1688
+ instanceMethods: instanceNames,
1689
+ staticMethods: staticNames,
1690
+ instanceGetters,
1691
+ staticGetters,
1692
+ instanceCount: instanceNames?.length,
1693
+ staticCount: staticNames?.length,
1694
+ totalGetters: instanceGetters?.length + staticGetters?.length,
1695
+ totalMethods: instanceNames?.length + staticNames?.length
1696
+ };
1697
+ }
1698
+ /**
1699
+ * * Create a deterministic JSON string representation of any value.
1700
+ * - The output format matches standard JSON but with guaranteed sorted keys.
1701
+ *
1702
+ * @remarks
1703
+ * - This function guarantees **stable, repeatable output** by:
1704
+ * - Sorting all object keys alphabetically.
1705
+ * - Recursively stabilizing nested objects and arrays.
1706
+ * - Converting all `undefined` values into `null` so the output remains valid JSON.
1707
+ * - Converting date-like objects (`Date`, `Chronos`, `Moment.js`, `Day.js`, `Luxon`, `JS-Joda`, `Temporal`) **in the same way that {@link JSON.stringify} would serialize them**, ensuring predictable and JSON-compliant output.
1708
+ * - Falling back to native JSON serialization for primitives.
1709
+ *
1710
+ * - **Useful for:**
1711
+ * - Hash generation (e.g., signatures, cache keys)
1712
+ * - Deep equality checks
1713
+ * - Producing predictable output across environments
1714
+ *
1715
+ * @param obj - The value to stringify into a deterministic JSON string.
1716
+ * @returns A stable, deterministic string representation of the input.
1717
+ */
1718
+ function stableStringify(obj) {
1719
+ const _replacer = (_, v) => v === void 0 ? null : v;
1720
+ if (isNotEmptyObject(obj)) return "{" + Object.keys(obj).sort().map((k) => JSON.stringify(k, _replacer) + ":" + (isDateLike(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k]))).join(",") + "}";
1721
+ if (isValidArray(obj)) return "[" + obj.map((v) => stableStringify(v)).join(",") + "]";
1722
+ return JSON.stringify(obj, _replacer);
1723
+ }
1724
+ /**
1725
+ * * Remove trailing or leading garbage characters **after/before JSON object or array**.
1726
+ * @param str String to sanitize/strip.
1727
+ * @returns Sanitized/stripped JSON string.
1728
+ */
1729
+ function stripJsonEdgeGarbage(str) {
1730
+ if (!isNonEmptyString(str)) return "";
1731
+ const lastIdx = Math.max(str.lastIndexOf("}"), str.lastIndexOf("]"));
1732
+ const _idxOf = (sym) => str.indexOf(sym) !== -1 ? str.indexOf(sym) : Infinity;
1733
+ const firstIdx = Math.min(_idxOf("{"), _idxOf("["));
1734
+ if (lastIdx === -1 || firstIdx === Infinity) return str;
1735
+ return str.slice(firstIdx, lastIdx + 1);
1736
+ }
1737
+ /**
1738
+ * * Parses any valid JSON string, optionally converting stringified primitives inside (nested) arrays or objects.
1739
+ *
1740
+ * @typeParam T - Expected return type (default is unknown).
1741
+ * @param value - The JSON string to parse.
1742
+ * @param parsePrimitives - Whether to convert stringified primitives (default: `true`).
1743
+ * @returns The parsed JSON value typed as `T`, or the original parsed value with optional primitive conversion.
1744
+ * - Returns `{}` if parsing fails, such as when the input is malformed or invalid JSON or passing single quoted string.
1745
+ *
1746
+ * - *Unlike {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/object/parse-json-to-object parseJsonToObject}, which ensures the root value is an object,
1747
+ * this function returns any valid JSON structure such as arrays, strings, numbers, or objects.*
1748
+ *
1749
+ * This is useful when you're not sure of the root structure of the JSON, or when you expect something other than an object.
1750
+ *
1751
+ * @see {@link https://toolbox-x.nazmul-nhb.dev/docs/utils/object/parse-json-to-object parseJsonToObject} for strict object-only parsing.
1752
+ */
1753
+ const parseJSON = (value, parsePrimitives = true) => {
1754
+ try {
1755
+ const parsed = JSON.parse(value);
1756
+ return parsePrimitives ? deepParsePrimitives(parsed) : parsed;
1757
+ } catch {
1758
+ return {};
1759
+ }
1760
+ };
1761
+ /**
1762
+ * * Recursively parses primitive values inside objects and arrays.
1763
+ *
1764
+ * @typeParam T - Expected return type after parsing (default is unknown).
1765
+ * @param input - Any input value to parse recursively.
1766
+ * @returns Input with primitives (strings like "true", "123") converted, typed as `T`.
1767
+ */
1768
+ function deepParsePrimitives(input) {
1769
+ if (Array.isArray(input)) return input?.map(deepParsePrimitives);
1770
+ if (isObject(input)) {
1771
+ const result = {};
1772
+ for (const [key, value] of Object.entries(input)) result[key] = deepParsePrimitives(value);
1773
+ return result;
1774
+ }
1775
+ if (isString(input)) {
1776
+ if (/^(true|false)$/i.test(input)) return input?.toLowerCase() === "true";
1777
+ if (isNumericString(input)) return Number(input);
1778
+ if (input === "null") return null;
1779
+ if (input === "undefined") return;
1780
+ return input;
1781
+ }
1782
+ return input;
1783
+ }
1784
+ /**
1785
+ * * Defines a method on any prototype — including built-in prototypes — in a safe, idempotent manner.
1786
+ * - The method is non-enumerable by default and will not overwrite an existing method unless explicitly allowed.
1787
+ *
1788
+ * @param proto The target prototype object (e.g., String.prototype).
1789
+ * @param name The method name to define on the prototype.
1790
+ * @param impl The function implementation for the method.
1791
+ * @param options Optional property-descriptor settings and overwrite rules.
1792
+ *
1793
+ * @example
1794
+ * // Safely augment prototype methods by extending the global interface:
1795
+ * declare global {
1796
+ * interface String {
1797
+ * toBang(): string;
1798
+ * }
1799
+ * }
1800
+ *
1801
+ * // Define a custom method on String.prototype
1802
+ * definePrototypeMethod(String.prototype, 'toBang', function (this: String) {
1803
+ * return this.toString().concat('!');
1804
+ * // or
1805
+ * // return this.concat('!');
1806
+ * });
1807
+ *
1808
+ * "Hi".toBang(); // "Hi!"
1809
+ *
1810
+ * // Attempting to redefine without overwrite option is ignored
1811
+ * definePrototypeMethod(String.prototype, 'toBang', () => 'x'); // ignored
1812
+ *
1813
+ * // Overwrite intentionally using the overwrite option
1814
+ * definePrototypeMethod(
1815
+ * String.prototype,
1816
+ * 'toBang',
1817
+ * function (this: String) { return this.concat('!!!'); },
1818
+ * { overwrite: true }
1819
+ * );
1820
+ *
1821
+ * "Hi".toBang(); // "Hi!!!"
1822
+ */
1823
+ function definePrototypeMethod(proto, name, impl, options) {
1824
+ if (Object.hasOwn(proto, name) && !options?.overwrite) return;
1825
+ Object.defineProperty(proto, name, {
1826
+ value: function(...args) {
1827
+ return impl.apply(this, args);
1828
+ },
1829
+ enumerable: options?.enumerable ?? false,
1830
+ configurable: options?.configurable ?? false,
1831
+ writable: options?.writable ?? true
1832
+ });
1750
1833
  }
1751
1834
 
1752
1835
  //#endregion
1753
- export { uint8To32ArrayBE as A, getInstanceMethodNames as B, bytesToUtf8 as C, intTo4BytesBE as D, hmacSha256 as E, debounceAction as F, stableStringify as G, getStaticMethodNames as H, deepParsePrimitives as I, naturalSort as J, stripJsonEdgeGarbage as K, definePrototypeMethod as L, convertArrayToString as M, countInstanceMethods as N, randomHex as O, countStaticMethods as P, getClassDetails as R, bytesToHex as S, hexToBytes as T, isDeepEqual as U, getStaticGetterNames as V, parseJSON as W, _getNumericProp as X, sortAnArray as Y, _resolveNestedKey as Z, _constantTimeEquals as _, isUUIDv1 as a, base64ToBytes as b, isUUIDv4 as c, isUUIDv7 as d, isUUIDv8 as f, sha256 as g, sha1 as h, decodeUUID as i, utf8ToBytes as j, sha256Bytes as k, isUUIDv5 as l, md5 as m, trimString as n, isUUIDv2 as o, uuid as p, throttleAction as q, truncateString as r, isUUIDv3 as s, generateRandomID as t, isUUIDv6 as u, _padStartWith0 as v, concatBytes as w, bytesToBase64 as x, _splitByCharLength as y, getInstanceGetterNames as z };
1836
+ export { trimString as $, uuid as A, bytesToUtf8 as B, isUUIDv2 as C, isUUIDv6 as D, isUUIDv5 as E, _padStartWith0 as F, randomAlphaNumeric as G, hexToBytes as H, _splitByCharLength as I, randomNumeric as J, randomBytes as K, base64ToBytes as L, sha1 as M, sha256 as N, isUUIDv7 as O, _constantTimeEquals as P, generateRandomID as Q, bytesToBase64 as R, isUUIDv1 as S, isUUIDv4 as T, hmacSha256 as U, concatBytes as V, intTo4BytesBE as W, uint8To32ArrayBE as X, sha256Bytes as Y, utf8ToBytes as Z, naturalSort as _, deepParsePrimitives as a, _resolveNestedKey as b, getInstanceGetterNames as c, getStaticMethodNames as d, truncateString as et, isDeepEqual as f, throttleAction as g, stripJsonEdgeGarbage as h, debounceAction as i, md5 as j, isUUIDv8 as k, getInstanceMethodNames as l, stableStringify as m, countInstanceMethods as n, definePrototypeMethod as o, parseJSON as p, randomHex as q, countStaticMethods as r, getClassDetails as s, convertArrayToString as t, getStaticGetterNames as u, sortAnArray as v, isUUIDv3 as w, decodeUUID as x, _getNumericProp as y, bytesToHex as z };