@h3ravel/support 0.10.4 → 0.11.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.cjs CHANGED
@@ -5,6 +5,14 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (all) => {
9
+ let target = {};
10
+ for (var name in all) __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true
13
+ });
14
+ return target;
15
+ };
8
16
  var __copyProps = (to, from, except, desc) => {
9
17
  if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
18
  key = keys[i];
@@ -21,12 +29,33 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
29
  }) : target, mod));
22
30
 
23
31
  //#endregion
32
+ let crypto = require("crypto");
33
+ crypto = __toESM(crypto);
24
34
  let process = require("process");
25
35
  process = __toESM(process);
26
36
  let util = require("util");
27
37
  util = __toESM(util);
28
38
 
29
39
  //#region src/Helpers/Arr.ts
40
+ var Arr_exports = /* @__PURE__ */ __export({
41
+ alternate: () => alternate,
42
+ chunk: () => chunk,
43
+ collapse: () => collapse,
44
+ combine: () => combine,
45
+ find: () => find,
46
+ first: () => first,
47
+ flatten: () => flatten,
48
+ forget: () => forget,
49
+ isEmpty: () => isEmpty,
50
+ isNotEmpty: () => isNotEmpty,
51
+ last: () => last,
52
+ pop: () => pop,
53
+ prepend: () => prepend,
54
+ range: () => range,
55
+ reverse: () => reverse,
56
+ shift: () => shift,
57
+ take: () => take
58
+ });
30
59
  /**
31
60
  * Splits an array into chunks of a specified size.
32
61
  *
@@ -42,6 +71,67 @@ const chunk = (arr, size = 2) => {
42
71
  return chunks;
43
72
  };
44
73
  /**
74
+ * Collapse an array of arrays into a single array.
75
+ */
76
+ const collapse = (arr) => {
77
+ const result = [];
78
+ for (const item of arr) if (Array.isArray(item)) result.push(...item);
79
+ else result.push(item);
80
+ return result;
81
+ };
82
+ /**
83
+ * Alternates between two arrays, creating a zipped result.
84
+ */
85
+ const alternate = (a, b) => {
86
+ const result = [];
87
+ const max = Math.max(a.length, b.length);
88
+ for (let i = 0; i < max; i++) {
89
+ if (i < a.length) result.push(a[i]);
90
+ if (i < b.length) result.push(b[i]);
91
+ }
92
+ return result;
93
+ };
94
+ /**
95
+ * Combine arrays and sum their values element by element.
96
+ */
97
+ const combine = (...arr) => {
98
+ const maxLength = Math.max(...arr.map((a) => a.length));
99
+ const result = new Array(maxLength).fill(0);
100
+ for (let i = 0; i < maxLength; i++) for (const array of arr) result[i] += array[i] || 0;
101
+ return result;
102
+ };
103
+ /** Find the value associated with a given key. */
104
+ const find = (key, arr) => arr.find((item) => item === key) || null;
105
+ /** Returns a new array without the given indices. */
106
+ const forget = (arr, keys) => arr.filter((_, i) => !keys.includes(i));
107
+ /** Remove the first element and return tuple [el, rest]. */
108
+ const first = (arr) => {
109
+ if (!arr.length) throw new Error("Cannot shift from empty array");
110
+ return [arr[0], arr.slice(1)];
111
+ };
112
+ /** Remove the last element and return tuple [el, rest]. */
113
+ const last = (arr) => {
114
+ if (!arr.length) throw new Error("Cannot pop from empty array");
115
+ return [arr[arr.length - 1], arr.slice(0, -1)];
116
+ };
117
+ /** Check if array is empty. */
118
+ const isEmpty = (arr) => {
119
+ if (arr.length === 0) return true;
120
+ else return false;
121
+ };
122
+ /** Check if array is empty. */
123
+ const isNotEmpty = (arr) => arr.length > 0;
124
+ /** Pop the element off the end of array. */
125
+ const pop = (arr) => arr.slice(0, -1);
126
+ /** Add elements to the beginning of array. */
127
+ const prepend = (arr, ...elements) => [...elements, ...arr];
128
+ /** Take first n elements of array. */
129
+ const take = (amount, arr) => arr.slice(0, Math.max(0, amount));
130
+ /** Create a new array in reverse order. */
131
+ const reverse = (arr) => [...arr].reverse();
132
+ /** Alias for first element removal. */
133
+ const shift = first;
134
+ /**
45
135
  * Generates an array of sequential numbers.
46
136
  *
47
137
  * @param size - Number of elements in the range
@@ -52,40 +142,197 @@ const range = (size, startAt = 0) => {
52
142
  if (size <= 0 || !Number.isFinite(size)) return [];
53
143
  return Array.from({ length: size }, (_, i) => startAt + i);
54
144
  };
145
+ /** Flatten multi-dimensional arrays into single level. */
146
+ const flatten = (arr) => {
147
+ const result = [];
148
+ const recurse = (input) => {
149
+ for (const item of input) Array.isArray(item) ? recurse(item) : result.push(item);
150
+ };
151
+ recurse(arr);
152
+ return result;
153
+ };
55
154
 
56
155
  //#endregion
