typia 13.1.19 → 13.3.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 (235) hide show
  1. package/lib/executable/FileSystemIdentity.d.ts +23 -0
  2. package/lib/executable/FileSystemIdentity.js +30 -0
  3. package/lib/executable/FileSystemIdentity.js.map +1 -1
  4. package/lib/executable/FileSystemIdentity.mjs +4 -0
  5. package/lib/executable/FileSystemIdentity.mjs.map +1 -1
  6. package/lib/executable/TypiaGenerateWizard.js +15 -9
  7. package/lib/executable/TypiaGenerateWizard.js.map +1 -1
  8. package/lib/executable/TypiaGenerateWizard.mjs +11 -7
  9. package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
  10. package/lib/http.d.ts +3 -3
  11. package/lib/http.js.map +1 -1
  12. package/lib/http.mjs.map +1 -1
  13. package/lib/internal/_ProtobufReader.d.ts +18 -3
  14. package/lib/internal/_ProtobufReader.js +39 -11
  15. package/lib/internal/_ProtobufReader.js.map +1 -1
  16. package/lib/internal/_ProtobufReader.mjs +37 -10
  17. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  18. package/lib/internal/_assertGuard.js +13 -3
  19. package/lib/internal/_assertGuard.js.map +1 -1
  20. package/lib/internal/_assertGuard.mjs +4 -2
  21. package/lib/internal/_assertGuard.mjs.map +1 -1
  22. package/lib/internal/_isFormatIdnHostname.js +5 -1
  23. package/lib/internal/_isFormatIdnHostname.js.map +1 -1
  24. package/lib/internal/_isFormatIdnHostname.mjs +1 -1
  25. package/lib/internal/_isFormatIdnHostname.mjs.map +1 -1
  26. package/lib/internal/_isFormatTime.js +19 -2
  27. package/lib/internal/_isFormatTime.js.map +1 -1
  28. package/lib/internal/_isFormatTime.mjs +9 -2
  29. package/lib/internal/_isFormatTime.mjs.map +1 -1
  30. package/lib/internal/_jsonStringifyArray.d.ts +1 -0
  31. package/lib/internal/_jsonStringifyArray.js +48 -0
  32. package/lib/internal/_jsonStringifyArray.js.map +1 -0
  33. package/lib/internal/_jsonStringifyArray.mjs +40 -0
  34. package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
  35. package/lib/internal/_jsonStringifyElement.d.ts +1 -0
  36. package/lib/internal/_jsonStringifyElement.js +23 -0
  37. package/lib/internal/_jsonStringifyElement.js.map +1 -0
  38. package/lib/internal/_jsonStringifyElement.mjs +23 -0
  39. package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
  40. package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
  41. package/lib/internal/_jsonStringifyProperty.js +31 -0
  42. package/lib/internal/_jsonStringifyProperty.js.map +1 -0
  43. package/lib/internal/_jsonStringifyProperty.mjs +31 -0
  44. package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
  45. package/lib/internal/_llmApplicationFinalize.js +1 -1
  46. package/lib/internal/_llmApplicationFinalize.js.map +1 -1
  47. package/lib/internal/_llmApplicationFinalize.mjs +1 -1
  48. package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
  49. package/lib/internal/_randomArray.js +37 -4
  50. package/lib/internal/_randomArray.js.map +1 -1
  51. package/lib/internal/_randomArray.mjs +16 -3
  52. package/lib/internal/_randomArray.mjs.map +1 -1
  53. package/lib/internal/_randomFormatByte.js +28 -2
  54. package/lib/internal/_randomFormatByte.js.map +1 -1
  55. package/lib/internal/_randomFormatByte.mjs +22 -3
  56. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  57. package/lib/internal/_randomFormatDate.d.ts +3 -6
  58. package/lib/internal/_randomFormatDate.js +2 -10
  59. package/lib/internal/_randomFormatDate.js.map +1 -1
  60. package/lib/internal/_randomFormatDate.mjs +2 -6
  61. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  62. package/lib/internal/_randomFormatDatetime.d.ts +3 -6
  63. package/lib/internal/_randomFormatDatetime.js +25 -8
  64. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  65. package/lib/internal/_randomFormatDatetime.mjs +17 -7
  66. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  67. package/lib/internal/_randomFormatDuration.js +23 -15
  68. package/lib/internal/_randomFormatDuration.js.map +1 -1
  69. package/lib/internal/_randomFormatDuration.mjs +23 -15
  70. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  71. package/lib/internal/_randomFormatHostname.d.ts +2 -2
  72. package/lib/internal/_randomFormatHostname.js +2 -2
  73. package/lib/internal/_randomFormatHostname.mjs +2 -2
  74. package/lib/internal/_randomFormatHostname.mjs.map +1 -1
  75. package/lib/internal/_randomFormatIdnHostname.js +9 -10
  76. package/lib/internal/_randomFormatIdnHostname.js.map +1 -1
  77. package/lib/internal/_randomFormatIdnHostname.mjs +3 -4
  78. package/lib/internal/_randomFormatIdnHostname.mjs.map +1 -1
  79. package/lib/internal/_randomFormatIpv4.js +31 -1
  80. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  81. package/lib/internal/_randomFormatIpv4.mjs +23 -2
  82. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  83. package/lib/internal/_randomFormatIpv6.js +57 -1
  84. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  85. package/lib/internal/_randomFormatIpv6.mjs +45 -2
  86. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  87. package/lib/internal/_randomFormatJsonPointer.js +14 -2
  88. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  89. package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
  90. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  91. package/lib/internal/_randomFormatRegex.js +15 -2
  92. package/lib/internal/_randomFormatRegex.js.map +1 -1
  93. package/lib/internal/_randomFormatRegex.mjs +14 -3
  94. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  95. package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
  96. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  97. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
  98. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  99. package/lib/internal/_randomFormatTime.js +38 -7
  100. package/lib/internal/_randomFormatTime.js.map +1 -1
  101. package/lib/internal/_randomFormatTime.mjs +40 -5
  102. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  103. package/lib/internal/_randomPattern.js.map +1 -1
  104. package/lib/internal/_randomPattern.mjs.map +1 -1
  105. package/lib/internal/_randomStringLength.d.ts +41 -10
  106. package/lib/internal/_randomStringLength.js +49 -13
  107. package/lib/internal/_randomStringLength.js.map +1 -1
  108. package/lib/internal/_randomStringLength.mjs +48 -13
  109. package/lib/internal/_randomStringLength.mjs.map +1 -1
  110. package/lib/internal/private/__notationRename.js.map +1 -1
  111. package/lib/internal/private/__notationRename.mjs.map +1 -1
  112. package/lib/internal/private/__randomComposition.d.ts +31 -0
  113. package/lib/internal/private/__randomComposition.js +68 -0
  114. package/lib/internal/private/__randomComposition.js.map +1 -0
  115. package/lib/internal/private/__randomComposition.mjs +71 -0
  116. package/lib/internal/private/__randomComposition.mjs.map +1 -0
  117. package/lib/internal/private/__randomEpoch.d.ts +19 -0
  118. package/lib/internal/private/__randomEpoch.js +31 -0
  119. package/lib/internal/private/__randomEpoch.js.map +1 -0
  120. package/lib/internal/private/__randomEpoch.mjs +28 -0
  121. package/lib/internal/private/__randomEpoch.mjs.map +1 -0
  122. package/lib/json.d.ts +2 -2
  123. package/lib/json.js.map +1 -1
  124. package/lib/json.mjs.map +1 -1
  125. package/lib/module.d.ts +28 -13
  126. package/lib/module.js.map +1 -1
  127. package/lib/module.mjs.map +1 -1
  128. package/lib/notations.d.ts +4 -4
  129. package/lib/notations.js.map +1 -1
  130. package/lib/notations.mjs.map +1 -1
  131. package/lib/plain.d.ts +3 -3
  132. package/lib/plain.js.map +1 -1
  133. package/lib/plain.mjs.map +1 -1
  134. package/lib/protobuf.d.ts +2 -2
  135. package/lib/protobuf.js.map +1 -1
  136. package/lib/protobuf.mjs.map +1 -1
  137. package/native/cmd/ttsc-typia/assert_guard_factory_contract_test.go +17 -4
  138. package/native/cmd/ttsc-typia/build.go +3 -0
  139. package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
  140. package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
  141. package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
  142. package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
  143. package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +309 -0
  144. package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
  145. package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
  146. package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
  147. package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
  148. package/native/cmd/ttsc-typia/local_function_named_like_typia_operation_transform_test.go +185 -0
  149. package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
  150. package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
  151. package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
  152. package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
  153. package/native/cmd/ttsc-typia/recursive_conditional_alias_name_transform_test.go +307 -0
  154. package/native/cmd/ttsc-typia/shadowed_typia_module_declaration_diagnostic_test.go +152 -0
  155. package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
  156. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +1 -3
  157. package/native/cmd/ttsc-typia/transform.go +23 -0
  158. package/native/cmd/ttsc-typia/transform_helpers_test.go +166 -25
  159. package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
  160. package/native/core/factories/FormatCheatSheet.go +2 -2
  161. package/native/core/factories/MetadataCommentTagFactory.go +26 -11
  162. package/native/core/factories/ProtobufFactory.go +6 -1
  163. package/native/core/factories/factory_utility_coverage_test.go +896 -907
  164. package/native/core/factories/internal/metadata/MetadataHelper.go +190 -58
  165. package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
  166. package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
  167. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
  168. package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
  169. package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
  170. package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
  171. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +2 -2
  172. package/native/core/programmers/RandomProgrammer.go +5 -2
  173. package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
  174. package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
  175. package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
  176. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
  177. package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
  178. package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
  179. package/native/core/programmers/iterate/json_schema_object.go +49 -7
  180. package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
  181. package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
  182. package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
  183. package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
  184. package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
  185. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
  186. package/native/core/schemas/metadata/MetadataCollection.go +47 -14
  187. package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
  188. package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
  189. package/native/go.mod +4 -4
  190. package/native/transform/CallExpressionTransformer.go +167 -0
  191. package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
  192. package/package.json +3 -7
  193. package/src/executable/FileSystemIdentity.ts +33 -0
  194. package/src/executable/TypiaGenerateWizard.ts +18 -12
  195. package/src/http.ts +18 -4
  196. package/src/internal/_ProtobufReader.ts +40 -11
  197. package/src/internal/_assertGuard.ts +13 -2
  198. package/src/internal/_isFormatIdnHostname.ts +5 -1
  199. package/src/internal/_isFormatTime.ts +19 -2
  200. package/src/internal/_jsonStringifyArray.ts +50 -0
  201. package/src/internal/_jsonStringifyElement.ts +19 -0
  202. package/src/internal/_jsonStringifyProperty.ts +30 -0
  203. package/src/internal/_llmApplicationFinalize.ts +6 -1
  204. package/src/internal/_randomArray.ts +42 -6
  205. package/src/internal/_randomFormatByte.ts +36 -4
  206. package/src/internal/_randomFormatDate.ts +4 -20
  207. package/src/internal/_randomFormatDatetime.ts +34 -20
  208. package/src/internal/_randomFormatDuration.ts +19 -4
  209. package/src/internal/_randomFormatHostname.ts +2 -2
  210. package/src/internal/_randomFormatIdnHostname.ts +8 -9
  211. package/src/internal/_randomFormatIpv4.ts +43 -3
  212. package/src/internal/_randomFormatIpv6.ts +67 -3
  213. package/src/internal/_randomFormatJsonPointer.ts +23 -3
  214. package/src/internal/_randomFormatRegex.ts +22 -6
  215. package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
  216. package/src/internal/_randomFormatTime.ts +50 -12
  217. package/src/internal/_randomPattern.ts +4 -1
  218. package/src/internal/_randomStringLength.ts +61 -17
  219. package/src/internal/private/__notationRename.ts +1 -4
  220. package/src/internal/private/__randomComposition.ts +74 -0
  221. package/src/internal/private/__randomEpoch.ts +34 -0
  222. package/src/json.ts +16 -4
  223. package/src/module.ts +56 -22
  224. package/src/notations.ts +16 -4
  225. package/src/plain.ts +12 -3
  226. package/src/protobuf.ts +16 -4
  227. package/native/adapter/visit.go +0 -173
  228. package/native/adapter/visit_property_chain_edges_test.go +0 -129
  229. package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
  230. package/native/core/programmers/iterate/check_union_array_like.go +0 -422
  231. package/native/core/programmers/iterate/prune_object_properties.go +0 -105
  232. package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
  233. package/native/core/programmers/iterate/stringify_native.go +0 -14
  234. package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
  235. package/native/core/schemas/metadata/MetadataApplication.go +0 -41
