typia 13.1.19 → 13.2.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 (169) 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/internal/_ProtobufReader.d.ts +18 -3
  11. package/lib/internal/_ProtobufReader.js +39 -11
  12. package/lib/internal/_ProtobufReader.js.map +1 -1
  13. package/lib/internal/_ProtobufReader.mjs +37 -10
  14. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  15. package/lib/internal/_jsonStringifyArray.d.ts +1 -0
  16. package/lib/internal/_jsonStringifyArray.js +48 -0
  17. package/lib/internal/_jsonStringifyArray.js.map +1 -0
  18. package/lib/internal/_jsonStringifyArray.mjs +40 -0
  19. package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
  20. package/lib/internal/_jsonStringifyElement.d.ts +1 -0
  21. package/lib/internal/_jsonStringifyElement.js +23 -0
  22. package/lib/internal/_jsonStringifyElement.js.map +1 -0
  23. package/lib/internal/_jsonStringifyElement.mjs +23 -0
  24. package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
  25. package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
  26. package/lib/internal/_jsonStringifyProperty.js +31 -0
  27. package/lib/internal/_jsonStringifyProperty.js.map +1 -0
  28. package/lib/internal/_jsonStringifyProperty.mjs +31 -0
  29. package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
  30. package/lib/internal/_llmApplicationFinalize.js +1 -1
  31. package/lib/internal/_llmApplicationFinalize.js.map +1 -1
  32. package/lib/internal/_llmApplicationFinalize.mjs +1 -1
  33. package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
  34. package/lib/internal/_randomFormatByte.js +24 -1
  35. package/lib/internal/_randomFormatByte.js.map +1 -1
  36. package/lib/internal/_randomFormatByte.mjs +20 -2
  37. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  38. package/lib/internal/_randomFormatDate.d.ts +3 -6
  39. package/lib/internal/_randomFormatDate.js +2 -10
  40. package/lib/internal/_randomFormatDate.js.map +1 -1
  41. package/lib/internal/_randomFormatDate.mjs +2 -6
  42. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  43. package/lib/internal/_randomFormatDatetime.d.ts +3 -6
  44. package/lib/internal/_randomFormatDatetime.js +25 -8
  45. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  46. package/lib/internal/_randomFormatDatetime.mjs +17 -7
  47. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  48. package/lib/internal/_randomFormatDuration.js +23 -15
  49. package/lib/internal/_randomFormatDuration.js.map +1 -1
  50. package/lib/internal/_randomFormatDuration.mjs +23 -15
  51. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  52. package/lib/internal/_randomFormatIpv4.js +31 -1
  53. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  54. package/lib/internal/_randomFormatIpv4.mjs +23 -2
  55. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  56. package/lib/internal/_randomFormatIpv6.js +57 -1
  57. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  58. package/lib/internal/_randomFormatIpv6.mjs +45 -2
  59. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  60. package/lib/internal/_randomFormatJsonPointer.js +14 -2
  61. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  62. package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
  63. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  64. package/lib/internal/_randomFormatRegex.js +14 -1
  65. package/lib/internal/_randomFormatRegex.js.map +1 -1
  66. package/lib/internal/_randomFormatRegex.mjs +14 -2
  67. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  68. package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
  69. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  70. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
  71. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  72. package/lib/internal/_randomFormatTime.js +33 -7
  73. package/lib/internal/_randomFormatTime.js.map +1 -1
  74. package/lib/internal/_randomFormatTime.mjs +37 -5
  75. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  76. package/lib/internal/_randomPattern.js.map +1 -1
  77. package/lib/internal/_randomPattern.mjs.map +1 -1
  78. package/lib/internal/_randomStringLength.d.ts +41 -10
  79. package/lib/internal/_randomStringLength.js +49 -13
  80. package/lib/internal/_randomStringLength.js.map +1 -1
  81. package/lib/internal/_randomStringLength.mjs +48 -13
  82. package/lib/internal/_randomStringLength.mjs.map +1 -1
  83. package/lib/internal/private/__notationRename.js.map +1 -1
  84. package/lib/internal/private/__notationRename.mjs.map +1 -1
  85. package/lib/internal/private/__randomComposition.d.ts +23 -0
  86. package/lib/internal/private/__randomComposition.js +48 -0
  87. package/lib/internal/private/__randomComposition.js.map +1 -0
  88. package/lib/internal/private/__randomComposition.mjs +54 -0
  89. package/lib/internal/private/__randomComposition.mjs.map +1 -0
  90. package/lib/internal/private/__randomEpoch.d.ts +19 -0
  91. package/lib/internal/private/__randomEpoch.js +31 -0
  92. package/lib/internal/private/__randomEpoch.js.map +1 -0
  93. package/lib/internal/private/__randomEpoch.mjs +28 -0
  94. package/lib/internal/private/__randomEpoch.mjs.map +1 -0
  95. package/native/cmd/ttsc-typia/build.go +3 -0
  96. package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
  97. package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
  98. package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
  99. package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
  100. package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
  101. package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
  102. package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
  103. package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
  104. package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
  105. package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
  106. package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
  107. package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
  108. package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
  109. package/native/cmd/ttsc-typia/transform.go +23 -0
  110. package/native/cmd/ttsc-typia/transform_helpers_test.go +77 -2
  111. package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
  112. package/native/core/factories/ProtobufFactory.go +6 -1
  113. package/native/core/factories/internal/metadata/MetadataHelper.go +185 -30
  114. package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
  115. package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
  116. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
  117. package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
  118. package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
  119. package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
  120. package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
  121. package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
  122. package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
  123. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
  124. package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
  125. package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
  126. package/native/core/programmers/iterate/json_schema_object.go +49 -7
  127. package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
  128. package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
  129. package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
  130. package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
  131. package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
  132. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
  133. package/native/core/schemas/metadata/MetadataCollection.go +0 -9
  134. package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
  135. package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
  136. package/native/go.mod +4 -4
  137. package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
  138. package/package.json +3 -7
  139. package/src/executable/FileSystemIdentity.ts +33 -0
  140. package/src/executable/TypiaGenerateWizard.ts +18 -12
  141. package/src/internal/_ProtobufReader.ts +40 -11
  142. package/src/internal/_jsonStringifyArray.ts +50 -0
  143. package/src/internal/_jsonStringifyElement.ts +19 -0
  144. package/src/internal/_jsonStringifyProperty.ts +30 -0
  145. package/src/internal/_llmApplicationFinalize.ts +6 -1
  146. package/src/internal/_randomFormatByte.ts +30 -3
  147. package/src/internal/_randomFormatDate.ts +4 -20
  148. package/src/internal/_randomFormatDatetime.ts +34 -20
  149. package/src/internal/_randomFormatDuration.ts +19 -4
  150. package/src/internal/_randomFormatIpv4.ts +43 -3
  151. package/src/internal/_randomFormatIpv6.ts +67 -3
  152. package/src/internal/_randomFormatJsonPointer.ts +23 -3
  153. package/src/internal/_randomFormatRegex.ts +21 -3
  154. package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
  155. package/src/internal/_randomFormatTime.ts +45 -12
  156. package/src/internal/_randomPattern.ts +4 -1
  157. package/src/internal/_randomStringLength.ts +61 -17
  158. package/src/internal/private/__notationRename.ts +1 -4
  159. package/src/internal/private/__randomComposition.ts +50 -0
  160. package/src/internal/private/__randomEpoch.ts +34 -0
  161. package/native/adapter/visit.go +0 -173
  162. package/native/adapter/visit_property_chain_edges_test.go +0 -129
  163. package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
  164. package/native/core/programmers/iterate/check_union_array_like.go +0 -422
  165. package/native/core/programmers/iterate/prune_object_properties.go +0 -105
  166. package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
  167. package/native/core/programmers/iterate/stringify_native.go +0 -14
  168. package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
  169. package/native/core/schemas/metadata/MetadataApplication.go +0 -41
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Serializes the elements of an array the way ECMAScript `JSON.stringify` does.
3
+ *
4
+ * `SerializeJSONArray` walks index `0` to `LengthOfArrayLike(value) - 1` and
5
+ * writes `null` wherever the element serializes to `undefined`. Neither
6
+ * `Array.prototype.map` nor `Array.prototype.join` reproduces that:
7
+ *
8
+ * - `map` never visits a hole and leaves one behind, and `join` renders a hole as
9
+ * empty text, so a sparse array joined into malformed text such as `[,1]`. A
10
+ * hole exists at runtime whatever the element type declares, so this is not
11
+ * an `any` concern.
12
+ * - `join` renders a mapped `undefined` as empty text too, which is what an `any`
13
+ * or `unknown` element holding a function, a symbol, or a `toJSON` that
14
+ * returns nothing serializes to.
15
+ *
16
+ * The length is converted with `ToLength` and read once, which is both what
17
+ * `JSON.stringify` does and what `Array.prototype.every` - the traversal
18
+ * typia's own array checkers emit - does, so the checker and the serializer
19
+ * walk one index range rather than two that merely usually coincide.
20
+ *
21
+ * @param elements Array being serialized.
22
+ * @param mapper Serializer of one element, emitted by the transform.
23
+ * @returns Comma separated element text, without the enclosing brackets.
24
+ * @internal
25
+ */
26
+ export const _jsonStringifyArray = <T>(
27
+ elements: ArrayLike<T>,
28
+ mapper: (elem: T, index: number) => string,
29
+ ): string => {
30
+ const length: number = Math.min(
31
+ Math.max(Math.trunc(elements.length) || 0, 0),
32
+ Number.MAX_SAFE_INTEGER,
33
+ );
34
+ let output: string = "";
35
+ for (let i: number = 0; i < length; ++i) {
36
+ const elem: T | undefined = elements[i];
37
+ // A hole and an explicit `undefined` are answered without calling the
38
+ // mapper, because the mapper is the element type's own serializer and a
39
+ // typed one has no answer for a missing value. Everything else is answered
40
+ // from the mapper's *result*: an element that is present but serializes to
41
+ // nothing — a function, a symbol, or a `toJSON` returning nothing in an
42
+ // `any` slot — is `null` in an array position, exactly as
43
+ // SerializeJSONArray specifies, and testing the input instead would let its
44
+ // text become the literal `undefined`.
45
+ const text: string | undefined =
46
+ elem === undefined ? undefined : mapper(elem, i);
47
+ output += (i === 0 ? "" : ",") + (text === undefined ? "null" : text);
48
+ }
49
+ return output;
50
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Writes one array or tuple element the way ECMAScript `JSON.stringify` writes
3
+ * it.
4
+ *
5
+ * `SerializeJSONArray` writes `null` wherever an element serializes to
6
+ * `undefined`, because an array position cannot be omitted without shifting
7
+ * every element after it. A present value with no serialization — a function, a
8
+ * symbol, or a `toJSON` returning nothing — is therefore `null`, not the
9
+ * literal text `undefined` and not an empty slot.
10
+ *
11
+ * This is the fixed-position counterpart of `_jsonStringifyArray`, which
12
+ * answers the same question while walking an array's own index range.
13
+ *
14
+ * @param text Serialized element value, or `undefined` when it has none.
15
+ * @returns Element text, or `null` when the element has no serialization.
16
+ * @internal
17
+ */
18
+ export const _jsonStringifyElement = (text: string | undefined): string =>
19
+ text === undefined ? "null" : text;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Writes one object member the way ECMAScript `JSON.stringify` writes it.
3
+ *
4
+ * `SerializeJSONObject` serializes each member first and drops the member
5
+ * entirely when that result is `undefined`. Deciding omission from the _input_
6
+ * instead cannot reach the same answer: a symbol and a `toJSON` returning
7
+ * nothing are both present, non-`undefined`, non-function values whose
8
+ * serialization is `undefined`, so the member's text became the literal
9
+ * `"k":undefined` — output that is not JSON at all.
10
+ *
11
+ * The serialized text is passed in already evaluated, so the member's value is
12
+ * serialized exactly once. Testing the input and then serializing would
13
+ * evaluate a `toJSON` twice, and a `toJSON` is free to answer differently each
14
+ * call.
15
+ *
16
+ * The trailing separator belongs to the member because a dropped member must
17
+ * take its comma with it; `_jsonStringifyTail` removes the one that is left
18
+ * behind when the last written member is the one that dropped.
19
+ *
20
+ * @param head Quoted key and colon, emitted by the transform.
21
+ * @param text Serialized member value, or `undefined` when it has none.
22
+ * @param tail Separator following this member, empty for the last one.
23
+ * @returns Member text, or an empty string when the member is omitted.
24
+ * @internal
25
+ */
26
+ export const _jsonStringifyProperty = (
27
+ head: string,
28
+ text: string | undefined,
29
+ tail: string,
30
+ ): string => (text === undefined ? "" : head + text + tail);
@@ -7,7 +7,12 @@ export const _llmApplicationFinalize = <Class extends object = any>(
7
7
  ): ILlmApplication<Class> => ({
8
8
  ...app,
9
9
  config: {
10
- ...LlmSchemaConverter.getConfig(),
10
+ // The schema configuration comes from the emitted application, which is
11
+ // where the `Config` generic was resolved. Rebuilding it from the
12
+ // converter's defaults reported `strict: false` for a strict build, and
13
+ // `@typia/mcp` then inverted a strict output schema without strict, which
14
+ // drops every constraint it carries as a description tag (issue #2293).
15
+ ...LlmSchemaConverter.getConfig(app.config),
11
16
  validate: config?.validate ?? null,
12
17
  },
13
18
  functions: app.functions.map((func) => ({
@@ -1,6 +1,33 @@
1
- import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
1
+ import { _randomString } from "./_randomString";
2
+ import {
3
+ _ILengthProps,
4
+ _RANDOM_LENGTH_ERROR,
5
+ _randomLengthPick,
6
+ _randomLengthWindow,
7
+ } from "./_randomStringLength";
2
8
 
3
- export const _randomFormatByte = (props?: _ILengthProps): string =>
4
- _randomFormatLength(props, () => FIXED);
9
+ export const _randomFormatByte = (props?: _ILengthProps): string => {
10
+ if (props?.minLength === undefined && props?.maxLength === undefined)
11
+ return FIXED;
12
+ // Base64 encodes three bytes as four characters, so a valid length is always
13
+ // a multiple of four; the window is raised to the first multiple it contains
14
+ // and the draw steps by four from there. Every character `_randomString`
15
+ // emits is in the base64 alphabet, so the result needs no padding.
16
+ const window = _randomLengthWindow(props, { minimum: 0, spread: 16 });
17
+ const low: number = Math.ceil(window.low / 4) * 4;
18
+ if (low > window.high) throw new Error(_RANDOM_LENGTH_ERROR);
19
+ const length: number =
20
+ low +
21
+ 4 *
22
+ _randomLengthPick({
23
+ low: 0,
24
+ high: Math.floor((window.high - low) / 4),
25
+ });
26
+ return _randomString({
27
+ type: "string",
28
+ minLength: length,
29
+ maxLength: length,
30
+ });
31
+ };
5
32
 
6
33
  const FIXED = "vt7ekz4lIoNTTS9sDQYdWKharxIFAR54+z/umIxSgUM=";
@@ -1,23 +1,7 @@
1
- import { _randomInteger } from "./_randomInteger";
2
- import { _randomFormatLength } from "./_randomStringLength";
1
+ import { _ILengthProps, _randomFormatLength } from "./_randomStringLength";
2
+ import { __IEpochProps, __randomEpoch } from "./private/__randomEpoch";
3
3
 
4
- export const _randomFormatDate = (props?: {
5
- minimum?: number;
6
- maximum?: number;
7
- minLength?: number;
8
- maxLength?: number;
9
- }) =>
4
+ export const _randomFormatDate = (props?: __IEpochProps & _ILengthProps) =>
10
5
  _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
- )
21
- .toISOString()
22
- .substring(0, 10),
6
+ new Date(__randomEpoch(props)).toISOString().substring(0, 10),
23
7
  );
@@ -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)
@@ -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,25 @@
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);
8
+ export const _randomFormatRegex = (props?: _ILengthProps): string => {
9
+ if (props?.minLength === undefined && props?.maxLength === undefined)
10
+ return FIXED;
11
+ // Every character `_randomString` emits is a literal in regular expression
12
+ // syntax, so a source of any length — including the empty source `new
13
+ // RegExp("")` accepts — compiles.
14
+ const length: number = _randomLengthPick(
15
+ _randomLengthWindow(props, { minimum: 0, spread: 16 }),
16
+ );
17
+ return _randomString({
18
+ type: "string",
19
+ minLength: length,
20
+ maxLength: length,
21
+ });
22
+ };
5
23
 
6
24
  const FIXED =
7
25
  "/^(?:(?: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)$/";
@@ -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,50 @@
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 of one to nine digits between them.
19
+ // Together they express 9 and every length from 11 through 24; 10 is the one
20
+ // gap, because a fraction needs both a dot and a digit.
21
+ const window = _randomLengthWindow(props, {
22
+ minimum: CLOCK + 1,
23
+ maximum: CLOCK + 1 + FRACTION_MAX + OFFSET,
24
+ spread: 6,
25
+ });
26
+ let length: number = _randomLengthPick(window);
27
+ if (length === CLOCK + 2)
28
+ length = window.high >= CLOCK + 3 ? CLOCK + 3 : CLOCK + 1;
29
+ if (length < window.low || length > window.high)
30
+ throw new Error(_RANDOM_LENGTH_ERROR);
31
+ const base: string = clock().substring(11, 11 + CLOCK);
32
+ if (length === CLOCK + 1) return `${base}Z`;
33
+ // Nine fraction digits cap the `Z` form at 19 characters, so anything longer
34
+ // spends the extra five on a numeric offset instead.
35
+ return length <= CLOCK + 2 + FRACTION_MAX
36
+ ? `${base}.${__randomDigits(length - CLOCK - 2)}Z`
37
+ : `${base}.${__randomDigits(length - CLOCK - 1 - OFFSET)}${offset()}`;
38
+ };
16
39
 
17
40
  const DAY = 86_400_000;
41
+ const CLOCK = "00:00:00".length;
42
+ const OFFSET = "+00:00".length;
43
+ const FRACTION_MAX = 9;
44
+
45
+ const offset = (): string =>
46
+ `${_randomInteger({ type: "integer", minimum: 0, maximum: 1 }) === 0 ? "+" : "-"}${pad(
47
+ _randomInteger({ type: "integer", minimum: 0, maximum: 23 }),
48
+ )}:${pad(_randomInteger({ type: "integer", minimum: 0, maximum: 59 }))}`;
49
+
50
+ 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;