ts-data-forge 10.0.0 → 11.0.1

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 (249) hide show
  1. package/dist/array/impl/array-utils-creation.d.mts +3 -3
  2. package/dist/array/impl/array-utils-creation.d.mts.map +1 -1
  3. package/dist/array/impl/array-utils-creation.mjs.map +1 -1
  4. package/dist/array/impl/array-utils-element-access.d.mts +4 -4
  5. package/dist/array/impl/array-utils-element-access.mjs.map +1 -1
  6. package/dist/{guard/as-length-bounded-array.d.mts → array/impl/array-utils-length-bounded-array-cast.d.mts} +9 -9
  7. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -0
  8. package/dist/{guard/as-length-bounded-array.mjs → array/impl/array-utils-length-bounded-array-cast.mjs} +2 -2
  9. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -0
  10. package/dist/{guard/is-length-bounded-array.d.mts → array/impl/array-utils-length-bounded-array-guard.d.mts} +13 -13
  11. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -0
  12. package/dist/{guard/is-length-bounded-array.mjs → array/impl/array-utils-length-bounded-array-guard.mjs} +1 -1
  13. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -0
  14. package/dist/array/impl/array-utils-modification.d.mts +9 -9
  15. package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
  16. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  17. package/dist/array/impl/array-utils-reducing-value.d.mts +9 -9
  18. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  19. package/dist/array/impl/array-utils-size.d.mts +3 -3
  20. package/dist/array/impl/array-utils-size.mjs.map +1 -1
  21. package/dist/array/impl/array-utils-slicing.d.mts +9 -9
  22. package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
  23. package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
  24. package/dist/array/impl/array-utils-transformation.d.mts +16 -10
  25. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  26. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  27. package/dist/array/impl/index.d.mts +2 -0
  28. package/dist/array/impl/index.d.mts.map +1 -1
  29. package/dist/array/impl/index.mjs +2 -0
  30. package/dist/array/impl/index.mjs.map +1 -1
  31. package/dist/entry-point.mjs +1 -3
  32. package/dist/entry-point.mjs.map +1 -1
  33. package/dist/guard/index.d.mts +0 -3
  34. package/dist/guard/index.d.mts.map +1 -1
  35. package/dist/guard/index.mjs +0 -3
  36. package/dist/guard/index.mjs.map +1 -1
  37. package/dist/index.d.mts +1 -0
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.mjs +1 -3
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/number/branded-types/finite-number.d.mts +47 -61
  42. package/dist/number/branded-types/finite-number.d.mts.map +1 -1
  43. package/dist/number/branded-types/finite-number.mjs +37 -41
  44. package/dist/number/branded-types/finite-number.mjs.map +1 -1
  45. package/dist/number/branded-types/int.d.mts +40 -46
  46. package/dist/number/branded-types/int.d.mts.map +1 -1
  47. package/dist/number/branded-types/int.mjs +29 -31
  48. package/dist/number/branded-types/int.mjs.map +1 -1
  49. package/dist/number/branded-types/int16.d.mts +65 -58
  50. package/dist/number/branded-types/int16.d.mts.map +1 -1
  51. package/dist/number/branded-types/int16.mjs +49 -45
  52. package/dist/number/branded-types/int16.mjs.map +1 -1
  53. package/dist/number/branded-types/int32.d.mts +65 -58
  54. package/dist/number/branded-types/int32.d.mts.map +1 -1
  55. package/dist/number/branded-types/int32.mjs +49 -45
  56. package/dist/number/branded-types/int32.mjs.map +1 -1
  57. package/dist/number/branded-types/negative-finite-number.d.mts +68 -59
  58. package/dist/number/branded-types/negative-finite-number.d.mts.map +1 -1
  59. package/dist/number/branded-types/negative-finite-number.mjs +52 -46
  60. package/dist/number/branded-types/negative-finite-number.mjs.map +1 -1
  61. package/dist/number/branded-types/negative-int.d.mts +60 -48
  62. package/dist/number/branded-types/negative-int.d.mts.map +1 -1
  63. package/dist/number/branded-types/negative-int.mjs +40 -36
  64. package/dist/number/branded-types/negative-int.mjs.map +1 -1
  65. package/dist/number/branded-types/negative-safe-int.d.mts +57 -56
  66. package/dist/number/branded-types/negative-safe-int.d.mts.map +1 -1
  67. package/dist/number/branded-types/negative-safe-int.mjs +40 -41
  68. package/dist/number/branded-types/negative-safe-int.mjs.map +1 -1
  69. package/dist/number/branded-types/non-negative-finite-number.d.mts +74 -64
  70. package/dist/number/branded-types/non-negative-finite-number.d.mts.map +1 -1
  71. package/dist/number/branded-types/non-negative-finite-number.mjs +58 -51
  72. package/dist/number/branded-types/non-negative-finite-number.mjs.map +1 -1
  73. package/dist/number/branded-types/non-negative-int16.d.mts +64 -57
  74. package/dist/number/branded-types/non-negative-int16.d.mts.map +1 -1
  75. package/dist/number/branded-types/non-negative-int16.mjs +47 -43
  76. package/dist/number/branded-types/non-negative-int16.mjs.map +1 -1
  77. package/dist/number/branded-types/non-negative-int32.d.mts +64 -58
  78. package/dist/number/branded-types/non-negative-int32.d.mts.map +1 -1
  79. package/dist/number/branded-types/non-negative-int32.mjs +47 -44
  80. package/dist/number/branded-types/non-negative-int32.mjs.map +1 -1
  81. package/dist/number/branded-types/non-positive-finite-number.d.mts +64 -54
  82. package/dist/number/branded-types/non-positive-finite-number.d.mts.map +1 -1
  83. package/dist/number/branded-types/non-positive-finite-number.mjs +48 -41
  84. package/dist/number/branded-types/non-positive-finite-number.mjs.map +1 -1
  85. package/dist/number/branded-types/non-positive-int.d.mts +41 -146
  86. package/dist/number/branded-types/non-positive-int.d.mts.map +1 -1
  87. package/dist/number/branded-types/non-positive-int.mjs +27 -107
  88. package/dist/number/branded-types/non-positive-int.mjs.map +1 -1
  89. package/dist/number/branded-types/non-positive-safe-int.d.mts +54 -53
  90. package/dist/number/branded-types/non-positive-safe-int.d.mts.map +1 -1
  91. package/dist/number/branded-types/non-positive-safe-int.mjs +37 -39
  92. package/dist/number/branded-types/non-positive-safe-int.mjs.map +1 -1
  93. package/dist/number/branded-types/non-zero-finite-number.d.mts +62 -49
  94. package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
  95. package/dist/number/branded-types/non-zero-finite-number.mjs +46 -37
  96. package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
  97. package/dist/number/branded-types/non-zero-int.d.mts +51 -38
  98. package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
  99. package/dist/number/branded-types/non-zero-int.mjs +31 -27
  100. package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
  101. package/dist/number/branded-types/non-zero-int16.d.mts +52 -53
  102. package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
  103. package/dist/number/branded-types/non-zero-int16.mjs +36 -39
  104. package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
  105. package/dist/number/branded-types/non-zero-int32.d.mts +52 -54
  106. package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
  107. package/dist/number/branded-types/non-zero-int32.mjs +36 -40
  108. package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
  109. package/dist/number/branded-types/non-zero-safe-int.d.mts +53 -54
  110. package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
  111. package/dist/number/branded-types/non-zero-safe-int.mjs +36 -40
  112. package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
  113. package/dist/number/branded-types/non-zero-uint16.d.mts +52 -53
  114. package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
  115. package/dist/number/branded-types/non-zero-uint16.mjs +35 -39
  116. package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
  117. package/dist/number/branded-types/non-zero-uint32.d.mts +52 -53
  118. package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
  119. package/dist/number/branded-types/non-zero-uint32.mjs +35 -39
  120. package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
  121. package/dist/number/branded-types/positive-finite-number.d.mts +74 -63
  122. package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
  123. package/dist/number/branded-types/positive-finite-number.mjs +58 -50
  124. package/dist/number/branded-types/positive-finite-number.mjs.map +1 -1
  125. package/dist/number/branded-types/positive-int.d.mts +46 -68
  126. package/dist/number/branded-types/positive-int.d.mts.map +1 -1
  127. package/dist/number/branded-types/positive-int.mjs +34 -49
  128. package/dist/number/branded-types/positive-int.mjs.map +1 -1
  129. package/dist/number/branded-types/positive-int16.d.mts +61 -57
  130. package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
  131. package/dist/number/branded-types/positive-int16.mjs +44 -43
  132. package/dist/number/branded-types/positive-int16.mjs.map +1 -1
  133. package/dist/number/branded-types/positive-int32.d.mts +61 -57
  134. package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
  135. package/dist/number/branded-types/positive-int32.mjs +44 -43
  136. package/dist/number/branded-types/positive-int32.mjs.map +1 -1
  137. package/dist/number/branded-types/positive-safe-int.d.mts +62 -57
  138. package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
  139. package/dist/number/branded-types/positive-safe-int.mjs +45 -43
  140. package/dist/number/branded-types/positive-safe-int.mjs.map +1 -1
  141. package/dist/number/branded-types/positive-uint16.d.mts +61 -57
  142. package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
  143. package/dist/number/branded-types/positive-uint16.mjs +44 -43
  144. package/dist/number/branded-types/positive-uint16.mjs.map +1 -1
  145. package/dist/number/branded-types/positive-uint32.d.mts +61 -58
  146. package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
  147. package/dist/number/branded-types/positive-uint32.mjs +44 -44
  148. package/dist/number/branded-types/positive-uint32.mjs.map +1 -1
  149. package/dist/number/branded-types/safe-int.d.mts +43 -62
  150. package/dist/number/branded-types/safe-int.d.mts.map +1 -1
  151. package/dist/number/branded-types/safe-int.mjs +35 -42
  152. package/dist/number/branded-types/safe-int.mjs.map +1 -1
  153. package/dist/number/branded-types/safe-uint.d.mts +62 -57
  154. package/dist/number/branded-types/safe-uint.d.mts.map +1 -1
  155. package/dist/number/branded-types/safe-uint.mjs +46 -44
  156. package/dist/number/branded-types/safe-uint.mjs.map +1 -1
  157. package/dist/number/branded-types/uint.d.mts +63 -50
  158. package/dist/number/branded-types/uint.d.mts.map +1 -1
  159. package/dist/number/branded-types/uint.mjs +42 -39
  160. package/dist/number/branded-types/uint.mjs.map +1 -1
  161. package/dist/number/branded-types/uint16.d.mts +60 -58
  162. package/dist/number/branded-types/uint16.d.mts.map +1 -1
  163. package/dist/number/branded-types/uint16.mjs +44 -43
  164. package/dist/number/branded-types/uint16.mjs.map +1 -1
  165. package/dist/number/branded-types/uint32.d.mts +59 -55
  166. package/dist/number/branded-types/uint32.d.mts.map +1 -1
  167. package/dist/number/branded-types/uint32.mjs +42 -42
  168. package/dist/number/branded-types/uint32.mjs.map +1 -1
  169. package/dist/number/enum/int8.d.mts +56 -65
  170. package/dist/number/enum/int8.d.mts.map +1 -1
  171. package/dist/number/enum/int8.mjs +44 -43
  172. package/dist/number/enum/int8.mjs.map +1 -1
  173. package/dist/number/enum/uint8.d.mts +60 -58
  174. package/dist/number/enum/uint8.d.mts.map +1 -1
  175. package/dist/number/enum/uint8.mjs +44 -43
  176. package/dist/number/enum/uint8.mjs.map +1 -1
  177. package/dist/string/index.d.mts +2 -0
  178. package/dist/string/index.d.mts.map +1 -0
  179. package/dist/string/index.mjs +2 -0
  180. package/dist/string/index.mjs.map +1 -0
  181. package/dist/string/str.d.mts +273 -0
  182. package/dist/string/str.d.mts.map +1 -0
  183. package/dist/string/str.mjs +42 -0
  184. package/dist/string/str.mjs.map +1 -0
  185. package/package.json +31 -92
  186. package/src/array/impl/array-utils-creation.mts +2 -1
  187. package/src/array/impl/array-utils-element-access.mts +3 -3
  188. package/src/array/impl/array-utils-element-access.test.mts +3 -3
  189. package/src/{guard/as-length-bounded-array.mts → array/impl/array-utils-length-bounded-array-cast.mts} +9 -9
  190. package/src/{guard/as-length-bounded-array.test.mts → array/impl/array-utils-length-bounded-array-cast.test.mts} +2 -2
  191. package/src/{guard/is-length-bounded-array.mts → array/impl/array-utils-length-bounded-array-guard.mts} +12 -12
  192. package/src/{guard/is-length-bounded-array.test.mts → array/impl/array-utils-length-bounded-array-guard.test.mts} +2 -2
  193. package/src/array/impl/array-utils-modification.mts +9 -8
  194. package/src/array/impl/array-utils-modification.test.mts +6 -1
  195. package/src/array/impl/array-utils-reducing-value.mts +9 -9
  196. package/src/array/impl/array-utils-size.mts +2 -2
  197. package/src/array/impl/array-utils-slicing.mts +24 -13
  198. package/src/array/impl/array-utils-transformation.mts +18 -12
  199. package/src/array/impl/array-utils-transformation.test.mts +12 -12
  200. package/src/array/impl/index.mts +2 -0
  201. package/src/guard/index.mts +0 -3
  202. package/src/index.mts +1 -0
  203. package/src/number/branded-types/finite-number.mts +47 -61
  204. package/src/number/branded-types/int.mts +40 -46
  205. package/src/number/branded-types/int16.mts +65 -58
  206. package/src/number/branded-types/int32.mts +65 -58
  207. package/src/number/branded-types/negative-finite-number.mts +68 -68
  208. package/src/number/branded-types/negative-int.mts +60 -57
  209. package/src/number/branded-types/negative-safe-int.mts +57 -65
  210. package/src/number/branded-types/non-negative-finite-number.mts +74 -64
  211. package/src/number/branded-types/non-negative-int16.mts +64 -57
  212. package/src/number/branded-types/non-negative-int32.mts +64 -58
  213. package/src/number/branded-types/non-positive-finite-number.mts +64 -54
  214. package/src/number/branded-types/non-positive-int.mts +41 -146
  215. package/src/number/branded-types/non-positive-safe-int.mts +54 -53
  216. package/src/number/branded-types/non-zero-finite-number.mts +62 -51
  217. package/src/number/branded-types/non-zero-int.mts +51 -38
  218. package/src/number/branded-types/non-zero-int16.mts +52 -53
  219. package/src/number/branded-types/non-zero-int32.mts +52 -54
  220. package/src/number/branded-types/non-zero-safe-int.mts +53 -54
  221. package/src/number/branded-types/non-zero-uint16.mts +52 -53
  222. package/src/number/branded-types/non-zero-uint32.mts +52 -53
  223. package/src/number/branded-types/positive-finite-number.mts +74 -63
  224. package/src/number/branded-types/positive-int.mts +46 -68
  225. package/src/number/branded-types/positive-int16.mts +61 -57
  226. package/src/number/branded-types/positive-int32.mts +61 -57
  227. package/src/number/branded-types/positive-safe-int.mts +62 -57
  228. package/src/number/branded-types/positive-uint16.mts +61 -57
  229. package/src/number/branded-types/positive-uint32.mts +61 -58
  230. package/src/number/branded-types/safe-int.mts +43 -62
  231. package/src/number/branded-types/safe-uint.mts +62 -57
  232. package/src/number/branded-types/uint.mts +63 -50
  233. package/src/number/branded-types/uint16.mts +60 -58
  234. package/src/number/branded-types/uint32.mts +59 -55
  235. package/src/number/enum/int8.mts +56 -65
  236. package/src/number/enum/uint8.mts +60 -58
  237. package/src/string/index.mts +1 -0
  238. package/src/string/str.mts +371 -0
  239. package/src/string/str.test.mts +215 -0
  240. package/dist/guard/as-length-bounded-array.d.mts.map +0 -1
  241. package/dist/guard/as-length-bounded-array.mjs.map +0 -1
  242. package/dist/guard/is-length-bounded-array.d.mts.map +0 -1
  243. package/dist/guard/is-length-bounded-array.mjs.map +0 -1
  244. package/dist/guard/is-length-bounded-string.d.mts +0 -163
  245. package/dist/guard/is-length-bounded-string.d.mts.map +0 -1
  246. package/dist/guard/is-length-bounded-string.mjs +0 -7
  247. package/dist/guard/is-length-bounded-string.mjs.map +0 -1
  248. package/src/guard/is-length-bounded-string.mts +0 -199
  249. package/src/guard/is-length-bounded-string.test.mts +0 -170