@@ -1,21 +1,35 @@
1
- import { _randomInteger } from "./_randomInteger";
2
- import { _randomFormatLength } from "./_randomStringLength";
1
+ import {
2
+ _ILengthProps,
3
+ _RANDOM_LENGTH_ERROR,
4
+ _randomLengthPick,
5
+ _randomLengthWindow,
6
+ } from "./_randomStringLength";
7
+ import { __randomDigits } from "./private/__randomComposition";
8
+ import { __IEpochProps, __randomEpoch } from "./private/__randomEpoch";
3
9
 
4
- export const _randomFormatDatetime = (props?: {
5
- minimum?: number;
6
- maximum?: number;
7
- minLength?: number;
8
- maxLength?: number;
9
- }) =>
10
- _randomFormatLength(props, () =>
11
- new Date(
12
- _randomInteger({
13
- type: "integer",
14
- minimum: props?.minimum ?? 0,
15
- maximum:
16
- (props?.maximum ?? props?.minimum === undefined)
17
- ? Date.now()
18
- : props.minimum + 365 * 24 * 60 * 60 * 1_000,
19
- }),
20
- ).toISOString(),
21
- );
10
+ export const _randomFormatDatetime = (
11
+ props?: __IEpochProps & _ILengthProps,
12
+ ) => {
13
+ const instant = (): string => new Date(__randomEpoch(props)).toISOString();
14
+ if (props?.minLength === undefined && props?.maxLength === undefined)
15
+ return instant();
16
+ // `YYYY-MM-DDTHH:MM:SS` plus `Z` is the shortest instant, and a fractional
17
+ // second grows it one digit at a time. Because that fraction needs both a dot
18
+ // and at least one digit, 21 is the single length between the two forms that
19
+ // no instant can have.
20
+ const window = _randomLengthWindow(props, {
21
+ minimum: SECONDS + 1,
22
+ spread: 8,
23
+ });
24
+ let length: number = _randomLengthPick(window);
25
+ if (length === SECONDS + 2)
26
+ length = window.high >= SECONDS + 3 ? SECONDS + 3 : SECONDS + 1;
27
+ if (length < window.low || length > window.high)
28
+ throw new Error(_RANDOM_LENGTH_ERROR);
29
+ const base: string = instant().substring(0, SECONDS);
30
+ return length === SECONDS + 1
31
+ ? `${base}Z`
32
+ : `${base}.${__randomDigits(length - SECONDS - 2)}Z`;
33
+ };
34
+
35
+ const SECONDS = "0000-00-00T00:00:00".length;
@@ -1,8 +1,13 @@
1
1
  import { _randomInteger } from "./_randomInteger";