57
- //#region src/Helpers/DumpDie.ts
58
- const inspect = (thing) => {
59
- return util.default.inspect(thing, {
60
- showHidden: true,
61
- depth: null,
62
- colors: true
63
- });
156
+ //#region src/Helpers/Crypto.ts
157
+ var Crypto_exports = /* @__PURE__ */ __export({
158
+ base64Decode: () => base64Decode,
159
+ base64Encode: () => base64Encode,
160
+ caesarCipher: () => caesarCipher,
161
+ checksum: () => checksum,
162
+ hash: () => hash,
163
+ hmac: () => hmac,
164
+ random: () => random,
165
+ randomColor: () => randomColor,
166
+ randomPassword: () => randomPassword,
167
+ randomSecure: () => randomSecure,
168
+ secureToken: () => secureToken,
169
+ uuid: () => uuid,
170
+ verifyChecksum: () => verifyChecksum,
171
+ xor: () => xor
172
+ });
173
+ /**
174
+ * Generate a random UUID string.
175
+ *
176
+ * @returns A random UUID string
177
+ */
178
+ const uuid = () => {
179
+ return (0, crypto.randomUUID)();
64
180
  };
65
181
  /**
66
- * Dump something and kill the process for quick debugging. Based on Laravel's dd()
182
+ * Generate a random string of specified length.
67
183
  *
68
- * @param args
184
+ * @param length - Length of the random string (default: 16)
185
+ * @param charset - Character set to use (default: alphanumeric)
186
+ * @returns A random string
69
187
  */
70
- const dd = (...args) => {
71
- args.forEach((thing) => {
72
- console.log(inspect(thing));
73
- });
74
- process.default.exit(1);
188
+ const random = (length = 16, charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") => {
189
+ let result = "";
190
+ for (let i = 0; i < length; i++) result += charset.charAt(Math.floor(Math.random() * charset.length));
191
+ return result;
75
192
  };
76
193
  /**
77
- * Dump something but keep the process for quick debugging. Based on Laravel's dump()
194
+ * Secure random string generator that uses crypto.randomBytes.
78
195
  *
79
- * @param args
196
+ * @param length - Length of the random string (default: 32)
197
+ * @returns A cryptographically secure random string
80
198
  */
81
- const dump = (...args) => {
82
- args.forEach((thing) => {
83
- console.log(inspect(thing));
199
+ const randomSecure = (length = 32) => {
200
+ return (0, crypto.randomBytes)(Math.ceil(length / 2)).toString("hex").slice(0, length);
201
+ };
202
+ /**
203
+ * Hash a string using the specified algorithm.
204
+ *
205
+ * @param data - Data to hash
206
+ * @param algorithm - Hash algorithm (default: 'sha256')
207
+ * @returns Hexadecimal hash string
208
+ */
209
+ const hash = (data, algorithm = "sha256") => {
210
+ return (0, crypto.createHash)(algorithm).update(data).digest("hex");
211
+ };
212
+ /**
213
+ * Hash a string with salt using HMAC.
214
+ *
215
+ * @param data - Data to hash
216
+ * @param key - Secret key for HMAC
217
+ * @param algorithm - Hash algorithm (default: 'sha256')
218
+ * @returns Hexadecimal hash string
219
+ */
220
+ const hmac = (data, key, algorithm = "sha256") => {
221
+ return (0, crypto.createHmac)(algorithm, key).update(data).digest("hex");
222
+ };
223
+ /**
224
+ * Encode data to base64.
225
+ *
226
+ * @param data - Data to encode
227
+ * @returns Base64 encoded string
228
+ */
229
+ const base64Encode = (data) => {
230
+ return Buffer.from(data, "utf8").toString("base64");
231
+ };
232
+ /**
233
+ * Decode base64 data.
234
+ *
235
+ * @param data - Base64 string to decode
236
+ * @returns Decoded string
237
+ */
238
+ const base64Decode = (data) => {
239
+ return Buffer.from(data, "base64").toString("utf8");
240
+ };
241
+ /**
242
+ * Simple XOR encryption/decryption.
243
+ *
244
+ * @param data - Data to encrypt/decrypt
245
+ * @param key - Encryption key
246
+ * @returns Encrypted/decrypted string
247
+ */
248
+ const xor = (data, key) => {
249
+ let result = "";
250
+ const keyLength = key.length;
251
+ for (let i = 0; i < data.length; i++) {
252
+ const dataCharCode = data.charCodeAt(i);
253
+ const keyCharCode = key.charCodeAt(i % keyLength);
254
+ result += String.fromCharCode(dataCharCode ^ keyCharCode);
255
+ }
256
+ return result;
257
+ };
258
+ /**
259
+ * Generate a random hex color code.
260
+ *
261
+ * @returns A hex color code string (e.g., '#a3b2f3')
262
+ */
263
+ const randomColor = () => {
264
+ return `#${random(6, "0123456789abcdef").toLowerCase()}`;
265
+ };
266
+ const randomPassword = (length = 16, options = {}) => {
267
+ const opts = {
268
+ useUppercase: true,
269
+ useLowercase: true,
270
+ useNumbers: true,
271
+ useSymbols: true,
272
+ ...options
273
+ };
274
+ let charset = "";
275
+ if (opts.useUppercase) charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
276
+ if (opts.useLowercase) charset += "abcdefghijklmnopqrstuvwxyz";
277
+ if (opts.useNumbers) charset += "0123456789";
278
+ if (opts.useSymbols) charset += "!@#$%^&*()_+-=[]{}|;:,.<>?";
279
+ if (charset.length === 0) throw new Error("At least one character type must be enabled");
280
+ return random(length, charset);
281
+ };
282
+ /**
283
+ * Generate a cryptographically secure token for APIs, sessions, etc.
284
+ *
285
+ * @param strength - Token strength (bytes) (default: 32)
286
+ * @returns A secure token string
287
+ */
288
+ const secureToken = (strength = 32) => {
289
+ return (0, crypto.randomBytes)(strength).toString("hex");
290
+ };
291
+ /**
292
+ * Create a checksum for data integrity verification.
293
+ *
294
+ * @param data - Data to create checksum for
295
+ * @param algorithm - Hash algorithm (default: 'sha256')
296
+ * @returns SHA256 checksum
297
+ */
298
+ const checksum = (data, algorithm = "sha256") => {
299
+ return hash(data, algorithm);
300
+ };
301
+ /**
302
+ * Verify data integrity using checksum.
303
+ *
304
+ * @param data - Data to verify
305
+ * @param expectedChecksum - Expected checksum
306
+ * @param algorithm - Hash algorithm (default: 'sha256')
307
+ * @returns True if checksums match
308
+ */
309
+ const verifyChecksum = (data, expectedChecksum, algorithm = "sha256") => {
310
+ return checksum(data, algorithm) === expectedChecksum;
311
+ };
312
+ /**
313
+ * Simple Caesar cipher implementation.
314
+ *
315
+ * @param text - Text to encrypt/decrypt
316
+ * @param shift - Number of positions to shift (default: 13)
317
+ * @returns Encrypted/decrypted text
318
+ */
319
+ const caesarCipher = (text, shift$1 = 13) => {
320
+ return text.replace(/[a-zA-Z]/g, (char) => {
321
+ const baseCharCode = char === char.toUpperCase() ? "A" : "a";
322
+ const shiftedCharCode = (char.charCodeAt(0) - baseCharCode.charCodeAt(0) + shift$1) % 26;
323
+ const newCharCode = (shiftedCharCode < 0 ? 26 + shiftedCharCode : shiftedCharCode) + baseCharCode.charCodeAt(0);
324
+ return String.fromCharCode(newCharCode);
84
325
  });
85
326
  };
86
327
 
87
328
  //#endregion
88
329
  //#region src/Helpers/Number.ts
330
+ var Number_exports = /* @__PURE__ */ __export({
331
+ abbreviate: () => abbreviate,
332
+ humanize: () => humanize,
333
+ toBytes: () => toBytes,
334
+ toHumanTime: () => toHumanTime
335
+ });
89
336
  /**
90
337
  * Abbreviates large numbers using SI symbols (K, M, B...)
91
338
  * and formats the output according to the given locale.
@@ -185,10 +432,10 @@ const humanize = (num, slugify$1) => {
185
432
  if (numString.length == 3) if (numString[1] === "0" && numString[2] === "0") return ones[numString[0]] + " hundred";
186
433
  else return ones[numString[0]] + " hundred and " + humanize(+((numString[1] || "") + numString[2]), slugify$1);
187
434
  if (numString.length === 4) {
188
- const end = +((numString[1] || "") + numString[2] + numString[3]);
189
- if (end === 0) return ones[numString[0]] + " thousand";
190
- if (end < 100) return ones[numString[0]] + " thousand and " + humanize(end, slugify$1);
191
- return ones[numString[0]] + " thousand " + humanize(end, slugify$1);
435
+ const end$1 = +((numString[1] || "") + numString[2] + numString[3]);
436
+ if (end$1 === 0) return ones[numString[0]] + " thousand";
437
+ if (end$1 < 100) return ones[numString[0]] + " thousand and " + humanize(end$1, slugify$1);
438
+ return ones[numString[0]] + " thousand " + humanize(end$1, slugify$1);
192
439
  }
193
440
  return num;
194
441
  };
@@ -251,12 +498,21 @@ const toHumanTime = (seconds = 0, worded = false) => {
251
498
  }
252
499
  const hh = hours > 0 ? `${hours}:` : "";
253
500
  const mm = (hours > 0 && minutes < 10 ? `0${minutes}` : minutes) + ":";
254
- const ss = secs < 10 ? `0${secs}` : secs;
255
- return `${hh}${mm}${ss}`;
501
+ const ss$1 = secs < 10 ? `0${secs}` : secs;
502
+ return `${hh}${mm}${ss$1}`;
256
503
  };
257
504
 
258
505
  //#endregion
259
506
  //#region src/Helpers/Obj.ts
507
+ var Obj_exports = /* @__PURE__ */ __export({
508
+ dot: () => dot,
509
+ extractProperties: () => extractProperties,
510
+ getValue: () => getValue,
511
+ modObj: () => modObj,
512
+ safeDot: () => safeDot,
513
+ setNested: () => setNested,
514
+ slugifyKeys: () => slugifyKeys
515
+ });
260
516
  /**
261
517
  * Flattens a nested object into a single-level object
262
518
  * with dot-separated keys.
@@ -401,6 +657,33 @@ const slugifyKeys = (obj, only = [], separator = "_") => {
401
657
 
402
658
  //#endregion
403
659
  //#region src/Helpers/Str.ts
660
+ var Str_exports = /* @__PURE__ */ __export({
661
+ after: () => after,
662
+ afterLast: () => afterLast,
663
+ before: () => before,
664
+ beforeLast: () => beforeLast,
665
+ capitalize: () => capitalize,
666
+ chop: () => chop,
667
+ esc: () => esc,
668
+ firstLines: () => firstLines,
669
+ isInteger: () => isInteger,
670
+ isNumber: () => isNumber,
671
+ lastLines: () => lastLines,
672
+ padString: () => padString,
673
+ pluralize: () => pluralize,
674
+ replacePunctuation: () => replacePunctuation,
675
+ rot: () => rot,
676
+ singularize: () => singularize,
677
+ slugify: () => slugify,
678
+ split: () => split,
679
+ ss: () => ss,
680
+ sub: () => sub,
681
+ subString: () => subString,
682
+ substitute: () => substitute,
683
+ substr: () => substr,
684
+ translate: () => translate,
685
+ truncate: () => truncate
686
+ });
404
687
  /**
405
688
  * Get the portion of the string after the first occurrence of the given value.
406
689
  *
@@ -449,22 +732,13 @@ const beforeLast = (value, search) => {
449
732
  const lastIndex = value.lastIndexOf(search);
450
733
  return lastIndex !== -1 ? value.slice(0, lastIndex) : value;
451
734
  };
452
- /**
453
- * Capitalizes the first character of a string.
454
- *
455
- * @param str - The input string
456
- * @returns The string with the first character capitalized
457
- */
735
+ /** Capitalizes the first character of a string. */
458
736
  function capitalize(str) {
459
737
  if (!str) return "";
460
738
  return str[0].toUpperCase() + str.slice(1);
461
739
  }
462
740
  /**
463
741
  * Returns the pluralized form of a word based on the given number.
464
- *
465
- * @param word - The word to pluralize
466
- * @param count - The number determining pluralization
467
- * @returns Singular if count === 1, otherwise plural form
468
742
  */
469
743
  const pluralize = (word, count) => {
470
744
  if (count === 1) return word;
@@ -484,16 +758,11 @@ const pluralize = (word, count) => {
484
758
  "i",
485
759
  "o",
486
760
  "u"
487
- ].includes(word[word.length - 2]?.toLowerCase() ?? "")) return word.slice(0, -1) + "ies";
761
+ ].includes(word.at(-2)?.toLowerCase() ?? "")) return word.slice(0, -1) + "ies";
488
762
  if (/(s|ss|sh|ch|x|z)$/i.test(word)) return word + "es";
489
763
  return word + "s";
490
764
  };
491
- /**
492
- * Converts a plural English word into its singular form.
493
- *
494
- * @param word - The word to singularize
495
- * @returns The singular form of the word
496
- */
765
+ /** Converts a plural English word into its singular form. */
497
766
  const singularize = (word) => {
498
767
  const irregulars = {
499
768
  feet: "foot",
@@ -510,42 +779,17 @@ const singularize = (word) => {
510
779
  if (/s$/i.test(word) && word.length > 1) return word.replace(/s$/i, "");
511
780
  return word;
512
781
  };
513
- /**
514
- * Converts a string into a slug format.
515
- * Handles camelCase, spaces, and non-alphanumeric characters.
516
- *
517
- * @param str - The input string to slugify
518
- * @param joiner - The character used to join words (default: "_")
519
- * @returns A slugified string
520
- */
782
+ /** Converts a string into a slug format. */
521
783
  const slugify = (str, joiner = "_") => {
522
- return str.replace(/([a-z])([A-Z])/g, `$1${joiner}$2`).replace(/[\s\W]+/g, joiner).replace(new RegExp(`${joiner}{2,}`, "g"), joiner).replace(new RegExp(`^${joiner}|${joiner}$`, "g"), "").toLowerCase();
784
+ return str.replace(/([a-z])([A-Z])/g, `$1${joiner}$2`).replace(/[\s\W]+/g, joiner).replace(new RegExp(`${joiner}{2,}`, "g"), joiner).toLowerCase();
523
785
  };
524
- /**
525
- * Truncates a string to a specified length and appends an ellipsis if needed.
526
- *
527
- * @param str - The input string
528
- * @param len - Maximum length of the result (including ellipsis)
529
- * @param ellipsis - String to append if truncated (default: "...")
530
- * @returns The truncated string
531
- */
786
+ /** Truncates a string to a specified length and appends an ellipsis if needed. */
532
787
  const subString = (str, len, ellipsis = "...") => {
533
788
  if (!str) return "";
534
789
  if (len <= ellipsis.length) return ellipsis;
535
790
  return str.length > len ? str.substring(0, len - ellipsis.length).trimEnd() + ellipsis : str;
536
791
  };
537
- /**
538
- * Replaces placeholders in a string with corresponding values from a data object.
539
- *
540
- * Example:
541
- * substitute("Hello { user.name }!", { user: { name: "John" } })
542
- * // "Hello John!"
543
- *
544
- * @param str - The string containing placeholders wrapped in { } braces.
545
- * @param data - Object containing values to substitute. Supports nested keys via dot notation.
546
- * @param def - Default value to use if a key is missing. (Optional)
547
- * @returns The substituted string or undefined if the input string or data is invalid.
548
- */
792
+ /** Substitute placeholders { key } using object with dot notation. */
549
793
  const substitute = (str, data = {}, def) => {
550
794
  if (!str || !data) return void 0;
551
795
  const regex = /{\s*([a-zA-Z0-9_.]+)\s*}/g;
@@ -555,46 +799,674 @@ const substitute = (str, data = {}, def) => {
555
799
  return value !== void 0 ? String(value) : def ?? "";
556
800
  });
557
801
  };
558
- /**
559
- * Truncates a string to a specified length, removing HTML tags and
560
- * appending a suffix if the string exceeds the length.
561
- *
562
- * @param str - The string to truncate
563
- * @param len - Maximum length (default: 20)
564
- * @param suffix - Suffix to append if truncated (default: "...")
565
- * @returns The truncated string
566
- */
802
+ /** Truncate string removing HTML tags and append suffix if needed. */
567
803
  const truncate = (str, len = 20, suffix = "...") => {
568
804
  if (!str) return "";
569
805
  const clean = str.replace(/<[^>]+>/g, "");
570
806
  return (clean.length > len ? clean.substring(0, len - suffix.length) + suffix : clean).replace(/\n/g, " ").replace(/* @__PURE__ */ new RegExp(`\\s+${suffix.replace(/\./g, "\\.")}$`), suffix);
571
807
  };
808
+ /** Get substring from offset/length similar to PHP substr. */
809
+ const substr = (string, offset, length) => {
810
+ if (offset < 0) offset += string.length;
811
+ if (length === void 0) return string.substring(offset);
812
+ return string.substring(offset, offset + length);
813
+ };
814
+ /** Get substring by start/stop indexes. */
815
+ const sub = (string, start$1, stop) => string.substring(start$1, stop);
816
+ /** Escape string for JSON encoding (returns string without quotes). */
817
+ const esc = (string) => JSON.stringify(string).slice(1, -1);
818
+ /** Padding to a fixed size, right by default. */
819
+ const padString = (string, size, padString$1 = " ", padRight = true) => {
820
+ if (string.length >= size) return string;
821
+ const pad = padString$1.repeat(size - string.length);
822
+ return padRight ? string + pad : pad + string;
823
+ };
824
+ /** Split by delimiter with edge-case rule. */
825
+ const split = (string, delimiter) => {
826
+ if (string.startsWith(delimiter) || string.endsWith(delimiter)) return [""];
827
+ return string.split(delimiter);
828
+ };
829
+ /** Returns all the characters except the last. */
830
+ const chop = (string) => string.slice(0, -1);
831
+ /** Number checks. */
832
+ const isNumber = (string) => !isNaN(Number(string)) && string.trim() !== "";
833
+ const isInteger = (string) => Number.isInteger(Number(string)) && string.trim() !== "";
834
+ /** ROT-N cipher. */
835
+ const rot = (string, n = 13) => {
836
+ return string.replace(/[a-zA-Z]/g, (char) => {
837
+ const code = char.charCodeAt(0);
838
+ const start$1 = char >= "a" ? "a".charCodeAt(0) : "A".charCodeAt(0);
839
+ const end$1 = char >= "a" ? "z".charCodeAt(0) : "Z".charCodeAt(0);
840
+ let next = code + n;
841
+ while (next < start$1) next += 26;
842
+ while (next > end$1) next -= 26;
843
+ return String.fromCharCode(next);
844
+ });
845
+ };
846
+ /** Replace trailing punctuation with new format. */
847
+ const replacePunctuation = (string, newFormat) => string.replace(/[.,;:!?]*$/, "") + newFormat;
848
+ /** Array/object driven text replacement. */
849
+ const translate = (string, replacements) => {
850
+ let result = string;
851
+ if (Array.isArray(replacements)) for (const [from, to] of replacements) result = result.replace(new RegExp(from, "g"), to);
852
+ else for (const [from, to] of Object.entries(replacements)) result = result.replace(new RegExp(from, "g"), to);
853
+ return result;
854
+ };
855
+ /** Strip slashes recursively. */
856
+ const ss = (string) => string.replace(/\\(.)/g, "$1");
857
+ /** First and last N lines. */
858
+ const firstLines = (string, amount = 1) => string.split("\n").slice(0, amount).join("\n");
859
+ const lastLines = (string, amount = 1) => string.split("\n").slice(-amount).join("\n");
860
+
861
+ //#endregion
862
+ //#region src/Helpers/Time.ts
863
+ var Time_exports = /* @__PURE__ */ __export({
864
+ add: () => add,
865
+ dayOfYear: () => dayOfYear,
866
+ diff: () => diff,
867
+ end: () => end,
868
+ firstDayOfMonth: () => firstDayOfMonth,
869
+ format: () => format,
870
+ fromNow: () => fromNow,
871
+ fromTimestamp: () => fromTimestamp,
872
+ isBetween: () => isBetween,
873
+ isLeapYear: () => isLeapYear,
874
+ lastDayOfMonth: () => lastDayOfMonth,
875
+ now: () => now,
876
+ randomTime: () => randomTime,
877
+ start: () => start,
878
+ subtract: () => subtract,
879
+ unix: () => unix
880
+ });
881
+ /**
882
+ * Get current timestamp in milliseconds.
883
+ *
884
+ * @returns Current timestamp as number
885
+ */
886
+ const now = () => {
887
+ return Date.now();
888
+ };
889
+ /**
890
+ * Get current Unix timestamp.
891
+ *
892
+ * @returns Current Unix timestamp
893
+ */
894
+ const unix = () => {
895
+ return Math.floor(Date.now() / 1e3);
896
+ };
897
+ /**
898
+ * Format a date string according to a specified format (UTC-based for determinism).
899
+ *
900
+ * @param date - Date string or Date object
901
+ * @param format - Format to output (default: 'Y-m-d H:i:s')
902
+ * @returns Formatted date string
903
+ */
904
+ const format = (date, format$1 = "Y-m-d H:i:s") => {
905
+ const d = new Date(date);
906
+ if (isNaN(d.getTime())) throw new Error("Invalid date provided");
907
+ const year = d.getUTCFullYear();
908
+ const month = String(d.getUTCMonth() + 1).padStart(2, "0");
909
+ const day = String(d.getUTCDate()).padStart(2, "0");
910
+ const hours = String(d.getUTCHours()).padStart(2, "0");
911
+ const minutes = String(d.getUTCMinutes()).padStart(2, "0");
912
+ const seconds = String(d.getUTCSeconds()).padStart(2, "0");
913
+ const monthNames = [
914
+ "January",
915
+ "February",
916
+ "March",
917
+ "April",
918
+ "May",
919
+ "June",
920
+ "July",
921
+ "August",
922
+ "September",
923
+ "October",
924
+ "November",
925
+ "December"
926
+ ];
927
+ const monthNamesShort = [
928
+ "Jan",
929
+ "Feb",
930
+ "Mar",
931
+ "Apr",
932
+ "May",
933
+ "Jun",
934
+ "Jul",
935
+ "Aug",
936
+ "Sep",
937
+ "Oct",
938
+ "Nov",
939
+ "Dec"
940
+ ];
941
+ const dayNames = [
942
+ "Sun",
943
+ "Mon",
944
+ "Tue",
945
+ "Wed",
946
+ "Thu",
947
+ "Fri",
948
+ "Sat"
949
+ ];
950
+ switch (format$1) {
951
+ case "Y-m-d": return `${year}-${month}-${day}`;
952
+ case "Y-m-d H:i:s": return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
953
+ case "d-m-Y": return `${day}-${month}-${year}`;
954
+ case "d/m/Y": return `${day}/${month}/${year}`;
955
+ case "M j, Y": return `${monthNamesShort[d.getUTCMonth()]} ${d.getUTCDate()}, ${year}`;
956
+ case "F j, Y": return `${monthNames[d.getUTCMonth()]} ${d.getUTCDate()}, ${year}`;
957
+ case "D j M": return `${dayNames[d.getUTCDay()]} ${d.getUTCDate()} ${monthNamesShort[d.getUTCMonth()]}`;
958
+ case "timestamp": return d.toISOString();
959
+ case "unix": return Math.floor(d.getTime() / 1e3).toString();
960
+ default: return d.toISOString();
961
+ }
962
+ };
963
+ /**
964
+ * Create a date for a given timestamp.
965
+ *
966
+ * @param timestamp - Unix timestamp
967
+ * @returns Date object
968
+ */
969
+ const fromTimestamp = (timestamp) => {
970
+ return /* @__PURE__ */ new Date(timestamp * 1e3);
971
+ };
972
+ /**
973
+ * Return the difference for given date in seconds.
974
+ *
975
+ * @param date - Date to compare
976
+ * @param referenceDate - Reference date (optional, defaults to now)
977
+ * @returns Number of seconds difference
978
+ */
979
+ const diff = (date, referenceDate) => {
980
+ const d1 = new Date(date);
981
+ const d2 = referenceDate ? new Date(referenceDate) : /* @__PURE__ */ new Date();
982
+ if (isNaN(d1.getTime()) || isNaN(d2.getTime())) throw new Error("Invalid date provided");
983
+ return Math.floor((d2.getTime() - d1.getTime()) / 1e3);
984
+ };
985
+ /**
986
+ * Subtract time from the given date.
987
+ */
988
+ const subtract = (date, amount = 1, unit = "days") => {
989
+ const d = new Date(date);
990
+ if (isNaN(d.getTime())) throw new Error("Invalid date provided");
991
+ const multiplier = {
992
+ milliseconds: 1,
993
+ seconds: 1e3,
994
+ minutes: 60 * 1e3,
995
+ hours: 3600 * 1e3,
996
+ days: 1440 * 60 * 1e3
997
+ }[unit] || 1e3;
998
+ return new Date(d.getTime() - amount * multiplier);
999
+ };
1000
+ /**
1001
+ * Add time to the given date.
1002
+ */
1003
+ const add = (date, amount = 1, unit = "days") => {
1004
+ const d = new Date(date);
1005
+ if (isNaN(d.getTime())) throw new Error("Invalid date provided");
1006
+ const multiplier = {
1007
+ milliseconds: 1,
1008
+ seconds: 1e3,
1009
+ minutes: 60 * 1e3,
1010
+ hours: 3600 * 1e3,
1011
+ days: 1440 * 60 * 1e3
1012
+ }[unit] || 1e3;
1013
+ return new Date(d.getTime() + amount * multiplier);
1014
+ };
1015
+ /**
1016
+ * Start time of a specific unit.
1017
+ */
1018
+ const start = (date, unit = "days") => {
1019
+ const d = new Date(date);
1020
+ if (isNaN(d.getTime())) throw new Error("Invalid date provided");
1021
+ const newDt = new Date(d);
1022
+ switch (unit) {
1023
+ case "days":
1024
+ newDt.setHours(0, 0, 0, 0);
1025
+ break;
1026
+ case "hours":
1027
+ newDt.setMinutes(0, 0, 0);
1028
+ break;
1029
+ case "minutes":
1030
+ newDt.setSeconds(0, 0);
1031
+ break;
1032
+ case "seconds":
1033
+ newDt.setMilliseconds(0);
1034
+ break;
1035
+ case "milliseconds": break;
1036
+ }
1037
+ return newDt;
1038
+ };
1039
+ /**
1040
+ * End time of a specific unit.
1041
+ */
1042
+ const end = (date, unit = "days") => {
1043
+ const d = new Date(date);
1044
+ if (isNaN(d.getTime())) throw new Error("Invalid date provided");
1045
+ const newDt = new Date(d);
1046
+ switch (unit) {
1047
+ case "days":
1048
+ newDt.setHours(23, 59, 59, 999);
1049
+ break;
1050
+ case "hours":
1051
+ newDt.setMinutes(59, 59, 999);
1052
+ break;
1053
+ case "minutes":
1054
+ newDt.setSeconds(59, 999);
1055
+ break;
1056
+ case "seconds":
1057
+ newDt.setMilliseconds(999);
1058
+ break;
1059
+ case "milliseconds": break;
1060
+ }
1061
+ return newDt;
1062
+ };
1063
+ /**
1064
+ * Get the difference in days from today.
1065
+ */
1066
+ const fromNow = (date) => {
1067
+ return diff(date) / (1440 * 60);
1068
+ };
1069
+ /**
1070
+ * Get a random time between the specified hour and minute.
1071
+ */
1072
+ const randomTime = (startHour = 9, startMinute = 0, endHour = 17, endMinute = 0) => {
1073
+ const today = /* @__PURE__ */ new Date();
1074
+ const startMinutes = startHour * 60 + startMinute;
1075
+ const endMinutes = endHour * 60 + endMinute;
1076
+ const randomMinutes = Math.floor(Math.random() * (endMinutes - startMinutes)) + startMinutes;
1077
+ const hour = Math.floor(randomMinutes / 60);
1078
+ const minute = randomMinutes % 60;
1079
+ const date = new Date(today);
1080
+ date.setHours(hour, minute, 0, 0);
1081
+ return date;
1082
+ };
1083
+ /**
1084
+ * Check if the current time is between the specified durations.
1085
+ */
1086
+ const isBetween = (startTime, endTime) => {
1087
+ const now$1 = /* @__PURE__ */ new Date();
1088
+ const currentHours = now$1.getHours();
1089
+ const currentMinutes = now$1.getMinutes();
1090
+ const currentTotalMinutes = currentHours * 60 + currentMinutes;
1091
+ const parseTime = (timeStr) => {
1092
+ const [hours, minutes] = timeStr.split(":").map(Number);
1093
+ return hours * 60 + minutes;
1094
+ };
1095
+ const startTotalMinutes = parseTime(startTime);
1096
+ const endTotalMinutes = parseTime(endTime);
1097
+ if (startTotalMinutes <= endTotalMinutes) return currentTotalMinutes >= startTotalMinutes && currentTotalMinutes <= endTotalMinutes;
1098
+ else return currentTotalMinutes >= startTotalMinutes || currentTotalMinutes <= endTotalMinutes;
1099
+ };
1100
+ /** Day of year, first/last day of month, leap year checks. */
1101
+ const dayOfYear = (date = /* @__PURE__ */ new Date()) => {
1102
+ const d = new Date(date);
1103
+ const start$1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 0));
1104
+ const diff$1 = d.getTime() - start$1.getTime();
1105
+ return Math.floor(diff$1 / (1e3 * 60 * 60 * 24));
1106
+ };
1107
+ const firstDayOfMonth = (date = /* @__PURE__ */ new Date()) => {
1108
+ const d = new Date(date);
1109
+ return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
1110
+ };
1111
+ const lastDayOfMonth = (date = /* @__PURE__ */ new Date()) => {
1112
+ const d = new Date(date);
1113
+ return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0));
1114
+ };
1115
+ const isLeapYear = (year = (/* @__PURE__ */ new Date()).getUTCFullYear()) => {
1116
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
1117
+ };
1118
+
1119
+ //#endregion
1120
+ //#region src/Helpers/DumpDie.ts
1121
+ const inspect = (thing) => {
1122
+ return util.default.inspect(thing, {
1123
+ showHidden: true,
1124
+ depth: null,
1125
+ colors: true
1126
+ });
1127
+ };
1128
+ /**
1129
+ * Dump something and kill the process for quick debugging. Based on Laravel's dd()
1130
+ *
1131
+ * @param args
1132
+ */
1133
+ const dd = (...args) => {
1134
+ args.forEach((thing) => {
1135
+ console.log(inspect(thing));
1136
+ });
1137
+ process.default.exit(1);
1138
+ };
1139
+ /**
1140
+ * Dump something but keep the process for quick debugging. Based on Laravel's dump()
1141
+ *
1142
+ * @param args
1143
+ */
1144
+ const dump = (...args) => {
1145
+ args.forEach((thing) => {
1146
+ console.log(inspect(thing));
1147
+ });
1148
+ };
1149
+
1150
+ //#endregion
1151
+ //#region src/GlobalBootstrap.ts
1152
+ /**
1153
+ * Bootstrap the global helpers into the global scope.
1154
+ * This enables optional global access to all helper functions.
1155
+ *
1156
+ * Example usage:
1157
+ * ```typescript
1158
+ * import { bootstrap } from '@h3ravel/support'
1159
+ *
1160
+ * // Make helpers globally available
1161
+ * bootstrap()
1162
+ *
1163
+ * // Now you can use:
1164
+ * Arr.chunk([1, 2, 3, 4], 2)
1165
+ * // or directly:
1166
+ * chunk([1, 2, 3, 4], 2)
1167
+ * Str.capitalize('hello world')
1168
+ * // or directly:
1169
+ * capitalize('hello world')
1170
+ * ```
1171
+ *
1172
+ * @param target - The target object to attach helpers to (default: globalThis)
1173
+ */
1174
+ function bootstrap(target = globalThis) {
1175
+ const globalHelpers = {
1176
+ Arr: Arr_exports,
1177
+ Crypto: Crypto_exports,
1178
+ Number: Number_exports,
1179
+ Obj: Obj_exports,
1180
+ Str: Str_exports,
1181
+ Time: Time_exports,
1182
+ chunk,
1183
+ collapse,
1184
+ alternate,
1185
+ combine,
1186
+ find,
1187
+ forget,
1188
+ first,
1189
+ last,
1190
+ isEmpty,
1191
+ isNotEmpty,
1192
+ pop,
1193
+ prepend,
1194
+ take,
1195
+ reverse,
1196
+ shift,
1197
+ range,
1198
+ flatten,
1199
+ after,
1200
+ afterLast,
1201
+ before,
1202
+ beforeLast,
1203
+ capitalize,
1204
+ pluralize,
1205
+ singularize,
1206
+ slugify,
1207
+ subString,
1208
+ substitute,
1209
+ truncate,
1210
+ substr,
1211
+ sub,
1212
+ esc,
1213
+ padString,
1214
+ split,
1215
+ chop,
1216
+ isNumber,
1217
+ isInteger,
1218
+ rot,
1219
+ replacePunctuation,
1220
+ translate,
1221
+ ss,
1222
+ firstLines,
1223
+ lastLines,
1224
+ dot,
1225
+ extractProperties,
1226
+ getValue,
1227
+ modObj,
1228
+ safeDot,
1229
+ setNested,
1230
+ slugifyKeys,
1231
+ uuid,
1232
+ random,
1233
+ randomSecure,
1234
+ hash,
1235
+ hmac,
1236
+ base64Encode,
1237
+ base64Decode,
1238
+ xor,
1239
+ randomColor,
1240
+ randomPassword,
1241
+ secureToken,
1242
+ checksum,
1243
+ verifyChecksum,
1244
+ caesarCipher,
1245
+ now,
1246
+ unix,
1247
+ format,
1248
+ fromTimestamp,
1249
+ diff,
1250
+ subtract,
1251
+ add,
1252
+ start,
1253
+ end,
1254
+ fromNow,
1255
+ randomTime,
1256
+ isBetween,
1257
+ dayOfYear,
1258
+ firstDayOfMonth,
1259
+ lastDayOfMonth,
1260
+ isLeapYear,
1261
+ abbreviate,
1262
+ humanize,
1263
+ toBytes,
1264
+ toHumanTime,
1265
+ dump,
1266
+ dd
1267
+ };
1268
+ Object.assign(target, globalHelpers);
1269
+ }
1270
+ /**
1271
+ * Clean up global helpers by removing them from the global scope.
1272
+ * This function removes all global helper attachments.
1273
+ *
1274
+ * @param target - The target object to clean up (default: globalThis)
1275
+ */
1276
+ function cleanBootstrap(target = globalThis) {
1277
+ [
1278
+ "Arr",
1279
+ "chunk",
1280
+ "collapse",
1281
+ "alternate",
1282
+ "combine",
1283
+ "each",
1284
+ "keys",
1285
+ "find",
1286
+ "forget",
1287
+ "first",
1288
+ "last",
1289
+ "isEmpty",
1290
+ "isNotEmpty",
1291
+ "pop",
1292
+ "prepend",
1293
+ "take",
1294
+ "reverse",
1295
+ "shift",
1296
+ "range",
1297
+ "where",
1298
+ "skip",
1299
+ "flatten",
1300
+ "Str",
1301
+ "after",
1302
+ "afterLast",
1303
+ "before",
1304
+ "beforeLast",
1305
+ "capitalize",
1306
+ "pluralize",
1307
+ "singularize",
1308
+ "slugify",
1309
+ "subString",
1310
+ "substitute",
1311
+ "truncate",
1312
+ "startsWith",
1313
+ "endsWith",
1314
+ "substr",
1315
+ "sub",
1316
+ "esc",
1317
+ "padString",
1318
+ "trim",
1319
+ "ltrim",
1320
+ "rtrim",
1321
+ "trimChars",
1322
+ "split",
1323
+ "chop",
1324
+ "isNumber",
1325
+ "isInteger",
1326
+ "rot",
1327
+ "replacePunctuation",
1328
+ "translate",
1329
+ "ss",
1330
+ "firstLines",
1331
+ "lastLines",
1332
+ "Obj",
1333
+ "dot",
1334
+ "extractProperties",
1335
+ "getValue",
1336
+ "modObj",
1337
+ "safeDot",
1338
+ "setNested",
1339
+ "slugifyKeys",
1340
+ "Crypto",
1341
+ "uuid",
1342
+ "random",
1343
+ "randomSecure",
1344
+ "hash",
1345
+ "hmac",
1346
+ "base64Encode",
1347
+ "base64Decode",
1348
+ "xor",
1349
+ "randomColor",
1350
+ "randomPassword",
1351
+ "secureToken",
1352
+ "checksum",
1353
+ "verifyChecksum",
1354
+ "caesarCipher",
1355
+ "Time",
1356
+ "now",
1357
+ "unix",
1358
+ "format",
1359
+ "fromTimestamp",
1360
+ "diff",
1361
+ "subtract",
1362
+ "add",
1363
+ "start",
1364
+ "end",
1365
+ "fromNow",
1366
+ "randomTime",
1367
+ "isBetween",
1368
+ "dayOfYear",
1369
+ "firstDayOfMonth",
1370
+ "lastDayOfMonth",
1371
+ "isLeapYear",
1372
+ "Number",
1373
+ "abbreviate",
1374
+ "humanize",
1375
+ "toBytes",
1376
+ "toHumanTime",
1377
+ "dump",
1378
+ "dd"
1379
+ ].forEach((helper) => {
1380
+ if (helper in target) delete target[helper];
1381
+ });
1382
+ }
572
1383
 