@@ -0,0 +1,273 @@
1
+ import { type BoundedLengthString, type FixedLengthString, type MaxLengthString, type MinLengthString, type SupportedLength } from 'ts-type-forge';
2
+ /**
3
+ * Namespace providing type guards and runtime-checked casts for the branded
4
+ * length-constrained string types (`MinLengthString`, `MaxLengthString`,
5
+ * `BoundedLengthString`, `FixedLengthString`).
6
+ *
7
+ * Lengths are measured in UTF-16 code units (the same unit as
8
+ * `String.prototype.length`), so characters outside the Basic Multilingual
9
+ * Plane (e.g. emoji) count as 2.
10
+ */
11
+ export declare namespace Str {
12
+ /**
13
+ * Type guard that checks if a string has at least `minLength` characters.
14
+ *
15
+ * **Type Narrowing Behavior:**
16
+ *
17
+ * - Narrows the input to `MinLengthString<MinLength>` while preserving the
18
+ * original string type (e.g. literal types) via intersection.
19
+ * - The result participates in the length-constraint subtyping relation: for
20
+ * example, a value narrowed to `MinLengthString<3>` is assignable to
21
+ * `MinLengthString<1>` (= `NonEmptyString`).
22
+ *
23
+ * @example
24
+ *
25
+ * ```ts
26
+ * const input: string = 'very-secret-password';
27
+ *
28
+ * assert.isTrue(Str.isMinLengthString(input, 12));
29
+ *
30
+ * assert.isFalse(Str.isMinLengthString('short', 12));
31
+ *
32
+ * if (Str.isMinLengthString(input, 12)) {
33
+ * const nonEmpty: NonEmptyString = input; // OK (12 >= 1)
34
+ *
35
+ * assert.isTrue(nonEmpty.length >= 12);
36
+ * }
37
+ * ```
38
+ *
39
+ * @template S - The input string type (literal types are preserved).
40
+ * @template MinLength - The minimum number of characters (inclusive).
41
+ * @param s - The string to check.
42
+ * @param minLength - The minimum number of characters (inclusive).
43
+ * @returns `true` if `s.length >= minLength`, `false` otherwise. When `true`,
44
+ * TypeScript narrows `s` to `MinLengthString<MinLength> & S`.
45
+ */
46
+ const isMinLengthString: <S extends string, MinLength extends SupportedLength>(s: S, minLength: MinLength) => s is MinLengthString<MinLength> & S;
47
+ /**
48
+ * Type guard that checks if a string has at most `maxLength` characters.
49
+ *
50
+ * **Type Narrowing Behavior:**
51
+ *
52
+ * - Narrows the input to `MaxLengthString<MaxLength>` while preserving the
53
+ * original string type (e.g. literal types) via intersection.
54
+ * - The result participates in the length-constraint subtyping relation: for
55
+ * example, a value narrowed to `MaxLengthString<16>` is assignable to
56
+ * `MaxLengthString<32>`.
57
+ *
58
+ * @example
59
+ *
60
+ * ```ts
61
+ * const input: string = 'noshiro';
62
+ *
63
+ * assert.isTrue(Str.isMaxLengthString(input, 32));
64
+ *
65
+ * assert.isFalse(Str.isMaxLengthString(input, 3));
66
+ *
67
+ * if (Str.isMaxLengthString(input, 32)) {
68
+ * const relaxed: MaxLengthString<64> = input; // OK (32 <= 64)
69
+ *
70
+ * assert.isTrue(relaxed.length <= 32);
71
+ * }
72
+ * ```
73
+ *
74
+ * @template S - The input string type (literal types are preserved).
75
+ * @template MaxLength - The maximum number of characters (inclusive).
76
+ * @param s - The string to check.
77
+ * @param maxLength - The maximum number of characters (inclusive).
78
+ * @returns `true` if `s.length <= maxLength`, `false` otherwise. When `true`,
79
+ * TypeScript narrows `s` to `MaxLengthString<MaxLength> & S`.
80
+ */
81
+ const isMaxLengthString: <S extends string, MaxLength extends SupportedLength>(s: S, maxLength: MaxLength) => s is MaxLengthString<MaxLength> & S;
82
+ /**
83
+ * Type guard that checks if a string's length is within the inclusive range
84
+ * `[minLength, maxLength]`.
85
+ *
86
+ * **Type Narrowing Behavior:**
87
+ *
88
+ * - Narrows the input to `BoundedLengthString<MinLength, MaxLength>` while
89
+ * preserving the original string type (e.g. literal types) via intersection.
90
+ * - Since `BoundedLengthString` is the intersection of `MinLengthString` and
91
+ * `MaxLengthString`, the narrowed value is assignable to both, and both
92
+ * bounds can be weakened independently.
93
+ *
94
+ * @example
95
+ *
96
+ * ```ts
97
+ * const input: string = 'user-12345678';
98
+ *
99
+ * assert.isTrue(Str.isBoundedLengthString(input, 8, 16));
100
+ *
101
+ * assert.isFalse(Str.isBoundedLengthString('user', 8, 16));
102
+ *
103
+ * if (Str.isBoundedLengthString(input, 8, 16)) {
104
+ * const userId: BoundedLengthString<1, 255> = input; // OK ([8, 16] ⊆ [1, 255])
105
+ *
106
+ * assert.isTrue(userId.length >= 8 && userId.length <= 16);
107
+ * }
108
+ * ```
109
+ *
110
+ * @template S - The input string type (literal types are preserved).
111
+ * @template MinLength - The minimum number of characters (inclusive).
112
+ * @template MaxLength - The maximum number of characters (inclusive).
113
+ * @param s - The string to check.
114
+ * @param minLength - The minimum number of characters (inclusive).
115
+ * @param maxLength - The maximum number of characters (inclusive).
116
+ * @returns `true` if `minLength <= s.length && s.length <= maxLength`, `false`
117
+ * otherwise. When `true`, TypeScript narrows `s` to
118
+ * `BoundedLengthString<MinLength, MaxLength> & S`.
119
+ */
120
+ const isBoundedLengthString: <S extends string, MinLength extends SupportedLength, MaxLength extends SupportedLength>(s: S, minLength: MinLength, maxLength: MaxLength) => s is BoundedLengthString<MinLength, MaxLength> & S;
121
+ /**
122
+ * Type guard that checks if a string has exactly `length` characters.
123
+ *
124
+ * **Type Narrowing Behavior:**
125
+ *
126
+ * - Narrows the input to `FixedLengthString<Length>` while preserving the
127
+ * original string type (e.g. literal types) via intersection.
128
+ * - Since `FixedLengthString<Length>` is defined as
129
+ * `BoundedLengthString<Length, Length>`, the narrowed value is assignable to
130
+ * any `MinLengthString<N>` with `N <= Length` and any `MaxLengthString<N>`
131
+ * with `N >= Length`.
132
+ *
133
+ * @example
134
+ *
135
+ * ```ts
136
+ * const input: string = 'JP';
137
+ *
138
+ * assert.isTrue(Str.isFixedLengthString(input, 2));
139
+ *
140
+ * assert.isFalse(Str.isFixedLengthString(input, 3));
141
+ *
142
+ * if (Str.isFixedLengthString(input, 2)) {
143
+ * const atMost5: MaxLengthString<5> = input; // OK (2 <= 5)
144
+ *
145
+ * assert.isTrue(atMost5.length === 2);
146
+ * }
147
+ * ```
148
+ *
149
+ * @template S - The input string type (literal types are preserved).
150
+ * @template Length - The exact number of characters.
151
+ * @param s - The string to check.
152
+ * @param length - The exact number of characters.
153
+ * @returns `true` if `s.length === length`, `false` otherwise. When `true`,
154
+ * TypeScript narrows `s` to `FixedLengthString<Length> & S`.
155
+ */
156
+ const isFixedLengthString: <S extends string, Length extends SupportedLength>(s: S, length: Length) => s is FixedLengthString<Length> & S;
157
+ /**
158
+ * Casts a string to `MinLengthString<MinLength>` after checking that it has
159
+ * at least `minLength` characters.
160
+ *
161
+ * Use this instead of writing `s as unknown as MinLengthString<N>`: the
162
+ * length is verified at runtime, and the original string type (e.g. literal
163
+ * types) is preserved via intersection.
164
+ *
165
+ * @example
166
+ *
167
+ * ```ts
168
+ * const password = Str.asMinLengthString('very-secret-password', 12);
169
+ *
170
+ * const nonEmpty: NonEmptyString = password; // OK (>= 1)
171
+ *
172
+ * assert.isTrue(nonEmpty.length >= 12);
173
+ *
174
+ * assert.throws(() => Str.asMinLengthString('short', 12)); // length 5 < 12
175
+ * ```
176
+ *
177
+ * @template S - The input string type (literal types are preserved).
178
+ * @template MinLength - The minimum number of characters (inclusive).
179
+ * @param s - The string to cast.
180
+ * @param minLength - The minimum number of characters (inclusive).
181
+ * @returns `s` typed as `MinLengthString<MinLength> & S`.
182
+ * @throws {TypeError} If `s.length < minLength`.
183
+ */
184
+ const asMinLengthString: <S extends string, MinLength extends SupportedLength>(s: S, minLength: MinLength) => MinLengthString<MinLength> & S;
185
+ /**
186
+ * Casts a string to `MaxLengthString<MaxLength>` after checking that it has
187
+ * at most `maxLength` characters.
188
+ *
189
+ * Use this instead of writing `s as unknown as MaxLengthString<N>`: the
190
+ * length is verified at runtime, and the original string type (e.g. literal
191
+ * types) is preserved via intersection.
192
+ *
193
+ * @example
194
+ *
195
+ * ```ts
196
+ * const userName = Str.asMaxLengthString('noshiro', 32);
197
+ *
198
+ * const relaxed: MaxLengthString<64> = userName; // OK (32 <= 64)
199
+ *
200
+ * assert.isTrue(relaxed.length <= 32);
201
+ *
202
+ * assert.throws(() => Str.asMaxLengthString('noshiro', 3)); // length 7 > 3
203
+ * ```
204
+ *
205
+ * @template S - The input string type (literal types are preserved).
206
+ * @template MaxLength - The maximum number of characters (inclusive).
207
+ * @param s - The string to cast.
208
+ * @param maxLength - The maximum number of characters (inclusive).
209
+ * @returns `s` typed as `MaxLengthString<MaxLength> & S`.
210
+ * @throws {TypeError} If `s.length > maxLength`.
211
+ */
212
+ const asMaxLengthString: <S extends string, MaxLength extends SupportedLength>(s: S, maxLength: MaxLength) => MaxLengthString<MaxLength> & S;
213
+ /**
214
+ * Casts a string to `BoundedLengthString<MinLength, MaxLength>` after
215
+ * checking that its length is within the inclusive range
216
+ * `[minLength, maxLength]`.
217
+ *
218
+ * Use this instead of writing `s as unknown as BoundedLengthString<M, N>`:
219
+ * the length is verified at runtime, and the original string type (e.g.
220
+ * literal types) is preserved via intersection.
221
+ *
222
+ * @example
223
+ *
224
+ * ```ts
225
+ * const userId = Str.asBoundedLengthString('user-12345678', 8, 16);
226
+ *
227
+ * const relaxed: BoundedLengthString<1, 255> = userId; // OK ([8, 16] ⊆ [1, 255])
228
+ *
229
+ * assert.isTrue(relaxed.length >= 8 && relaxed.length <= 16);
230
+ *
231
+ * assert.throws(() => Str.asBoundedLengthString('user', 8, 16)); // length 4 < 8
232
+ * ```
233
+ *
234
+ * @template S - The input string type (literal types are preserved).
235
+ * @template MinLength - The minimum number of characters (inclusive).
236
+ * @template MaxLength - The maximum number of characters (inclusive).
237
+ * @param s - The string to cast.
238
+ * @param minLength - The minimum number of characters (inclusive).
239
+ * @param maxLength - The maximum number of characters (inclusive).
240
+ * @returns `s` typed as `BoundedLengthString<MinLength, MaxLength> & S`.
241
+ * @throws {TypeError} If `s.length < minLength` or `s.length > maxLength`.
242
+ */
243
+ const asBoundedLengthString: <S extends string, MinLength extends SupportedLength, MaxLength extends SupportedLength>(s: S, minLength: MinLength, maxLength: MaxLength) => BoundedLengthString<MinLength, MaxLength> & S;
244
+ /**
245
+ * Casts a string to `FixedLengthString<Length>` after checking that it has
246
+ * exactly `length` characters.
247
+ *
248
+ * Use this instead of writing `s as unknown as FixedLengthString<N>`: the
249
+ * length is verified at runtime, and the original string type (e.g. literal
250
+ * types) is preserved via intersection.
251
+ *
252
+ * @example
253
+ *
254
+ * ```ts
255
+ * const countryCode = Str.asFixedLengthString('JP', 2);
256
+ *
257
+ * const atMost5: MaxLengthString<5> = countryCode; // OK (2 <= 5)
258
+ *
259
+ * assert.isTrue(atMost5.length === 2);
260
+ *
261
+ * assert.throws(() => Str.asFixedLengthString('JP', 3)); // length 2 !== 3
262
+ * ```
263
+ *
264
+ * @template S - The input string type (literal types are preserved).
265
+ * @template Length - The exact number of characters.
266
+ * @param s - The string to cast.
267
+ * @param length - The exact number of characters.
268
+ * @returns `s` typed as `FixedLengthString<Length> & S`.
269
+ * @throws {TypeError} If `s.length !== length`.
270
+ */
271
+ const asFixedLengthString: <S extends string, Length extends SupportedLength>(s: S, length: Length) => FixedLengthString<Length> & S;
272
+ }
273
+ //# sourceMappingURL=str.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"str.d.mts","sourceRoot":"","sources":["../../src/string/str.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;GAQG;AACH,yBAAiB,GAAG,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACI,MAAM,iBAAiB,GAC5B,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,KACnB,CAAC,IAAI,eAAe,CAAC,SAAS,CAAC,GAAG,CAA0B,CAAC;IAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACI,MAAM,iBAAiB,GAC5B,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,KACnB,CAAC,IAAI,eAAe,CAAC,SAAS,CAAC,GAAG,CAA0B,CAAC;IAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACI,MAAM,qBAAqB,GAChC,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,EACjC,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,aACT,SAAS,KACnB,CAAC,IAAI,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,CACJ,CAAC;IAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACI,MAAM,mBAAmB,GAC9B,CAAC,SAAS,MAAM,EAChB,MAAM,SAAS,eAAe,KAE3B,CAAC,UACI,MAAM,KACb,CAAC,IAAI,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAwB,CAAC;IAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACI,MAAM,iBAAiB,GAC5B,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,KACnB,eAAe,CAAC,SAAS,CAAC,GAAG,CAQ/B,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACI,MAAM,iBAAiB,GAC5B,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,KACnB,eAAe,CAAC,SAAS,CAAC,GAAG,CAQ/B,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACI,MAAM,qBAAqB,GAChC,CAAC,SAAS,MAAM,EAChB,SAAS,SAAS,eAAe,EACjC,SAAS,SAAS,eAAe,KAE9B,CAAC,aACO,SAAS,aACT,SAAS,KACnB,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,CAQ9C,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACI,MAAM,mBAAmB,GAC9B,CAAC,SAAS,MAAM,EAChB,MAAM,SAAS,eAAe,KAE3B,CAAC,UACI,MAAM,KACb,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAQ9B,CAAC;CACH"}
@@ -0,0 +1,42 @@
1
+ var Str;
2
+ ((Str2) => {
3
+ Str2.isMinLengthString = (s, minLength) => s.length >= minLength;
4
+ Str2.isMaxLengthString = (s, maxLength) => s.length <= maxLength;
5
+ Str2.isBoundedLengthString = (s, minLength, maxLength) => s.length >= minLength && s.length <= maxLength;
6
+ Str2.isFixedLengthString = (s, length) => s.length === length;
7
+ Str2.asMinLengthString = (s, minLength) => {
8
+ if (!(0, Str2.isMinLengthString)(s, minLength)) {
9
+ throw new TypeError(
10
+ `Expected a string of length >= ${minLength}, got a string of length ${s.length}`
11
+ );
12
+ }
13
+ return s;
14
+ };
15
+ Str2.asMaxLengthString = (s, maxLength) => {
16
+ if (!(0, Str2.isMaxLengthString)(s, maxLength)) {
17
+ throw new TypeError(
18
+ `Expected a string of length <= ${maxLength}, got a string of length ${s.length}`
19
+ );
20
+ }
21
+ return s;
22
+ };
23
+ Str2.asBoundedLengthString = (s, minLength, maxLength) => {
24
+ if (!(0, Str2.isBoundedLengthString)(s, minLength, maxLength)) {
25
+ throw new TypeError(
26
+ `Expected a string of length in [${minLength}, ${maxLength}], got a string of length ${s.length}`
27
+ );
28
+ }
29
+ return s;
30
+ };
31
+ Str2.asFixedLengthString = (s, length) => {
32
+ if (!(0, Str2.isFixedLengthString)(s, length)) {
33
+ throw new TypeError(
34
+ `Expected a string of length ${length}, got a string of length ${s.length}`
35
+ );
36
+ }
37
+ return s;
38
+ };
39
+ })(Str || (Str = {}));
40
+
41
+ export { Str };
42
+ //# sourceMappingURL=str.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"str.mjs","sources":["../../src/string/str.mts"],"sourcesContent":["import {\n type BoundedLengthString,\n type FixedLengthString,\n type MaxLengthString,\n type MinLengthString,\n type SupportedLength,\n} from 'ts-type-forge';\n\n/**\n * Namespace providing type guards and runtime-checked casts for the branded\n * length-constrained string types (`MinLengthString`, `MaxLengthString`,\n * `BoundedLengthString`, `FixedLengthString`).\n *\n * Lengths are measured in UTF-16 code units (the same unit as\n * `String.prototype.length`), so characters outside the Basic Multilingual\n * Plane (e.g. emoji) count as 2.\n */\nexport namespace Str {\n /**\n * Type guard that checks if a string has at least `minLength` characters.\n *\n * **Type Narrowing Behavior:**\n *\n * - Narrows the input to `MinLengthString<MinLength>` while preserving the\n * original string type (e.g. literal types) via intersection.\n * - The result participates in the length-constraint subtyping relation: for\n * example, a value narrowed to `MinLengthString<3>` is assignable to\n * `MinLengthString<1>` (= `NonEmptyString`).\n *\n * @example\n *\n * ```ts\n * const input: string = 'very-secret-password';\n *\n * assert.isTrue(Str.isMinLengthString(input, 12));\n *\n * assert.isFalse(Str.isMinLengthString('short', 12));\n *\n * if (Str.isMinLengthString(input, 12)) {\n * const nonEmpty: NonEmptyString = input; // OK (12 >= 1)\n *\n * assert.isTrue(nonEmpty.length >= 12);\n * }\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MinLength - The minimum number of characters (inclusive).\n * @param s - The string to check.\n * @param minLength - The minimum number of characters (inclusive).\n * @returns `true` if `s.length >= minLength`, `false` otherwise. When `true`,\n * TypeScript narrows `s` to `MinLengthString<MinLength> & S`.\n */\n export const isMinLengthString = <\n S extends string,\n MinLength extends SupportedLength,\n >(\n s: S,\n minLength: MinLength,\n ): s is MinLengthString<MinLength> & S => s.length >= minLength;\n\n /**\n * Type guard that checks if a string has at most `maxLength` characters.\n *\n * **Type Narrowing Behavior:**\n *\n * - Narrows the input to `MaxLengthString<MaxLength>` while preserving the\n * original string type (e.g. literal types) via intersection.\n * - The result participates in the length-constraint subtyping relation: for\n * example, a value narrowed to `MaxLengthString<16>` is assignable to\n * `MaxLengthString<32>`.\n *\n * @example\n *\n * ```ts\n * const input: string = 'noshiro';\n *\n * assert.isTrue(Str.isMaxLengthString(input, 32));\n *\n * assert.isFalse(Str.isMaxLengthString(input, 3));\n *\n * if (Str.isMaxLengthString(input, 32)) {\n * const relaxed: MaxLengthString<64> = input; // OK (32 <= 64)\n *\n * assert.isTrue(relaxed.length <= 32);\n * }\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MaxLength - The maximum number of characters (inclusive).\n * @param s - The string to check.\n * @param maxLength - The maximum number of characters (inclusive).\n * @returns `true` if `s.length <= maxLength`, `false` otherwise. When `true`,\n * TypeScript narrows `s` to `MaxLengthString<MaxLength> & S`.\n */\n export const isMaxLengthString = <\n S extends string,\n MaxLength extends SupportedLength,\n >(\n s: S,\n maxLength: MaxLength,\n ): s is MaxLengthString<MaxLength> & S => s.length <= maxLength;\n\n /**\n * Type guard that checks if a string's length is within the inclusive range\n * `[minLength, maxLength]`.\n *\n * **Type Narrowing Behavior:**\n *\n * - Narrows the input to `BoundedLengthString<MinLength, MaxLength>` while\n * preserving the original string type (e.g. literal types) via intersection.\n * - Since `BoundedLengthString` is the intersection of `MinLengthString` and\n * `MaxLengthString`, the narrowed value is assignable to both, and both\n * bounds can be weakened independently.\n *\n * @example\n *\n * ```ts\n * const input: string = 'user-12345678';\n *\n * assert.isTrue(Str.isBoundedLengthString(input, 8, 16));\n *\n * assert.isFalse(Str.isBoundedLengthString('user', 8, 16));\n *\n * if (Str.isBoundedLengthString(input, 8, 16)) {\n * const userId: BoundedLengthString<1, 255> = input; // OK ([8, 16] ⊆ [1, 255])\n *\n * assert.isTrue(userId.length >= 8 && userId.length <= 16);\n * }\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MinLength - The minimum number of characters (inclusive).\n * @template MaxLength - The maximum number of characters (inclusive).\n * @param s - The string to check.\n * @param minLength - The minimum number of characters (inclusive).\n * @param maxLength - The maximum number of characters (inclusive).\n * @returns `true` if `minLength <= s.length && s.length <= maxLength`, `false`\n * otherwise. When `true`, TypeScript narrows `s` to\n * `BoundedLengthString<MinLength, MaxLength> & S`.\n */\n export const isBoundedLengthString = <\n S extends string,\n MinLength extends SupportedLength,\n MaxLength extends SupportedLength,\n >(\n s: S,\n minLength: MinLength,\n maxLength: MaxLength,\n ): s is BoundedLengthString<MinLength, MaxLength> & S =>\n s.length >= minLength && s.length <= maxLength;\n\n /**\n * Type guard that checks if a string has exactly `length` characters.\n *\n * **Type Narrowing Behavior:**\n *\n * - Narrows the input to `FixedLengthString<Length>` while preserving the\n * original string type (e.g. literal types) via intersection.\n * - Since `FixedLengthString<Length>` is defined as\n * `BoundedLengthString<Length, Length>`, the narrowed value is assignable to\n * any `MinLengthString<N>` with `N <= Length` and any `MaxLengthString<N>`\n * with `N >= Length`.\n *\n * @example\n *\n * ```ts\n * const input: string = 'JP';\n *\n * assert.isTrue(Str.isFixedLengthString(input, 2));\n *\n * assert.isFalse(Str.isFixedLengthString(input, 3));\n *\n * if (Str.isFixedLengthString(input, 2)) {\n * const atMost5: MaxLengthString<5> = input; // OK (2 <= 5)\n *\n * assert.isTrue(atMost5.length === 2);\n * }\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template Length - The exact number of characters.\n * @param s - The string to check.\n * @param length - The exact number of characters.\n * @returns `true` if `s.length === length`, `false` otherwise. When `true`,\n * TypeScript narrows `s` to `FixedLengthString<Length> & S`.\n */\n export const isFixedLengthString = <\n S extends string,\n Length extends SupportedLength,\n >(\n s: S,\n length: Length,\n ): s is FixedLengthString<Length> & S => s.length === length;\n\n /**\n * Casts a string to `MinLengthString<MinLength>` after checking that it has\n * at least `minLength` characters.\n *\n * Use this instead of writing `s as unknown as MinLengthString<N>`: the\n * length is verified at runtime, and the original string type (e.g. literal\n * types) is preserved via intersection.\n *\n * @example\n *\n * ```ts\n * const password = Str.asMinLengthString('very-secret-password', 12);\n *\n * const nonEmpty: NonEmptyString = password; // OK (>= 1)\n *\n * assert.isTrue(nonEmpty.length >= 12);\n *\n * assert.throws(() => Str.asMinLengthString('short', 12)); // length 5 < 12\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MinLength - The minimum number of characters (inclusive).\n * @param s - The string to cast.\n * @param minLength - The minimum number of characters (inclusive).\n * @returns `s` typed as `MinLengthString<MinLength> & S`.\n * @throws {TypeError} If `s.length < minLength`.\n */\n export const asMinLengthString = <\n S extends string,\n MinLength extends SupportedLength,\n >(\n s: S,\n minLength: MinLength,\n ): MinLengthString<MinLength> & S => {\n if (!isMinLengthString(s, minLength)) {\n throw new TypeError(\n `Expected a string of length >= ${minLength}, got a string of length ${s.length}`,\n );\n }\n\n return s;\n };\n\n /**\n * Casts a string to `MaxLengthString<MaxLength>` after checking that it has\n * at most `maxLength` characters.\n *\n * Use this instead of writing `s as unknown as MaxLengthString<N>`: the\n * length is verified at runtime, and the original string type (e.g. literal\n * types) is preserved via intersection.\n *\n * @example\n *\n * ```ts\n * const userName = Str.asMaxLengthString('noshiro', 32);\n *\n * const relaxed: MaxLengthString<64> = userName; // OK (32 <= 64)\n *\n * assert.isTrue(relaxed.length <= 32);\n *\n * assert.throws(() => Str.asMaxLengthString('noshiro', 3)); // length 7 > 3\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MaxLength - The maximum number of characters (inclusive).\n * @param s - The string to cast.\n * @param maxLength - The maximum number of characters (inclusive).\n * @returns `s` typed as `MaxLengthString<MaxLength> & S`.\n * @throws {TypeError} If `s.length > maxLength`.\n */\n export const asMaxLengthString = <\n S extends string,\n MaxLength extends SupportedLength,\n >(\n s: S,\n maxLength: MaxLength,\n ): MaxLengthString<MaxLength> & S => {\n if (!isMaxLengthString(s, maxLength)) {\n throw new TypeError(\n `Expected a string of length <= ${maxLength}, got a string of length ${s.length}`,\n );\n }\n\n return s;\n };\n\n /**\n * Casts a string to `BoundedLengthString<MinLength, MaxLength>` after\n * checking that its length is within the inclusive range\n * `[minLength, maxLength]`.\n *\n * Use this instead of writing `s as unknown as BoundedLengthString<M, N>`:\n * the length is verified at runtime, and the original string type (e.g.\n * literal types) is preserved via intersection.\n *\n * @example\n *\n * ```ts\n * const userId = Str.asBoundedLengthString('user-12345678', 8, 16);\n *\n * const relaxed: BoundedLengthString<1, 255> = userId; // OK ([8, 16] ⊆ [1, 255])\n *\n * assert.isTrue(relaxed.length >= 8 && relaxed.length <= 16);\n *\n * assert.throws(() => Str.asBoundedLengthString('user', 8, 16)); // length 4 < 8\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template MinLength - The minimum number of characters (inclusive).\n * @template MaxLength - The maximum number of characters (inclusive).\n * @param s - The string to cast.\n * @param minLength - The minimum number of characters (inclusive).\n * @param maxLength - The maximum number of characters (inclusive).\n * @returns `s` typed as `BoundedLengthString<MinLength, MaxLength> & S`.\n * @throws {TypeError} If `s.length < minLength` or `s.length > maxLength`.\n */\n export const asBoundedLengthString = <\n S extends string,\n MinLength extends SupportedLength,\n MaxLength extends SupportedLength,\n >(\n s: S,\n minLength: MinLength,\n maxLength: MaxLength,\n ): BoundedLengthString<MinLength, MaxLength> & S => {\n if (!isBoundedLengthString(s, minLength, maxLength)) {\n throw new TypeError(\n `Expected a string of length in [${minLength}, ${maxLength}], got a string of length ${s.length}`,\n );\n }\n\n return s;\n };\n\n /**\n * Casts a string to `FixedLengthString<Length>` after checking that it has\n * exactly `length` characters.\n *\n * Use this instead of writing `s as unknown as FixedLengthString<N>`: the\n * length is verified at runtime, and the original string type (e.g. literal\n * types) is preserved via intersection.\n *\n * @example\n *\n * ```ts\n * const countryCode = Str.asFixedLengthString('JP', 2);\n *\n * const atMost5: MaxLengthString<5> = countryCode; // OK (2 <= 5)\n *\n * assert.isTrue(atMost5.length === 2);\n *\n * assert.throws(() => Str.asFixedLengthString('JP', 3)); // length 2 !== 3\n * ```\n *\n * @template S - The input string type (literal types are preserved).\n * @template Length - The exact number of characters.\n * @param s - The string to cast.\n * @param length - The exact number of characters.\n * @returns `s` typed as `FixedLengthString<Length> & S`.\n * @throws {TypeError} If `s.length !== length`.\n */\n export const asFixedLengthString = <\n S extends string,\n Length extends SupportedLength,\n >(\n s: S,\n length: Length,\n ): FixedLengthString<Length> & S => {\n if (!isFixedLengthString(s, length)) {\n throw new TypeError(\n `Expected a string of length ${length}, got a string of length ${s.length}`,\n );\n }\n\n return s;\n };\n}\n"],"names":["Str"],"mappings":"AAiBO,IAAU;AAAA,CAAV,CAAUA,IAAAA,KAAV;AAmCE,EAAMA,KAAA,iBAAA,GAAoB,CAI/B,CAAA,EACA,SAAA,KACwC,EAAE,MAAA,IAAU,SAAA;AAoC/C,EAAMA,KAAA,iBAAA,GAAoB,CAI/B,CAAA,EACA,SAAA,KACwC,EAAE,MAAA,IAAU,SAAA;AAwC/C,EAAMA,IAAAA,CAAA,qBAAA,GAAwB,CAKnC,CAAA,EACA,SAAA,EACA,cAEA,CAAA,CAAE,MAAA,IAAU,SAAA,IAAa,CAAA,CAAE,MAAA,IAAU,SAAA;AAqChC,EAAMA,KAAA,mBAAA,GAAsB,CAIjC,CAAA,EACA,MAAA,KACuC,EAAE,MAAA,KAAW,MAAA;AA6B/C,EAAMA,IAAAA,CAAA,iBAAA,GAAoB,CAI/B,CAAA,EACA,SAAA,KACmC;AACnC,IAAA,IAAI,CAAA,IAACA,IAAAA,CAAA,iBAAA,EAAkB,CAAA,EAAG,SAAS,CAAA,EAAG;AACpC,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,CAAA,+BAAA,EAAkC,SAAS,CAAA,yBAAA,EAA4B,CAAA,CAAE,MAAM,CAAA;AAAA,OACjF;AAAA,IACF;AAEA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AA6BO,EAAMA,IAAAA,CAAA,iBAAA,GAAoB,CAI/B,CAAA,EACA,SAAA,KACmC;AACnC,IAAA,IAAI,CAAA,IAACA,IAAAA,CAAA,iBAAA,EAAkB,CAAA,EAAG,SAAS,CAAA,EAAG;AACpC,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,CAAA,+BAAA,EAAkC,SAAS,CAAA,yBAAA,EAA4B,CAAA,CAAE,MAAM,CAAA;AAAA,OACjF;AAAA,IACF;AAEA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAgCO,EAAMA,IAAAA,CAAA,qBAAA,GAAwB,CAKnC,CAAA,EACA,WACA,SAAA,KACkD;AAClD,IAAA,IAAI,KAACA,IAAAA,CAAA,qBAAA,EAAsB,CAAA,EAAG,SAAA,EAAW,SAAS,CAAA,EAAG;AACnD,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,mCAAmC,SAAS,CAAA,EAAA,EAAK,SAAS,CAAA,0BAAA,EAA6B,EAAE,MAAM,CAAA;AAAA,OACjG;AAAA,IACF;AAEA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AA6BO,EAAMA,IAAAA,CAAA,mBAAA,GAAsB,CAIjC,CAAA,EACA,MAAA,KACkC;AAClC,IAAA,IAAI,CAAA,IAACA,IAAAA,CAAA,mBAAA,EAAoB,CAAA,EAAG,MAAM,CAAA,EAAG;AACnC,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,CAAA,4BAAA,EAA+B,MAAM,CAAA,yBAAA,EAA4B,CAAA,CAAE,MAAM,CAAA;AAAA,OAC3E;AAAA,IACF;AAEA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAAA,CAAA,EAhWe,GAAA,KAAA,GAAA,GAAA,EAAA,CAAA,CAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-data-forge",
3
- "version": "10.0.0",
3
+ "version": "11.0.1",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -34,117 +34,56 @@
34
34
  "README.md",