2
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
2
+ import {
3
+ _ILengthProps,
4
+ _randomLengthPick,
5
+ _randomLengthWindow,
6
+ } from "./_randomStringLength";
7
+ import { __randomNumeric } from "./private/__randomComposition";
3
8
 
4
- export const _randomFormatDuration = (props?: _ILengthProps): string =>
5
- _randomFormatLength(props, () => {
9
+ export const _randomFormatDuration = (props?: _ILengthProps): string => {
10
+ if (props?.minLength === undefined && props?.maxLength === undefined) {
6
11
  const period: string = durate([
7
12
  ["Y", random(0, 100)],
8
13
  ["M", random(0, 12)],
@@ -15,7 +20,17 @@ export const _randomFormatDuration = (props?: _ILengthProps): string =>
15
20
  ]);
16
21
  if (period.length + time.length === 0) return "PT0S";
17
22
  return `P${period}${time.length ? "T" : ""}${time}`;
18
- });
23
+ }
24
+ // A single designator carries an unbounded digit count, so `P<n>Y` expresses
25
+ // every length from three upward and `P1Y` is the shortest duration there is.
26
+ const length: number = _randomLengthPick(
27
+ _randomLengthWindow(props, { minimum: MINIMUM, spread: 6 }),
28
+ );
29
+ return `P${__randomNumeric(length - MINIMUM + 1)}Y`;
30
+ };
31
+
32
+ const MINIMUM = "P1Y".length;
33
+
19
34
  const durate = (elements: [string, number][]) =>