573
1384
  //#endregion
574
1385
  exports.abbreviate = abbreviate;
1386
+ exports.add = add;
575
1387
  exports.after = after;
576
1388
  exports.afterLast = afterLast;
1389
+ exports.alternate = alternate;
1390
+ exports.base64Decode = base64Decode;
1391
+ exports.base64Encode = base64Encode;
577
1392
  exports.before = before;
578
1393
  exports.beforeLast = beforeLast;
1394
+ exports.bootstrap = bootstrap;
1395
+ exports.caesarCipher = caesarCipher;
579
1396
  exports.capitalize = capitalize;
1397
+ exports.checksum = checksum;
1398
+ exports.chop = chop;
580
1399
  exports.chunk = chunk;
1400
+ exports.cleanBootstrap = cleanBootstrap;
1401
+ exports.collapse = collapse;
1402
+ exports.combine = combine;
1403
+ exports.dayOfYear = dayOfYear;
581
1404
  exports.dd = dd;
1405
+ exports.diff = diff;
582
1406
  exports.dot = dot;
583
1407
  exports.dump = dump;
1408
+ exports.end = end;
1409
+ exports.esc = esc;
584
1410
  exports.extractProperties = extractProperties;
1411
+ exports.find = find;
1412
+ exports.first = first;
1413
+ exports.firstDayOfMonth = firstDayOfMonth;
1414
+ exports.firstLines = firstLines;
1415
+ exports.flatten = flatten;
1416
+ exports.forget = forget;
1417
+ exports.format = format;
1418
+ exports.fromNow = fromNow;
1419
+ exports.fromTimestamp = fromTimestamp;
585
1420
  exports.getValue = getValue;
