toolbox-x 2.2.5 → 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 +10 -0
- 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 +19 -23
- 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,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-
|
|
20
|
-
import { t as isDateLike } from "./guards-
|
|
19
|
+
import { a as normalizeNumber } from "./utilities-CmPwOkdy.mjs";
|
|
20
|
+
import { t as isDateLike } from "./guards-DBunDnng.mjs";
|
|
21
21
|
|
|
22
|
-
//#region src/
|
|
22
|
+
//#region src/string/basics.ts
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* * Utility to truncate a string to a specified length.
|
|
25
25
|
*
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @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`).
|
|
29
29
|
*/
|
|
30
|
-
function
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
*
|
|
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
|
|
40
|
-
* @
|
|
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
|
-
* @
|
|
54
|
-
* @
|
|
55
|
-
*
|
|
56
|
-
* @
|
|
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
|
|
59
|
-
const {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
* *
|
|
105
|
+
* * Trims all whitespaces in a string or an array of strings.
|
|
111
106
|
*
|
|
112
|
-
* @param
|
|
113
|
-
* @
|
|
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
|
|
117
|
-
if (!
|
|
118
|
-
if (
|
|
119
|
-
if (
|
|
120
|
-
|
|
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
|
|
118
|
+
//#region src/hash/utils.ts
|
|
138
119
|
/**
|
|
139
|
-
* *
|
|
120
|
+
* * Generates random bytes in the {@link Uint8Array} format.
|
|
140
121
|
*
|
|
141
|
-
* @param
|
|
142
|
-
* @
|
|
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
|
-
* @
|
|
165
|
-
*
|
|
166
|
-
*
|
|
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
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
130
|
+
* // Empty array
|
|
131
|
+
* const empty = randomBytes(0);
|
|
132
|
+
* // Returns: Uint8Array(0) []
|
|
182
133
|
*
|
|
183
|
-
*
|
|
184
|
-
* const
|
|
185
|
-
*
|
|
186
|
-
*
|
|
134
|
+
* // Zero or negative values are treated as 0
|
|
135
|
+
* const zero = randomBytes(-5);
|
|
136
|
+
* // Returns: Uint8Array(0) []
|
|
137
|
+
* ```
|
|
187
138
|
*
|
|
188
|
-
*
|
|
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
|
|
191
|
-
|
|
192
|
-
return (
|
|
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
|
-
* *
|
|
152
|
+
* * Generates a random hexadecimal string of the specified length.
|
|
201
153
|
*
|
|
202
|
-
* @param
|
|
203
|
-
* @param
|
|
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
|
-
* @
|
|
207
|
-
* const throttledResize = throttleAction(() => {
|
|
208
|
-
* console.log('Resized');
|
|
209
|
-
* }, 300);
|
|
157
|
+
* @returns A randomly generated hexadecimal string.
|
|
210
158
|
*
|
|
211
|
-
*
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
* @
|
|
227
|
-
*
|
|
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
|
-
* @
|
|
240
|
-
*
|
|
169
|
+
* @example
|
|
170
|
+
* // 8-character uppercase hex
|
|
171
|
+
* const token = randomHex(8, true);
|
|
241
172
|
*/
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
* *
|
|
179
|
+
* * Generates a random numeric string of the specified length.
|
|
249
180
|
*
|
|
250
|
-
* @param
|
|
251
|
-
* @returns
|
|
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
|
-
* @
|
|
260
|
-
*
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
* @
|
|
269
|
-
*
|
|
190
|
+
* @remarks
|
|
191
|
+
* - If `length` is `0` or negative, an empty string is returned.
|
|
270
192
|
*/
|
|
271
|
-
function
|
|
272
|
-
|
|
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
|
-
* *
|
|
197
|
+
* * Generates a random alphanumeric string (letters and numbers) of the specified length.
|
|
277
198
|
*
|
|
278
|
-
* @param
|
|
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.
|
|
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
|
-
* @
|
|
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
|
-
* @
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
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
|
-
* -
|
|
319
|
-
*
|
|
320
|
-
*
|
|
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
|
-
*
|
|
324
|
-
*
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
const
|
|
342
|
-
|
|
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
|
-
* *
|
|
230
|
+
* * Converts a UTF-8 string to a byte array (`Uint8Array`).
|
|
347
231
|
*
|
|
348
|
-
*
|
|
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
|
-
*
|
|
355
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
* @
|
|
373
|
-
*
|
|
374
|
-
*
|
|
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
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
|
282
|
+
return new Uint8Array(out);
|
|
391
283
|
}
|
|
392
284
|
/**
|
|
393
|
-
* *
|
|
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
|
-
*
|
|
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
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
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
|
-
* //
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
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/
|
|
1414
|
+
//#region src/array/helpers.ts
|
|
1658
1415
|
/**
|
|
1659
|
-
*
|
|
1416
|
+
* Safely resolves value of nested key (dot-notation key like `"user.city"`).
|
|
1660
1417
|
*
|
|
1661
|
-
* @param
|
|
1662
|
-
* @param
|
|
1663
|
-
* @returns
|
|
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
|
|
1666
|
-
if (
|
|
1667
|
-
|
|
1668
|
-
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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"
|
|
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
|
|
1724
|
-
|
|
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
|
-
*
|
|
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
|
|
1743
|
-
* @
|
|
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
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
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 {
|
|
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 };
|