@rzl-zone/utils-js 3.7.1 → 3.9.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.
Files changed (124) hide show
  1. package/README.md +28 -1
  2. package/dist/assertions/index.cjs +11 -11
  3. package/dist/assertions/index.d.ts +169 -58
  4. package/dist/assertions/index.js +5 -5
  5. package/dist/{chunk-EK7FSI7F.cjs → chunk-2XGQQZ6A.cjs} +3 -3
  6. package/dist/{chunk-YS27V6LS.js → chunk-3LE6NX57.js} +5 -176
  7. package/dist/{chunk-PZQC3FZY.js → chunk-44X74C26.js} +4 -4
  8. package/dist/{chunk-4ACKNPL5.js → chunk-5KDVIEVO.js} +2 -2
  9. package/dist/{chunk-JY4HLZ4W.js → chunk-5O66AUEC.js} +2 -2
  10. package/dist/chunk-5Y6JL47L.js +302 -0
  11. package/dist/{chunk-KIYALQQF.cjs → chunk-62FS7WMB.cjs} +35 -35
  12. package/dist/{chunk-VJVCXEH7.cjs → chunk-6AMDHVS2.cjs} +9 -181
  13. package/dist/{chunk-6PKW4WCT.js → chunk-6WVOUVWD.js} +27 -15
  14. package/dist/{chunk-BYUT376O.cjs → chunk-76ATVDCR.cjs} +3 -3
  15. package/dist/{chunk-F3WBQKRI.cjs → chunk-7C7TQC5J.cjs} +29 -7
  16. package/dist/{chunk-QUITZ3GP.js → chunk-7EIFPHV3.js} +32 -16
  17. package/dist/{chunk-6RFNZ2ZZ.cjs → chunk-7NXFGJJE.cjs} +14 -14
  18. package/dist/{chunk-TFDXRT6D.cjs → chunk-ALRISPTL.cjs} +3 -3
  19. package/dist/chunk-BAV5T2E3.cjs +1 -1
  20. package/dist/{chunk-4ZOXSUXB.js → chunk-C7GC2PFX.js} +3 -3
  21. package/dist/chunk-DVMHRLKP.cjs +1 -1
  22. package/dist/{chunk-XFTUHS4Y.js → chunk-DXPM4NOU.js} +10 -8
  23. package/dist/{chunk-DPLL67OT.js → chunk-EJV5AF4L.js} +2 -2
  24. package/dist/{chunk-NREACG6M.cjs → chunk-FWWPEL7J.cjs} +3 -3
  25. package/dist/{chunk-LEX4TQW2.js → chunk-GHU356XQ.js} +4 -6
  26. package/dist/chunk-GKDSBOYE.js +209 -0
  27. package/dist/{chunk-YC7AK3KX.cjs → chunk-H44QVAZL.cjs} +31 -31
  28. package/dist/{chunk-AKKM6MOX.cjs → chunk-I33PB44Q.cjs} +15 -15
  29. package/dist/{chunk-LIU4S3JA.cjs → chunk-IX6PF5ZP.cjs} +4 -4
  30. package/dist/{chunk-3KTD3QDI.js → chunk-J4TT33ZX.js} +29 -7
  31. package/dist/{chunk-SZJ7OI4S.js → chunk-J6VLFVIL.js} +3 -3
  32. package/dist/{chunk-KTQLDIIT.cjs → chunk-JI57K7D4.cjs} +173 -163
  33. package/dist/{chunk-OFBFGFVH.js → chunk-JYOCB6OV.js} +2 -2
  34. package/dist/chunk-KHO2SBNA.cjs +1 -1
  35. package/dist/{chunk-66WLOZOD.cjs → chunk-KUVRZ2JW.cjs} +53 -51
  36. package/dist/chunk-L5RDAVVH.js +1 -1
  37. package/dist/{chunk-VCVND6CH.js → chunk-M5QB2GM5.js} +2 -2
  38. package/dist/{chunk-3LEWQV3R.js → chunk-MBFVTGYS.js} +8 -8
  39. package/dist/{chunk-UKAUXY2U.cjs → chunk-MMRHKYT6.cjs} +12 -12
  40. package/dist/{chunk-U5VR4TJN.js → chunk-MS2KSKD7.js} +9 -9
  41. package/dist/{chunk-7ZNEUWYP.js → chunk-MZ3T6L7Z.js} +2 -2
  42. package/dist/{chunk-ATLFMKAF.cjs → chunk-NAOVH4OH.cjs} +7 -7
  43. package/dist/chunk-NJ24M6ZH.cjs +308 -0
  44. package/dist/chunk-OCTHWEZK.cjs +249 -0
  45. package/dist/chunk-ONZFBJVW.js +1 -1
  46. package/dist/{chunk-FI76UZRF.js → chunk-OSSFLQDD.js} +3 -4
  47. package/dist/{chunk-7WBMA2VE.cjs → chunk-OYFUBKEG.cjs} +4 -5
  48. package/dist/{chunk-B4SDEBN7.cjs → chunk-PWKOFPAH.cjs} +3 -3
  49. package/dist/{chunk-2CQI36UD.cjs → chunk-QGTFQ7RO.cjs} +8 -6
  50. package/dist/chunk-QNKGP5DY.js +1 -1
  51. package/dist/chunk-QXTJVDWE.js +676 -0
  52. package/dist/{chunk-B6UIKBHR.cjs → chunk-QZI5PVCI.cjs} +4 -4
  53. package/dist/{chunk-WNO3EPYT.js → chunk-R2DR7SPJ.js} +102 -26
  54. package/dist/{chunk-TDYGYHSH.js → chunk-SN5HAK3Y.js} +4 -4
  55. package/dist/{chunk-D53CE4BT.js → chunk-SRWL4YCP.js} +11 -8
  56. package/dist/{chunk-7QQV66RX.cjs → chunk-TJ5OY6MC.cjs} +10 -10
  57. package/dist/{chunk-6WMB5AJR.js → chunk-TXOVQZPU.js} +3 -4
  58. package/dist/chunk-UDA26MCU.cjs +1 -1
  59. package/dist/{chunk-R3PBF6F7.cjs → chunk-UFYMRRJH.cjs} +73 -61
  60. package/dist/{chunk-5NN4ZDE2.cjs → chunk-UV5BKAYW.cjs} +6 -8
  61. package/dist/{chunk-GAJBF6DR.js → chunk-UXT4XSUK.js} +2 -2
  62. package/dist/{chunk-TDPYR5JY.js → chunk-VBSLIIDB.js} +24 -14
  63. package/dist/chunk-VCYXNIZ2.cjs +678 -0
  64. package/dist/chunk-VJDDGRIK.cjs +1 -1
  65. package/dist/{chunk-VNADVWSJ.js → chunk-WB3FT62A.js} +6 -4
  66. package/dist/{chunk-K63WO3XA.cjs → chunk-WKM6UVMG.cjs} +4 -5
  67. package/dist/{chunk-OS5OT5JA.cjs → chunk-WLEZ2KSG.cjs} +142 -126
  68. package/dist/{chunk-ZN53RM3R.js → chunk-WRGN6UBK.js} +2 -2
  69. package/dist/chunk-WVSPXFTY.js +1 -1
  70. package/dist/{chunk-2VO2CBTU.js → chunk-X6ULJZ3X.js} +2 -2
  71. package/dist/{chunk-CKUEZF4R.cjs → chunk-XYWC4EQ3.cjs} +71 -71
  72. package/dist/{chunk-A3YI6Y2P.js → chunk-YHFRCVTN.js} +3 -3
  73. package/dist/{chunk-RMJC3B5P.cjs → chunk-YQHJB7KR.cjs} +30 -27
  74. package/dist/{chunk-YGB2BQPB.cjs → chunk-YVRUY4EW.cjs} +8 -8
  75. package/dist/chunk-YWHHVDT4.js +1 -1
  76. package/dist/chunk-ZTHJQJ5F.cjs +211 -0
  77. package/dist/conversions/index.cjs +34 -34
  78. package/dist/conversions/index.d.ts +10 -12
  79. package/dist/conversions/index.js +15 -15
  80. package/dist/events/index.cjs +8 -8
  81. package/dist/events/index.d.ts +9 -9
  82. package/dist/events/index.js +4 -4
  83. package/dist/formatters/index.cjs +19 -19
  84. package/dist/formatters/index.d.ts +19 -24
  85. package/dist/formatters/index.js +9 -9
  86. package/dist/generators/index.cjs +12 -8
  87. package/dist/generators/index.d.ts +155 -26
  88. package/dist/generators/index.js +4 -4
  89. package/dist/index.d.ts +1 -1
  90. package/dist/{isPlainObject-FWmcJF6k.d.ts → isPlainObject-BTPjv6zB.d.ts} +2 -2
  91. package/dist/next/index.cjs +39 -36
  92. package/dist/next/index.d.ts +11 -11
  93. package/dist/next/index.js +12 -9
  94. package/dist/next/server/index.cjs +4 -4
  95. package/dist/next/server/index.d.ts +4 -4
  96. package/dist/next/server/index.js +2 -2
  97. package/dist/operations/index.cjs +11 -11
  98. package/dist/operations/index.d.ts +8 -9
  99. package/dist/operations/index.js +8 -8
  100. package/dist/parsers/index.cjs +6 -4
  101. package/dist/parsers/index.d.ts +224 -32
  102. package/dist/parsers/index.js +5 -3
  103. package/dist/predicates/index.cjs +77 -76
  104. package/dist/predicates/index.d.ts +15 -28
  105. package/dist/predicates/index.js +14 -13
  106. package/dist/promises/index.cjs +6 -6
  107. package/dist/promises/index.d.ts +5 -7
  108. package/dist/promises/index.js +4 -4
  109. package/dist/rzl-utils.global.js +2 -2
  110. package/dist/strings/index.cjs +23 -23
  111. package/dist/strings/index.d.ts +1 -1
  112. package/dist/strings/index.js +7 -7
  113. package/dist/tailwind/index.cjs +13 -13
  114. package/dist/tailwind/index.d.ts +18 -18
  115. package/dist/tailwind/index.js +5 -5
  116. package/dist/urls/index.cjs +23 -21
  117. package/dist/urls/index.d.ts +188 -121
  118. package/dist/urls/index.js +16 -14
  119. package/package.json +1 -1
  120. package/dist/chunk-ABA2ZSBQ.js +0 -152
  121. package/dist/chunk-BG3AS5BU.cjs +0 -173
  122. package/dist/chunk-K3SONK25.cjs +0 -157
  123. package/dist/chunk-KPCDDYTZ.js +0 -417
  124. package/dist/chunk-QAPYHLHC.cjs +0 -419