1421
+ exports.hash = hash;
1422
+ exports.hmac = hmac;
586
1423
  exports.humanize = humanize;
1424
+ exports.isBetween = isBetween;
1425
+ exports.isEmpty = isEmpty;
1426
+ exports.isInteger = isInteger;
1427
+ exports.isLeapYear = isLeapYear;
1428
+ exports.isNotEmpty = isNotEmpty;
1429
+ exports.isNumber = isNumber;
1430
+ exports.last = last;
1431
+ exports.lastDayOfMonth = lastDayOfMonth;
1432
+ exports.lastLines = lastLines;
587
1433
  exports.modObj = modObj;
1434
+ exports.now = now;
1435
+ exports.padString = padString;
588
1436
  exports.pluralize = pluralize;
1437
+ exports.pop = pop;
1438
+ exports.prepend = prepend;
1439
+ exports.random = random;
1440
+ exports.randomColor = randomColor;
1441
+ exports.randomPassword = randomPassword;
1442
+ exports.randomSecure = randomSecure;
1443
+ exports.randomTime = randomTime;
589
1444
  exports.range = range;
1445
+ exports.replacePunctuation = replacePunctuation;
1446
+ exports.reverse = reverse;
1447
+ exports.rot = rot;
590
1448
  exports.safeDot = safeDot;
1449
+ exports.secureToken = secureToken;
591
1450
  exports.setNested = setNested;
1451
+ exports.shift = shift;
592
1452
  exports.singularize = singularize;
593
1453
  exports.slugify = slugify;
594
1454
  exports.slugifyKeys = slugifyKeys;
1455
+ exports.split = split;
1456
+ exports.ss = ss;
1457
+ exports.start = start;
1458
+ exports.sub = sub;
595
1459
  exports.subString = subString;
596
1460
  exports.substitute = substitute;
1461
+ exports.substr = substr;
1462
+ exports.subtract = subtract;
1463
+ exports.take = take;
597
1464
  exports.toBytes = toBytes;
598
1465
  exports.toHumanTime = toHumanTime;
1466
+ exports.translate = translate;
599
1467
  exports.truncate = truncate;
1468
+ exports.unix = unix;
1469
+ exports.uuid = uuid;
1470
+ exports.verifyChecksum = verifyChecksum;
1471
+ exports.xor = xor;
600
1472
  //# sourceMappingURL=index.cjs.map