@xxanderwp/jstoolkit 1.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,1506 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var md5 = require('md5');
6
+
7
+ /**
8
+ * Generate a random string of specified length
9
+ * @param length - Length of the string to generate
10
+ * @param characters - Characters to use (default: alphanumeric)
11
+ * @returns Random string
12
+ */
13
+ function randomString(length, characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
14
+ let result = '';
15
+ const charactersLength = characters.length;
16
+ for (let i = 0; i < length; i++) {
17
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
18
+ }
19
+ return result;
20
+ }
21
+ /**
22
+ * Truncate a string to a specified length and add ellipsis
23
+ * @param str - String to truncate
24
+ * @param maxLength - Maximum length
25
+ * @param ellipsis - Ellipsis string (default: '...')
26
+ * @returns Truncated string
27
+ */
28
+ function truncate(str, maxLength, ellipsis = '...') {
29
+ if (str.length <= maxLength)
30
+ return str;
31
+ return str.slice(0, maxLength - ellipsis.length) + ellipsis;
32
+ }
33
+ /**
34
+ * Capitalize the first letter of a string
35
+ * @param str - String to capitalize
36
+ * @returns Capitalized string
37
+ */
38
+ function capitalize(str) {
39
+ if (!str)
40
+ return str;
41
+ return str.charAt(0).toUpperCase() + str.slice(1);
42
+ }
43
+ /**
44
+ * Convert string to camelCase
45
+ * @param str - String to convert
46
+ * @returns camelCase string
47
+ */
48
+ function toCamelCase(str) {
49
+ return str
50
+ .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
51
+ .replace(/^[A-Z]/, (c) => c.toLowerCase());
52
+ }
53
+ /**
54
+ * Convert string to snake_case
55
+ * @param str - String to convert
56
+ * @returns snake_case string
57
+ */
58
+ function toSnakeCase(str) {
59
+ return str
60
+ .replace(/([A-Z])/g, '_$1')
61
+ .toLowerCase()
62
+ .replace(/^_/, '');
63
+ }
64
+ /**
65
+ * Convert string to kebab-case
66
+ * @param str - String to convert
67
+ * @returns kebab-case string
68
+ */
69
+ function toKebabCase(str) {
70
+ return str
71
+ .replace(/([A-Z])/g, '-$1')
72
+ .toLowerCase()
73
+ .replace(/^-/, '');
74
+ }
75
+ /**
76
+ * Remove all whitespace from a string
77
+ * @param str - String to process
78
+ * @returns String without whitespace
79
+ */
80
+ function removeWhitespace(str) {
81
+ return str.replace(/\s+/g, '');
82
+ }
83
+ /**
84
+ * Count occurrences of a substring in a string
85
+ * @param str - String to search in
86
+ * @param substring - Substring to count
87
+ * @returns Number of occurrences
88
+ */
89
+ function countOccurrences(str, substring) {
90
+ if (!substring)
91
+ return 0;
92
+ return (str.match(new RegExp(substring, 'g')) || []).length;
93
+ }
94
+
95
+ var string = /*#__PURE__*/Object.freeze({
96
+ __proto__: null,
97
+ capitalize: capitalize,
98
+ countOccurrences: countOccurrences,
99
+ randomString: randomString,
100
+ removeWhitespace: removeWhitespace,
101
+ toCamelCase: toCamelCase,
102
+ toKebabCase: toKebabCase,
103
+ toSnakeCase: toSnakeCase,
104
+ truncate: truncate
105
+ });
106
+
107
+ /**
108
+ * Get a random element from an array
109
+ * @param arr - Array to pick from
110
+ * @returns Random element
111
+ */
112
+ function randomElement(arr) {
113
+ return arr[Math.floor(Math.random() * arr.length)];
114
+ }
115
+ /**
116
+ * Get a random index from an array
117
+ * @param arr - Array to pick from
118
+ * @returns Random index
119
+ */
120
+ function randomElementIndex(arr) {
121
+ return Math.floor(Math.random() * arr.length);
122
+ }
123
+ /**
124
+ * Shuffle an array using Fisher-Yates algorithm
125
+ * @param arr - Array to shuffle
126
+ * @returns Shuffled array (new array)
127
+ */
128
+ function shuffle(arr) {
129
+ const result = [...arr];
130
+ for (let i = result.length - 1; i > 0; i--) {
131
+ const j = Math.floor(Math.random() * (i + 1));
132
+ [result[i], result[j]] = [result[j], result[i]];
133
+ }
134
+ return result;
135
+ }
136
+ /**
137
+ * Split an array into chunks of specified size
138
+ * @param array - Array to chunk
139
+ * @param size - Size of each chunk
140
+ * @returns Array of chunks
141
+ */
142
+ function chunk(array, size) {
143
+ const result = [];
144
+ for (let i = 0; i < array.length; i += size) {
145
+ result.push(array.slice(i, i + size));
146
+ }
147
+ return result;
148
+ }
149
+ /**
150
+ * Remove duplicate values from an array
151
+ * @param arr - Array to deduplicate
152
+ * @returns Array without duplicates
153
+ */
154
+ function unique(arr) {
155
+ return [...new Set(arr)];
156
+ }
157
+ /**
158
+ * Get the intersection of two arrays
159
+ * @param arr1 - First array
160
+ * @param arr2 - Second array
161
+ * @returns Intersection array
162
+ */
163
+ function intersection(arr1, arr2) {
164
+ const set2 = new Set(arr2);
165
+ return arr1.filter((item) => set2.has(item));
166
+ }
167
+ /**
168
+ * Get the difference of two arrays (elements in arr1 but not in arr2)
169
+ * @param arr1 - First array
170
+ * @param arr2 - Second array
171
+ * @returns Difference array
172
+ */
173
+ function difference(arr1, arr2) {
174
+ const set2 = new Set(arr2);
175
+ return arr1.filter((item) => !set2.has(item));
176
+ }
177
+ /**
178
+ * Sort array in ascending or descending order
179
+ * @param array - Array to sort
180
+ * @param order - Sort order ('ASC' or 'DESC')
181
+ * @returns Sorted array
182
+ */
183
+ function sort(array, order = 'ASC') {
184
+ return [...array].sort((a, b) => {
185
+ if (order === 'ASC') {
186
+ return a < b ? -1 : a > b ? 1 : 0;
187
+ }
188
+ else {
189
+ return a < b ? 1 : a > b ? -1 : 0;
190
+ }
191
+ });
192
+ }
193
+ /**
194
+ * Sort array of objects by multiple properties
195
+ * @param array - Array to sort
196
+ * @param params - Sort parameters
197
+ * @returns Sorted array
198
+ */
199
+ function sortBy(array, params) {
200
+ return [...array].sort((a, b) => {
201
+ for (const param of params) {
202
+ const aVal = a[param.key];
203
+ const bVal = b[param.key];
204
+ let result = 0;
205
+ if (param.order === 'ASC') {
206
+ result = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
207
+ }
208
+ else {
209
+ result = aVal < bVal ? 1 : aVal > bVal ? -1 : 0;
210
+ }
211
+ if (result !== 0)
212
+ return result;
213
+ }
214
+ return 0;
215
+ });
216
+ }
217
+ /**
218
+ * Sort array items by key order priority
219
+ * @param items - Array to sort
220
+ * @param keyOrder - Priority order of keys
221
+ * @returns Sorted array
222
+ */
223
+ function sortByKeys(items, keyOrder) {
224
+ const keyOrderMap = new Map(keyOrder.map((key, index) => [key, index]));
225
+ return [...items].sort((a, b) => {
226
+ let orderA = keyOrder.length;
227
+ let orderB = keyOrder.length;
228
+ for (const [key, index] of keyOrderMap) {
229
+ if (a.startsWith(key)) {
230
+ orderA = index;
231
+ break;
232
+ }
233
+ }
234
+ for (const [key, index] of keyOrderMap) {
235
+ if (b.startsWith(key)) {
236
+ orderB = index;
237
+ break;
238
+ }
239
+ }
240
+ return orderA - orderB;
241
+ });
242
+ }
243
+ /**
244
+ * Group array elements by a key function
245
+ * @param arr - Array to group
246
+ * @param keyFn - Function that returns the group key
247
+ * @returns Object with grouped elements
248
+ */
249
+ function groupBy(arr, keyFn) {
250
+ return arr.reduce((result, item) => {
251
+ const key = keyFn(item);
252
+ if (!result[key]) {
253
+ result[key] = [];
254
+ }
255
+ result[key].push(item);
256
+ return result;
257
+ }, {});
258
+ }
259
+ /**
260
+ * Flatten nested arrays to specified depth
261
+ * @param arr - Array to flatten
262
+ * @param depth - Depth to flatten (default: 1)
263
+ * @returns Flattened array
264
+ */
265
+ function flatten$1(arr, depth = 1) {
266
+ if (depth === 0)
267
+ return arr;
268
+ return arr.reduce((acc, val) => {
269
+ return acc.concat(Array.isArray(val) ? flatten$1(val, depth - 1) : val);
270
+ }, []);
271
+ }
272
+
273
+ var array = /*#__PURE__*/Object.freeze({
274
+ __proto__: null,
275
+ chunk: chunk,
276
+ difference: difference,
277
+ flatten: flatten$1,
278
+ groupBy: groupBy,
279
+ intersection: intersection,
280
+ randomElement: randomElement,
281
+ randomElementIndex: randomElementIndex,
282
+ shuffle: shuffle,
283
+ sort: sort,
284
+ sortBy: sortBy,
285
+ sortByKeys: sortByKeys,
286
+ unique: unique
287
+ });
288
+
289
+ /**
290
+ * Generate a random integer between min and max (inclusive)
291
+ * @param min - Minimum value
292
+ * @param max - Maximum value
293
+ * @returns Random integer
294
+ */
295
+ function randomInt$1(min, max) {
296
+ if (max < min) {
297
+ [max, min] = [min, max];
298
+ }
299
+ return Math.floor(Math.random() * (max - min + 1)) + min;
300
+ }
301
+ /**
302
+ * Generate a random float between min and max
303
+ * @param min - Minimum value
304
+ * @param max - Maximum value
305
+ * @returns Random float
306
+ */
307
+ function randomFloat$1(min, max) {
308
+ if (max < min) {
309
+ [max, min] = [min, max];
310
+ }
311
+ return Math.random() * (max - min) + min;
312
+ }
313
+ /**
314
+ * Round a number to specified decimal places
315
+ * @param value - Value to round
316
+ * @param decimals - Number of decimal places
317
+ * @param mode - Rounding mode ('round' or 'truncate')
318
+ * @returns Rounded number
319
+ */
320
+ function round(value, decimals, mode = 'round') {
321
+ const factor = Math.pow(10, decimals);
322
+ if (mode === 'truncate') {
323
+ return Math.trunc(value * factor) / factor;
324
+ }
325
+ return Math.round(value * factor) / factor;
326
+ }
327
+ /**
328
+ * Linear interpolation between two values
329
+ * @param start - Start value
330
+ * @param end - End value
331
+ * @param amount - Interpolation amount (0-1)
332
+ * @returns Interpolated value
333
+ */
334
+ function lerp(start, end, amount) {
335
+ amount = Math.max(0, Math.min(1, amount));
336
+ return start + (end - start) * amount;
337
+ }
338
+ /**
339
+ * Linear interpolation between two 2D points
340
+ * @param point1 - First point
341
+ * @param point2 - Second point
342
+ * @param amount - Interpolation amount (0-1)
343
+ * @returns Interpolated point
344
+ */
345
+ function lerp2D(point1, point2, amount) {
346
+ return {
347
+ x: lerp(point1.x, point2.x, amount),
348
+ y: lerp(point1.y, point2.y, amount),
349
+ };
350
+ }
351
+ /**
352
+ * Linear interpolation between two 3D vectors
353
+ * @param vec1 - First vector
354
+ * @param vec2 - Second vector
355
+ * @param amount - Interpolation amount (0-1)
356
+ * @returns Interpolated vector
357
+ */
358
+ function lerp3D(vec1, vec2, amount) {
359
+ return {
360
+ x: lerp(vec1.x, vec2.x, amount),
361
+ y: lerp(vec1.y, vec2.y, amount),
362
+ z: lerp(vec1.z, vec2.z, amount),
363
+ };
364
+ }
365
+ /**
366
+ * Calculate time-based interpolation value
367
+ * @param start - Start timestamp
368
+ * @param end - End timestamp
369
+ * @param current - Current timestamp (default: Date.now())
370
+ * @returns Interpolation value (0-1)
371
+ */
372
+ function lerpTime(start, end, current = Date.now()) {
373
+ const duration = current - start;
374
+ return Math.max(0, Math.min(1, duration / (end - start)));
375
+ }
376
+ /**
377
+ * Clamp a value between min and max
378
+ * @param value - Value to clamp
379
+ * @param min - Minimum value
380
+ * @param max - Maximum value
381
+ * @returns Clamped value
382
+ */
383
+ function clamp(value, min, max) {
384
+ return Math.max(min, Math.min(max, value));
385
+ }
386
+ /**
387
+ * Map a value from one range to another
388
+ * @param value - Value to map
389
+ * @param inMin - Input range minimum
390
+ * @param inMax - Input range maximum
391
+ * @param outMin - Output range minimum
392
+ * @param outMax - Output range maximum
393
+ * @returns Mapped value
394
+ */
395
+ function mapRange(value, inMin, inMax, outMin, outMax) {
396
+ return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
397
+ }
398
+ /**
399
+ * Calculate percentage
400
+ * @param value - Value
401
+ * @param total - Total value
402
+ * @returns Percentage (0-100)
403
+ */
404
+ function percentage(value, total) {
405
+ if (total === 0)
406
+ return 0;
407
+ return (value / total) * 100;
408
+ }
409
+ /**
410
+ * Calculate average of numbers
411
+ * @param numbers - Array of numbers
412
+ * @returns Average value
413
+ */
414
+ function average(numbers) {
415
+ if (numbers.length === 0)
416
+ return 0;
417
+ return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
418
+ }
419
+ /**
420
+ * Calculate sum of numbers
421
+ * @param numbers - Array of numbers
422
+ * @returns Sum
423
+ */
424
+ function sum(numbers) {
425
+ return numbers.reduce((total, num) => total + num, 0);
426
+ }
427
+ /**
428
+ * Find minimum value in array
429
+ * @param numbers - Array of numbers
430
+ * @returns Minimum value
431
+ */
432
+ function min(numbers) {
433
+ return Math.min(...numbers);
434
+ }
435
+ /**
436
+ * Find maximum value in array
437
+ * @param numbers - Array of numbers
438
+ * @returns Maximum value
439
+ */
440
+ function max(numbers) {
441
+ return Math.max(...numbers);
442
+ }
443
+
444
+ var math = /*#__PURE__*/Object.freeze({
445
+ __proto__: null,
446
+ average: average,
447
+ clamp: clamp,
448
+ lerp: lerp,
449
+ lerp2D: lerp2D,
450
+ lerp3D: lerp3D,
451
+ lerpTime: lerpTime,
452
+ mapRange: mapRange,
453
+ max: max,
454
+ min: min,
455
+ percentage: percentage,
456
+ randomFloat: randomFloat$1,
457
+ randomInt: randomInt$1,
458
+ round: round,
459
+ sum: sum
460
+ });
461
+
462
+ /**
463
+ * Get current Unix timestamp in seconds
464
+ * @returns Current timestamp
465
+ */
466
+ function timestamp() {
467
+ return Math.floor(Date.now() / 1000);
468
+ }
469
+ /**
470
+ * Get current Unix timestamp in milliseconds
471
+ * @returns Current timestamp in ms
472
+ */
473
+ function timestampMs() {
474
+ return Date.now();
475
+ }
476
+ /**
477
+ * Format a number with leading zero
478
+ * @param num - Number to format
479
+ * @returns Formatted string
480
+ */
481
+ function padZero(num) {
482
+ return `0${num}`.slice(-2);
483
+ }
484
+ /**
485
+ * Get full date and time string
486
+ * @param date - Date object (default: current date)
487
+ * @returns Formatted date string (DD.MM.YYYY HH:MM)
488
+ */
489
+ function formatDateTime(date = new Date()) {
490
+ return `${padZero(date.getDate())}.${padZero(date.getMonth() + 1)}.${date.getFullYear()} ${padZero(date.getHours())}:${padZero(date.getMinutes())}`;
491
+ }
492
+ /**
493
+ * Get full date and time string with seconds
494
+ * @param date - Date object (default: current date)
495
+ * @returns Formatted date string (DD.MM.YYYY HH:MM:SS)
496
+ */
497
+ function formatDateTimeSeconds(date = new Date()) {
498
+ return `${padZero(date.getDate())}.${padZero(date.getMonth() + 1)}.${date.getFullYear()} ${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`;
499
+ }
500
+ /**
501
+ * Get date without time
502
+ * @param date - Date object (default: current date)
503
+ * @returns Formatted date string (DD.MM.YYYY)
504
+ */
505
+ function formatDate(date = new Date()) {
506
+ return `${padZero(date.getDate())}.${padZero(date.getMonth() + 1)}.${date.getFullYear()}`;
507
+ }
508
+ /**
509
+ * Format timestamp to readable date/time string
510
+ * Shows only time if date is today, otherwise shows date and time
511
+ * @param time - Unix timestamp in seconds (default: current time)
512
+ * @param alwaysShowDate - Always show date even if today
513
+ * @returns Formatted string
514
+ */
515
+ function formatTimestamp(time = timestamp(), alwaysShowDate = false) {
516
+ const now = new Date();
517
+ const date = new Date(time * 1000);
518
+ let result = `${padZero(date.getHours())}:${padZero(date.getMinutes())}`;
519
+ const isToday = now.getDate() === date.getDate() &&
520
+ now.getMonth() === date.getMonth() &&
521
+ now.getFullYear() === date.getFullYear();
522
+ if (alwaysShowDate || !isToday) {
523
+ const showYear = now.getFullYear() !== date.getFullYear() || alwaysShowDate;
524
+ result = `${padZero(date.getDate())}.${padZero(date.getMonth() + 1)}${showYear ? `.${date.getFullYear()}` : ''} ${result}`;
525
+ }
526
+ return result;
527
+ }
528
+ /**
529
+ * Convert seconds to formatted duration string (HH:MM:SS or D:HH:MM:SS)
530
+ * @param seconds - Duration in seconds
531
+ * @returns Formatted duration string
532
+ */
533
+ function formatDuration(seconds) {
534
+ const days = Math.floor(seconds / 86400);
535
+ const hours = Math.floor((seconds % 86400) / 3600);
536
+ const minutes = Math.floor((seconds % 3600) / 60);
537
+ const secs = seconds % 60;
538
+ let result = '';
539
+ if (days > 0) {
540
+ result += `${days}:`;
541
+ }
542
+ result += `${hours.toString().padStart(2, '0')}:`;
543
+ result += `${minutes.toString().padStart(2, '0')}:`;
544
+ result += `${secs.toString().padStart(2, '0')}`;
545
+ return result;
546
+ }
547
+ /**
548
+ * Convert milliseconds to formatted duration string with ms
549
+ * @param ms - Duration in milliseconds
550
+ * @returns Formatted duration string (HH:MM:SS.mmm)
551
+ */
552
+ function formatDurationMs(ms) {
553
+ const seconds = Math.floor(ms / 1000);
554
+ let result = formatDuration(seconds);
555
+ const milliseconds = (ms % 1000).toString().padStart(3, '0');
556
+ result += `.${milliseconds}`;
557
+ return result;
558
+ }
559
+ /**
560
+ * Sleep/delay for specified milliseconds
561
+ * @param ms - Milliseconds to sleep
562
+ * @returns Promise that resolves after delay
563
+ */
564
+ function sleep(ms) {
565
+ return new Promise((resolve) => setTimeout(resolve, ms));
566
+ }
567
+ /**
568
+ * Check if a date is today
569
+ * @param date - Date to check
570
+ * @returns True if date is today
571
+ */
572
+ function isToday(date) {
573
+ const today = new Date();
574
+ return (date.getDate() === today.getDate() &&
575
+ date.getMonth() === today.getMonth() &&
576
+ date.getFullYear() === today.getFullYear());
577
+ }
578
+ /**
579
+ * Check if a date is yesterday
580
+ * @param date - Date to check
581
+ * @returns True if date is yesterday
582
+ */
583
+ function isYesterday(date) {
584
+ const yesterday = new Date();
585
+ yesterday.setDate(yesterday.getDate() - 1);
586
+ return (date.getDate() === yesterday.getDate() &&
587
+ date.getMonth() === yesterday.getMonth() &&
588
+ date.getFullYear() === yesterday.getFullYear());
589
+ }
590
+ /**
591
+ * Get relative time string (e.g., "2 hours ago", "in 3 days")
592
+ * @param date - Date to compare
593
+ * @param now - Reference date (default: current date)
594
+ * @returns Relative time string
595
+ */
596
+ function timeAgo(date, now = new Date()) {
597
+ const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
598
+ const isFuture = seconds < 0;
599
+ const absSeconds = Math.abs(seconds);
600
+ const intervals = [
601
+ { label: 'year', seconds: 31536000 },
602
+ { label: 'month', seconds: 2592000 },
603
+ { label: 'week', seconds: 604800 },
604
+ { label: 'day', seconds: 86400 },
605
+ { label: 'hour', seconds: 3600 },
606
+ { label: 'minute', seconds: 60 },
607
+ ];
608
+ for (const interval of intervals) {
609
+ const count = Math.floor(absSeconds / interval.seconds);
610
+ if (count >= 1) {
611
+ const plural = count > 1 ? 's' : '';
612
+ return isFuture
613
+ ? `in ${count} ${interval.label}${plural}`
614
+ : `${count} ${interval.label}${plural} ago`;
615
+ }
616
+ }
617
+ return 'just now';
618
+ }
619
+
620
+ var time = /*#__PURE__*/Object.freeze({
621
+ __proto__: null,
622
+ formatDate: formatDate,
623
+ formatDateTime: formatDateTime,
624
+ formatDateTimeSeconds: formatDateTimeSeconds,
625
+ formatDuration: formatDuration,
626
+ formatDurationMs: formatDurationMs,
627
+ formatTimestamp: formatTimestamp,
628
+ isToday: isToday,
629
+ isYesterday: isYesterday,
630
+ padZero: padZero,
631
+ sleep: sleep,
632
+ timeAgo: timeAgo,
633
+ timestamp: timestamp,
634
+ timestampMs: timestampMs
635
+ });
636
+
637
+ /**
638
+ * Encode string to Base64
639
+ * @param str - String to encode
640
+ * @returns Base64 encoded string
641
+ */
642
+ function toBase64(str) {
643
+ if (typeof Buffer !== 'undefined') {
644
+ return Buffer.from(str, 'utf-8').toString('base64');
645
+ }
646
+ // Browser environment
647
+ const codeUnits = new Uint16Array(str.length);
648
+ for (let i = 0; i < codeUnits.length; i++) {
649
+ codeUnits[i] = str.charCodeAt(i);
650
+ }
651
+ const uint8Array = new Uint8Array(codeUnits.buffer);
652
+ const chunkSize = 0x8000;
653
+ let result = '';
654
+ for (let i = 0; i < uint8Array.length; i += chunkSize) {
655
+ const chunk = uint8Array.subarray(i, i + chunkSize);
656
+ result += String.fromCharCode(...chunk);
657
+ }
658
+ return btoa(result);
659
+ }
660
+ /**
661
+ * Decode Base64 string
662
+ * @param encoded - Base64 encoded string
663
+ * @returns Decoded string
664
+ */
665
+ function fromBase64(encoded) {
666
+ if (typeof Buffer !== 'undefined') {
667
+ return Buffer.from(encoded, 'base64').toString('utf-8');
668
+ }
669
+ // Browser environment
670
+ const binary = atob(encoded);
671
+ const bytes = new Uint8Array(binary.length);
672
+ for (let i = 0; i < bytes.length; i++) {
673
+ bytes[i] = binary.charCodeAt(i);
674
+ }
675
+ return String.fromCharCode(...new Uint16Array(bytes.buffer));
676
+ }
677
+ /**
678
+ * Generate MD5 hash of a string
679
+ * @param text - Text to hash
680
+ * @returns MD5 hash
681
+ */
682
+ function hash(text) {
683
+ return md5(text);
684
+ }
685
+ /**
686
+ * Encode URI component safely
687
+ * @param str - String to encode
688
+ * @returns Encoded URI component
689
+ */
690
+ function encodeUri(str) {
691
+ return encodeURIComponent(str);
692
+ }
693
+ /**
694
+ * Decode URI component safely
695
+ * @param str - String to decode
696
+ * @returns Decoded URI component
697
+ */
698
+ function decodeUri(str) {
699
+ try {
700
+ return decodeURIComponent(str);
701
+ }
702
+ catch {
703
+ return str;
704
+ }
705
+ }
706
+ /**
707
+ * Convert ArrayBuffer to Buffer (Node.js)
708
+ * @param ab - ArrayBuffer to convert
709
+ * @returns Buffer
710
+ */
711
+ function arrayBufferToBuffer(ab) {
712
+ const buf = Buffer.alloc(ab.byteLength);
713
+ const view = new Uint8Array(ab);
714
+ for (let i = 0; i < buf.length; i++) {
715
+ buf[i] = view[i];
716
+ }
717
+ return buf;
718
+ }
719
+ /**
720
+ * Convert hex string to bytes
721
+ * @param hex - Hex string
722
+ * @returns Uint8Array
723
+ */
724
+ function hexToBytes(hex) {
725
+ const bytes = new Uint8Array(hex.length / 2);
726
+ for (let i = 0; i < bytes.length; i++) {
727
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
728
+ }
729
+ return bytes;
730
+ }
731
+ /**
732
+ * Convert bytes to hex string
733
+ * @param bytes - Byte array
734
+ * @returns Hex string
735
+ */
736
+ function bytesToHex(bytes) {
737
+ return Array.from(bytes)
738
+ .map((b) => b.toString(16).padStart(2, '0'))
739
+ .join('');
740
+ }
741
+
742
+ var encoding = /*#__PURE__*/Object.freeze({
743
+ __proto__: null,
744
+ arrayBufferToBuffer: arrayBufferToBuffer,
745
+ bytesToHex: bytesToHex,
746
+ decodeUri: decodeUri,
747
+ encodeUri: encodeUri,
748
+ fromBase64: fromBase64,
749
+ hash: hash,
750
+ hexToBytes: hexToBytes,
751
+ toBase64: toBase64
752
+ });
753
+
754
+ /**
755
+ * Check if a string is a valid emoji
756
+ * @param str - String to check
757
+ * @returns True if string is an emoji
758
+ */
759
+ function isEmoji(str) {
760
+ const emojiRegex = new RegExp('^(' +
761
+ // Regular and compound emojis
762
+ '(?:\\p{Extended_Pictographic}(?:\\p{Emoji_Modifier}|\\uFE0F)?' +
763
+ '(?:\\u200D\\p{Extended_Pictographic}(?:\\p{Emoji_Modifier}|\\uFE0F)?)*)' +
764
+ '|' +
765
+ // Flags (regional indicator pairs)
766
+ '(?:\\p{Regional_Indicator}{2})' +
767
+ ')$', 'u');
768
+ return emojiRegex.test(str);
769
+ }
770
+ /**
771
+ * Check if a URL is an image link
772
+ * @param url - URL to check
773
+ * @returns True if URL points to an image
774
+ */
775
+ function isImageUrl(url) {
776
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)(\?.*)?$/i;
777
+ return imageExtensions.test(url);
778
+ }
779
+ /**
780
+ * Check if a string is a valid email
781
+ * @param email - Email string to validate
782
+ * @returns True if email is valid
783
+ */
784
+ function isEmail(email) {
785
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
786
+ return emailRegex.test(email);
787
+ }
788
+ /**
789
+ * Check if a string is a valid URL
790
+ * @param url - URL string to validate
791
+ * @returns True if URL is valid
792
+ */
793
+ function isUrl(url) {
794
+ try {
795
+ new URL(url);
796
+ return true;
797
+ }
798
+ catch {
799
+ return false;
800
+ }
801
+ }
802
+ /**
803
+ * Check if a string contains only numbers
804
+ * @param str - String to check
805
+ * @returns True if string contains only numbers
806
+ */
807
+ function isNumeric(str) {
808
+ return /^\d+$/.test(str);
809
+ }
810
+ /**
811
+ * Check if a string contains only letters
812
+ * @param str - String to check
813
+ * @returns True if string contains only letters
814
+ */
815
+ function isAlpha(str) {
816
+ return /^[a-zA-Z]+$/.test(str);
817
+ }
818
+ /**
819
+ * Check if a string contains only letters and numbers
820
+ * @param str - String to check
821
+ * @returns True if string is alphanumeric
822
+ */
823
+ function isAlphanumeric(str) {
824
+ return /^[a-zA-Z0-9]+$/.test(str);
825
+ }
826
+ /**
827
+ * Check if a value is empty (null, undefined, empty string, empty array, empty object)
828
+ * @param value - Value to check
829
+ * @returns True if value is empty
830
+ */
831
+ function isEmpty(value) {
832
+ if (value === null || value === undefined)
833
+ return true;
834
+ if (typeof value === 'string')
835
+ return value.trim().length === 0;
836
+ if (Array.isArray(value))
837
+ return value.length === 0;
838
+ if (typeof value === 'object')
839
+ return Object.keys(value).length === 0;
840
+ return false;
841
+ }
842
+ /**
843
+ * Check if a value is a plain object
844
+ * @param value - Value to check
845
+ * @returns True if value is a plain object
846
+ */
847
+ function isPlainObject(value) {
848
+ return (typeof value === 'object' &&
849
+ value !== null &&
850
+ value.constructor === Object &&
851
+ Object.prototype.toString.call(value) === '[object Object]');
852
+ }
853
+ /**
854
+ * Extract URL information from a string
855
+ * @param str - String containing URL
856
+ * @returns URL info or null if no URL found
857
+ */
858
+ function extractUrl(str) {
859
+ const urlRegex = /(https?:\/\/[^\s]+|www\.[^\s]+|[\w-]+\.[\w-]+[^\s]*)/i;
860
+ const match = str.match(urlRegex);
861
+ if (!match)
862
+ return null;
863
+ const rawUrl = match[0].startsWith('http') ? match[0] : `https://${match[0]}`;
864
+ try {
865
+ const parsed = new URL(rawUrl);
866
+ return {
867
+ url: parsed.href,
868
+ domain: parsed.hostname.replace(/^www\./, ''),
869
+ };
870
+ }
871
+ catch {
872
+ return null;
873
+ }
874
+ }
875
+ /**
876
+ * Check if a string is a valid IPv4 address
877
+ * @param ip - IP address string
878
+ * @returns True if valid IPv4
879
+ */
880
+ function isIPv4(ip) {
881
+ const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
882
+ return ipv4Regex.test(ip);
883
+ }
884
+ /**
885
+ * Check if a string is a valid hex color
886
+ * @param color - Color string
887
+ * @returns True if valid hex color
888
+ */
889
+ function isHexColor(color) {
890
+ return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);
891
+ }
892
+
893
+ var validation = /*#__PURE__*/Object.freeze({
894
+ __proto__: null,
895
+ extractUrl: extractUrl,
896
+ isAlpha: isAlpha,
897
+ isAlphanumeric: isAlphanumeric,
898
+ isEmail: isEmail,
899
+ isEmoji: isEmoji,
900
+ isEmpty: isEmpty,
901
+ isHexColor: isHexColor,
902
+ isIPv4: isIPv4,
903
+ isImageUrl: isImageUrl,
904
+ isNumeric: isNumeric,
905
+ isPlainObject: isPlainObject,
906
+ isUrl: isUrl
907
+ });
908
+
909
+ /**
910
+ * Format a number with thousands separators
911
+ * @param num - Number to format
912
+ * @param removeTrailingZeros - Remove .00 from integers (default: true)
913
+ * @returns Formatted number string
914
+ */
915
+ function formatNumber(num, removeTrailingZeros = true) {
916
+ if (typeof num !== 'number') {
917
+ num = Number(num);
918
+ }
919
+ let n = num.toFixed(2);
920
+ if (removeTrailingZeros) {
921
+ n = n.replace('.00', '');
922
+ }
923
+ return n.replace(/.+?(?=\D|$)/, (match) => {
924
+ return match.replace(/(\d)(?=(?:\d{3})+$)/g, '$1 ');
925
+ });
926
+ }
927
+ /**
928
+ * Format bytes to human-readable size
929
+ * @param bytes - Number of bytes
930
+ * @param decimals - Decimal places (default: 2)
931
+ * @returns Formatted size string
932
+ */
933
+ function formatBytes(bytes, decimals = 2) {
934
+ if (bytes === 0)
935
+ return '0 Bytes';
936
+ const k = 1024;
937
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
938
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
939
+ return (parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]);
940
+ }
941
+ /**
942
+ * Format a number as currency
943
+ * @param amount - Amount to format
944
+ * @param currency - Currency code (default: 'USD')
945
+ * @param locale - Locale for formatting (default: 'en-US')
946
+ * @returns Formatted currency string
947
+ */
948
+ function formatCurrency(amount, currency = 'USD', locale = 'en-US') {
949
+ return new Intl.NumberFormat(locale, {
950
+ style: 'currency',
951
+ currency: currency,
952
+ }).format(amount);
953
+ }
954
+ /**
955
+ * Format a phone number (basic US format)
956
+ * @param phone - Phone number string
957
+ * @returns Formatted phone number
958
+ */
959
+ function formatPhone(phone) {
960
+ const cleaned = phone.replace(/\D/g, '');
961
+ if (cleaned.length === 10) {
962
+ return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;
963
+ }
964
+ if (cleaned.length === 11 && cleaned[0] === '1') {
965
+ return `+1 (${cleaned.slice(1, 4)}) ${cleaned.slice(4, 7)}-${cleaned.slice(7)}`;
966
+ }
967
+ return phone;
968
+ }
969
+ /**
970
+ * Format a credit card number with spaces
971
+ * @param cardNumber - Card number string
972
+ * @returns Formatted card number
973
+ */
974
+ function formatCardNumber(cardNumber) {
975
+ const cleaned = cardNumber.replace(/\s/g, '');
976
+ const groups = cleaned.match(/.{1,4}/g);
977
+ return groups ? groups.join(' ') : cardNumber;
978
+ }
979
+ /**
980
+ * Mask sensitive data (show only last N characters)
981
+ * @param str - String to mask
982
+ * @param visibleChars - Number of visible characters at the end (default: 4)
983
+ * @param maskChar - Character to use for masking (default: '*')
984
+ * @returns Masked string
985
+ */
986
+ function maskString(str, visibleChars = 4, maskChar = '*') {
987
+ if (str.length <= visibleChars)
988
+ return str;
989
+ const masked = maskChar.repeat(str.length - visibleChars);
990
+ return masked + str.slice(-visibleChars);
991
+ }
992
+ /**
993
+ * Format percentage
994
+ * @param value - Value to format
995
+ * @param decimals - Decimal places (default: 2)
996
+ * @returns Formatted percentage string
997
+ */
998
+ function formatPercentage(value, decimals = 2) {
999
+ return `${value.toFixed(decimals)}%`;
1000
+ }
1001
+ /**
1002
+ * Pluralize a word based on count
1003
+ * @param count - Count number
1004
+ * @param singular - Singular form
1005
+ * @param plural - Plural form (optional, will add 's' if not provided)
1006
+ * @returns Pluralized string with count
1007
+ */
1008
+ function pluralize(count, singular, plural) {
1009
+ const word = count === 1 ? singular : plural || `${singular}s`;
1010
+ return `${count} ${word}`;
1011
+ }
1012
+ /**
1013
+ * Abbreviate large numbers (1000 -> 1K, 1000000 -> 1M)
1014
+ * @param num - Number to abbreviate
1015
+ * @param decimals - Decimal places (default: 1)
1016
+ * @returns Abbreviated number string
1017
+ */
1018
+ function abbreviateNumber(num, decimals = 1) {
1019
+ if (num < 1000)
1020
+ return num.toString();
1021
+ const units = ['K', 'M', 'B', 'T'];
1022
+ const order = Math.floor(Math.log10(num) / 3);
1023
+ const unitIndex = order - 1;
1024
+ if (unitIndex >= units.length) {
1025
+ return num.toExponential(decimals);
1026
+ }
1027
+ const value = num / Math.pow(1000, order);
1028
+ return `${value.toFixed(decimals)}${units[unitIndex]}`;
1029
+ }
1030
+ /**
1031
+ * Format file name with extension
1032
+ * @param name - File name without extension
1033
+ * @param extension - File extension
1034
+ * @returns Formatted file name
1035
+ */
1036
+ function formatFileName(name, extension) {
1037
+ const cleanName = name.replace(/[^a-z0-9_-]/gi, '_');
1038
+ const cleanExt = extension.replace(/^\./, '');
1039
+ return `${cleanName}.${cleanExt}`;
1040
+ }
1041
+ /**
1042
+ * Title case a string (capitalize first letter of each word)
1043
+ * @param str - String to title case
1044
+ * @returns Title cased string
1045
+ */
1046
+ function titleCase(str) {
1047
+ return str
1048
+ .toLowerCase()
1049
+ .split(' ')
1050
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
1051
+ .join(' ');
1052
+ }
1053
+
1054
+ var format = /*#__PURE__*/Object.freeze({
1055
+ __proto__: null,
1056
+ abbreviateNumber: abbreviateNumber,
1057
+ formatBytes: formatBytes,
1058
+ formatCardNumber: formatCardNumber,
1059
+ formatCurrency: formatCurrency,
1060
+ formatFileName: formatFileName,
1061
+ formatNumber: formatNumber,
1062
+ formatPercentage: formatPercentage,
1063
+ formatPhone: formatPhone,
1064
+ maskString: maskString,
1065
+ pluralize: pluralize,
1066
+ titleCase: titleCase
1067
+ });
1068
+
1069
+ /**
1070
+ * Generate a random integer between min and max (inclusive)
1071
+ * @param min - Minimum value
1072
+ * @param max - Maximum value
1073
+ * @returns Random integer
1074
+ */
1075
+ function randomInt(min, max) {
1076
+ if (max < min) {
1077
+ [max, min] = [min, max];
1078
+ }
1079
+ return Math.floor(Math.random() * (max - min + 1)) + min;
1080
+ }
1081
+ /**
1082
+ * Generate a random float between min and max
1083
+ * @param min - Minimum value
1084
+ * @param max - Maximum value
1085
+ * @returns Random float
1086
+ */
1087
+ function randomFloat(min, max) {
1088
+ if (max < min) {
1089
+ [max, min] = [min, max];
1090
+ }
1091
+ return Math.random() * (max - min) + min;
1092
+ }
1093
+ /**
1094
+ * Generate a random boolean
1095
+ * @param probability - Probability of true (0-1, default: 0.5)
1096
+ * @returns Random boolean
1097
+ */
1098
+ function randomBoolean(probability = 0.5) {
1099
+ return Math.random() < probability;
1100
+ }
1101
+ /**
1102
+ * Pick N random unique elements from an array
1103
+ * @param arr - Array to pick from
1104
+ * @param count - Number of elements to pick
1105
+ * @returns Array of random elements
1106
+ */
1107
+ function randomSample(arr, count) {
1108
+ const shuffled = [...arr].sort(() => Math.random() - 0.5);
1109
+ return shuffled.slice(0, Math.min(count, arr.length));
1110
+ }
1111
+ /**
1112
+ * Generate a random hex color
1113
+ * @returns Random hex color string
1114
+ */
1115
+ function randomColor() {
1116
+ return `#${Math.floor(Math.random() * 16777215)
1117
+ .toString(16)
1118
+ .padStart(6, '0')}`;
1119
+ }
1120
+ /**
1121
+ * Generate a random UUID v4
1122
+ * @returns UUID string
1123
+ */
1124
+ function randomUUID() {
1125
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
1126
+ const r = (Math.random() * 16) | 0;
1127
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
1128
+ return v.toString(16);
1129
+ });
1130
+ }
1131
+ /**
1132
+ * Generate random weighted choice based on weights
1133
+ * @param items - Array of items
1134
+ * @param weights - Array of weights (must match items length)
1135
+ * @returns Random item based on weights
1136
+ */
1137
+ function randomWeighted(items, weights) {
1138
+ if (items.length !== weights.length) {
1139
+ throw new Error('Items and weights arrays must have the same length');
1140
+ }
1141
+ const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
1142
+ let random = Math.random() * totalWeight;
1143
+ for (let i = 0; i < items.length; i++) {
1144
+ random -= weights[i];
1145
+ if (random <= 0) {
1146
+ return items[i];
1147
+ }
1148
+ }
1149
+ return items[items.length - 1];
1150
+ }
1151
+ /**
1152
+ * Generate a random date between two dates
1153
+ * @param start - Start date
1154
+ * @param end - End date
1155
+ * @returns Random date
1156
+ */
1157
+ function randomDate(start, end) {
1158
+ return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
1159
+ }
1160
+
1161
+ var random = /*#__PURE__*/Object.freeze({
1162
+ __proto__: null,
1163
+ randomBoolean: randomBoolean,
1164
+ randomColor: randomColor,
1165
+ randomDate: randomDate,
1166
+ randomFloat: randomFloat,
1167
+ randomInt: randomInt,
1168
+ randomSample: randomSample,
1169
+ randomUUID: randomUUID,
1170
+ randomWeighted: randomWeighted
1171
+ });
1172
+
1173
+ /**
1174
+ * Deep clone an object
1175
+ * @param obj - Object to clone
1176
+ * @returns Cloned object
1177
+ */
1178
+ function deepClone(obj) {
1179
+ if (obj === null || typeof obj !== 'object')
1180
+ return obj;
1181
+ if (obj instanceof Date)
1182
+ return new Date(obj.getTime());
1183
+ if (obj instanceof Array)
1184
+ return obj.map((item) => deepClone(item));
1185
+ if (obj instanceof Object) {
1186
+ const cloned = {};
1187
+ for (const key in obj) {
1188
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1189
+ cloned[key] = deepClone(obj[key]);
1190
+ }
1191
+ }
1192
+ return cloned;
1193
+ }
1194
+ return obj;
1195
+ }
1196
+ /**
1197
+ * Deep merge two or more objects (mutates target)
1198
+ */
1199
+ function deepMerge(target, ...sources) {
1200
+ for (const source of sources) {
1201
+ if (!isObject(source))
1202
+ continue;
1203
+ for (const key in source) {
1204
+ if (!Object.prototype.hasOwnProperty.call(source, key))
1205
+ continue;
1206
+ const sourceValue = source[key];
1207
+ const targetValue = target[key];
1208
+ if (isObject(sourceValue)) {
1209
+ if (!isObject(targetValue)) {
1210
+ target[key] = {};
1211
+ }
1212
+ deepMerge(target[key], sourceValue);
1213
+ }
1214
+ else {
1215
+ target[key] = sourceValue;
1216
+ }
1217
+ }
1218
+ }
1219
+ return target;
1220
+ }
1221
+ /**
1222
+ * Get nested property value from object using path
1223
+ * @param obj - Object to get value from
1224
+ * @param path - Property path (e.g., 'user.address.city')
1225
+ * @param defaultValue - Default value if path not found
1226
+ * @returns Property value or default
1227
+ */
1228
+ function get(obj, path, defaultValue) {
1229
+ const keys = path.split('.');
1230
+ let result = obj;
1231
+ for (const key of keys) {
1232
+ if (result && typeof result === 'object' && key in result) {
1233
+ result = result[key];
1234
+ }
1235
+ else {
1236
+ return defaultValue;
1237
+ }
1238
+ }
1239
+ return result;
1240
+ }
1241
+ /**
1242
+ * Set nested property value in object using path
1243
+ * @param obj - Object to set value in
1244
+ * @param path - Property path (e.g., 'user.address.city')
1245
+ * @param value - Value to set
1246
+ * @returns Modified object
1247
+ */
1248
+ function set(obj, path, value) {
1249
+ const keys = path.split('.');
1250
+ const lastKey = keys.pop();
1251
+ let current = obj;
1252
+ for (const key of keys) {
1253
+ if (!(key in current) || typeof current[key] !== 'object') {
1254
+ current[key] = {};
1255
+ }
1256
+ current = current[key];
1257
+ }
1258
+ current[lastKey] = value;
1259
+ return obj;
1260
+ }
1261
+ /**
1262
+ * Pick specific properties from object
1263
+ * @param obj - Source object
1264
+ * @param keys - Keys to pick
1265
+ * @returns New object with picked properties
1266
+ */
1267
+ function pick(obj, keys) {
1268
+ const result = {};
1269
+ for (const key of keys) {
1270
+ if (key in obj) {
1271
+ result[key] = obj[key];
1272
+ }
1273
+ }
1274
+ return result;
1275
+ }
1276
+ /**
1277
+ * Omit specific properties from object
1278
+ * @param obj - Source object
1279
+ * @param keys - Keys to omit
1280
+ * @returns New object without omitted properties
1281
+ */
1282
+ function omit(obj, keys) {
1283
+ const result = { ...obj };
1284
+ for (const key of keys) {
1285
+ delete result[key];
1286
+ }
1287
+ return result;
1288
+ }
1289
+ /**
1290
+ * Check if value is a plain object
1291
+ * @param value - Value to check
1292
+ * @returns True if plain object
1293
+ */
1294
+ function isObject(value) {
1295
+ return value && typeof value === 'object' && !Array.isArray(value);
1296
+ }
1297
+ /**
1298
+ * Flatten nested object to single level with dot notation keys
1299
+ * @param obj - Object to flatten
1300
+ * @param prefix - Key prefix (used internally)
1301
+ * @returns Flattened object
1302
+ */
1303
+ function flatten(obj, prefix = '') {
1304
+ const result = {};
1305
+ for (const key in obj) {
1306
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1307
+ const newKey = prefix ? `${prefix}.${key}` : key;
1308
+ if (isObject(obj[key]) && !Array.isArray(obj[key])) {
1309
+ Object.assign(result, flatten(obj[key], newKey));
1310
+ }
1311
+ else {
1312
+ result[newKey] = obj[key];
1313
+ }
1314
+ }
1315
+ }
1316
+ return result;
1317
+ }
1318
+ /**
1319
+ * Unflatten object with dot notation keys to nested object
1320
+ * @param obj - Flattened object
1321
+ * @returns Nested object
1322
+ */
1323
+ function unflatten(obj) {
1324
+ const result = {};
1325
+ for (const key in obj) {
1326
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1327
+ set(result, key, obj[key]);
1328
+ }
1329
+ }
1330
+ return result;
1331
+ }
1332
+ /**
1333
+ * Get all keys from object including nested keys (dot notation)
1334
+ * @param obj - Object to get keys from
1335
+ * @param prefix - Key prefix (used internally)
1336
+ * @returns Array of all keys
1337
+ */
1338
+ function keys(obj, prefix = '') {
1339
+ const result = [];
1340
+ for (const key in obj) {
1341
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1342
+ const newKey = prefix ? `${prefix}.${key}` : key;
1343
+ result.push(newKey);
1344
+ if (isObject(obj[key]) && !Array.isArray(obj[key])) {
1345
+ result.push(...keys(obj[key], newKey));
1346
+ }
1347
+ }
1348
+ }
1349
+ return result;
1350
+ }
1351
+ /**
1352
+ * Get all values from object including nested values
1353
+ * @param obj - Object to get values from
1354
+ * @returns Array of all values
1355
+ */
1356
+ function values(obj) {
1357
+ const result = [];
1358
+ for (const key in obj) {
1359
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
1360
+ if (isObject(obj[key]) && !Array.isArray(obj[key])) {
1361
+ result.push(...values(obj[key]));
1362
+ }
1363
+ else {
1364
+ result.push(obj[key]);
1365
+ }
1366
+ }
1367
+ }
1368
+ return result;
1369
+ }
1370
+ /**
1371
+ * Check if two objects are deeply equal
1372
+ * @param obj1 - First object
1373
+ * @param obj2 - Second object
1374
+ * @returns True if objects are equal
1375
+ */
1376
+ function isEqual(obj1, obj2) {
1377
+ if (obj1 === obj2)
1378
+ return true;
1379
+ if (typeof obj1 !== 'object' ||
1380
+ typeof obj2 !== 'object' ||
1381
+ obj1 === null ||
1382
+ obj2 === null) {
1383
+ return false;
1384
+ }
1385
+ const keys1 = Object.keys(obj1);
1386
+ const keys2 = Object.keys(obj2);
1387
+ if (keys1.length !== keys2.length)
1388
+ return false;
1389
+ for (const key of keys1) {
1390
+ if (!keys2.includes(key) || !isEqual(obj1[key], obj2[key])) {
1391
+ return false;
1392
+ }
1393
+ }
1394
+ return true;
1395
+ }
1396
+
1397
+ var object = /*#__PURE__*/Object.freeze({
1398
+ __proto__: null,
1399
+ deepClone: deepClone,
1400
+ deepMerge: deepMerge,
1401
+ flatten: flatten,
1402
+ get: get,
1403
+ isEqual: isEqual,
1404
+ keys: keys,
1405
+ omit: omit,
1406
+ pick: pick,
1407
+ set: set,
1408
+ unflatten: unflatten,
1409
+ values: values
1410
+ });
1411
+
1412
+ // Import all modules
1413
+ // Default export - all utilities in one object (like original System class)
1414
+ const toolkit = {
1415
+ string,
1416
+ array,
1417
+ math,
1418
+ time,
1419
+ encoding,
1420
+ validation,
1421
+ format,
1422
+ random,
1423
+ object,
1424
+ // Convenience shortcuts at top level
1425
+ randomString: randomString,
1426
+ capitalize: capitalize,
1427
+ truncate: truncate,
1428
+ randomElement: randomElement,
1429
+ chunk: chunk,
1430
+ unique: unique,
1431
+ shuffle: shuffle,
1432
+ randomInt: randomInt$1,
1433
+ randomFloat: randomFloat$1,
1434
+ lerp: lerp,
1435
+ clamp: clamp,
1436
+ round: round,
1437
+ timestamp: timestamp,
1438
+ timestampMs: timestampMs,
1439
+ formatDateTime: formatDateTime,
1440
+ formatDuration: formatDuration,
1441
+ sleep: sleep,
1442
+ toBase64: toBase64,
1443
+ fromBase64: fromBase64,
1444
+ hash: hash,
1445
+ isEmail: isEmail,
1446
+ isUrl: isUrl,
1447
+ isEmpty: isEmpty,
1448
+ isEmoji: isEmoji,
1449
+ formatNumber: formatNumber,
1450
+ formatBytes: formatBytes,
1451
+ pluralize: pluralize,
1452
+ randomBoolean: randomBoolean,
1453
+ randomColor: randomColor,
1454
+ randomUUID: randomUUID,
1455
+ deepClone: deepClone,
1456
+ pick: pick,
1457
+ omit: omit,
1458
+ get: get,
1459
+ set: set,
1460
+ };
1461
+
1462
+ exports.array = array;
1463
+ exports.capitalize = capitalize;
1464
+ exports.chunk = chunk;
1465
+ exports.clamp = clamp;
1466
+ exports.deepClone = deepClone;
1467
+ exports.default = toolkit;
1468
+ exports.encoding = encoding;
1469
+ exports.format = format;
1470
+ exports.formatBytes = formatBytes;
1471
+ exports.formatDateTime = formatDateTime;
1472
+ exports.formatDuration = formatDuration;
1473
+ exports.formatNumber = formatNumber;
1474
+ exports.fromBase64 = fromBase64;
1475
+ exports.get = get;
1476
+ exports.hash = hash;
1477
+ exports.isEmail = isEmail;
1478
+ exports.isEmoji = isEmoji;
1479
+ exports.isEmpty = isEmpty;
1480
+ exports.isUrl = isUrl;
1481
+ exports.lerp = lerp;
1482
+ exports.math = math;
1483
+ exports.object = object;
1484
+ exports.omit = omit;
1485
+ exports.pick = pick;
1486
+ exports.pluralize = pluralize;
1487
+ exports.random = random;
1488
+ exports.randomBoolean = randomBoolean;
1489
+ exports.randomColor = randomColor;
1490
+ exports.randomElement = randomElement;
1491
+ exports.randomFloat = randomFloat$1;
1492
+ exports.randomInt = randomInt$1;
1493
+ exports.randomString = randomString;
1494
+ exports.randomUUID = randomUUID;
1495
+ exports.round = round;
1496
+ exports.set = set;
1497
+ exports.shuffle = shuffle;
1498
+ exports.sleep = sleep;
1499
+ exports.string = string;
1500
+ exports.time = time;
1501
+ exports.timestamp = timestamp;
1502
+ exports.timestampMs = timestampMs;
1503
+ exports.toBase64 = toBase64;
1504
+ exports.unique = unique;
1505
+ exports.validation = validation;
1506
+ //# sourceMappingURL=index.js.map