35
35
  "LICENSE"
36
36
  ],
37
+ "dependencies": {
38
+ "@sindresorhus/is": "^8.1.0",
39
+ "ts-type-forge": "^7.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@emotion/react": "11.14.0",
43
+ "@emotion/styled": "11.14.1",
44
+ "@mui/material": "9.2.0",
45
+ "@types/react": "19.2.17",
46
+ "immer": "11.1.11",
47
+ "react": "19.2.7",
48
+ "typedoc": "0.28.19",
49
+ "typedoc-github-theme": "0.4.0"
50
+ },
51
+ "peerDependencies": {
52
+ "typescript": ">=4.8"
53
+ },
54
+ "engines": {
55
+ "node": ">=22.22.2",
56
+ "pnpm": ">=9.0.0"
57
+ },
37
58
  "scripts": {
38
59
  "build": "tsx ./scripts/cmd/build.mts",
39
60
  "build:min": "tsx ./scripts/cmd/build.mts --skip-check",
40
61
  "check:ext": "tsx ./scripts/cmd/check-ext.mts",
41
- "check-all": "tsx ./scripts/cmd/check-all.mts",
42
- "clean": "pnpm run /clean:.*/",
43
- "clean:logs": "npx rimraf ./*.log",
44
- "codemod": "run-s codemod:uncommitted:as-const fmt codemod:uncommitted:readonly fmt",
45
- "codemod:diff": "run-s codemod:diff:as-const fmt codemod:diff:readonly fmt",
46
- "codemod:diff:as-const": "append-as-const --diff-from origin/main '{src,scripts,samples,test}/**/*.{mts,tsx}'",
47
- "codemod:diff:readonly": "convert-to-readonly --diff-from origin/main '{src,scripts,samples,test}/**/*.{mts,tsx}'",
48
- "codemod:full": "run-s codemod:full:as-const fmt codemod:full:readonly fmt",
49
- "codemod:full:as-const": "append-as-const '{src,scripts,samples,test}/**/*.{mts,tsx}'",
50
- "codemod:full:readonly": "convert-to-readonly '{src,scripts,samples,test}/**/*.{mts,tsx}'",
51
- "codemod:uncommitted:as-const": "append-as-const --uncommitted '{src,scripts,samples,test}/**/*.{mts,tsx}'",
52
- "codemod:uncommitted:readonly": "convert-to-readonly --uncommitted '{src,scripts,samples,test}/**/*.{mts,tsx}'",
53
- "cspell": "cspell \"**\" --gitignore --gitignore-root ./ --no-progress",
54
62
  "doc": "tsx ./scripts/cmd/gen-docs.mts",
55
63
  "doc:embed": "tsx ./scripts/cmd/embed-examples.mts",
56
64
  "doc:embed:jsdoc": "tsx ./scripts/cmd/embed-examples-in-jsdoc.mts",
57
65
  "doc:preview": "vite preview --config ./configs/vite.doc.config.mts",
58
66
  "doc:watch": "typedoc --options ./configs/typedoc.config.mjs --watch",
59
- "fmt": "format-uncommitted",
60
- "fmt:diff": "format-diff-from origin/main",
61
- "fmt:full": "prettier --write .",
62
- "gh:apply-all": "gh-apply-all",
63
- "gh:apply-repository-settings": "gh-apply-repository-settings",
64
- "gh:apply-rulesets": "gh-apply-rulesets",
65
- "gh:apply-variables": "gh-apply-variables",
66
- "gh:backup-all": "gh-backup-all",
67
- "gh:backup-repository-settings": "gh-backup-repository-settings",
68
- "gh:backup-rulesets": "gh-backup-rulesets",
67
+ "fmt": "format-uncommitted --cwd .",
68
+ "fmt:diff": "format-diff-from origin/main --cwd .",
69
+ "fmt:full": "pnpm run z:prettier .",
70
+ "gen:branded-number": "tsx ./scripts/gen-branded-number/generate.mts && pnpm run doc:embed:jsdoc && pnpm run z:prettier 'src/number/branded-types/*.mts' 'src/number/enum/*.mts'",
69
71
  "gi": "run-s gi:src fmt",
70
72
  "gi:src": "tsx scripts/cmd/gen-index.mts",
71
73
  "lint": "eslint .",
72
74
  "lint:fix": "eslint . --fix",
73
- "md": "markdownlint-cli2",
74
75
  "test": "pnpm run z:vitest:node run",
75
76
  "test:browser": "pnpm run z:vitest --project='Browser' run",
76
77
  "test:cov": "pnpm run z:vitest:node run --coverage",
77
78
  "test:cov:ui": "vite preview --outDir ./coverage",
78
79
  "test:ui": "pnpm run z:vitest:node --ui",
79
80
  "testw": "pnpm run z:vitest:node watch",
80
- "tsc": "node ./node_modules/typescript-native/bin/tsc --noEmit",
81
- "tscw": "node ./node_modules/typescript-native/bin/tsc --noEmit --watch -p ./tsconfig.json",
82
- "type-check": "node ./node_modules/typescript-native/bin/tsc --noEmit",
81
+ "tsc": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
82
+ "tscw": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch -p ./tsconfig.json",
83
+ "type-check": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
83
84
  "update-packages": "pnpm update --latest",
85
+ "z:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --ignore-path ../../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
84
86
  "z:vitest": "vitest --config ./configs/vitest.config.mts",
85
87
  "z:vitest:node": "pnpm run z:vitest --project='Node.js'"
86
- },
87
- "dependencies": {
88
- "@sindresorhus/is": "^8.1.0",
89
- "ts-type-forge": "^6.0.0"
90
- },
91
- "devDependencies": {
92
- "@emotion/react": "11.14.0",
93
- "@emotion/styled": "11.14.1",
94
- "@mui/material": "9.2.0",
95
- "@rollup/plugin-replace": "6.0.3",
96
- "@rollup/plugin-strip": "3.0.4",
97
- "@semantic-release/changelog": "6.0.3",
98
- "@semantic-release/commit-analyzer": "13.0.1",
99
- "@semantic-release/exec": "7.1.0",
100
- "@semantic-release/git": "10.0.1",
101
- "@semantic-release/github": "12.0.9",
102
- "@semantic-release/npm": "13.1.5",
103
- "@semantic-release/release-notes-generator": "14.1.1",
104
- "@types/node": "26.1.0",
105
- "@types/react": "19.2.17",
106
- "@vitest/browser-playwright": "4.1.9",
107
- "@vitest/coverage-v8": "4.1.10",
108
- "@vitest/ui": "4.1.9",
109
- "conventional-changelog-conventionalcommits": "10.2.0",
110
- "cspell": "10.0.1",
111
- "dedent": "1.7.2",
112
- "esbuild": "0.28.1",
113
- "eslint": "9.39.4",
114
- "eslint-config-typed": "5.3.0",
115
- "github-settings-as-code": "1.2.9",
116
- "immer": "11.1.11",
117
- "jiti": "2.7.0",
118
- "markdownlint": "0.41.0",
119
- "markdownlint-cli2": "0.23.0",
120
- "npm-run-all2": "9.0.2",
121
- "playwright": "1.61.1",
122
- "prettier": "3.9.4",
123
- "prettier-plugin-organize-imports": "4.3.0",
124
- "prettier-plugin-packagejson": "3.0.2",
125
- "react": "19.2.7",
126
- "rollup": "4.62.2",
127
- "rollup-plugin-esbuild": "6.2.1",
128
- "semantic-release": "25.0.5",
129
- "ts-codemod-lib": "2.2.1",
130
- "ts-repo-utils": "10.1.2",
131
- "tsx": "4.22.4",
132
- "typedoc": "0.28.19",
133
- "typedoc-github-theme": "0.4.0",
134
- "typescript": "6.0.3",
135
- "typescript-native": "npm:typescript@7.0.1-rc",
136
- "vite": "8.1.3",
137
- "vitest": "4.1.10"
138
- },
139
- "peerDependencies": {
140
- "typescript": ">=4.8"
141
- },
142
- "packageManager": "pnpm@11.10.0+sha512.0b7f8b98060031904c017e3a41eb187a16d40eeb829b95c4f8cb03681761fc4ab53dd219115b9b447f4dce1a05a214764461e7d3703392a9f32f9511ce8c86c8",
143
- "engines": {
144
- "node": ">=22.22.2",
145
- "pnpm": ">=9.0.0"
146
- },
147
- "volta": {
148
- "node": "26.3.1"
149
88
  }