20
35
  elements
21
36
  .filter(([_unit, value]) => value !== 0)
@@ -29,8 +29,8 @@ const pickLength = (props: _ILengthProps): number => {
29
29
 
30
30
  /**
31
31
  * Builds dot-joined hostname labels totaling exactly `length` characters, each
32
- * label within 63 chars. Shared with the idn-hostname generator, which reserves
33
- * a fixed `.<tld>` suffix and realizes the rest as these leading labels.
32
+ * label within 63 chars. Shared with the idn-hostname generator, which realizes
33
+ * its length the same way since #2317 gave the two formats one structure.
34
34
  */
35
35
  export const _randomHostnameLabels = (length: number): string => {
36
36
  const parts: string[] = [];
@@ -6,20 +6,19 @@ import { _ILengthProps } from "./_randomStringLength";
6
6
  export const _randomFormatIdnHostname = (props?: _ILengthProps): string => {
7
7
  if (props?.minLength === undefined && props?.maxLength === undefined)
8
8
  return `${random(10)}.${random(3)}`;
9
- // `_isFormatIdnHostname` requires at least one label, a dot, and a >=2-char
10
- // TLD (`(…\.)+[a-z¡-￿]{2,}`), none of which the non-idn hostname generator
11
- // guarantees on its length path (it can emit a single dotless label). Reserve
12
- // a fixed `.<2-char TLD>` and realize the rest as dot-joined leading labels.
13
- const length: number = pickLength(props);
14
- return `${_randomHostnameLabels(length - 3)}.${random(2)}`;
9
+ // idn-hostname shares hostname's structure (a single label of 1..63 chars is
10
+ // valid, no dot or trailing label required), so the requested length is
11
+ // realized the same way: split it across dot-joined labels. #2317 dropped the
12
+ // mandatory dot and two-character trailing label this generator used to
13
+ // reserve, which is why it now realizes a length below four.
14
+ return _randomHostnameLabels(pickLength(props));
15
15
  };
16
16
 
17
17
  const MAX_TOTAL = 253;
18
- const MIN_TOTAL = 4; // the shortest idn hostname, `x.yy`: label(1) + `.` + tld(2)
19
18
 
20
19
  const pickLength = (props: _ILengthProps): number => {
21
- let low: number = props.minLength === undefined ? MIN_TOTAL : props.minLength;
22
- if (low < MIN_TOTAL) low = MIN_TOTAL;
20
+ let low: number = props.minLength === undefined ? 1 : props.minLength;
21
+ if (low < 1) low = 1;
23
22
  const high: number =
24
23
  props.maxLength === undefined
25
24
  ? Math.min(MAX_TOTAL, low + 14)
@@ -1,8 +1,37 @@
1
1
  import { _randomInteger } from "./_randomInteger";
2
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
2
+ import {
3
+ _ILengthProps,
4
+ _randomLengthPick,
5
+ _randomLengthWindow,
6
+ } from "./_randomStringLength";
7
+ import { __randomComposition } from "./private/__randomComposition";
3
8
 
4
- export const _randomFormatIpv4 = (props?: _ILengthProps): string =>
5
- _randomFormatLength(props, () => new Array(4).fill(0).map(random).join("."));
9
+ export const _randomFormatIpv4 = (props?: _ILengthProps): string => {
10
+ if (props?.minLength === undefined && props?.maxLength === undefined)
11
+ return new Array(4).fill(0).map(random).join(".");
12
+ // Three dots plus four octets of one to three digits: `0.0.0.0` is the
13
+ // shortest address and `255.255.255.255` the longest, and every length
14
+ // between them is reached by choosing how many digits each octet spends.
15
+ const length: number = _randomLengthPick(
16
+ _randomLengthWindow(props, {
17
+ minimum: 4 * DIGITS_MIN + DOTS,
18
+ maximum: 4 * DIGITS_MAX + DOTS,
19
+ spread: 8,
20
+ }),
21
+ );
22
+ return __randomComposition({
23
+ total: length - DOTS,
24
+ count: 4,
25
+ minimum: DIGITS_MIN,
26
+ maximum: DIGITS_MAX,
27
+ })
28
+ .map(octet)
29
+ .join(".");
30
+ };
31
+
32
+ const DOTS = 3;
33
+ const DIGITS_MIN = 1;
34
+ const DIGITS_MAX = 3;
6
35
 
7
36
  const random = () =>
8
37
  _randomInteger({
@@ -10,3 +39,14 @@ const random = () =>
10
39
  minimum: 0,
11
40
  maximum: 255,
12
41
  });
42
+
43
+ // An octet is bounded by 255, so a three-digit one starts at 100 and stops
44
+ // there rather than at 999.
45
+ const octet = (digits: number): string =>
46
+ String(
47
+ _randomInteger({
48
+ type: "integer",
49
+ minimum: digits === 1 ? 0 : Math.pow(10, digits - 1),
50
+ maximum: digits === 3 ? 255 : Math.pow(10, digits) - 1,
51
+ }),
52
+ );
@@ -1,8 +1,61 @@
1
+ import { _randomFormatIpv4 } from "./_randomFormatIpv4";
1
2
  import { _randomInteger } from "./_randomInteger";
2
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
3
+ import {
4
+ _ILengthProps,
5
+ _randomLengthPick,
6
+ _randomLengthWindow,
7
+ } from "./_randomStringLength";
8
+ import { __randomComposition } from "./private/__randomComposition";
3
9
 
4
- export const _randomFormatIpv6 = (props?: _ILengthProps): string =>
5
- _randomFormatLength(props, () => new Array(8).fill(0).map(random).join(":"));
10
+ export const _randomFormatIpv6 = (props?: _ILengthProps): string => {
11
+ if (props?.minLength === undefined && props?.maxLength === undefined)
12
+ return new Array(GROUPS).fill(0).map(random).join(":");
13
+ const length: number = _randomLengthPick(
14
+ _randomLengthWindow(props, {
15
+ minimum: SHORTEST,
16
+ maximum: LONGEST,
17
+ spread: 12,
18
+ }),
19
+ );
20
+ // `::` alone is the all-zero address, and the three forms below cover every
21
+ // length between it and the padded IPv4-suffixed address: a compressed prefix
22
+ // for the short ones, eight groups of one to four hexadecimal digits for the
23
+ // middle, and six groups plus a dotted-quad tail for the long ones.
24
+ if (length === SHORTEST) return "::";
25
+ if (length < GROUPS * DIGITS_MIN + COLONS) {
26
+ // `::` plus `count` groups spends one colon between each pair.
27
+ const count: number = Math.ceil((length - 1) / (DIGITS_MAX + 1));
28
+ return `::${compose(length - 1 - count, count)}`;
29
+ }
30
+ if (length <= GROUPS * DIGITS_MAX + COLONS)
31
+ return compose(length - COLONS, GROUPS);
32
+ // The dotted-quad tail is drawn at its longest so the six leading groups keep
33
+ // a composable number of digits.
34
+ const tail: string = _randomFormatIpv4({
35
+ minLength: IPV4_MAX,
36
+ maxLength: IPV4_MAX,
37
+ });
38
+ return `${compose(length - IPV4_MAX - EMBEDDED, EMBEDDED)}:${tail}`;
39
+ };
40
+
41
+ const GROUPS = 8;
42
+ const COLONS = GROUPS - 1;
43
+ const DIGITS_MIN = 1;
44
+ const DIGITS_MAX = 4;
45
+ const EMBEDDED = 6; // groups preceding a dotted-quad tail
46
+ const IPV4_MAX = "255.255.255.255".length;
47
+ const SHORTEST = "::".length;
48
+ const LONGEST = EMBEDDED * DIGITS_MAX + EMBEDDED + IPV4_MAX;
49
+
50
+ const compose = (digits: number, count: number): string =>
51
+ __randomComposition({
52
+ total: digits,
53
+ count,
54
+ minimum: DIGITS_MIN,
55
+ maximum: DIGITS_MAX,
56
+ })
57
+ .map(group)
58
+ .join(":");
6
59
 
7
60
  const random = () =>
8
61
  _randomInteger({
@@ -10,3 +63,14 @@ const random = () =>
10
63
  minimum: 0,
11
64
  maximum: 65_535,
12
65
  }).toString(16);
66
+
67
+ const group = (digits: number): string => {
68
+ let text: string = "";
69
+ for (let i: number = 0; i < digits; ++i)
70
+ text += _randomInteger({
71
+ type: "integer",
72
+ minimum: 0,
73
+ maximum: 15,
74
+ }).toString(16);
75
+ return text;
76
+ };
@@ -1,13 +1,33 @@
1
1
  import { _randomString } from "./_randomString";
2
- import { _ILengthProps, _randomSegmentLength } from "./_randomStringLength";
2
+ import {
3
+ _ILengthProps,
4
+ _randomLengthPick,
5
+ _randomLengthWindow,
6
+ _randomSegmentLength,
7
+ } from "./_randomStringLength";
3
8
 
4
9
  export const _randomFormatJsonPointer = (props?: _ILengthProps): string => {
5
10
  if (props?.minLength === undefined && props?.maxLength === undefined)
6
- return `/components/schemas/${random()}`;
11
+ return `${PREFIX}${random()}`;
7
12
  // The `/components/schemas/` prefix (20 chars) is fixed; the reference token
8
13
  // after it grows or shrinks to hit the requested length.
9
- return `/components/schemas/${_randomSegmentLength(props, 20, 10, 0)}`;
14
+ if (props.maxLength === undefined || props.maxLength >= PREFIX.length)
15
+ return `${PREFIX}${_randomSegmentLength(props, PREFIX.length, 10, 0)}`;
16
+ // Below that prefix a pointer still exists: the empty pointer addresses the
17
+ // whole document, and one `/`-prefixed token addresses a member of it.
18
+ const length: number = _randomLengthPick(
19
+ _randomLengthWindow(props, { minimum: 0, spread: 6 }),
20
+ );
21
+ return length === 0
22
+ ? ""
23
+ : `/${_randomString({
24
+ type: "string",
25
+ minLength: length - 1,
26
+ maxLength: length - 1,
27
+ })}`;
10
28
  };
11
29
 
30
+ const PREFIX = "/components/schemas/";
31
+
12
32
  const random = () =>
13
33
  _randomString({ type: "string", minLength: 10, maxLength: 10 });
@@ -1,7 +1,23 @@
1
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
1
+ import { _randomString } from "./_randomString";
2
+ import {
3
+ _ILengthProps,
4
+ _randomLengthPick,
5
+ _randomLengthWindow,
6
+ } from "./_randomStringLength";
2
7
 
3
- export const _randomFormatRegex = (props?: _ILengthProps): string =>
4
- _randomFormatLength(props, () => FIXED);
5
-
6
- const FIXED =
7
- "/^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/";
8
+ export const _randomFormatRegex = (props?: _ILengthProps): string => {
9
+ // Every character `_randomString` emits is a literal in regular expression
10
+ // syntax, so a source of any length — including the empty source `new
11
+ // RegExp("")` accepts — compiles. An unconstrained draw is therefore an
12
+ // unconstrained string, and a constrained one fixes the length first.
13
+ if (props?.minLength === undefined && props?.maxLength === undefined)
14
+ return _randomString({ type: "string" });
15
+ const length: number = _randomLengthPick(
16
+ _randomLengthWindow(props, { minimum: 0, spread: 16 }),
17
+ );
18
+ return _randomString({
19
+ type: "string",
20
+ minLength: length,
21
+ maxLength: length,
22
+ });
23
+ };
@@ -1,15 +1,28 @@
1
1
  import { _randomInteger } from "./_randomInteger";
2
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
2
+ import { _randomString } from "./_randomString";
3
+ import {
4
+ _ILengthProps,
5
+ _randomLengthPick,
6
+ _randomLengthWindow,
7
+ } from "./_randomStringLength";
8
+ import { __randomNumeric } from "./private/__randomComposition";
3
9
 
4
10
  export const _randomFormatRelativeJsonPointer = (
5
11
  props?: _ILengthProps,
6
- ): string =>
7
- _randomFormatLength(
8
- props,
9
- () =>
10
- `${_randomInteger({
11
- type: "integer",
12
- minimum: 0,
13
- maximum: 10,
14
- })}#`,
12
+ ): string => {
13
+ if (props?.minLength === undefined && props?.maxLength === undefined)
14
+ return `${_randomInteger({ type: "integer", minimum: 0, maximum: 10 })}#`;
15
+ // The leading non-negative integer stands alone as a pointer, so a single
16
+ // digit is the shortest form; `#` names the key and a `/`-prefixed token names
17
+ // a member, which absorbs any remaining length.
18
+ const length: number = _randomLengthPick(
19
+ _randomLengthWindow(props, { minimum: 1, spread: 6 }),
15
20
  );
21
+ if (length === 1) return __randomNumeric(1);
22
+ if (length === 2) return `${__randomNumeric(1)}#`;
23
+ return `${__randomNumeric(1)}/${_randomString({
24
+ type: "string",
25
+ minLength: length - 2,
26
+ maxLength: length - 2,
27
+ })}`;
28
+ };
@@ -1,17 +1,55 @@
1
1
  import { _randomInteger } from "./_randomInteger";
2
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
2
+ import {
3
+ _ILengthProps,
4
+ _RANDOM_LENGTH_ERROR,
5
+ _randomLengthPick,
6
+ _randomLengthWindow,
7
+ } from "./_randomStringLength";
8
+ import { __randomDigits } from "./private/__randomComposition";
3
9
 
4
- export const _randomFormatTime = (props?: _ILengthProps): string =>
5
- _randomFormatLength(props, () =>
10
+ export const _randomFormatTime = (props?: _ILengthProps): string => {
11
+ const clock = (): string =>
6
12
  new Date(
7
- _randomInteger({
8
- type: "integer",
9
- minimum: 0,
10
- maximum: DAY,
11
- }),
12
- )
13
- .toISOString()
14
- .substring(11),
15
- );
13
+ _randomInteger({ type: "integer", minimum: 0, maximum: DAY }),
14
+ ).toISOString();
15
+ if (props?.minLength === undefined && props?.maxLength === undefined)
16
+ return clock().substring(11);
17
+ // `HH:MM:SS` carries a mandatory offset — one character as `Z`, six as
18
+ // `+HH:MM` — and an optional fraction between them that RFC 3339 leaves
19
+ // open above. Together they express 9 and every length from 11 upward; 10 is
20
+ // the one gap, because a fraction needs both a dot and a digit.
21
+ const window = _randomLengthWindow(props, {
22
+ minimum: CLOCK + 1,
23
+ spread: 6,
24
+ });
25
+ let length: number = _randomLengthPick(window);
26
+ if (length === CLOCK + 2)
27
+ length = window.high >= CLOCK + 3 ? CLOCK + 3 : CLOCK + 1;
28
+ if (length < window.low || length > window.high)
29
+ throw new Error(_RANDOM_LENGTH_ERROR);
30
+ const base: string = clock().substring(11, 11 + CLOCK);
31
+ if (length === CLOCK + 1) return `${base}Z`;
32
+ // The `Z` form reaches every remaining length by itself, so the numeric
33
+ // offset is a choice rather than a fallback: it spends six characters, which
34
+ // leaves either nothing (14, `HH:MM:SS+HH:MM`) or a whole fraction (16 and
35
+ // up). At 15 only the `Z` form fits, since the offset would demand a dot
36
+ // with no digit after it.
37
+ const fraction: number = length - CLOCK - OFFSET - 1;
38
+ return (fraction === -1 || fraction >= 1) &&
39
+ _randomInteger({ type: "integer", minimum: 0, maximum: 1 }) === 1
40
+ ? fraction === -1
41
+ ? `${base}${offset()}`
42
+ : `${base}.${__randomDigits(fraction)}${offset()}`
43
+ : `${base}.${__randomDigits(length - CLOCK - 2)}Z`;
44
+ };
16
45
 
17
46
  const DAY = 86_400_000;
47
+ const CLOCK = "00:00:00".length;
48
+ const OFFSET = "+00:00".length;
49
+
50
+ const offset = (): string =>
51
+ `${_randomInteger({ type: "integer", minimum: 0, maximum: 1 }) === 0 ? "+" : "-"}${pad(
52
+ _randomInteger({ type: "integer", minimum: 0, maximum: 23 }),
53
+ )}:${pad(_randomInteger({ type: "integer", minimum: 0, maximum: 59 }))}`;
54
+
55
+ const pad = (value: number): string => String(value).padStart(2, "0");
@@ -2,7 +2,10 @@ import RandExp from "randexp";
2
2
 
3
3
  import { _ILengthProps } from "./_randomStringLength";
4
4
 
5
- export const _randomPattern = (regex: RegExp, props?: _ILengthProps): string => {
5
+ export const _randomPattern = (
6
+ regex: RegExp,
7
+ props?: _ILengthProps,
8
+ ): string => {
6
9
  const r: RandExp = new RandExp(regex);
7
10
  const min: number | undefined = props?.minLength;
8
11
  const max: number | undefined = props?.maxLength;
@@ -1,5 +1,9 @@
1
+ import { _randomInteger } from "./_randomInteger";
1
2
  import { _randomString } from "./_randomString";
2
3
 
4
+ export const _RANDOM_LENGTH_ERROR =
5
+ "unable to generate a random string satisfying both the format and the length constraints.";
6
+
3
7
  /**
4
8
  * Length bounds forwarded to a string format or pattern generator.
5
9
  *
@@ -18,10 +22,10 @@ export interface _ILengthProps {
18
22
  * length `fixed + segment.length` lands inside the requested window.
19
23
  *
20
24
  * `fixed` is the number of characters the format always contributes around the
21
- * segment, `fallback` is the segment length used when the leaf is
22
- * unconstrained on that side, and `minimum` is the smallest segment the format
23
- * still validates with. Throws when the window cannot be satisfied by this
24
- * format's shape (e.g. `Format<"email"> & MaxLength<3>`).
25
+ * segment, `fallback` is the segment length used when the leaf is unconstrained
26
+ * on that side, and `minimum` is the smallest segment the format still
27
+ * validates with. Throws when the window cannot be satisfied by this format's
28
+ * shape (e.g. `Format<"email"> & MaxLength<3>`).
25
29
  */
26
30
  export const _randomSegmentLength = (
27
31
  props: _ILengthProps | undefined,
@@ -36,21 +40,63 @@ export const _randomSegmentLength = (
36
40
  // characters so the generated length varies, mirroring `_randomString`.
37
41
  const high: number =
38
42
  props?.maxLength === undefined ? low + fallback : props.maxLength - fixed;
39
- if (high < low || high < minimum)
40
- throw new Error(
41
- "unable to generate a random string satisfying both the format and the length constraints.",
42
- );
43
+ if (high < low || high < minimum) throw new Error(_RANDOM_LENGTH_ERROR);
43
44
  return _randomString({ type: "string", minLength: low, maxLength: high });
44
45
  };
45
46
 
46
47
  /**
47
- * Wraps a fixed- or narrow-length format generator (uuid, ipv4, date, ...) with
48
- * the requested length window.
48
+ * Intersects the requested length window with the lengths a format's grammar
49
+ * can express, and draws one of them.
50
+ *
51
+ * `minimum` and `maximum` are the shortest and longest values the format admits
52
+ * — omit `maximum` when the grammar is open above — and `spread` is how far
53
+ * past the floor an unbounded request may reach, so an open side still varies
54
+ * the way `_randomString` does. The caller draws from the returned window and
55
+ * applies whatever step its grammar has (base64 lengths are multiples of four,
56
+ * a fractional second needs at least one digit).
57
+ *
58
+ * Throws only when the window and the grammar do not overlap at all. That is
59
+ * the distinction the retry driver below cannot make: it redraws one shape, so
60
+ * it gives up on every length that shape never emits even when the format
61
+ * itself accepts one (issue #2284).
62
+ */
63
+ export const _randomLengthWindow = (
64
+ props: _ILengthProps | undefined,
65
+ format: { minimum: number; maximum?: number; spread?: number },
66
+ ): { low: number; high: number } => {
67
+ const ceiling: number = format.maximum ?? Number.MAX_SAFE_INTEGER;
68
+ const low: number = Math.max(
69
+ props?.minLength ?? format.minimum,
70
+ format.minimum,
71
+ );
72
+ const high: number = Math.min(
73
+ props?.maxLength ?? low + (format.spread ?? 0),
74
+ ceiling,
75
+ );
76
+ if (low > high) throw new Error(_RANDOM_LENGTH_ERROR);
77
+ return { low, high };
78
+ };
79
+
80
+ /** Draws a length inside a window produced by {@link _randomLengthWindow}. */
81
+ export const _randomLengthPick = (window: {
82
+ low: number;
83
+ high: number;
84
+ }): number =>
85
+ _randomInteger({
86
+ type: "integer",
87
+ minimum: window.low,
88
+ maximum: window.high,
89
+ });
90
+
91
+ /**
92
+ * Wraps a fixed-length format generator (uuid, date) with the requested length
93
+ * window.
49
94
  *
50
- * These formats cannot grow an arbitrary segment, so the generator is retried a
51
- * bounded number of times and the first draw inside the window is returned. A
52
- * window that excludes every length the format can produce is unsatisfiable and
53
- * throws instead of silently yielding an out-of-range value.
95
+ * Use it only where the grammar admits exactly one length, so a window that
96
+ * excludes it is genuinely unsatisfiable. A format that can express more than
97
+ * one length must build its value at a length drawn from
98
+ * {@link _randomLengthWindow} instead; redrawing one shape cannot reach a length
99
+ * that shape never emits.
54
100
  */
55
101
  export const _randomFormatLength = (
56
102
  props: _ILengthProps | undefined,
@@ -66,7 +112,5 @@ export const _randomFormatLength = (
66
112
  )
67
113
  return value;
68
114
  }
69
- throw new Error(
70
- "unable to generate a random string satisfying both the format and the length constraints.",
71
- );
115
+ throw new Error(_RANDOM_LENGTH_ERROR);
72
116
  };
@@ -9,10 +9,7 @@
9
9
  * collapsing it to the underscore-free `plain` path.
10
10
  */
11
11
  export const __notationRename =
12
- (props: {
13
- plain: (str: string) => string;
14
- snake: (str: string) => string;
15
- }) =>
12
+ (props: { plain: (str: string) => string; snake: (str: string) => string }) =>
16
13
  (str: string): string => {
17
14
  let prefix: string = "";
18
15
  while (str.startsWith("_")) {
@@ -0,0 +1,74 @@
1
+ import { _randomInteger } from "../_randomInteger";
2
+
3
+ /**
4
+ * Splits `total` into `count` parts, each inside `[minimum, maximum]`.
5
+ *
6
+ * Used where a format's length is the sum of its segments — an IPv4 octet spans
7
+ * one to three digits, an IPv6 group one to four — so a requested total length
8
+ * is realized by choosing how many characters each segment contributes instead
9
+ * of redrawing whole addresses and hoping one lands in the window (issue
10
+ * #2284).
11
+ *
12
+ * The caller guarantees `count * minimum <= total <= count * maximum`; each
13
+ * part is drawn from the range that still leaves the remaining parts
14
+ * satisfiable.
15
+ */
16
+ export const __randomComposition = (props: {
17
+ total: number;
18
+ count: number;
19
+ minimum: number;
20
+ maximum: number;
21
+ }): number[] => {
22
+ const parts: number[] = [];
23
+ let remaining: number = props.total;
24
+ for (let i: number = 0; i < props.count; ++i) {
25
+ const rest: number = props.count - i - 1;
26
+ const value: number = _randomInteger({
27
+ type: "integer",
28
+ minimum: Math.max(props.minimum, remaining - rest * props.maximum),
29
+ maximum: Math.min(props.maximum, remaining - rest * props.minimum),
30
+ });
31
+ parts.push(value);
32
+ remaining -= value;
33
+ }
34
+ return parts;
35
+ };
36
+
37
+ /**
38
+ * Draws `length` characters of the base64 alphabet.
39
+ *
40
+ * The caller passes a multiple of four, which `format: "byte"` accepts without
41
+ * padding; every character below is in the alphabet its validator spells out,
42
+ * so the result needs no encoding step.
43
+ */
44
+ export const __randomBase64 = (length: number): string => {
45
+ let text: string = "";
46
+ for (let i: number = 0; i < length; ++i)
47
+ text +=
48
+ BASE64[
49
+ _randomInteger({
50
+ type: "integer",
51
+ minimum: 0,
52
+ maximum: BASE64.length - 1,
53
+ })
54
+ ];
55
+ return text;
56
+ };
57
+
58
+ const BASE64 =
59
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60
+
61
+ /** Draws `length` decimal digits, leading zeros included. */
62
+ export const __randomDigits = (length: number): string => {
63
+ let text: string = "";
64
+ for (let i: number = 0; i < length; ++i)
65
+ text += String(_randomInteger({ type: "integer", minimum: 0, maximum: 9 }));
66
+ return text;
67
+ };
68
+
69
+ /** Draws a decimal number of exactly `length` digits without a leading zero. */
70
+ export const __randomNumeric = (length: number): string =>
71
+ length <= 1
72
+ ? String(_randomInteger({ type: "integer", minimum: 0, maximum: 9 }))
73
+ : String(_randomInteger({ type: "integer", minimum: 1, maximum: 9 })) +
74
+ __randomDigits(length - 1);