@@ -2,7 +2,7 @@
2
2
  * ====================================================
3
3
  * Rzl Utils-JS.
4
4
  * ----------------------------------------------------
5
- * Version: 3.7.1.
5
+ * Version: 3.9.0.
6
6
  * Author: Rizalvin Dwiky.
7
7
  * Repository: https://github.com/rzl-zone/utils-js.
8
8
  * ====================================================
@@ -12,7 +12,7 @@
12
12
  * ----------------------------------------------------------
13
13
  * **Represents a non-empty array of key–value pairs.**
14
14
  * @description
15
- * Type for `queryParams` parameter, the second parameter of **{@link constructURL | `constructURL`}**.
15
+ * Type for `queryParams` parameter, the second parameter of ***`constructURL` utility function***.
16
16
  * - **Behavior:**
17
17
  * - Each inner tuple strictly follows the `[string, string | number]` shape.
18
18
  * - Ensures the outer array contains **at least one pair** (non-empty).
@@ -44,7 +44,7 @@ type QueryParamPairs=[[string,string|number],...[string,string|number][]];
44
44
  * @param {string[]} [removeParams]
45
45
  * A list of query parameter keys to remove from the final URL, whether they were in the base URL or provided queryParams.
46
46
  * @returns {URL} A new URL object representing the constructed URL with merged and cleaned query parameters.