150
- }
89
+ }
@@ -15,6 +15,7 @@ import {
15
15
  type SafeUintWithSmallInt,
16
16
  type Seq,
17
17
  type SmallUint,
18
+ type StructuralPrefixLength,
18
19
  } from 'ts-type-forge';
19
20
  import { expectType } from '../../expect-type.mjs';
20
21
  import { range as rangeIterator } from '../../iterator/index.mjs';
@@ -88,7 +89,7 @@ export const seq = <N extends SizeType.ArgArr>(
88
89
  export const create = <N extends SizeType.ArgArr, const V>(
89
90
  len: N,
90
91
  init: V,
91
- ): N extends SmallUint
92
+ ): N extends StructuralPrefixLength
92
93
  ? FixedLengthTuple<N, V>
93
94
  : N extends SizeType.ArgArrPositive
94
95
  ? NonEmptyArray<V>
@@ -1,4 +1,4 @@
1
- import { type NonEmptyArray } from 'ts-type-forge';
1
+ import { type NonEmptyTuple } from 'ts-type-forge';
2
2
  import { Optional, pipe } from '../../functional/index.mjs';
3
3
  import {
4
4
  type ArgArrayIndexWithNegative,
@@ -90,7 +90,7 @@ export const head = <const Ar extends readonly unknown[]>(
90
90
  ? None
91
91
  : Ar extends readonly [infer E, ...unknown[]]
92
92
  ? Some<E>
93
- : Ar extends NonEmptyArray<infer E>
93
+ : Ar extends NonEmptyTuple<infer E>
94
94
  ? Some<E>
95
95
  : Optional<Ar[number]> =>
96
96
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -121,7 +121,7 @@ export const last = <const Ar extends readonly unknown[]>(
121
121
  ? None
122
122
  : Ar extends readonly [...unknown[], infer E]
123
123
  ? Some<E>
124
- : Ar extends NonEmptyArray<infer E>
124
+ : Ar extends NonEmptyTuple<infer E>
125
125
  ? Some<E>
126
126
  : Optional<Ar[number]> =>
127
127
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -1,4 +1,4 @@
1
- import { type MutableNonEmptyArray } from 'ts-type-forge';
1
+ import { type NonEmptyTuple } from 'ts-type-forge';
2
2
  import { expectType } from '../../expect-type.mjs';
3
3
  import { Optional } from '../../functional/index.mjs';
4
4
  import { asInt32, asUint32 } from '../../number/index.mjs';
@@ -64,7 +64,7 @@ describe('Arr element access', () => {
64
64
  });
65
65
 
66
66
  test('case 2', () => {
67
- const xs: MutableNonEmptyArray<number> = [1, 2, 3] as const;
67
+ const xs: NonEmptyTuple<number> = [1, 2, 3] as const;
68
68
 
69
69
  const h = head(xs);
70
70
 
@@ -134,7 +134,7 @@ describe('Arr element access', () => {
134
134
  });
135
135
 
136
136
  test('case 2', () => {
137
- const xs: MutableNonEmptyArray<number> = [1, 2, 3] as const;
137
+ const xs: NonEmptyTuple<number> = [1, 2, 3] as const;
138
138
 
139
139
  const l = last(xs);
140
140
 
@@ -10,7 +10,7 @@ import {
10
10
  isFixedLengthArray,
11
11
  isMaxLengthArray,
12
12
  isMinLengthArray,
13
- } from './is-length-bounded-array.mjs';
13
+ } from './array-utils-length-bounded-array-guard.mjs';
14
14
 
15
15
  /**
16
16
  * Casts an array to `FixedLengthArray<Length, E>` after checking that it has
@@ -25,12 +25,12 @@ import {
25
25
  * @example
26
26
  *
27
27
  * ```ts
28
- * const rgb = asFixedLengthArray([255, 128, 0], 3);
28
+ * const rgb = Arr.asFixedLengthArray([255, 128, 0], 3);
29
29
  *
30
30
  * const atMost5: MaxLengthArray<5, number> = rgb; // OK (3 <= 5)
31
31
  * const red: number = rgb[0]; // OK — no `undefined`
32
32
  *
33
- * // asFixedLengthArray([255, 128], 3); // throws TypeError
33
+ * // Arr.asFixedLengthArray([255, 128], 3); // throws TypeError
34
34
  * ```
35
35
  *
36
36
  * @template Xs - The input array type (tuple types are preserved).
@@ -69,12 +69,12 @@ export const asFixedLengthArray = <
69
69
  * @example
70
70
  *
71
71
  * ```ts
72
- * const history = asMinLengthArray([0, 1, 2, 3], 3);
72
+ * const history = Arr.asMinLengthArray([0, 1, 2, 3], 3);
73
73
  *
74
74
  * const nonEmpty: MinLengthArray<1, number> = history; // OK (3 >= 1)
75
75
  * const first: number = history[0]; // OK — no `undefined`
76
76
  *
77
- * // asMinLengthArray([0], 3); // throws TypeError
77
+ * // Arr.asMinLengthArray([0], 3); // throws TypeError
78
78
  * ```
79
79
  *
80
80
  * @template Xs - The input array type (tuple types are preserved).
@@ -111,11 +111,11 @@ export const asMinLengthArray = <
111
111
  * @example
112
112
  *
113
113
  * ```ts
114
- * const tags = asMaxLengthArray(['a', 'b', 'c'], 8);
114
+ * const tags = Arr.asMaxLengthArray(['a', 'b', 'c'], 8);
115
115
  *
116
116
  * const relaxed: MaxLengthArray<16, string> = tags; // OK (8 <= 16)
117
117
  *
118
- * // asMaxLengthArray(['a', 'b', 'c'], 2); // throws TypeError
118
+ * // Arr.asMaxLengthArray(['a', 'b', 'c'], 2); // throws TypeError
119
119
  * ```
120
120
  *
121
121
  * @template Xs - The input array type (tuple types are preserved).
@@ -154,11 +154,11 @@ export const asMaxLengthArray = <
154
154
  * @example
155
155
  *
156
156
  * ```ts
157
- * const selection = asBoundedLengthArray([1, 2, 3], 1, 5);
157
+ * const selection = Arr.asBoundedLengthArray([1, 2, 3], 1, 5);
158
158
  *
159
159
  * const relaxed: BoundedLengthArray<0, 100, number> = selection; // OK
160
160
  *
161
- * // asBoundedLengthArray([], 1, 5); // throws TypeError
161
+ * // Arr.asBoundedLengthArray([], 1, 5); // throws TypeError
162
162
  * ```
163
163
  *
164
164
  * @template Xs - The input array type (tuple types are preserved).
@@ -4,13 +4,13 @@ import {
4
4
  type MaxLengthArray,
5
5
  type MinLengthArray,
6
6
  } from 'ts-type-forge';
7
- import { expectType } from '../expect-type.mjs';
7
+ import { expectType } from '../../expect-type.mjs';
8
8
  import {
9
9
  asBoundedLengthArray,
10
10
  asFixedLengthArray,
11
11
  asMaxLengthArray,
12
12
  asMinLengthArray,
13
- } from './as-length-bounded-array.mjs';
13
+ } from './array-utils-length-bounded-array-cast.mjs';
14
14
 
15
15
  describe(asFixedLengthArray, () => {
16
16
  test('should return the input when the length matches exactly', () => {