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.
- package/CHANGELOG.md +23 -4
- package/dist/{guards-Dc9MB9on.mjs → basics-B7Sqf33u.mjs} +233 -233
- package/dist/{guards-BSwFQX1M.cjs → basics-Cif013VV.cjs} +233 -233
- package/dist/{colors.cjs → colors/index.cjs} +6 -6
- package/dist/{colors.d.mts → colors/index.d.cts} +2 -2
- package/dist/{colors.d.cts → colors/index.d.mts} +2 -2
- package/dist/{colors.mjs → colors/index.mjs} +6 -6
- package/dist/constants.cjs +13 -13
- package/dist/constants.mjs +3 -3
- package/dist/{converter.cjs → converter/index.cjs} +1 -1
- package/dist/{converter.d.cts → converter/index.d.cts} +2 -2
- package/dist/{converter.d.mts → converter/index.d.mts} +2 -2
- package/dist/{converter.mjs → converter/index.mjs} +1 -1
- package/dist/{date.cjs → date/index.cjs} +7 -7
- package/dist/{date.d.cts → date/index.d.cts} +1 -1
- package/dist/{date.d.mts → date/index.d.mts} +1 -1
- package/dist/{date.mjs → date/index.mjs} +7 -7
- package/dist/{dom.cjs → dom/index.cjs} +8 -8
- package/dist/{dom.d.cts → dom/index.d.cts} +3 -3
- package/dist/{dom.d.mts → dom/index.d.mts} +3 -3
- package/dist/{dom.mjs → dom/index.mjs} +5 -5
- package/dist/{guards.cjs → guards/index.cjs} +38 -38
- package/dist/{guards.d.mts → guards/index.d.cts} +4 -4
- package/dist/{guards.d.cts → guards/index.d.mts} +4 -4
- package/dist/{guards.mjs → guards/index.mjs} +6 -6
- package/dist/{guards-CqbVT4L5.cjs → guards-BD2Fkugj.cjs} +2 -2
- package/dist/{guards-DKGBsd6x.mjs → guards-DBunDnng.mjs} +2 -2
- package/dist/{hash.cjs → hash/index.cjs} +69 -66
- package/dist/{hash.d.cts → hash/index.d.cts} +77 -5
- package/dist/{hash.d.mts → hash/index.d.mts} +77 -5
- package/dist/{hash.mjs → hash/index.mjs} +5 -5
- package/dist/{http-status.cjs → http-status/index.cjs} +1 -1
- package/dist/{http-status.d.mts → http-status/index.d.cts} +2 -2
- package/dist/{http-status.d.cts → http-status/index.d.mts} +2 -2
- package/dist/{http-status.mjs → http-status/index.mjs} +1 -1
- package/dist/index.cjs +84 -84
- package/dist/index.mjs +5 -5
- package/dist/{parse-TuFyLeVH.mjs → parse-CILDG7TG.mjs} +3 -3
- package/dist/{parse-jh637S25.cjs → parse-CffWYCuy.cjs} +3 -3
- package/dist/{query-sWSi-d7u.cjs → query-Blm7AiEZ.cjs} +9 -9
- package/dist/{query-BomnyWh3.mjs → query-PGFEup3p.mjs} +2 -2
- package/dist/{stylog.cjs → stylog/index.cjs} +5 -5
- package/dist/{stylog.d.cts → stylog/index.d.cts} +2 -2
- package/dist/{stylog.d.mts → stylog/index.d.mts} +2 -2
- package/dist/{stylog.mjs → stylog/index.mjs} +5 -5
- package/dist/types/pluralizer.d.cts +25 -1
- package/dist/types/pluralizer.d.mts +25 -1
- package/dist/{utilities-BSv8VbnM.mjs → utilities-CmPwOkdy.mjs} +1 -1
- package/dist/{utilities-BVpk3LKy.cjs → utilities-_COSGq1U.cjs} +1 -1
- package/dist/{basics-20lm69yy.mjs → utils-BO5CcsjK.mjs} +631 -548
- package/dist/{basics-byj0VH1c.cjs → utils-DR9g0Sef.cjs} +580 -479
- package/dist/{verbalizer.cjs → verbalizer/index.cjs} +1 -1
- package/dist/{verbalizer.mjs → verbalizer/index.mjs} +1 -1
- package/package.json +22 -25
- package/dist/pluralizer-DXMuPUAK.d.mts +0 -42
- package/dist/pluralizer-DYsDqq9c.d.cts +0 -42
- package/dist/pluralizer.cjs +0 -678
- package/dist/pluralizer.d.cts +0 -152
- package/dist/pluralizer.d.mts +0 -152
- package/dist/pluralizer.mjs +0 -676
- /package/dist/{verbalizer.d.cts → verbalizer/index.d.cts} +0 -0
- /package/dist/{verbalizer.d.mts → verbalizer/index.d.mts} +0 -0
|
@@ -16,458 +16,215 @@
|
|
|
16
16
|
|
|
17
17
|
const require_primitives = require('./primitives-CBGICrDR.cjs');
|
|
18
18
|
const require_specials = require('./specials-DU8u108m.cjs');
|
|
19
|
-
const require_utilities = require('./utilities-
|
|
20
|
-
const require_guards = require('./guards-
|
|
19
|
+
const require_utilities = require('./utilities-_COSGq1U.cjs');
|
|
20
|
+
const require_guards = require('./guards-BD2Fkugj.cjs');
|
|
21
21
|
|
|
22
|
-
//#region src/
|
|
23
|
-
/**
|
|
24
|
-
* Safely resolves value of nested key (dot-notation key like `"user.city"`).
|
|
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`
|
|
29
|
-
*/
|
|
30
|
-
function _resolveNestedKey(obj, path) {
|
|
31
|
-
if (require_specials.isNotEmptyObject(obj)) return path?.split(".").reduce((acc, key) => {
|
|
32
|
-
if (require_specials.isNotEmptyObject(acc)) return acc[key];
|
|
33
|
-
}, obj);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
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
|
-
*
|
|
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 require_utilities.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.
|
|
52
|
-
*
|
|
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.
|
|
57
|
-
*/
|
|
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 && require_primitives.isString(aChunk) && require_primitives.isString(bChunk)) {
|
|
92
|
-
aChunk = aChunk?.toLowerCase();
|
|
93
|
-
bChunk = bChunk?.toLowerCase();
|
|
94
|
-
}
|
|
95
|
-
if (typeof aChunk !== typeof bChunk) return require_primitives.isString(aChunk) ? 1 : -1;
|
|
96
|
-
if (aChunk !== bChunk) {
|
|
97
|
-
if (require_primitives.isNumber(aChunk) && require_primitives.isNumber(bChunk)) return aChunk - bChunk;
|
|
98
|
-
if (require_primitives.isString(aChunk) && require_primitives.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
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return aChunks?.length - bChunks?.length;
|
|
108
|
-
}
|
|
22
|
+
//#region src/string/basics.ts
|
|
109
23
|
/**
|
|
110
|
-
* *
|
|
24
|
+
* * Utility to truncate a string to a specified length.
|
|
111
25
|
*
|
|
112
|
-
* @param
|
|
113
|
-
* @param
|
|
114
|
-
* @returns
|
|
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`).
|
|
115
29
|
*/
|
|
116
|
-
function
|
|
117
|
-
if (!
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
if (
|
|
121
|
-
|
|
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 (require_primitives.isString(keyA) && require_primitives.isString(keyB)) return options?.sortOrder === "desc" ? naturalSort(keyB, keyA) : naturalSort(keyA, keyB);
|
|
129
|
-
if (require_primitives.isNumber(keyA) && require_primitives.isNumber(keyB)) return options?.sortOrder === "desc" ? keyB - keyA : keyA - keyB;
|
|
130
|
-
if (require_primitives.isBoolean(keyA) && require_primitives.isBoolean(keyB)) return options?.sortOrder === "desc" ? Number(keyB) - Number(keyA) : Number(keyA) - Number(keyB);
|
|
131
|
-
return 0;
|
|
132
|
-
});
|
|
133
|
-
return [...array];
|
|
30
|
+
function truncateString(str, maxLength) {
|
|
31
|
+
if (!require_primitives.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("...");
|
|
134
36
|
}
|
|
135
|
-
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/utils/index.ts
|
|
138
|
-
/**
|
|
139
|
-
* * Deeply compare two values (arrays, objects, or primitive values).
|
|
140
|
-
*
|
|
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 (require_specials.isArray(a) && require_specials.isArray(b)) {
|
|
150
|
-
if (a?.length !== b?.length) return false;
|
|
151
|
-
return a?.every((element, index) => isDeepEqual(element, b?.[index]));
|
|
152
|
-
}
|
|
153
|
-
if (require_specials.isObject(a) && require_specials.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
37
|
/**
|
|
162
|
-
* *
|
|
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`.
|
|
163
39
|
*
|
|
164
|
-
* @param
|
|
165
|
-
* @
|
|
166
|
-
* @returns String representation of array values.
|
|
167
|
-
*/
|
|
168
|
-
function convertArrayToString(array, options) {
|
|
169
|
-
if (!require_specials.isValidArray(array)) return "";
|
|
170
|
-
const { separator = ", " } = options ?? {};
|
|
171
|
-
if (require_specials.isArrayOfType(array, require_primitives.isPrimitive)) return array?.join(separator);
|
|
172
|
-
else if (require_specials.isArrayOfType(array, require_specials.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.
|
|
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`.
|
|
178
42
|
*
|
|
179
|
-
* @
|
|
180
|
-
* @
|
|
181
|
-
* @returns A debounced version of the callback function.
|
|
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
|
|
182
45
|
*
|
|
183
46
|
* @example
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
47
|
+
* // Generate an ID with all default options
|
|
48
|
+
* const id = generateRandomID();
|
|
49
|
+
* // Example output: "swo8ckxwsc13w7xw"
|
|
187
50
|
*
|
|
188
|
-
*
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return (...args) => {
|
|
193
|
-
clearTimeout(timeoutId);
|
|
194
|
-
timeoutId = setTimeout(() => {
|
|
195
|
-
callback(...args);
|
|
196
|
-
}, delay);
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* * A generic throttle function that ensures a callback is executed at most once per specified interval.
|
|
51
|
+
* @example
|
|
52
|
+
* // Generate an ID with a custom prefix and separator
|
|
53
|
+
* const id = generateRandomID({ prefix: 'ID', separator: '-' });
|
|
54
|
+
* // Example output: "ID-eh1ymwfxzwas9jte"
|
|
201
55
|
*
|
|
202
|
-
* @
|
|
203
|
-
*
|
|
204
|
-
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Generate an ID with a timestamp
|
|
58
|
+
* const id = generateRandomID({ timeStamp: false });
|
|
59
|
+
* // Example output: "1764610287501pd3r4w85qwkuulgf"
|
|
205
60
|
*
|
|
206
61
|
* @example
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
62
|
+
* // Generate an ID with a custom length for the random string
|
|
63
|
+
* const id = generateRandomID({ length: 8 });
|
|
64
|
+
* // Example output: "i623uiev"
|
|
210
65
|
*
|
|
211
|
-
*
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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.
|
|
66
|
+
* @example
|
|
67
|
+
* // Generate an ID with a custom suffix
|
|
68
|
+
* const id = generateRandomID({ suffix: 'END' });
|
|
69
|
+
* // Example output: "3csf27a4800rbli9END"
|
|
225
70
|
*
|
|
226
|
-
* @
|
|
227
|
-
*
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const prototype = cls.prototype;
|
|
231
|
-
return sortAnArray(Object.getOwnPropertyNames(prototype).filter((method) => {
|
|
232
|
-
if (method === "constructor") return false;
|
|
233
|
-
return require_specials.isMethodDescriptor(Object.getOwnPropertyDescriptor(prototype, method));
|
|
234
|
-
}));
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* * Retrieves the names of all static methods defined directly on a class constructor.
|
|
71
|
+
* @example
|
|
72
|
+
* // Generate an ID with a uppercase random string
|
|
73
|
+
* const id = generateRandomID({ caseOption: "upper" });
|
|
74
|
+
* // Example output: "H0VNU6O8XV1Y30HG"
|
|
238
75
|
*
|
|
239
|
-
* @
|
|
240
|
-
*
|
|
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"
|
|
241
87
|
*/
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}));
|
|
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;
|
|
102
|
+
}
|
|
246
103
|
}
|
|
247
104
|
/**
|
|
248
|
-
* *
|
|
105
|
+
* * Trims all whitespaces in a string or an array of strings.
|
|
249
106
|
*
|
|
250
|
-
* @param
|
|
251
|
-
* @returns
|
|
107
|
+
* @param input String or array of strings.
|
|
108
|
+
* @returns Trimmed string or array of strings.
|
|
252
109
|
*/
|
|
253
|
-
function
|
|
254
|
-
|
|
110
|
+
function trimString(input) {
|
|
111
|
+
if (!input) return "";
|
|
112
|
+
if (require_primitives.isNonEmptyString(input)) return input.trim().replace(/\s+/g, " ");
|
|
113
|
+
if (Array.isArray(input)) return input.map((str) => require_primitives.isNonEmptyString(str) ? str.trim().replace(/\s+/g, " ") : str);
|
|
114
|
+
throw new TypeError("Expected string or array of strings!", { cause: "Invalid Input Type" });
|
|
255
115
|
}
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/hash/utils.ts
|
|
256
119
|
/**
|
|
257
|
-
* *
|
|
120
|
+
* * Generates random bytes in the {@link Uint8Array} format.
|
|
258
121
|
*
|
|
259
|
-
* @param
|
|
260
|
-
* @returns
|
|
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.
|
|
122
|
+
* @param size - The length of the byte array to generate. Defaults to `8`.
|
|
123
|
+
* @returns A random array of bytes.
|
|
267
124
|
*
|
|
268
|
-
* @
|
|
269
|
-
*
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
const descriptors = Object.getOwnPropertyDescriptors(cls.prototype);
|
|
273
|
-
return sortAnArray(Object.entries(descriptors).filter(([key, desc]) => require_specials.isFunction(desc.get) && key !== "constructor").map(([key]) => key));
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* * Retrieves the names of all static getters defined directly on a class constructor.
|
|
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]
|
|
277
129
|
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
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.
|
|
130
|
+
* // Empty array
|
|
131
|
+
* const empty = randomBytes(0);
|
|
132
|
+
* // Returns: Uint8Array(0) []
|
|
286
133
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
|
|
290
|
-
|
|
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.
|
|
134
|
+
* // Zero or negative values are treated as 0
|
|
135
|
+
* const zero = randomBytes(-5);
|
|
136
|
+
* // Returns: Uint8Array(0) []
|
|
137
|
+
* ```
|
|
309
138
|
*
|
|
310
139
|
* @remarks
|
|
311
|
-
* -
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* - **Useful for:**
|
|
319
|
-
* - Hash generation (e.g., signatures, cache keys)
|
|
320
|
-
* - Deep equality checks
|
|
321
|
-
* - Producing predictable output across environments
|
|
322
|
-
*
|
|
323
|
-
* @param obj - The value to stringify into a deterministic JSON string.
|
|
324
|
-
* @returns A stable, deterministic string representation of the input.
|
|
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.
|
|
325
146
|
*/
|
|
326
|
-
function
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (require_specials.isValidArray(obj)) return "[" + obj.map((v) => stableStringify(v)).join(",") + "]";
|
|
330
|
-
return JSON.stringify(obj, _replacer);
|
|
147
|
+
function randomBytes(size = 8) {
|
|
148
|
+
if (size <= 0) return new Uint8Array(0);
|
|
149
|
+
return _fillWithRandomValues(new Uint8Array(size));
|
|
331
150
|
}
|
|
332
151
|
/**
|
|
333
|
-
* *
|
|
334
|
-
* @param str String to sanitize/strip.
|
|
335
|
-
* @returns Sanitized/stripped JSON string.
|
|
336
|
-
*/
|
|
337
|
-
function stripJsonEdgeGarbage(str) {
|
|
338
|
-
if (!require_primitives.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);
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* * Parses any valid JSON string, optionally converting stringified primitives inside (nested) arrays or objects.
|
|
152
|
+
* * Generates a random hexadecimal string of the specified length.
|
|
347
153
|
*
|
|
348
|
-
* @
|
|
349
|
-
* @param
|
|
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.
|
|
154
|
+
* @param length - Number of hex characters to generate.
|
|
155
|
+
* @param uppercase - Whether to return uppercase `A–F` characters. Defaults to `false` (lowercase).
|
|
353
156
|
*
|
|
354
|
-
*
|
|
355
|
-
* this function returns any valid JSON structure such as arrays, strings, numbers, or objects.*
|
|
157
|
+
* @returns A randomly generated hexadecimal string.
|
|
356
158
|
*
|
|
357
|
-
*
|
|
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.
|
|
358
164
|
*
|
|
359
|
-
* @
|
|
360
|
-
|
|
361
|
-
const
|
|
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.
|
|
165
|
+
* @example
|
|
166
|
+
* // 16-character lowercase hex
|
|
167
|
+
* const id = randomHex(16);
|
|
371
168
|
*
|
|
372
|
-
* @
|
|
373
|
-
*
|
|
374
|
-
*
|
|
169
|
+
* @example
|
|
170
|
+
* // 8-character uppercase hex
|
|
171
|
+
* const token = randomHex(8, true);
|
|
375
172
|
*/
|
|
376
|
-
function
|
|
377
|
-
if (
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
for (const [key, value] of Object.entries(input)) result[key] = deepParsePrimitives(value);
|
|
381
|
-
return result;
|
|
382
|
-
}
|
|
383
|
-
if (require_primitives.isString(input)) {
|
|
384
|
-
if (/^(true|false)$/i.test(input)) return input?.toLowerCase() === "true";
|
|
385
|
-
if (require_specials.isNumericString(input)) return Number(input);
|
|
386
|
-
if (input === "null") return null;
|
|
387
|
-
if (input === "undefined") return;
|
|
388
|
-
return input;
|
|
389
|
-
}
|
|
390
|
-
return input;
|
|
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;
|
|
391
177
|
}
|
|
392
178
|
/**
|
|
393
|
-
* *
|
|
394
|
-
* - The method is non-enumerable by default and will not overwrite an existing method unless explicitly allowed.
|
|
179
|
+
* * Generates a random numeric string of the specified length.
|
|
395
180
|
*
|
|
396
|
-
* @param
|
|
397
|
-
* @
|
|
398
|
-
* @param impl The function implementation for the method.
|
|
399
|
-
* @param options Optional property-descriptor settings and overwrite rules.
|
|
181
|
+
* @param length - Length of the numeric string. Defaults to `6`.
|
|
182
|
+
* @returns A randomly generated numeric string.
|
|
400
183
|
*
|
|
401
184
|
* @example
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
* }
|
|
407
|
-
* }
|
|
408
|
-
*
|
|
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
|
-
* );
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const otp = randomNumeric(6);
|
|
187
|
+
* // Returns something like: '123456'
|
|
188
|
+
* ```
|
|
428
189
|
*
|
|
429
|
-
*
|
|
190
|
+
* @remarks
|
|
191
|
+
* - If `length` is `0` or negative, an empty string is returned.
|
|
430
192
|
*/
|
|
431
|
-
function
|
|
432
|
-
|
|
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
|
-
});
|
|
193
|
+
function randomNumeric(length = 6) {
|
|
194
|
+
return randomBytes(length).map((byte) => byte & 10).join("");
|
|
441
195
|
}
|
|
442
|
-
|
|
443
|
-
//#endregion
|
|
444
|
-
//#region src/hash/utils.ts
|
|
445
196
|
/**
|
|
446
|
-
* * Generates a random
|
|
197
|
+
* * Generates a random alphanumeric string (letters and numbers) of the specified length.
|
|
447
198
|
*
|
|
448
|
-
* @param length -
|
|
449
|
-
* @param uppercase -
|
|
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).
|
|
450
201
|
*
|
|
451
|
-
* @returns A
|
|
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.
|
|
202
|
+
* @returns A random string composed of alphanumeric characters.
|
|
458
203
|
*
|
|
459
204
|
* @example
|
|
460
|
-
*
|
|
461
|
-
*
|
|
205
|
+
* ```typescript
|
|
206
|
+
* // Generate a random 8-character alphanumeric string (default: lowercase)
|
|
207
|
+
* const randomStr = randomAlphaNumeric(8);
|
|
208
|
+
* // Example output: "a7b2f9d1"
|
|
462
209
|
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
210
|
+
* // Generate a 12-character uppercase alphanumeric string
|
|
211
|
+
* const randomUpper = randomAlphaNumeric(12, true);
|
|
212
|
+
* // Example output: "X5K9P2M7H4L3"
|
|
213
|
+
*
|
|
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.
|
|
466
221
|
*/
|
|
467
|
-
function
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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;
|
|
471
228
|
}
|
|
472
229
|
/**
|
|
473
230
|
* * Converts a UTF-8 string to a byte array (`Uint8Array`).
|
|
@@ -1644,109 +1401,435 @@ function isUUIDv5(value) {
|
|
|
1644
1401
|
function isUUIDv6(value) {
|
|
1645
1402
|
return _checkUUIDVersion(value, "6");
|
|
1646
1403
|
}
|
|
1647
|
-
/** Check if a value is UUID version 7 */
|
|
1648
|
-
function isUUIDv7(value) {
|
|
1649
|
-
return _checkUUIDVersion(value, "7");
|
|
1404
|
+
/** Check if a value is UUID version 7 */
|
|
1405
|
+
function isUUIDv7(value) {
|
|
1406
|
+
return _checkUUIDVersion(value, "7");
|
|
1407
|
+
}
|
|
1408
|
+
/** Check if a value is UUID version 8 */
|
|
1409
|
+
function isUUIDv8(value) {
|
|
1410
|
+
return _checkUUIDVersion(value, "8");
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
//#endregion
|
|
1414
|
+
//#region src/array/helpers.ts
|
|
1415
|
+
/**
|
|
1416
|
+
* Safely resolves value of nested key (dot-notation key like `"user.city"`).
|
|
1417
|
+
*
|
|
1418
|
+
* @param obj - The source object
|
|
1419
|
+
* @param path - The nested path string (e.g. `"user.city"`)
|
|
1420
|
+
* @returns The resolved value or `undefined`
|
|
1421
|
+
*/
|
|
1422
|
+
function _resolveNestedKey(obj, path) {
|
|
1423
|
+
if (require_specials.isNotEmptyObject(obj)) return path?.split(".").reduce((acc, key) => {
|
|
1424
|
+
if (require_specials.isNotEmptyObject(acc)) return acc[key];
|
|
1425
|
+
}, obj);
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
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.
|
|
1430
|
+
*
|
|
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.
|
|
1434
|
+
*/
|
|
1435
|
+
function _getNumericProp(obj, path) {
|
|
1436
|
+
return require_utilities.normalizeNumber(_resolveNestedKey(obj, path)) ?? 0;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
//#endregion
|
|
1440
|
+
//#region src/array/sort.ts
|
|
1441
|
+
/**
|
|
1442
|
+
* Compare two strings using natural sorting (e.g., `"file2"` < `"file10"`).
|
|
1443
|
+
* - Optionally supports case-insensitive and locale-aware string chunk comparisons.
|
|
1444
|
+
*
|
|
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.
|
|
1449
|
+
*/
|
|
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 && require_primitives.isString(aChunk) && require_primitives.isString(bChunk)) {
|
|
1484
|
+
aChunk = aChunk?.toLowerCase();
|
|
1485
|
+
bChunk = bChunk?.toLowerCase();
|
|
1486
|
+
}
|
|
1487
|
+
if (typeof aChunk !== typeof bChunk) return require_primitives.isString(aChunk) ? 1 : -1;
|
|
1488
|
+
if (aChunk !== bChunk) {
|
|
1489
|
+
if (require_primitives.isNumber(aChunk) && require_primitives.isNumber(bChunk)) return aChunk - bChunk;
|
|
1490
|
+
if (require_primitives.isString(aChunk) && require_primitives.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 (!require_specials.isValidArray(array)) return array;
|
|
1510
|
+
if (require_specials.isArrayOfType(array, require_primitives.isString)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? naturalSort(b, a) : naturalSort(a, b));
|
|
1511
|
+
if (require_specials.isArrayOfType(array, require_primitives.isNumber)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? b - a : a - b);
|
|
1512
|
+
if (require_specials.isArrayOfType(array, require_primitives.isBoolean)) return [...array].sort((a, b) => options?.sortOrder === "desc" ? Number(b) - Number(a) : Number(a) - Number(b));
|
|
1513
|
+
if (require_specials.isArrayOfType(array, require_specials.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 (require_primitives.isString(keyA) && require_primitives.isString(keyB)) return options?.sortOrder === "desc" ? naturalSort(keyB, keyA) : naturalSort(keyA, keyB);
|
|
1521
|
+
if (require_primitives.isNumber(keyA) && require_primitives.isNumber(keyB)) return options?.sortOrder === "desc" ? keyB - keyA : keyA - keyB;
|
|
1522
|
+
if (require_primitives.isBoolean(keyA) && require_primitives.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 (require_specials.isArray(a) && require_specials.isArray(b)) {
|
|
1542
|
+
if (a?.length !== b?.length) return false;
|
|
1543
|
+
return a?.every((element, index) => isDeepEqual(element, b?.[index]));
|
|
1544
|
+
}
|
|
1545
|
+
if (require_specials.isObject(a) && require_specials.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 (!require_specials.isValidArray(array)) return "";
|
|
1562
|
+
const { separator = ", " } = options ?? {};
|
|
1563
|
+
if (require_specials.isArrayOfType(array, require_primitives.isPrimitive)) return array?.join(separator);
|
|
1564
|
+
else if (require_specials.isArrayOfType(array, require_specials.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 require_specials.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;
|
|
1650
1656
|
}
|
|
1651
|
-
/**
|
|
1652
|
-
|
|
1653
|
-
|
|
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]) => require_specials.isFunction(desc.get) && key !== "constructor").map(([key]) => key));
|
|
1654
1666
|
}
|
|
1655
|
-
|
|
1656
|
-
//#endregion
|
|
1657
|
-
//#region src/string/basics.ts
|
|
1658
1667
|
/**
|
|
1659
|
-
* *
|
|
1668
|
+
* * Retrieves the names of all static getters defined directly on a class constructor.
|
|
1660
1669
|
*
|
|
1661
|
-
* @param
|
|
1662
|
-
* @
|
|
1663
|
-
* @returns Truncated string with ellipsis (`...`) (only if it has more length than `maxLength`).
|
|
1670
|
+
* @param cls - The class constructor (not an instance).
|
|
1671
|
+
* @returns A sorted array of static getter names.
|
|
1664
1672
|
*/
|
|
1665
|
-
function
|
|
1666
|
-
|
|
1667
|
-
const trimmedString = str.trim();
|
|
1668
|
-
if (!trimmedString) return "";
|
|
1669
|
-
if (trimmedString.length <= maxLength) return trimmedString;
|
|
1670
|
-
return trimmedString.slice(0, maxLength).concat("...");
|
|
1673
|
+
function getStaticGetterNames(cls) {
|
|
1674
|
+
return sortAnArray(Object.entries(Object.getOwnPropertyDescriptors(cls)).filter(([key, desc]) => typeof desc.get === "function" && key !== "prototype").map(([key]) => key));
|
|
1671
1675
|
}
|
|
1672
1676
|
/**
|
|
1673
|
-
* *
|
|
1677
|
+
* * Gathers detailed information about the instance and static methods of a class.
|
|
1674
1678
|
*
|
|
1675
|
-
* @param
|
|
1676
|
-
* @returns
|
|
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.
|
|
1677
1701
|
*
|
|
1678
|
-
* @
|
|
1679
|
-
*
|
|
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.
|
|
1680
1709
|
*
|
|
1681
|
-
*
|
|
1682
|
-
*
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1710
|
+
* - **Useful for:**
|
|
1711
|
+
* - Hash generation (e.g., signatures, cache keys)
|
|
1712
|
+
* - Deep equality checks
|
|
1713
|
+
* - Producing predictable output across environments
|
|
1685
1714
|
*
|
|
1686
|
-
* @
|
|
1687
|
-
*
|
|
1688
|
-
|
|
1689
|
-
|
|
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 (require_specials.isNotEmptyObject(obj)) return "{" + Object.keys(obj).sort().map((k) => JSON.stringify(k, _replacer) + ":" + (require_guards.isDateLike(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k]))).join(",") + "}";
|
|
1721
|
+
if (require_specials.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 (!require_primitives.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.
|
|
1690
1739
|
*
|
|
1691
|
-
* @
|
|
1692
|
-
*
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
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.
|
|
1695
1745
|
*
|
|
1696
|
-
* @
|
|
1697
|
-
*
|
|
1698
|
-
* const id = generateRandomID({ length: 8 });
|
|
1699
|
-
* // Example output: "i623uiev"
|
|
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.*
|
|
1700
1748
|
*
|
|
1701
|
-
*
|
|
1702
|
-
* // Generate an ID with a custom suffix
|
|
1703
|
-
* const id = generateRandomID({ suffix: 'END' });
|
|
1704
|
-
* // Example output: "3csf27a4800rbli9END"
|
|
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.
|
|
1705
1750
|
*
|
|
1706
|
-
* @
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
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.
|
|
1710
1763
|
*
|
|
1711
|
-
* @
|
|
1712
|
-
*
|
|
1713
|
-
*
|
|
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"
|
|
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`.
|
|
1722
1767
|
*/
|
|
1723
|
-
function
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
default: return ID;
|
|
1768
|
+
function deepParsePrimitives(input) {
|
|
1769
|
+
if (Array.isArray(input)) return input?.map(deepParsePrimitives);
|
|
1770
|
+
if (require_specials.isObject(input)) {
|
|
1771
|
+
const result = {};
|
|
1772
|
+
for (const [key, value] of Object.entries(input)) result[key] = deepParsePrimitives(value);
|
|
1773
|
+
return result;
|
|
1774
|
+
}
|
|
1775
|
+
if (require_primitives.isString(input)) {
|
|
1776
|
+
if (/^(true|false)$/i.test(input)) return input?.toLowerCase() === "true";
|
|
1777
|
+
if (require_specials.isNumericString(input)) return Number(input);
|
|
1778
|
+
if (input === "null") return null;
|
|
1779
|
+
if (input === "undefined") return;
|
|
1780
|
+
return input;
|
|
1737
1781
|
}
|
|
1782
|
+
return input;
|
|
1738
1783
|
}
|
|
1739
1784
|
/**
|
|
1740
|
-
* *
|
|
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.
|
|
1741
1787
|
*
|
|
1742
|
-
* @param
|
|
1743
|
-
* @
|
|
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!!!"
|
|
1744
1822
|
*/
|
|
1745
|
-
function
|
|
1746
|
-
if (!
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
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
|
|
@@ -1978,12 +2061,30 @@ Object.defineProperty(exports, 'parseJSON', {
|
|
|
1978
2061
|
return parseJSON;
|
|
1979
2062
|
}
|
|
1980
2063
|
});
|
|
2064
|
+
Object.defineProperty(exports, 'randomAlphaNumeric', {
|
|
2065
|
+
enumerable: true,
|
|
2066
|
+
get: function () {
|
|
2067
|
+
return randomAlphaNumeric;
|
|
2068
|
+
}
|
|
2069
|
+
});
|
|
2070
|
+
Object.defineProperty(exports, 'randomBytes', {
|
|
2071
|
+
enumerable: true,
|
|
2072
|
+
get: function () {
|
|
2073
|
+
return randomBytes;
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
1981
2076
|
Object.defineProperty(exports, 'randomHex', {
|
|
1982
2077
|
enumerable: true,
|
|
1983
2078
|
get: function () {
|
|
1984
2079
|
return randomHex;
|
|
1985
2080
|
}
|
|
1986
2081
|
});
|
|
2082
|
+
Object.defineProperty(exports, 'randomNumeric', {
|
|
2083
|
+
enumerable: true,
|
|
2084
|
+
get: function () {
|
|
2085
|
+
return randomNumeric;
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
1987
2088
|
Object.defineProperty(exports, 'sha1', {
|
|
1988
2089
|
enumerable: true,
|
|
1989
2090
|
get: function () {
|