@salespark/toolkit 2.0.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/dist/index.js ADDED
@@ -0,0 +1,451 @@
1
+ // src/utils/array.ts
2
+ function uniqBy(arr, key) {
3
+ const seen = /* @__PURE__ */ new Set();
4
+ const out = [];
5
+ for (const item of arr) {
6
+ const k = key(item);
7
+ if (!seen.has(k)) {
8
+ seen.add(k);
9
+ out.push(item);
10
+ }
11
+ }
12
+ return out;
13
+ }
14
+ function chunk(arr, size) {
15
+ if (size <= 0) return [arr.slice()];
16
+ const res = [];
17
+ for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size));
18
+ return res;
19
+ }
20
+ function areArraysEqual(arr1, arr2) {
21
+ try {
22
+ if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;
23
+ if (arr1.length !== arr2.length) return false;
24
+ const normalize = (value) => {
25
+ if (Array.isArray(value)) {
26
+ return value.map(normalize);
27
+ }
28
+ if (value && typeof value === "object") {
29
+ const entries = Object.entries(value).map(([k, v]) => [k, normalize(v)]).sort(([k1], [k2]) => k1 < k2 ? -1 : k1 > k2 ? 1 : 0);
30
+ return Object.fromEntries(entries);
31
+ }
32
+ return value;
33
+ };
34
+ const a = arr1.map((el) => JSON.stringify(normalize(el))).sort();
35
+ const b = arr2.map((el) => JSON.stringify(normalize(el))).sort();
36
+ for (let i = 0; i < a.length; i++) {
37
+ if (a[i] !== b[i]) return false;
38
+ }
39
+ return true;
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+ var areArraysDeepEqualUnordered = areArraysEqual;
45
+ function uniq(arr) {
46
+ return Array.from(new Set(arr));
47
+ }
48
+ function flatten(arr) {
49
+ return arr.flat ? arr.flat() : [].concat(...arr);
50
+ }
51
+ function groupBy(arr, key) {
52
+ return arr.reduce((acc, item) => {
53
+ const group = typeof key === "function" ? key(item) : item[key];
54
+ (acc[group] = acc[group] || []).push(item);
55
+ return acc;
56
+ }, {});
57
+ }
58
+ function sortBy(arr, key) {
59
+ return [...arr].sort((a, b) => {
60
+ const aKey = typeof key === "function" ? key(a) : a[key];
61
+ const bKey = typeof key === "function" ? key(b) : b[key];
62
+ if (aKey < bKey) return -1;
63
+ if (aKey > bKey) return 1;
64
+ return 0;
65
+ });
66
+ }
67
+ function difference(arr1, arr2) {
68
+ const set2 = new Set(arr2);
69
+ return arr1.filter((x) => !set2.has(x));
70
+ }
71
+ function intersection(arr1, arr2) {
72
+ const set2 = new Set(arr2);
73
+ return arr1.filter((x) => set2.has(x));
74
+ }
75
+ function compact(arr) {
76
+ return arr.filter(Boolean);
77
+ }
78
+ function pluck(arr, key) {
79
+ return arr.map((item) => item[key]);
80
+ }
81
+ function shuffle(arr) {
82
+ const a = [...arr];
83
+ for (let i = a.length - 1; i > 0; i--) {
84
+ const j = Math.floor(Math.random() * (i + 1));
85
+ [a[i], a[j]] = [a[j], a[i]];
86
+ }
87
+ return a;
88
+ }
89
+ function isFlattenable(value) {
90
+ if (Array.isArray(value)) return true;
91
+ const isArgs = Object.prototype.toString.call(value) === "[object Arguments]";
92
+ if (isArgs) return true;
93
+ const spreadable = Symbol.isConcatSpreadable;
94
+ return spreadable ? !!value?.[spreadable] : false;
95
+ }
96
+ function pushAll(array, values) {
97
+ let index = -1;
98
+ const length = values.length;
99
+ const offset = array.length;
100
+ while (++index < length) {
101
+ array[offset + index] = values[index];
102
+ }
103
+ return array;
104
+ }
105
+ function flattenDepthBase(array, depth, predicate = isFlattenable, isStrict = false, result = []) {
106
+ let index = -1;
107
+ const length = array.length;
108
+ while (++index < length) {
109
+ const value = array[index];
110
+ if (depth > 0 && predicate(value)) {
111
+ if (depth > 1) {
112
+ flattenDepthBase(
113
+ value,
114
+ depth - 1,
115
+ predicate,
116
+ isStrict,
117
+ result
118
+ );
119
+ } else {
120
+ pushAll(result, value);
121
+ }
122
+ } else if (!isStrict) {
123
+ result[result.length] = value;
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ function flattenOnce(array) {
129
+ return flattenDepthBase(array, 1);
130
+ }
131
+ function flattenDepth(array, depth = 1, options) {
132
+ const { predicate = isFlattenable, isStrict = false } = options ?? {};
133
+ return flattenDepthBase(array, depth, predicate, isStrict);
134
+ }
135
+
136
+ // src/utils/object.ts
137
+ function pick(obj, keys) {
138
+ const out = {};
139
+ for (const k of keys) if (k in obj) out[k] = obj[k];
140
+ return out;
141
+ }
142
+ function omit(obj, keys) {
143
+ const set = new Set(keys);
144
+ const out = {};
145
+ for (const k in obj) if (!set.has(k)) out[k] = obj[k];
146
+ return out;
147
+ }
148
+ function objectToString(obj) {
149
+ try {
150
+ if (obj === null || obj === void 0) return "";
151
+ if (typeof obj !== "object") return String(obj);
152
+ return JSON.stringify(obj).replace(/[{}"]/g, "").replace(/:/g, "=").replace(/,/g, "_");
153
+ } catch {
154
+ try {
155
+ return String(obj);
156
+ } catch {
157
+ return "";
158
+ }
159
+ }
160
+ }
161
+ var isRemovable = (v) => v === null || v === void 0 || v === "null" || v === "undefined";
162
+ function cleanObject(obj) {
163
+ if (Array.isArray(obj)) {
164
+ const cleanedArray = obj.map((item) => cleanObject(item)).filter((item) => !isRemovable(item));
165
+ return cleanedArray;
166
+ }
167
+ if (obj !== null && typeof obj === "object") {
168
+ const cleaned = {};
169
+ for (const [key, value] of Object.entries(obj)) {
170
+ if (isRemovable(value)) continue;
171
+ const nested = cleanObject(value);
172
+ if (isRemovable(nested)) continue;
173
+ const isObj = typeof nested === "object" && nested !== null;
174
+ const isEmptyObj = isObj && !Array.isArray(nested) && Object.keys(nested).length === 0;
175
+ const isEmptyArr = Array.isArray(nested) && nested.length === 0;
176
+ if (isEmptyObj || isEmptyArr) continue;
177
+ cleaned[key] = nested;
178
+ }
179
+ return cleaned;
180
+ }
181
+ return obj;
182
+ }
183
+
184
+ // src/utils/string.ts
185
+ function slugify(input) {
186
+ return input.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
187
+ }
188
+ function fill(template, values) {
189
+ return template.replace(/\{(\w+)\}/g, (_, k) => String(values[k] ?? ""));
190
+ }
191
+ function deburr(str) {
192
+ try {
193
+ return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
194
+ } catch {
195
+ return str;
196
+ }
197
+ }
198
+ var removeDiacritics = deburr;
199
+ function sanitize(input, maxLength) {
200
+ if (typeof input !== "string") return "";
201
+ let cleaned = input.replace(/[\u0000-\u001F\u007F-\u009F]/g, "");
202
+ cleaned = cleaned.replace(/<(script|style|iframe)[^>]*>.*?<\/\1>/gis, "");
203
+ cleaned = cleaned.replace(/on\w+\s*=\s*(['"]).*?\1/gi, "");
204
+ cleaned = cleaned.replace(/expression\s*\([^)]*\)/gi, "");
205
+ cleaned = cleaned.replace(
206
+ /&#x3C;script&#x3E;[\s\S]*?&#x3C;\/script&#x3E;/gi,
207
+ ""
208
+ );
209
+ cleaned = cleaned.replace(/&#x3C;.*?&#x3E;/gi, "");
210
+ cleaned = cleaned.replace(/<[^>]+>/g, "");
211
+ cleaned = cleaned.replace(/\b(javascript:|data:|vbscript:|file:|ftp:)/gi, "");
212
+ cleaned = cleaned.replace(/[^\p{L}\p{N}\s\-.,!?@#%&()]/gu, "");
213
+ if (typeof maxLength === "number" && maxLength > 0) {
214
+ cleaned = cleaned.substring(0, maxLength);
215
+ }
216
+ cleaned = cleaned.trim();
217
+ return cleaned;
218
+ }
219
+ var basicSanitize = sanitize;
220
+
221
+ // src/utils/number.ts
222
+ var clamp = (n, min, max) => Math.min(Math.max(n, min), max);
223
+ function round(n, decimals = 0) {
224
+ const f = Math.pow(10, decimals);
225
+ return Math.round((n + Number.EPSILON) * f) / f;
226
+ }
227
+ function toInteger(value, defaultValue = 0) {
228
+ try {
229
+ const safeValue = parseInt(String(value), 10);
230
+ return isNaN(safeValue) ? defaultValue : safeValue;
231
+ } catch {
232
+ return defaultValue;
233
+ }
234
+ }
235
+ var safeParseInt = toInteger;
236
+ function toNumber(value, decimals = 6) {
237
+ try {
238
+ if (value === void 0 || value === null || value === "") return 0;
239
+ let str = String(value);
240
+ if (str.includes(",") && str.includes(".")) {
241
+ str = str.replace(/,/g, "");
242
+ } else if (str.includes(",")) {
243
+ str = str.replace(",", ".");
244
+ }
245
+ const num = parseFloat(str);
246
+ if (isNaN(num)) return 0;
247
+ return parseFloat(num.toFixed(decimals));
248
+ } catch {
249
+ return 0;
250
+ }
251
+ }
252
+ var parseToNumber = toNumber;
253
+ function secureRandomIndex(max) {
254
+ if (max <= 0) return 0;
255
+ const g = globalThis;
256
+ const crypto = g?.crypto;
257
+ if (crypto && typeof crypto.getRandomValues === "function") {
258
+ const range = 4294967296;
259
+ const threshold = range - range % max;
260
+ const buf = new Uint32Array(1);
261
+ do {
262
+ crypto.getRandomValues(buf);
263
+ } while (buf[0] >= threshold);
264
+ return buf[0] % max;
265
+ }
266
+ return Math.floor(Math.random() * max);
267
+ }
268
+ function randomDigits(length = 6, options) {
269
+ const charset = options?.charset ?? "0123456789";
270
+ if (length <= 0 || charset.length === 0) return "";
271
+ let out = "";
272
+ for (let i = 0; i < length; i++) {
273
+ if (i === 0 && options?.noLeadingZero && charset.includes("0")) {
274
+ const pool = charset.replace(/0/g, "");
275
+ if (pool.length === 0) return "";
276
+ out += pool[secureRandomIndex(pool.length)];
277
+ } else {
278
+ out += charset[secureRandomIndex(charset.length)];
279
+ }
280
+ }
281
+ return out;
282
+ }
283
+ var otp = randomDigits;
284
+
285
+ // src/utils/func.ts
286
+ function debounce(fn, wait = 250) {
287
+ let t;
288
+ return function(...args) {
289
+ clearTimeout(t);
290
+ t = setTimeout(() => fn.apply(this, args), wait);
291
+ };
292
+ }
293
+ function throttle(fn, wait = 250) {
294
+ let last = 0;
295
+ let timer;
296
+ return function(...args) {
297
+ const now = Date.now();
298
+ const remaining = wait - (now - last);
299
+ if (remaining <= 0) {
300
+ last = now;
301
+ fn.apply(this, args);
302
+ } else if (!timer) {
303
+ timer = setTimeout(() => {
304
+ last = Date.now();
305
+ timer = null;
306
+ fn.apply(this, args);
307
+ }, remaining);
308
+ }
309
+ };
310
+ }
311
+ var isNil = (value) => value === null || value === void 0;
312
+ var isNilText = (value) => {
313
+ if (value === null || value === void 0) return true;
314
+ if (typeof value === "string") {
315
+ const v = value.trim().toLowerCase();
316
+ return v === "null" || v === "undefined";
317
+ }
318
+ return false;
319
+ };
320
+ var isNilOrEmpty = (value) => {
321
+ try {
322
+ return isNil(value) || value === "";
323
+ } catch {
324
+ return true;
325
+ }
326
+ };
327
+ var hasNilOrEmpty = (array) => {
328
+ try {
329
+ if (!Array.isArray(array)) return true;
330
+ for (const item of array) {
331
+ if (isNilOrEmpty(item)) return true;
332
+ }
333
+ return false;
334
+ } catch {
335
+ return true;
336
+ }
337
+ };
338
+ var isNilEmptyOrZeroLen = (value) => {
339
+ try {
340
+ if (isNil(value) || value === "") return true;
341
+ const maybeLen = value?.length;
342
+ return typeof maybeLen === "number" && maybeLen === 0;
343
+ } catch {
344
+ return true;
345
+ }
346
+ };
347
+ var isNilOrZeroLen = (value) => {
348
+ try {
349
+ if (isNil(value)) return true;
350
+ const maybeLen = value?.length;
351
+ return typeof maybeLen === "number" && maybeLen === 0;
352
+ } catch {
353
+ return true;
354
+ }
355
+ };
356
+ var isNilOrNaN = (value) => {
357
+ try {
358
+ return isNil(value) || isNaN(value);
359
+ } catch {
360
+ return true;
361
+ }
362
+ };
363
+ var isNullOrUndefined = isNil;
364
+ var isNullOrUndefinedTextInc = isNilText;
365
+ var isNullUndefinedOrEmpty = isNilOrEmpty;
366
+ var isNullOrUndefinedInArray = hasNilOrEmpty;
367
+ var isNullOrUndefinedEmptyOrZero = isNilEmptyOrZeroLen;
368
+ var isNullUndefinedOrZero = isNilOrZeroLen;
369
+ var isNullOrUndefinedOrNaN = isNilOrNaN;
370
+ var formatBytes = (bytes, si = false, dp = 1) => {
371
+ if (!Number.isFinite(bytes)) return "NaN";
372
+ const thresh = si ? 1e3 : 1024;
373
+ const abs = Math.abs(bytes);
374
+ if (abs < thresh) return `${bytes} B`;
375
+ const units = si ? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"] : ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
376
+ let u = -1;
377
+ const r = 10 ** dp;
378
+ let value = bytes;
379
+ do {
380
+ value /= thresh;
381
+ ++u;
382
+ } while (Math.round(Math.abs(value) * r) / r >= thresh && u < units.length - 1);
383
+ return `${value.toFixed(dp)} ${units[u]}`;
384
+ };
385
+ var humanFileSize = formatBytes;
386
+ var levenshtein = (a, b) => {
387
+ if (a === b) return 0;
388
+ const al = a.length;
389
+ const bl = b.length;
390
+ if (al === 0) return bl;
391
+ if (bl === 0) return al;
392
+ if (al > bl) {
393
+ const tmp = a;
394
+ a = b;
395
+ b = tmp;
396
+ }
397
+ const n = a.length;
398
+ const m = b.length;
399
+ let prev = new Array(n + 1);
400
+ let curr = new Array(n + 1);
401
+ for (let i = 0; i <= n; i++) prev[i] = i;
402
+ for (let j = 1; j <= m; j++) {
403
+ curr[0] = j;
404
+ const bj = b.charCodeAt(j - 1);
405
+ for (let i = 1; i <= n; i++) {
406
+ const cost = a.charCodeAt(i - 1) === bj ? 0 : 1;
407
+ const del = prev[i] + 1;
408
+ const ins = curr[i - 1] + 1;
409
+ const sub = prev[i - 1] + cost;
410
+ curr[i] = del < ins ? del < sub ? del : sub : ins < sub ? ins : sub;
411
+ }
412
+ const tmp = prev;
413
+ prev = curr;
414
+ curr = tmp;
415
+ }
416
+ return prev[n];
417
+ };
418
+ var stringSimilarity = (s1, s2) => {
419
+ const a = s1 ?? "";
420
+ const b = s2 ?? "";
421
+ let longer = a;
422
+ let shorter = b;
423
+ if (a.length < b.length) {
424
+ longer = b;
425
+ shorter = a;
426
+ }
427
+ const L = longer.length;
428
+ if (L === 0) return 1;
429
+ const dist = levenshtein(longer, shorter);
430
+ return (L - dist) / L;
431
+ };
432
+ var getStringSimilarity = stringSimilarity;
433
+ var addThousandsSpace = (value) => {
434
+ try {
435
+ const str = value.toString();
436
+ const [intPart, decimalPart] = str.split(".");
437
+ const formattedInt = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, " ");
438
+ return decimalPart ? `${formattedInt}.${decimalPart}` : formattedInt;
439
+ } catch {
440
+ return value;
441
+ }
442
+ };
443
+ var addSpaceBetweenNumbers = addThousandsSpace;
444
+
445
+ // src/index.ts
446
+ var isBrowser = typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
447
+ var isNode = typeof process !== "undefined" && !!process.versions?.node;
448
+
449
+ export { addSpaceBetweenNumbers, addThousandsSpace, areArraysDeepEqualUnordered, areArraysEqual, basicSanitize, chunk, clamp, cleanObject, compact, debounce, deburr, difference, fill, flatten, flattenDepth, flattenDepthBase, flattenOnce, formatBytes, getStringSimilarity, groupBy, hasNilOrEmpty, humanFileSize, intersection, isBrowser, isFlattenable, isNil, isNilEmptyOrZeroLen, isNilOrEmpty, isNilOrNaN, isNilOrZeroLen, isNilText, isNode, isNullOrUndefined, isNullOrUndefinedEmptyOrZero, isNullOrUndefinedInArray, isNullOrUndefinedOrNaN, isNullOrUndefinedTextInc, isNullUndefinedOrEmpty, isNullUndefinedOrZero, objectToString, omit, otp, parseToNumber, pick, pluck, pushAll, randomDigits, removeDiacritics, round, safeParseInt, sanitize, shuffle, slugify, sortBy, stringSimilarity, throttle, toInteger, toNumber, uniq, uniqBy };
450
+ //# sourceMappingURL=index.js.map
451
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/array.ts","../src/utils/object.ts","../src/utils/string.ts","../src/utils/number.ts","../src/utils/func.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/******************************************************\r\n * ##: Unique by Key\r\n * Returns unique items in an array based on a computed key\r\n * @param {Array<T>} arr - The array to process\r\n * @param {Function} key - Function to compute the key for uniqueness\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function uniqBy<T, K>(arr: T[], key: (v: T) => K): T[] {\r\n const seen = new Set<K>();\r\n const out: T[] = [];\r\n for (const item of arr) {\r\n const k = key(item);\r\n if (!seen.has(k)) {\r\n seen.add(k);\r\n out.push(item);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/******************************************************\r\n * ##: Array Chunk\r\n * Splits an array into equally sized pieces\r\n * @param {Array<T>} arr - The array to chunk\r\n * @param {Number} size - Size of each chunk\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function chunk<T>(arr: T[], size: number): T[][] {\r\n if (size <= 0) return [arr.slice()];\r\n const res: T[][] = [];\r\n for (let i = 0; i < arr.length; i += size) res.push(arr.slice(i, i + size));\r\n return res;\r\n}\r\n\r\n/******************************************************\r\n * ##: Deep Array Equality\r\n * Deeply compares two arrays for equality, ignoring element order and property order in nested objects\r\n *\r\n * Notes:\r\n * - Uses JSON.stringify as the final canonical representation.\r\n * - Will return false on non-serializable inputs (e.g., circular structures).\r\n * - For primitives like NaN/Infinity, JSON.stringify follows JS semantics (NaN -> null).\r\n * @param {Array<T>} arr1 - First array to compare\r\n * @param {Array<T>} arr2 - Second array to compare\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function areArraysEqual<T = unknown>(arr1: T[], arr2: T[]): boolean {\r\n try {\r\n // Quick length check\r\n if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;\r\n if (arr1.length !== arr2.length) return false;\r\n\r\n // Canonicalize: sort object keys recursively\r\n const normalize = (value: unknown): unknown => {\r\n if (Array.isArray(value)) {\r\n // Normalize each element; order is handled later by sorting the stringified list\r\n return value.map(normalize);\r\n }\r\n if (value && typeof value === \"object\") {\r\n const entries = Object.entries(value as Record<string, unknown>)\r\n .map(([k, v]) => [k, normalize(v)] as const)\r\n .sort(([k1], [k2]) => (k1 < k2 ? -1 : k1 > k2 ? 1 : 0));\r\n return Object.fromEntries(entries);\r\n }\r\n return value;\r\n };\r\n\r\n // Stringify each normalized element and sort → order-independent comparison\r\n const a = arr1.map((el) => JSON.stringify(normalize(el))).sort();\r\n const b = arr2.map((el) => JSON.stringify(normalize(el))).sort();\r\n\r\n // Compare element-wise\r\n for (let i = 0; i < a.length; i++) {\r\n if (a[i] !== b[i]) return false;\r\n }\r\n return true;\r\n } catch {\r\n // Any unexpected error → treat as not equal\r\n return false;\r\n }\r\n}\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `areArraysEqual` instead.\r\n */\r\nexport const areArraysDeepEqualUnordered = areArraysEqual;\r\n\r\n/******************************************************\r\n * ##: Unique Values\r\n * Removes duplicate values from an array\r\n * @param {Array<T>} arr - The array to process\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function uniq<T>(arr: T[]): T[] {\r\n return Array.from(new Set(arr));\r\n}\r\n\r\n/******************************************************\r\n * ##: Flatten Array\r\n * Flattens nested arrays into a single array (1 level deep)\r\n * @param {Array<any>} arr - The array to flatten\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function flatten<T>(arr: any[]): T[] {\r\n return arr.flat ? arr.flat() : [].concat(...arr);\r\n}\r\n\r\n/******************************************************\r\n * ##: Group By\r\n * Groups array items by a key or function\r\n * @param {Array<T>} arr - The array to group\r\n * @param {Function|String} key - Key or function to group by\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function groupBy<T, K extends keyof any>(\r\n arr: T[],\r\n key: ((item: T) => K) | K\r\n): Record<string, T[]> {\r\n return arr.reduce((acc, item) => {\r\n const group = typeof key === \"function\" ? key(item) : (item as any)[key];\r\n (acc[group] = acc[group] || []).push(item);\r\n return acc;\r\n }, {} as Record<string, T[]>);\r\n}\r\n\r\n/******************************************************\r\n * ##: Sort By\r\n * Sorts array by a key or function\r\n * @param {Array<T>} arr - The array to sort\r\n * @param {Function|String} key - Key or function to sort by\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function sortBy<T>(arr: T[], key: ((item: T) => any) | keyof T): T[] {\r\n return [...arr].sort((a, b) => {\r\n const aKey = typeof key === \"function\" ? key(a) : a[key];\r\n const bKey = typeof key === \"function\" ? key(b) : b[key];\r\n if (aKey < bKey) return -1;\r\n if (aKey > bKey) return 1;\r\n return 0;\r\n });\r\n}\r\n\r\n/******************************************************\r\n * ##: Array Difference\r\n * Returns elements in arr1 not present in arr2\r\n * @param {Array<T>} arr1 - First array\r\n * @param {Array<T>} arr2 - Second array\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function difference<T>(arr1: T[], arr2: T[]): T[] {\r\n const set2 = new Set(arr2);\r\n return arr1.filter((x) => !set2.has(x));\r\n}\r\n\r\n/******************************************************\r\n * ##: Array Intersection\r\n * Returns elements common to both arrays\r\n * @param {Array<T>} arr1 - First array\r\n * @param {Array<T>} arr2 - Second array\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function intersection<T>(arr1: T[], arr2: T[]): T[] {\r\n const set2 = new Set(arr2);\r\n return arr1.filter((x) => set2.has(x));\r\n}\r\n\r\n/******************************************************\r\n * ##: Compact Array\r\n * Removes falsy values from array\r\n * @param {Array<T>} arr - The array to compact\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function compact<T>(arr: T[]): T[] {\r\n return arr.filter(Boolean);\r\n}\r\n\r\n/******************************************************\r\n * ##: Pluck Property\r\n * Extracts a property from each object in array\r\n * @param {Array<T>} arr - The array of objects\r\n * @param {String} key - Property name to extract\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function pluck<T, K extends keyof T>(arr: T[], key: K): Array<T[K]> {\r\n return arr.map((item) => item[key]);\r\n}\r\n\r\n/******************************************************\r\n * ##: Shuffle Array\r\n * Shuffles array elements randomly\r\n * @param {Array<T>} arr - The array to shuffle\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function shuffle<T>(arr: T[]): T[] {\r\n const a = [...arr];\r\n for (let i = a.length - 1; i > 0; i--) {\r\n const j = Math.floor(Math.random() * (i + 1));\r\n [a[i], a[j]] = [a[j], a[i]];\r\n }\r\n return a;\r\n}\r\n\r\n/**\r\n ****************************************************\r\n * ##: Flattenable Value Checker\r\n * Checks if a value can be flattened (array, arguments, or marked spreadable)\r\n *\r\n * Notes:\r\n * Mirrors lodash's behavior: checks Array.isArray, arguments object, and Symbol.isConcatSpreadable.\r\n * @param {unknown} value - Value to check for flattenability\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function isFlattenable(value: unknown): value is readonly unknown[] {\r\n // Quick path: arrays\r\n if (Array.isArray(value)) return true;\r\n\r\n // Check for arguments object\r\n const isArgs = Object.prototype.toString.call(value) === \"[object Arguments]\";\r\n\r\n if (isArgs) return true;\r\n\r\n // Respect Symbol.isConcatSpreadable when present\r\n // (some iterables/array-likes may opt-in)\r\n const spreadable = (Symbol as any).isConcatSpreadable as symbol | undefined;\r\n // Using bracket access to avoid TS downlevel issues\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n return spreadable ? !!(value as any)?.[spreadable] : false;\r\n}\r\n\r\n/**\r\n ****************************************************\r\n * ##: Array Push All\r\n * Appends all values into array in-place (similar to lodash arrayPush)\r\n * @param {Array<T>} array - Target array\r\n * @param {Array<T>} values - Values to append\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function pushAll<T>(array: T[], values: readonly T[]): T[] {\r\n let index = -1;\r\n const length = values.length;\r\n const offset = array.length;\r\n\r\n while (++index < length) {\r\n array[offset + index] = values[index] as T;\r\n }\r\n return array;\r\n}\r\n\r\n/**\r\n ****************************************************\r\n * ##: Base Array Flatten\r\n * Base flatten routine with configurable depth and predicate\r\n *\r\n * Notes:\r\n * Allows control of depth, predicate, and strict mode. Used internally for flattening.\r\n * @param {Array} array - Input array\r\n * @param {Number} depth - Maximum recursion depth\r\n * @param {Function} predicate - Function to determine if value is flattenable\r\n * @param {Boolean} isStrict - If true, only flattenable values are kept\r\n * @param {Array} result - Optional accumulator (internal)\r\n * @returns {Array} New flattened array\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function flattenDepthBase<T>(\r\n array: readonly unknown[],\r\n depth: number,\r\n predicate: (v: unknown) => boolean = isFlattenable,\r\n isStrict = false,\r\n result: T[] = []\r\n): T[] {\r\n let index = -1;\r\n const length = array.length;\r\n\r\n while (++index < length) {\r\n const value = array[index];\r\n if (depth > 0 && predicate(value)) {\r\n if (depth > 1) {\r\n // Recursively flatten (susceptible to call stack limits on huge nests).\r\n flattenDepthBase<T>(\r\n value as readonly unknown[],\r\n depth - 1,\r\n predicate,\r\n isStrict,\r\n result\r\n );\r\n } else {\r\n pushAll(result, value as T[]);\r\n }\r\n } else if (!isStrict) {\r\n // Keep non-flattenables when not strict\r\n (result as unknown[])[result.length] = value as unknown as T;\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n ****************************************************\r\n * ##: Flatten Array Once\r\n * Flattens array a single level deep (equivalent to lodash _.flatten)\r\n *\r\n * Notes:\r\n * Example: flattenOnce([1, [2, [3, [4]], 5]]) => [1, 2, [3, [4]], 5]\r\n * @param {Array} array - Array to flatten\r\n * @returns {Array} Flattened array (1 level)\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function flattenOnce<T>(\r\n array: ReadonlyArray<T | ReadonlyArray<T>>\r\n): T[] {\r\n // Type note: `flattenDepthBase` returns `unknown[]` at compile-time,\r\n // but we constrain inputs so a cast to `T[]` is safe here.\r\n return flattenDepthBase<T>(array as readonly unknown[], 1) as T[];\r\n}\r\n\r\n/******************************************************\r\n * ##: Flatten Array to Depth\r\n * Flattens array up to the specified depth (friendly wrapper, default 1)\r\n *\r\n * Notes:\r\n * Example: flattenDepth([1, [2, [3, [4]], 5]], 2) => [1, 2, 3, [4], 5]\r\n * @param {Array} array - Array to flatten\r\n * @param {Number} depth - Maximum depth\r\n * @param {Object} options - Options: predicate, isStrict\r\n * @returns {Array} Flattened array up to depth\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function flattenDepth<T = unknown>(\r\n array: readonly unknown[],\r\n depth = 1,\r\n options?: {\r\n predicate?: (v: unknown) => boolean;\r\n isStrict?: boolean;\r\n }\r\n): T[] {\r\n const { predicate = isFlattenable, isStrict = false } = options ?? {};\r\n return flattenDepthBase<T>(array, depth, predicate, isStrict);\r\n}\r\n","/**\r\n****************************************************\r\n * ##: Object Property Picker\r\n * Picks specified properties from an object and returns a new object\r\n * @param {Object} obj - Source object\r\n * @param {Array} keys - Array of keys to pick\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function pick<T extends object, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Pick<T, K> {\r\n const out = {} as Pick<T, K>;\r\n for (const k of keys) if (k in obj) out[k] = obj[k];\r\n return out;\r\n}\r\n\r\n/**\r\n****************************************************\r\n * ##: Object Property Omitter\r\n * Omits specified properties from an object and returns a new object\r\n * @param {Object} obj - Source object\r\n * @param {Array} keys - Array of keys to omit\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function omit<T extends object, K extends keyof T>(\r\n obj: T,\r\n keys: K[]\r\n): Omit<T, K> {\r\n const set = new Set<keyof T>(keys);\r\n const out = {} as any;\r\n for (const k in obj) if (!set.has(k)) out[k] = obj[k];\r\n return out;\r\n}\r\n\r\n/**\r\n****************************************************\r\n * ##: Object to Clean String\r\n * Converts an object or value to a clean string without JSON braces and quotes\r\n *\r\n * Notes:\r\n * Examples: { a: 1, b: \"x\" } -> \"a=1_b=x\", null -> \"\", 42 -> \"42\"\r\n * @param {unknown} obj - Object or value to convert\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function objectToString(obj: unknown): string {\r\n try {\r\n if (obj === null || obj === undefined) return \"\";\r\n if (typeof obj !== \"object\") return String(obj);\r\n\r\n return JSON.stringify(obj)\r\n .replace(/[{}\"]/g, \"\") // remove { } \"\r\n .replace(/:/g, \"=\") // replace : with =\r\n .replace(/,/g, \"_\"); // replace , with _\r\n } catch {\r\n // Fallback: best-effort stringify\r\n try {\r\n return String(obj);\r\n } catch {\r\n return \"\";\r\n }\r\n }\r\n}\r\n\r\n/**\r\n****************************************************\r\n * ##: Deep Object Cleaner\r\n * Deep-cleans an input by removing null, undefined, \"null\", \"undefined\" and recursively cleaning arrays/objects\r\n *\r\n * Notes:\r\n * - Falsy values like 0, false, \"\" are kept.\r\n * - Non-plain objects (e.g., Date, Map) are treated as generic objects via Object.entries.\r\n * - Prunes empty objects/arrays produced by the cleaning step.\r\n * @param {unknown} obj - Object or array to clean\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\ntype Removable = null | undefined | \"null\" | \"undefined\";\r\n\r\nconst isRemovable = (v: unknown): v is Removable =>\r\n v === null || v === undefined || v === \"null\" || v === \"undefined\";\r\n\r\nexport function cleanObject<T = unknown>(obj: T): any {\r\n // Handle arrays: map + clean each item, then filter removable values\r\n if (Array.isArray(obj)) {\r\n const cleanedArray = obj\r\n .map((item) => cleanObject(item))\r\n .filter((item) => !isRemovable(item));\r\n return cleanedArray;\r\n }\r\n\r\n // Handle objects (and only objects, excluding null)\r\n if (obj !== null && typeof obj === \"object\") {\r\n const cleaned: Record<string, any> = {};\r\n\r\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\r\n // Skip removable raw values fast\r\n if (isRemovable(value)) continue;\r\n\r\n // Recursively clean nested values\r\n const nested = cleanObject(value);\r\n\r\n // After cleaning, skip if still removable\r\n if (isRemovable(nested)) continue;\r\n\r\n // Prune empty objects/arrays (to mirror original behavior)\r\n const isObj = typeof nested === \"object\" && nested !== null;\r\n const isEmptyObj =\r\n isObj && !Array.isArray(nested) && Object.keys(nested).length === 0;\r\n const isEmptyArr = Array.isArray(nested) && nested.length === 0;\r\n if (isEmptyObj || isEmptyArr) continue;\r\n\r\n cleaned[key] = nested;\r\n }\r\n\r\n return cleaned;\r\n }\r\n\r\n // Primitives (and functions) are returned as-is\r\n return obj as any;\r\n}\r\n","/******************************************************\r\n * ##: Slugify String\r\n * Converts a string to a URL-friendly slug (basic ASCII, keeps numbers and dashes)\r\n * @param {String} input - String to slugify\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function slugify(input: string) {\r\n return input\r\n .normalize(\"NFKD\")\r\n .replace(/[\\u0300-\\u036f]/g, \"\")\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, \"-\")\r\n .replace(/^-+|-+$/g, \"\");\r\n}\r\n\r\n/******************************************************\r\n * ##: Simple String Template Filler\r\n * Fills a template string with values (e.g., \"Hello, {name}!\")\r\n * @param {String} template - Template string\r\n * @param {Object} values - Key-value pairs to fill\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function fill(\r\n template: string,\r\n values: Record<string, string | number>\r\n) {\r\n return template.replace(/\\{(\\w+)\\}/g, (_, k) => String(values[k] ?? \"\"));\r\n}\r\n\r\n/******************************************************\r\n * ##: Remove Diacritics\r\n * Removes diacritic marks from a string using NFD normalization\r\n *\r\n * Notes:\r\n * Examples: \"ação\" -> \"acao\", \"coração\" -> \"coracao\", \"résumé\" -> \"resume\", \"naïve\" -> \"naive\"\r\n * @param {String} str - String to deburr\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function deburr(str: string): string {\r\n try {\r\n return str.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\");\r\n } catch {\r\n return str;\r\n }\r\n}\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `deburr` instead.\r\n */\r\nexport const removeDiacritics = deburr;\r\n\r\n/******************************************************\r\n * ##: Basic String Sanitizer\r\n * Sanitizes input by removing control chars, HTML/script/style/iframe blocks, dangerous URL schemes, and keeps letters/numbers/spaces/punctuation\r\n *\r\n * Notes:\r\n * Non-string inputs return \"\". This is a light, generic sanitizer (not a full HTML sanitizer).\r\n * @param {unknown} input - Input to sanitize\r\n * @param {Number} maxLength - Optional max length for output\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function sanitize(input: unknown, maxLength?: number): string {\r\n if (typeof input !== \"string\") return \"\";\r\n\r\n // 1. Remove invisible spaces and control characters\r\n let cleaned = input.replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, \"\");\r\n\r\n // 2. Remove embedded script/style/iframe blocks\r\n cleaned = cleaned.replace(/<(script|style|iframe)[^>]*>.*?<\\/\\1>/gis, \"\");\r\n\r\n // 3. Remove event handler attributes (e.g., onclick, onerror)\r\n cleaned = cleaned.replace(/on\\w+\\s*=\\s*(['\"]).*?\\1/gi, \"\");\r\n\r\n // 4. Remove CSS expressions (expression(...))\r\n cleaned = cleaned.replace(/expression\\s*\\([^)]*\\)/gi, \"\");\r\n\r\n // 5. Remove blocks between dangerous HTML entities (e.g., &#x3C;script&#x3E;...&#x3C;/script&#x3E;)\r\n cleaned = cleaned.replace(\r\n /&#x3C;script&#x3E;[\\s\\S]*?&#x3C;\\/script&#x3E;/gi,\r\n \"\"\r\n );\r\n cleaned = cleaned.replace(/&#x3C;.*?&#x3E;/gi, \"\");\r\n\r\n // 6. Strip all remaining HTML tags\r\n cleaned = cleaned.replace(/<[^>]+>/g, \"\");\r\n\r\n // 7. Remove dangerous URL schemes\r\n cleaned = cleaned.replace(/\\b(javascript:|data:|vbscript:|file:|ftp:)/gi, \"\");\r\n\r\n // 8. Keep letters/numbers/spaces and basic punctuation\r\n cleaned = cleaned.replace(/[^\\p{L}\\p{N}\\s\\-.,!?@#%&()]/gu, \"\");\r\n // 9. Apply maxLength only if explicitly passed\r\n if (typeof maxLength === \"number\" && maxLength > 0) {\r\n cleaned = cleaned.substring(0, maxLength);\r\n }\r\n\r\n // 10. Trim\r\n cleaned = cleaned.trim();\r\n\r\n return cleaned;\r\n}\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `sanitize` instead.\r\n */\r\nexport const basicSanitize = sanitize;\r\n","/******************************************************\r\n * ##: Clamp Number\r\n * Restricts a number to be within the min and max bounds\r\n * @param {Number} n - Number to clamp\r\n * @param {Number} min - Minimum value\r\n * @param {Number} max - Maximum value\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const clamp = (n: number, min: number, max: number) =>\r\n Math.min(Math.max(n, min), max);\r\n\r\n/******************************************************\r\n * ##: Fixed Decimal Rounding\r\n * Rounds a number to a fixed number of decimals without floating point surprises\r\n * @param {Number} n - Number to round\r\n * @param {Number} decimals - Number of decimal places\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function round(n: number, decimals = 0) {\r\n const f = Math.pow(10, decimals);\r\n return Math.round((n + Number.EPSILON) * f) / f;\r\n}\r\n\r\n/******************************************************\r\n * ##: Safe Integer Conversion\r\n * Safely converts a value to an integer. Returns defaultValue if parsing fails or results in NaN.\r\n *\r\n * Notes:\r\n * Examples: toInteger(\"42\") -> 42, toInteger(\"abc\", 10) -> 10, toInteger(undefined) -> 0, toInteger(3.9) -> 3\r\n * @param {unknown} value - Value to convert\r\n * @param {Number} defaultValue - Default value if parsing fails\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function toInteger(value: unknown, defaultValue = 0): number {\r\n try {\r\n const safeValue = parseInt(String(value), 10);\r\n return isNaN(safeValue) ? defaultValue : safeValue;\r\n } catch {\r\n return defaultValue;\r\n }\r\n}\r\n\r\n/******************************************************\r\n * ##: Safe Parse Int (Alias)\r\n * Alias for safe integer conversion (for discoverability/backward naming)\r\n * @param {unknown} value - Value to convert\r\n * @param {Number} defaultValue - Default value if parsing fails\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const safeParseInt = toInteger;\r\n\r\n/******************************************************\r\n * ##: Safe Number Conversion\r\n * Safely parses a value into a number with optional decimal precision\r\n *\r\n * Notes:\r\n * Handles commas as decimal/thousands separators. Returns 0 for null/undefined/empty string or invalid parsing.\r\n * Examples: toNumber(\"123.45\") -> 123.45, toNumber(\"123,45\") -> 123.45, toNumber(\"1,234.56\") -> 1234.56, toNumber(\"abc\", 2) -> 0, toNumber(42) -> 42\r\n * @param {unknown} value - Value to convert\r\n * @param {Number} decimals - Number of decimal places\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function toNumber(value: unknown, decimals = 6): number {\r\n try {\r\n if (value === undefined || value === null || value === \"\") return 0;\r\n\r\n let str = String(value);\r\n\r\n // Normalize commas and dots\r\n if (str.includes(\",\") && str.includes(\".\")) {\r\n // Example: \"1,234.56\" -> \"1234.56\"\r\n str = str.replace(/,/g, \"\");\r\n } else if (str.includes(\",\")) {\r\n // Example: \"123,45\" -> \"123.45\"\r\n str = str.replace(\",\", \".\");\r\n }\r\n\r\n const num = parseFloat(str);\r\n if (isNaN(num)) return 0;\r\n\r\n // Apply decimal precision\r\n return parseFloat(num.toFixed(decimals));\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `toNumber` instead.\r\n */\r\nexport const parseToNumber = toNumber;\r\n\r\n/******************************************************\r\n * ##: Secure Random Index\r\n * Generates a uniformly distributed integer in [0, max) using Web Crypto when available\r\n *\r\n * Notes:\r\n * Falls back to Math.random() if crypto is unavailable (not cryptographically secure)\r\n * @param {Number} max - Upper bound (exclusive)\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nfunction secureRandomIndex(max: number): number {\r\n if (max <= 0) return 0;\r\n\r\n const g: any = globalThis as any;\r\n const crypto = g?.crypto;\r\n\r\n // Prefer Web Crypto (browser + Node 18+ expose crypto.getRandomValues)\r\n if (crypto && typeof crypto.getRandomValues === \"function\") {\r\n // Rejection sampling to avoid modulo bias\r\n const range = 0x100000000; // 2^32\r\n const threshold = range - (range % max);\r\n const buf = new Uint32Array(1);\r\n\r\n // Loop until we hit a value in the unbiased range\r\n // In practice this loops rarely (expected < 2 iterations).\r\n do {\r\n crypto.getRandomValues(buf);\r\n } while (buf[0] >= threshold);\r\n\r\n return buf[0] % max;\r\n }\r\n\r\n // Fallback (NOT cryptographically secure)\r\n return Math.floor(Math.random() * max);\r\n}\r\n\r\n/******************************************************\r\n * ##: Random Digits Generator\r\n * Generates a random string of digits with secure randomness when available\r\n *\r\n * Notes:\r\n * Options: length (default 6), charset (default \"0123456789\"), noLeadingZero (if true, first char not \"0\"). Returns a string to preserve leading zeros. Uses Web Crypto when possible; otherwise falls back to Math.random().\r\n * @param {Number} length - Number of digits\r\n * @param {Object} options - Options: charset, noLeadingZero\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function randomDigits(\r\n length = 6,\r\n options?: { charset?: string; noLeadingZero?: boolean }\r\n): string {\r\n const charset = options?.charset ?? \"0123456789\";\r\n if (length <= 0 || charset.length === 0) return \"\";\r\n\r\n let out = \"\";\r\n\r\n for (let i = 0; i < length; i++) {\r\n if (i === 0 && options?.noLeadingZero && charset.includes(\"0\")) {\r\n // Pick from charset without \"0\"\r\n const pool = charset.replace(/0/g, \"\");\r\n if (pool.length === 0) return \"\"; // nothing to pick\r\n out += pool[secureRandomIndex(pool.length)];\r\n } else {\r\n out += charset[secureRandomIndex(charset.length)];\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `randomDigits` instead.\r\n */\r\nexport const otp = randomDigits;\r\n","/******************************************************\r\n * ##: Debounce Function\r\n * Returns a debounced version of a function that delays execution until after wait ms\r\n * @param {Function} fn - Function to debounce\r\n * @param {Number} wait - Delay in milliseconds\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function debounce<T extends (...args: any[]) => any>(fn: T, wait = 250) {\r\n let t: any;\r\n return function (this: any, ...args: Parameters<T>) {\r\n clearTimeout(t);\r\n t = setTimeout(() => fn.apply(this, args), wait);\r\n } as T;\r\n}\r\n\r\n/******************************************************\r\n * ##: Throttle Function\r\n * Returns a throttled version of a function that only executes once per wait ms\r\n * @param {Function} fn - Function to throttle\r\n * @param {Number} wait - Delay in milliseconds\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport function throttle<T extends (...args: any[]) => any>(fn: T, wait = 250) {\r\n let last = 0;\r\n let timer: any;\r\n return function (this: any, ...args: Parameters<T>) {\r\n const now = Date.now();\r\n const remaining = wait - (now - last);\r\n if (remaining <= 0) {\r\n last = now;\r\n fn.apply(this, args);\r\n } else if (!timer) {\r\n timer = setTimeout(() => {\r\n last = Date.now();\r\n timer = null;\r\n fn.apply(this, args);\r\n }, remaining);\r\n }\r\n } as T;\r\n}\r\n\r\n/******************************************************\r\n * ##: Nil Value Check\r\n * Checks if a value is null or undefined (Type Guard)\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNil = (value: unknown): value is null | undefined =>\r\n value === null || value === undefined;\r\n\r\n/******************************************************\r\n * ##: Nil or Nil Text Check\r\n * Checks if value is null/undefined or the text \"null\"/\"undefined\"\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNilText = (value: unknown): boolean => {\r\n if (value === null || value === undefined) return true;\r\n if (typeof value === \"string\") {\r\n const v = value.trim().toLowerCase();\r\n return v === \"null\" || v === \"undefined\";\r\n }\r\n return false;\r\n};\r\n\r\n/******************************************************\r\n * ##: Nil or Empty String Check\r\n * Checks if value is null/undefined or an empty string \"\"\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNilOrEmpty = (value: unknown): boolean => {\r\n try {\r\n return isNil(value) || value === \"\";\r\n } catch {\r\n return true;\r\n }\r\n};\r\n\r\n/******************************************************\r\n * ##: Array Nil or Empty Element Check\r\n * Checks if any element in array is nil or empty (\"\"). Returns true if input is not an array.\r\n * @param {unknown} array - Array to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const hasNilOrEmpty = (array: unknown): boolean => {\r\n try {\r\n if (!Array.isArray(array)) return true;\r\n for (const item of array) {\r\n if (isNilOrEmpty(item)) return true;\r\n }\r\n return false;\r\n } catch {\r\n return true;\r\n }\r\n};\r\n\r\n/******************************************************\r\n * ##: Nil, Empty, or Zero Length Check\r\n * Checks if value is nil, empty string, or has zero length (applies to arrays, strings, typed arrays, buffers)\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNilEmptyOrZeroLen = (value: unknown): boolean => {\r\n try {\r\n if (isNil(value) || value === \"\") return true;\r\n\r\n // has length === 0 (string/array/typed-array/buffer-like)\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const maybeLen = (value as any)?.length;\r\n return typeof maybeLen === \"number\" && maybeLen === 0;\r\n } catch {\r\n return true;\r\n }\r\n};\r\n\r\n/******************************************************\r\n * ##: Nil or Zero Length Check\r\n * Checks if value is nil or has zero length (.length === 0). Does NOT treat \"\" specially.\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNilOrZeroLen = (value: unknown): boolean => {\r\n try {\r\n if (isNil(value)) return true;\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const maybeLen = (value as any)?.length;\r\n return typeof maybeLen === \"number\" && maybeLen === 0;\r\n } catch {\r\n return true;\r\n }\r\n};\r\n\r\n/******************************************************\r\n * ##: Nil or NaN Check\r\n * Checks if value is nil OR NaN (coercive, matches global isNaN)\r\n *\r\n * Notes:\r\n * Uses global isNaN for parity with JS behavior (coerces strings). Example: isNaN(\"foo\") === true.\r\n * @param {unknown} value - Value to check\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const isNilOrNaN = (value: unknown): boolean => {\r\n try {\r\n return isNil(value) || isNaN(value as number);\r\n } catch {\r\n return true;\r\n }\r\n};\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n\r\n/**\r\n * @deprecated Use `isNil` instead.\r\n */\r\nexport const isNullOrUndefined = isNil;\r\n\r\n/**\r\n * @deprecated Use `isNilText` instead.\r\n */\r\nexport const isNullOrUndefinedTextInc = isNilText;\r\n\r\n/**\r\n * @deprecated Use `isNilOrEmpty` instead.\r\n */\r\nexport const isNullUndefinedOrEmpty = isNilOrEmpty;\r\n\r\n/**\r\n * @deprecated Use `hasNilOrEmpty` instead.\r\n */\r\nexport const isNullOrUndefinedInArray = hasNilOrEmpty;\r\n\r\n/**\r\n * @deprecated Use `isNilEmptyOrZeroLen` instead.\r\n */\r\nexport const isNullOrUndefinedEmptyOrZero = isNilEmptyOrZeroLen;\r\n\r\n/**\r\n * @deprecated Use `isNilOrZeroLen` instead.\r\n */\r\nexport const isNullUndefinedOrZero = isNilOrZeroLen;\r\n\r\n/**\r\n * @deprecated Use `isNilOrNaN` instead.\r\n */\r\nexport const isNullOrUndefinedOrNaN = isNilOrNaN;\r\n\r\n/******************************************************\r\n * ##: Human-Readable Byte Formatter\r\n * Formats bytes as human-readable text (e.g., kB, MB, KiB, MiB)\r\n *\r\n * Notes:\r\n * SI (kB, MB, ...) uses 1000; IEC (KiB, MiB, ...) uses 1024. Negative values supported.\r\n * @param {Number} bytes - Number of bytes to format\r\n * @param {Boolean} si - True for metric (SI, base 1000), false for binary (IEC, base 1024)\r\n * @param {Number} dp - Decimal places\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const formatBytes = (\r\n bytes: number,\r\n si: boolean = false,\r\n dp: number = 1\r\n): string => {\r\n // Guard invalid numbers\r\n if (!Number.isFinite(bytes)) return \"NaN\";\r\n\r\n const thresh = si ? 1000 : 1024;\r\n const abs = Math.abs(bytes);\r\n\r\n // Bytes (no unit scaling)\r\n if (abs < thresh) return `${bytes} B`;\r\n\r\n const units = si\r\n ? [\"kB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"]\r\n : [\"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\", \"YiB\"];\r\n\r\n let u = -1;\r\n const r = 10 ** dp;\r\n let value = bytes;\r\n\r\n do {\r\n value /= thresh;\r\n ++u;\r\n // keep dividing while rounded value still reaches next threshold\r\n } while (\r\n Math.round(Math.abs(value) * r) / r >= thresh &&\r\n u < units.length - 1\r\n );\r\n\r\n return `${value.toFixed(dp)} ${units[u]}`;\r\n};\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `formatBytes` instead.\r\n */\r\nexport const humanFileSize = formatBytes;\r\n\r\n/******************************************************\r\n * ##: Levenshtein Distance\r\n * Calculates the Levenshtein distance between two strings (O(n*m), O(min(n,m)) space)\r\n * @param {String} a - First string\r\n * @param {String} b - Second string\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nconst levenshtein = (a: string, b: string): number => {\r\n if (a === b) return 0;\r\n const al = a.length;\r\n const bl = b.length;\r\n if (al === 0) return bl;\r\n if (bl === 0) return al;\r\n\r\n // Ensure `a` is the shorter to minimize memory\r\n if (al > bl) {\r\n const tmp = a;\r\n a = b;\r\n b = tmp;\r\n }\r\n\r\n const n = a.length;\r\n const m = b.length;\r\n\r\n let prev = new Array<number>(n + 1);\r\n let curr = new Array<number>(n + 1);\r\n\r\n for (let i = 0; i <= n; i++) prev[i] = i;\r\n\r\n for (let j = 1; j <= m; j++) {\r\n curr[0] = j;\r\n const bj = b.charCodeAt(j - 1);\r\n for (let i = 1; i <= n; i++) {\r\n const cost = a.charCodeAt(i - 1) === bj ? 0 : 1;\r\n const del = prev[i] + 1;\r\n const ins = curr[i - 1] + 1;\r\n const sub = prev[i - 1] + cost;\r\n curr[i] = del < ins ? (del < sub ? del : sub) : ins < sub ? ins : sub;\r\n }\r\n // swap\r\n const tmp = prev;\r\n prev = curr;\r\n curr = tmp;\r\n }\r\n\r\n return prev[n];\r\n};\r\n\r\n/******************************************************\r\n * ##: String Similarity\r\n * Returns the similarity between two strings (0..1)\r\n *\r\n * Notes:\r\n * Similarity = (|longer|-levenshtein(longer, shorter)) / |longer| ∈ [0, 1]. Safe for empty strings; if both empty => 1.0\r\n * @param {String} s1 - First string\r\n * @param {String} s2 - Second string\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const stringSimilarity = (s1: string, s2: string): number => {\r\n const a = s1 ?? \"\";\r\n const b = s2 ?? \"\";\r\n\r\n let longer = a;\r\n let shorter = b;\r\n if (a.length < b.length) {\r\n longer = b;\r\n shorter = a;\r\n }\r\n\r\n const L = longer.length;\r\n if (L === 0) return 1.0;\r\n\r\n const dist = levenshtein(longer, shorter);\r\n return (L - dist) / L;\r\n};\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `stringSimilarity` instead.\r\n */\r\nexport const getStringSimilarity = stringSimilarity;\r\n\r\n/******************************************************\r\n * ##: Thousand Separator Formatter\r\n * Adds spaces between thousands in a number (e.g., 1234567 -> \"1 234 567\")\r\n * @param {Number|String} value - Number or string to format\r\n * @returns {String} Formatted string with spaces as thousand separators\r\n * History:\r\n * 21-08-2025: Created\r\n ****************************************************/\r\nexport const addThousandsSpace = (value: number | string): string => {\r\n try {\r\n const str = value.toString();\r\n const [intPart, decimalPart] = str.split(\".\");\r\n\r\n const formattedInt = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, \" \");\r\n return decimalPart ? `${formattedInt}.${decimalPart}` : formattedInt;\r\n } catch {\r\n return value as string;\r\n }\r\n};\r\n\r\n/* ======================================================================================\r\n * Deprecated aliases (backward-compatibility)\r\n * Keep until downstream code is migrated. Remove in a major release.\r\n * ====================================================================================*/\r\n/**\r\n * @deprecated Use `addThousandsSpace` instead.\r\n */\r\nexport const addSpaceBetweenNumbers = addThousandsSpace;\r\n","export * from \"./utils/array\";\r\nexport * from \"./utils/object\";\r\nexport * from \"./utils/string\";\r\nexport * from \"./utils/number\";\r\nexport * from \"./utils/func\";\r\n\r\n/** Environment helpers (runtime-agnostic checks) */\r\nexport const isBrowser = typeof globalThis !== \"undefined\" && typeof (globalThis as any).document !== \"undefined\";\r\nexport const isNode = typeof process !== \"undefined\" && !!(process.versions?.node);\r\n"]}