47
- * @throws {TypeError} Throws if `baseUrl` is not a valid non-empty string or URL object, or if `queryParams` is not iterable, or if `removeParams` is not an array of strings.
47
+ * @throws **{@link TypeError | `TypeError`}** if `baseUrl` is not a valid non-empty string or URL object, or if `queryParams` is not iterable, or if `removeParams` is not an array of strings.
48
48
  * @example
49
49
  * 1. #### Basic Usage:
50
50
  * ```ts
@@ -202,8 +202,7 @@ declare const extractURLs:(url:string|null|undefined)=>string[]|null;
202
202
  * - Defaults to `"/"`.
203
203
  * @returns {string}
204
204
  * ***The first valid normalized pathname, or the normalized default.***
205
- * @throws {TypeError}
206
- * ***If `result` is not a valid type, or `defaultValue` is not a string or empty-string.***
205
+ * @throws **{@link TypeError | `TypeError`}** ***if `result` is not a valid type, or `defaultValue` is not a string or empty-string.***
207
206
  */
208
207
  declare const getFirstPrefixPathname:(result:string|string[]|null|undefined,defaultValue?:string)=>string;type GetPrefixPathnameOptions={
209
208
  /** The number of levels to include in the prefix (default is `1`).
@@ -252,8 +251,8 @@ removeDuplicates?:boolean;};
252
251
  * - A single string if only one unique prefix/base is found.
253
252
  * - An array of strings if multiple different prefixes/bases are found.
254
253
  * - `null` if no matching base is found when using `base`.
255
- * @throws {TypeError}
256
- * ***Throws if:***
254
+ * @throws **{@link TypeError | `TypeError`}**
255
+ * ***if:***
257
256
  * - `url` is `not a string` or `not an array of strings`.
258
257
  * - `base` is `not a string`, `array of strings`, or `null`.
259
258
  * - `options` is `not an object`.
@@ -384,153 +383,221 @@ defaultPath?:string;
384
383
  * **Must be `true` in this type.**
385
384
  */
386
385
  keepNullable?:true;};type MainNormalizePathnameOptions={
387
- /** * ***Preserve trailing slash at the end of the normalized pathname, defaultValue: `false`.***
386
+ /** --------------------------------------------------------
387
+ * * ***Preserve trailing slash at the end of the normalized pathname, defaultValue: `false`.***
388
+ * --------------------------------------------------------
388
389
  *
389
390
  * @defaultValue `false`
390
391
  */
391
- keepTrailingSlash?:boolean;};type NormalizePathnameOptionsKeepNullableTrue=MainNormalizePathnameOptions & KeepNullableOptions;type NormalizePathnameOptionsKeepNullableFalse=MainNormalizePathnameOptions & UnKeepNullableOptions;type ResUnKeepNullable<T>=T extends undefined?string:T extends null?string:T extends null|undefined?string:string;type ResKeepNullable<T>=T extends string?string:T extends undefined?undefined:T extends null?null:T extends null|undefined?null|undefined:string|null|undefined;
392
+ keepTrailingSlash?:boolean;
393
+ /** --------------------------------------------------------
394
+ * * ***Allow special localhost domain at the beginning of the pathname.***
395
+ * --------------------------------------------------------
396
+ * @description
397
+ * If `true`, the first segment of the pathname that is `/localhost` or `localhost`
398
+ * (with or without a port, e.g., `localhost:3000`) will be treated as a special domain
399
+ * and **removed** from the normalized pathname.
400
+ *
401
+ * - **Examples (`localhostDomain: true`)**:
402
+ * - `"/localhost/path"` ➔ `"/path"`
403
+ * - `"localhost:3000/path"` ➔ `"/path"`
404
+ * - `"localhost"` ➔ `"/"` (entire path removed)
405
+ *
406
+ * - Only the **first path segment** is affected. Any subsequent occurrences of `"localhost"`
407
+ * will remain intact.
408
+ *
409
+ * @defaultValue `false`
410
+ */
411
+ localhostDomain?:boolean;
412
+ /**
413
+ * --------------------------------------------------------
414
+ * * ***Custom list of file extensions that prevent the first path segment from being treated as a domain.***
415
+ * --------------------------------------------------------
416
+ *
417
+ * **Description:**
418
+ * - The first segment of a pathname is often interpreted as a domain (e.g., `example.com`).
419
+ * - If this first segment ends with any of the extensions listed here, it will **not** be considered a domain,
420
+ * and will instead be preserved as part of the relative path.
421
+ * - This is useful for cases where filenames appear at the start of a path and you want them treated as relative paths,
422
+ * such as `"image.png?version=2"` or `"archive.tar.gz#download"`.
423
+ * - Only the **first path segment** is affected; all other segments are processed normally.
424
+ * - **Ignored** if:
425
+ * 1. The pathname starts with a full URL protocol (`http://` or `https://`), e.g., `"https://example.com/file.png"`.
426
+ * 2. The first path segment is already a valid domain, e.g., `"example.com/image.png"`.
427
+ *
428
+ * **Type & Validation:**
429
+ * - Must be a `Set<string>` or `string[]`.
430
+ * - Each string **must include the leading dot**, e.g., `.png`, `.tar.gz`.
431
+ * - Multi-part extensions (like `.tar.gz`, `.tar.bz`) are supported.
432
+ * - Throws a **TypeError** if:
433
+ * 1. The type is not a `Set<string>` or `string[]`.
434
+ * 2. Any string in the array/set is empty.
435
+ * 3. Any string does not start with a dot (`.`).
436
+ *
437
+ * **Usage Notes:**
438
+ * - Only applied when the first segment is otherwise domain-like **and** pathname is relative or domain-like without protocol.
439
+ * - Query strings (`?x=1`) and hash fragments (`#section`) are preserved.
440
+ *
441
+ * **Examples (relative paths, option active):**
442
+ * ```ts
443
+ * normalizePathname("image.png?version=2", {
444
+ * ignoreDomainExtensions: [".png", ".jpg"]
445
+ * });
446
+ * // ➔ "/image.png?version=2"
447
+ *
448
+ * normalizePathname("archive.tar.gz#download", {
449
+ * ignoreDomainExtensions: new Set([".tar.gz"])
450
+ * });
451
+ * // ➔ "/archive.tar.gz#download"
452
+ *
453
+ * normalizePathname("script.js?module=true#top", {
454
+ * ignoreDomainExtensions: [".js"]
455
+ * });
456
+ * // ➔ "/script.js?module=true#top"
457
+ * ```
458
+ *
459
+ * **Examples (full URL or explicit domain - option ignored):**
460
+ * ```ts
461
+ * normalizePathname("https://example.com/image.png?version=2", {
462
+ * ignoreDomainExtensions: [".png"]
463
+ * });
464
+ * // ➔ "/image.png?version=2" // URL is parsed normally; ignoreDomainExtensions has no effect
465
+ *
466
+ * normalizePathname("example.com/script.js?module=true#top", {
467
+ * ignoreDomainExtensions: [".js"]
468
+ * });
469
+ * // ➔ "/script.js?module=true#top" // domain recognized; option ignored
470
+ * ```
471
+ *
472
+ * **Notes:**
473
+ * - Only the **first path segment** is checked.
474
+ * - Prevents false-positive domain stripping for filenames that look like domains.
475
+ * - Throws **TypeError** if invalid type or invalid string is provided.
476
+ *
477
+ * @defaultValue `undefined` (feature inactive if not provided)
478
+ */
479
+ ignoreDomainExtensions?:Set<string>|string[];};type NormalizePathnameOptionsKeepNullableTrue=MainNormalizePathnameOptions & KeepNullableOptions;type NormalizePathnameOptionsKeepNullableFalse=MainNormalizePathnameOptions & UnKeepNullableOptions;type ResUnKeepNullable<T>=T extends undefined?string:T extends null?string:T extends null|undefined?string:string;type ResKeepNullable<T>=T extends string?string:T extends undefined?undefined:T extends null?null:T extends null|undefined?null|undefined:string|null|undefined;
392
480
  /** --------------------------------------------------------
393
481
  * * ***Utility: `normalizePathname`.***
394
482
  * --------------------------------------------------------
483
+ *
395
484
  * - **Description:**
396
- * - Normalizes a given pathname string for consistent routing, URL handling, and string hygiene.
397
- * - It trims whitespace, collapses redundant slashes, handles full URLs, query strings, hash fragments,
398
- * - Unicode characters, emojis, and optionally preserves `null` or `undefined`.
399
- * - Trailing slash behavior can be controlled via `keepTrailingSlash`.
400
- *
401
- * - **Behavior Details:**
402
- * - Trims leading and trailing whitespace.
403
- * - Removes all internal spaces.
404
- * - Collapses multiple consecutive slashes into a single `/`.
405
- * - Prepends a leading slash if missing.
406
- * - Preserves trailing slash only if `keepTrailingSlash` is `true`.
407
- * - Supports full URLs (`http://` or `https://`) and relative paths only also detect valid domain and
408
- * subdomain (with support handle wildcard eg: *.example.com) (with optional with port) eg (localhost, localhost:3000, example.com, sub.domain.com, *.domain.test, etc).
409
- * - Preserves query strings (`?key=value`) and hash fragments (`#anchor`) intact.
410
- * - Handles emojis and Unicode safely.
411
- * - Returns `string`, `null` or `undefined` as-is if `keepNullable` is true.
412
- * - Returns `undefined` if pathname is not a string and `keepNullable` is `true`.
413
- * - Returns `defaultPath` if pathname is empty-string even when `keepNullable` is true.
414
- * - Returns `defaultPath` if pathname is empty/invalid and `keepNullable` is `false`.
415
- *
416
- * - **Options (`options`)**:
417
- * - `defaultPath` (***`string`***, default: **`"/"`**)
418
- * - Fallback path if the input is invalid (**empty-string**, **null**, **undefined**) and
419
- * `keepNullable` is **false**, if `keepNullable` is true, used only when pathname is empty-string.
420
- * - `keepNullable` (***`boolean`***, default: **`false`**)
421
- * - If **true**, preserves `null` or `undefined` as-is instead of returning
422
- * `defaultPath` (except if `pathname` is **empty-string**).
423
- * - `keepTrailingSlash` (***`boolean`***, default: **`false`**)
424
- * - If **true**, preserves a trailing slash at the end of the normalized pathname.
425
- *
426
- * @param {string | null | undefined} pathname - ***The pathname to normalize.***
427
- * @param {NormalizePathnameOptions} [options] - ***Configuration options.***
428
- *
429
- * @returns {string | null | undefined} ***Normalized pathname, or original nullable value if `keepNullable` is `true`
430
- * _(except if `pathname` is empty-string, will keep returning `defaultPath`)_.***
431
- *
432
- * @throws {TypeError} If `defaultPath` is invalid when `keepNullable` is false.
433
- * @throws {NormalizePathnameError} If normalization fails (e.g., invalid URL).
485
+ * Normalizes any pathname or URL string to a clean, predictable format.
486
+ * Useful for routing, file paths, and URL handling.
487
+ * - Handles:
488
+ * - Leading/trailing spaces
489
+ * - Internal spaces in path segments
490
+ * - Redundant slashes (`//`)
491
+ * - Full URLs vs relative paths
492
+ * - Query (`?`) and hash (`#`) preservation
493
+ * - Unicode & emoji characters
494
+ * - Optional nullable preservation (`keepNullable`)
495
+ * - Optional trailing slash preservation (`keepTrailingSlash`)
496
+ * - Optional removal of localhost first segment (`localhostDomain`)
497
+ * - Prevention of false-positive domain stripping (`ignoreDomainExtensions`)
498
+ *
499
+ * - **Key Steps Internally:**
500
+ * 1. Validate `options` (plain object, correct types)
501
+ * 2. Validate `defaultPath` (non-empty string if `keepNullable` is false)
502
+ * 3. Validate `ignoreDomainExtensions` (Set<string> | string[], each starts with `.`)
503
+ * 4. Handle nullable:
504
+ * - Returns `null` / `undefined` if `keepNullable: true`
505
+ * - Otherwise uses `defaultPath`
506
+ * 5. Trim spaces, remove internal spaces
507
+ * 6. If full URL: parse using `URL` constructor
508
+ * 7. If relative path or domain-like:
509
+ * - Remove `localhost`/`localhost:port` if `localhostDomain`
510
+ * - Remove first segment if domain-like and **not** in `ignoreDomainExtensions`
511
+ * 8. Normalize slashes
512
+ * 9. Ensure leading slash
513
+ * 10. Handle trailing slash
514
+ * 11. Decode Unicode safely
515
+ * 12. Return normalized pathname + search + hash
516
+ *
517
+ * - **Error Handling:**
518
+ * - **TypeError**:
519
+ * - `defaultPath` invalid (non-string or empty) when `keepNullable: false`
520
+ * - `keepNullable`, `keepTrailingSlash`, `localhostDomain` not boolean
521
+ * - `ignoreDomainExtensions` invalid
522
+ * - **NormalizePathnameError** (extends ***Error***):
523
+ * - Invalid URL parsing
524
+ * - Unexpected normalization errors
525
+ *
526
+ * - **Options:**
527
+ * ```ts
528
+ * {
529
+ * // fallback if invalid path, default: "/"
530
+ * defaultPath?: string;
531
+ * // preserve null/undefined, default: false
532
+ * keepNullable?: boolean;
533
+ * // preserve trailing slash, default: false
534
+ * keepTrailingSlash?: boolean;
535
+ * // remove localhost:port first segment, default: false
536
+ * localhostDomain?: boolean;
537
+ * // prevent domain stripping, default: undefined
538
+ * ignoreDomainExtensions?: Set<string> | string[];
539
+ * }
540
+ * ```
434
541
  *
435
542
  * @example
436
- * // Basic normalization
543
+ * // Basic path cleaning
437
544
  * normalizePathname(" /foo//bar ");
438
545
  * // ➔ "/foo/bar"
439
546
  *
440
- * // Full URL with query and hash
547
+ * // Trailing slash control
548
+ * normalizePathname("/api//v1//user//", { keepTrailingSlash: true });
549
+ * // ➔ "/api/v1/user/"
550
+ * normalizePathname("/api//v1//user//", { keepTrailingSlash: false });
551
+ * // ➔ "/api/v1/user"
552
+ *
553
+ * // Full URL normalization
441
554
  * normalizePathname("https://example.com//path///to/resource?x=1#hash");
442
555
  * // ➔ "/path/to/resource?x=1#hash"
443
556
  *
444
- * // Empty string returns defaultPath
445
- * normalizePathname(" ");
446
- * // ➔ "/"
447
- *
448
- * // Return defaultPath if isn't valid pathname and keepNullable is `undefined` or `false`.
449
- * normalizePathname(null, { defaultPath: "/home" });
450
- * // ➔ "/home"
451
- *
452
- * // Preserve null
557
+ * // Null/undefined preservation
453
558
  * normalizePathname(null, { keepNullable: true });
454
559
  * // ➔ null
455
- *
456
- * // Preserve undefined
457
560
  * normalizePathname(undefined, { keepNullable: true });
458
561
  * // ➔ undefined
459
562
  *
460
- * // Return defaultPath if pathname is empty-string even with keepNullable
461
- * normalizePathname(" ", { keepNullable: true, defaultPath:"/home" });
563
+ * // Default fallback
564
+ * normalizePathname("", { defaultPath: "/home" });
462
565
  * // ➔ "/home"
463
566
  *
464
- * // Return undefined if pathname is not a valid-string.
465
- * normalizePathname(true, { keepNullable: true, defaultPath:"/home" });
466
- * // ➔ undefined
467
- *
468
- * // Collapse multiple slashes
469
- * normalizePathname("/double//slashes");
470
- * // ➔ "/double/slashes"
471
- *
472
- * // Handles emoji and Unicode
473
- * normalizePathname(" nested / path / 🚀 ");
474
- * // ➔ "/nested/path/🚀"
567
+ * // Localhost removal
568
+ * normalizePathname("localhost:3000/path/to/resource", { localhostDomain: true });
569
+ * // ➔ "/path/to/resource"
475
570
  *
476
- * // Query and hash preserved
477
- * normalizePathname("/dashboard///stats?view=all#top");
478
- * // ➔ "/dashboard/stats?view=all#top"
571
+ * // Prevent false-positive domain stripping
572
+ * normalizePathname("archive.tar.gz#download", { ignoreDomainExtensions: [".tar.gz"] });
573
+ * // ➔ "/archive.tar.gz#download"
574
+ * normalizePathname("image.png?version=2", { ignoreDomainExtensions: [".png"] });
575
+ * // ➔ "/image.png?version=2"
479
576
  *
480
- * // Leading/trailing slashes normalized
481
- * normalizePathname("///api//v1///user/");
482
- * // ➔ "/api/v1/user"
483
- *
484
- * // Keep trailing slash if option enabled
485
- * normalizePathname("///api//v1///user//", { keepTrailingSlash: true });
486
- * // ➔ "/api/v1/user/"
487
- *
488
- * // Relative-like paths handled safely
489
- * normalizePathname("path/to/page");
490
- * // ➔ "/path/to/page"
577
+ * // Emojis and Unicode
578
+ * normalizePathname("🔥//deep//path///🚀");
579
+ * // ➔ "/🔥/deep/path/🚀"
491
580
  *
492
- * // Query-only path
581
+ * // Query-only or hash-only
493
582
  * normalizePathname("?page=2");
494
583
  * // ➔ "/?page=2"
495
- *
496
- * // Hash-only path
497
584
  * normalizePathname("#section3");
498
585
  * // ➔ "/#section3"
499
586
  *
500
- * // URL parsing failure triggers custom error
587
+ * // Complex nested paths
588
+ * normalizePathname(" //nested///folder//file.txt ");
589
+ * // ➔ "/nested/folder/file.txt"
590
+ *
591
+ * // Invalid URL triggers error
501
592
  * try {
502
- * normalizePathname("http://");
593
+ * normalizePathname("http://");
503
594
  * } catch (e) {
504
- * // console.log(e);
595
+ * // console.log(e);
505
596
  * }
506
597
  *
507
- * // Internal encoded spaces preserved
508
- * normalizePathname("/search/%20item%20");
509
- * // ➔ "/search/%20item%20"
510
- *
511
- * // Edge case: relative URL-like input
512
- * normalizePathname("localhost/path");
513
- * // ➔ "/path"
514
- * normalizePathname("localhost:3000/path");
515
- * // ➔ "/path"
516
- * normalizePathname("example.com/path");
517
- * // ➔ "/path"
518
- * normalizePathname("sub.domain.com/path");
519
- * // ➔ "/path"
520
- * normalizePathname("*.domain.com/path");
521
- * // ➔ "/path"
522
- *
523
- * // Deeply nested messy path
524
- * normalizePathname(" /🔥//deep//path///🚀 ");
525
- * // ➔ "/🔥/deep/path/🚀"
526
- *
527
- * // Edge case: root slash
528
- * normalizePathname("/");
529
- * // ➔ "/"
530
- *
531
- * // Edge case: multiple spaces only
532
- * normalizePathname(" ");
533
- * // ➔ "/"
598
+ * // First segment is domain but ignored due to extension
599
+ * normalizePathname("example.tar.bz/file", { ignoreDomainExtensions: [".tar.bz"] });
600
+ * // ➔ "/example.tar.bz/file"
534
601
  */
535
602
  declare function normalizePathname<T>(pathname:T,options?:NormalizePathnameOptionsKeepNullableFalse):ResUnKeepNullable<T>;declare function normalizePathname<T>(pathname:T,options?:NormalizePathnameOptionsKeepNullableTrue):ResKeepNullable<T>;type FormatEnvPortOptions={
536
603
  /** Add prefix with a colon, defaultValue: `false`.
@@ -550,7 +617,7 @@ prefixColon?:boolean;};
550
617
  * @param {string | null | undefined} envVar The environment variable string.
551
618
  * @param {FormatEnvPortOptions} [options] Optional object: `{ prefixColon?: boolean }`.
552
619
  * @returns {string} A string like `":8080"` or `"8080"`, or `""` if no digits.
553
- * @throws {TypeError} If `options` is not an object or `prefixColon` is not boolean.
620
+ * @throws **{@link TypeError | `TypeError`}** if `options` is not an object or `prefixColon` is not boolean.
554
621
  * @example
555
622
  * formatEnvPort("port:8080");
556
623
  * // ➔ "8080"
@@ -2,24 +2,26 @@
2
2
  * ====================================================
3
3
  * Rzl Utils-JS.
4
4
  * ----------------------------------------------------
5
- * Version: 3.7.1.
5
+ * Version: 3.9.0.
6
6
  * Author: Rizalvin Dwiky.
7
7
  * Repository: https://github.com/rzl-zone/utils-js.
8
8
  * ====================================================
9
9
  */
10
- export { constructURL, extractURLs, getFirstPrefixPathname, getPrefixPathname } from '../chunk-6PKW4WCT.js';
10
+ export { constructURL, extractURLs, getFirstPrefixPathname, getPrefixPathname } from '../chunk-6WVOUVWD.js';
11
11
  import '../chunk-ONZFBJVW.js';
12
- import '../chunk-GAJBF6DR.js';
13
- import '../chunk-TDYGYHSH.js';
14
- import '../chunk-PZQC3FZY.js';
15
- import '../chunk-7ZNEUWYP.js';
12
+ import '../chunk-UXT4XSUK.js';
13
+ import '../chunk-SN5HAK3Y.js';
14
+ import '../chunk-44X74C26.js';
15
+ import '../chunk-MZ3T6L7Z.js';
16
16
  import '../chunk-WVSPXFTY.js';
17
- export { formatEnvPort, normalizePathname } from '../chunk-WNO3EPYT.js';
18
- export { punycodeUtilsJS } from '../chunk-YS27V6LS.js';
19
- import '../chunk-4ACKNPL5.js';
20
- import '../chunk-JY4HLZ4W.js';
21
- import '../chunk-VCVND6CH.js';
22
- import '../chunk-6WMB5AJR.js';
23
- import '../chunk-2VO2CBTU.js';
17
+ export { formatEnvPort, normalizePathname } from '../chunk-R2DR7SPJ.js';
18
+ import '../chunk-3LE6NX57.js';
19
+ export { punycodeUtilsJS } from '../chunk-GKDSBOYE.js';
20
+ import '../chunk-5KDVIEVO.js';
21
+ import '../chunk-5O66AUEC.js';
22
+ import '../chunk-OSSFLQDD.js';
23
+ import '../chunk-M5QB2GM5.js';
24
+ import '../chunk-TXOVQZPU.js';
25
+ import '../chunk-X6ULJZ3X.js';
24
26
  import '../chunk-QNKGP5DY.js';
25
- import '../chunk-3KTD3QDI.js';
27
+ import '../chunk-J4TT33ZX.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rzl-zone/utils-js",
3
- "version": "3.7.1",
3
+ "version": "3.9.0",
4
4
  "sideEffects": false,
5
5
  "engineStrict": true,
6
6
  "license": "MIT",
@@ -1,152 +0,0 @@
1
- /*!
2
- * ====================================================
3
- * Rzl Utils-JS.
4
- * ----------------------------------------------------
5
- * Version: 3.7.1.
6
- * Author: Rizalvin Dwiky.
7
- * Repository: https://github.com/rzl-zone/utils-js.
8
- * ====================================================
9
- */
10
- import { isInteger } from './chunk-WVSPXFTY.js';
11
- import { safeStableStringify } from './chunk-2VO2CBTU.js';
12
- import { isNonEmptyArray, getPreciseType, isNumber, isPlainObject, assertIsBoolean, isNaN } from './chunk-3KTD3QDI.js';
13
-
14
- function getRandomItem(array) {
15
- if (!isNonEmptyArray(array)) return void 0;
16
- const randomIndex = Math.floor(Math.random() * (array.length || 0));
17
- return array[randomIndex];
18
- }
19
-
20
- var randomInt = (min, max) => {
21
- if (!isInteger(min) || !isInteger(max)) {
22
- throw new TypeError(
23
- `First parameter (\`min\`) and second parameter (\`max\`) must be of type \`integer-number\`${minValueNote(
24
- min,
25
- max
26
- )}value, but received: ['min': \`${getPreciseType(
27
- min
28
- )}\` - (with value: \`${safeStableStringify(min)})\`, 'max': \`${getPreciseType(
29
- max
30
- )}\` - (with value: \`${safeStableStringify(max)}\`)].`
31
- );
32
- }
33
- if (min > max) {
34
- throw new RangeError(
35
- `First parameter (\`min\`) must be less than or equal to second parameter (\`max\`), but received: ['min': ${formatValue(
36
- min
37
- )}, 'max': ${formatValue(max)}].`
38
- );
39
- }
40
- min = Math.max(1, min);
41
- max = Math.min(Number.MAX_SAFE_INTEGER, max);
42
- return Math.floor(Math.random() * (max - min + 1)) + min;
43
- };
44
- var formatValue = (value) => {
45
- return isNumber(value, { includeNaN: true }) ? value === Number.MIN_VALUE ? "`Number.MIN_VALUE`" : `${value}` : `\`${getPreciseType(value)}\``;
46
- };
47
- var minValueNote = (...values) => {
48
- return values.some((v) => isNumber(v, { includeNaN: true }) && v === Number.MIN_VALUE) ? " and can't be `Number.MIN_VALUE` " : " ";
49
- };
50
-
51
- var randomIntByLength = (options) => {
52
- if (!isPlainObject(options)) {
53
- options = {};
54
- }
55
- const { minLength = 1, maxLength = 16, avoidZero = false } = options;
56
- assertIsBoolean(avoidZero, {
57
- message({ currentType, validType }) {
58
- return `Parameters \`avoidZero\` must be of type \`${validType}\`, but received: \`${currentType}\`.`;
59
- }
60
- });
61
- if (!isInteger(minLength) || !isInteger(maxLength)) {
62
- throw new TypeError(
63
- `Parameters \`minLength\` and \`maxLength\` must be of type \`integer-number\`, but received: ['minLength': \`${getPreciseType(
64
- minLength
65
- )}\` - (with value: ${safeStableStringify(
66
- minLength
67
- )}), 'maxLength': \`${getPreciseType(
68
- maxLength
69
- )}\` - (with value: ${safeStableStringify(maxLength)})].`
70
- );
71
- }
72
- if (minLength < 1 || maxLength > 16 || minLength > maxLength) {
73
- throw new RangeError(
74
- `Invalid range at parameters \`minLength\` must be \u2265 1, \`maxLength\` must be \u2264 16, and \`minLength\` \u2264 \`maxLength\`, but received: ['minLength': \`${minLength}\`, 'maxLength': \`${maxLength}\`].`
75
- );
76
- }
77
- const randomLength = minLength === maxLength ? minLength : randomInt(minLength, maxLength);
78
- const minValue = 10 ** (randomLength - 1);
79
- const maxValue = 10 ** randomLength - 1;
80
- let result = randomInt(minValue, maxValue);
81
- if (avoidZero && result === 0) {
82
- result = minValue;
83
- }
84
- return result;
85
- };
86
-
87
- var randomStr = (options) => {
88
- if (!isPlainObject(options)) {
89
- options = {};
90
- }
91
- const {
92
- minLength = 40,
93
- maxLength = 40,
94
- type = "string",
95
- avoidWhiteSpace = true
96
- } = options;
97
- assertIsBoolean(avoidWhiteSpace, {
98
- message({ currentType, validType }) {
99
- return `Parameters \`avoidWhiteSpace\` property of the \`options\` (first-parameter) must be of type \`${validType}\`, but received: \`${currentType}\`.`;
100
- }
101
- });
102
- if (!isInteger(minLength) || !isInteger(maxLength)) {
103
- throw new TypeError(
104
- `Parameters \`minLength\` and \`maxLength\` must be of type \`integer-number\`, but received: ['minLength': \`${getPreciseType(
105
- minLength
106
- )}\` - (with value: ${safeStableStringify(
107
- minLength
108
- )}), 'maxLength': \`${getPreciseType(
109
- maxLength
110
- )}\` - (with value: ${safeStableStringify(maxLength)})].`
111
- );
112
- }
113
- if (minLength < 1 || maxLength > 5e3 || minLength > maxLength) {
114
- throw new RangeError(
115
- `Invalid range at parameters \`minLength\` must be \u2265 1, \`maxLength\` must be \u2264 5000, and \`minLength\` \u2264 \`maxLength\`, but received: ['minLength': \`${minLength}\`, 'maxLength': \`${maxLength}\`].`
116
- );
117
- }
118
- if (type !== "string" && type !== "number") {
119
- throw new TypeError(
120
- `Parameter \`type\` must be of type \`string\` with value one of "string" | "number", but received: \`${getPreciseType(
121
- type
122
- )}\`, with value: ${safeStableStringify(type)}.`
123
- );
124
- }
125
- const length = randomInt(minLength, maxLength);
126
- const cleanCharacters = (charSet) => {
127
- return avoidWhiteSpace ? charSet.replace(/\s|\n|\t/g, "") : charSet;
128
- };
129
- const defaultNumberSet = "0123456789";
130
- const defaultStringSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
131
- const baseCharSet = type === "number" ? (!isNaN(Number(options.replaceGenInt)) ? options.replaceGenInt : void 0) ?? defaultNumberSet : (options.replaceGenStr ? options.replaceGenStr : void 0) ?? defaultStringSet;
132
- const characterSet = cleanCharacters(baseCharSet) + (options.addChar || "");
133
- if (!characterSet.length) {
134
- const errCharSet = () => {
135
- if (type === "number") {
136
- if (avoidWhiteSpace) {
137
- return `If \`avoidWhiteSpace\` is true, and \`replaceGenInt\` cant be empty-string value, ensure \`replaceGenInt\` has valid characters and non-nan string number.`;
138
- }
139
- return `Ensure \`replaceGenInt\` has valid characters and not a NaN number string while convert to number.`;
140
- }
141
- return `Ensure \`replaceGenStr\` has valid characters and non empty string.`;
142
- };
143
- throw new Error(`Character set is empty. ${errCharSet()}`);
144
- }
145
- let result = "";
146
- for (let i = 0; i < length; i++) {
147
- result += characterSet.charAt(Math.floor(Math.random() * characterSet.length));
148
- }
149
- return result;
150
- };
151
-
152
- export { getRandomItem, randomInt, randomIntByLength, randomStr };