typia 14.0.6 → 15.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 (178) hide show
  1. package/README.md +3 -0
  2. package/lib/http.d.ts +49 -24
  3. package/lib/http.js.map +1 -1
  4. package/lib/http.mjs.map +1 -1
  5. package/lib/internal/_createLlmEvaluation.d.ts +1 -0
  6. package/lib/internal/_createLlmEvaluation.js +486 -0
  7. package/lib/internal/_createLlmEvaluation.js.map +1 -0
  8. package/lib/internal/_createLlmEvaluation.mjs +382 -0
  9. package/lib/internal/_createLlmEvaluation.mjs.map +1 -0
  10. package/lib/internal/_httpFormDataReadBigint.js +7 -5
  11. package/lib/internal/_httpFormDataReadBigint.js.map +1 -1
  12. package/lib/internal/_httpFormDataReadBigint.mjs +1 -1
  13. package/lib/internal/_httpFormDataReadBigint.mjs.map +1 -1
  14. package/lib/internal/_httpFormDataReadBoolean.js +12 -10
  15. package/lib/internal/_httpFormDataReadBoolean.js.map +1 -1
  16. package/lib/internal/_httpFormDataReadBoolean.mjs +1 -1
  17. package/lib/internal/_httpFormDataReadBoolean.mjs.map +1 -1
  18. package/lib/internal/_httpFormDataReadNumber.js +7 -5
  19. package/lib/internal/_httpFormDataReadNumber.js.map +1 -1
  20. package/lib/internal/_httpFormDataReadNumber.mjs +1 -1
  21. package/lib/internal/_httpFormDataReadNumber.mjs.map +1 -1
  22. package/lib/internal/_httpFormDataReadString.d.ts +9 -1
  23. package/lib/internal/_httpFormDataReadString.js +10 -2
  24. package/lib/internal/_httpFormDataReadString.js.map +1 -1
  25. package/lib/internal/_httpFormDataReadString.mjs +9 -1
  26. package/lib/internal/_httpFormDataReadString.mjs.map +1 -1
  27. package/lib/internal/_httpHeaderReadBigint.js +5 -1
  28. package/lib/internal/_httpHeaderReadBigint.js.map +1 -1
  29. package/lib/internal/_httpHeaderReadBigint.mjs +2 -1
  30. package/lib/internal/_httpHeaderReadBigint.mjs.map +1 -1
  31. package/lib/internal/_httpHeaderReadNumber.js +5 -1
  32. package/lib/internal/_httpHeaderReadNumber.js.map +1 -1
  33. package/lib/internal/_httpHeaderReadNumber.mjs +2 -1
  34. package/lib/internal/_httpHeaderReadNumber.mjs.map +1 -1
  35. package/lib/internal/_httpParameterReadBigint.js +4 -0
  36. package/lib/internal/_httpParameterReadBigint.js.map +1 -1
  37. package/lib/internal/_httpParameterReadBigint.mjs +1 -0
  38. package/lib/internal/_httpParameterReadBigint.mjs.map +1 -1
  39. package/lib/internal/_httpParameterReadNumber.js +4 -0
  40. package/lib/internal/_httpParameterReadNumber.js.map +1 -1
  41. package/lib/internal/_httpParameterReadNumber.mjs +1 -0
  42. package/lib/internal/_httpParameterReadNumber.mjs.map +1 -1
  43. package/lib/internal/_httpParameterReadString.d.ts +9 -1
  44. package/lib/internal/_httpParameterReadString.js +9 -1
  45. package/lib/internal/_httpParameterReadString.js.map +1 -1
  46. package/lib/internal/_httpParameterReadString.mjs +9 -1
  47. package/lib/internal/_httpParameterReadString.mjs.map +1 -1
  48. package/lib/internal/_httpQueryReadBigint.js +8 -1
  49. package/lib/internal/_httpQueryReadBigint.js.map +1 -1
  50. package/lib/internal/_httpQueryReadBigint.mjs +1 -1
  51. package/lib/internal/_httpQueryReadBigint.mjs.map +1 -1
  52. package/lib/internal/_httpQueryReadBoolean.js +4 -1
  53. package/lib/internal/_httpQueryReadBoolean.js.map +1 -1
  54. package/lib/internal/_httpQueryReadBoolean.mjs +1 -1
  55. package/lib/internal/_httpQueryReadBoolean.mjs.map +1 -1
  56. package/lib/internal/_httpQueryReadNumber.js +8 -1
  57. package/lib/internal/_httpQueryReadNumber.js.map +1 -1
  58. package/lib/internal/_httpQueryReadNumber.mjs +1 -1
  59. package/lib/internal/_httpQueryReadNumber.mjs.map +1 -1
  60. package/lib/internal/_httpQueryReadString.d.ts +9 -1
  61. package/lib/internal/_httpQueryReadString.js +9 -1
  62. package/lib/internal/_httpQueryReadString.js.map +1 -1
  63. package/lib/internal/_httpQueryReadString.mjs +9 -1
  64. package/lib/internal/_httpQueryReadString.mjs.map +1 -1
  65. package/lib/internal/_randomBigint.d.ts +12 -1
  66. package/lib/internal/_randomBigint.js +90 -2
  67. package/lib/internal/_randomBigint.js.map +1 -1
  68. package/lib/internal/_randomBigint.mjs +70 -2
  69. package/lib/internal/_randomBigint.mjs.map +1 -1
  70. package/lib/internal/_randomInteger.js +21 -12
  71. package/lib/internal/_randomInteger.js.map +1 -1
  72. package/lib/internal/_randomInteger.mjs +21 -16
  73. package/lib/internal/_randomInteger.mjs.map +1 -1
  74. package/lib/internal/_randomNumber.js +19 -10
  75. package/lib/internal/_randomNumber.js.map +1 -1
  76. package/lib/internal/_randomNumber.mjs +19 -14
  77. package/lib/internal/_randomNumber.mjs.map +1 -1
  78. package/lib/internal/_stringLengthGte.d.ts +1 -0
  79. package/lib/internal/_stringLengthGte.js +14 -0
  80. package/lib/internal/_stringLengthGte.js.map +1 -0
  81. package/lib/internal/_stringLengthGte.mjs +11 -0
  82. package/lib/internal/_stringLengthGte.mjs.map +1 -0
  83. package/lib/internal/_stringLengthLte.d.ts +1 -0
  84. package/lib/internal/_stringLengthLte.js +14 -0
  85. package/lib/internal/_stringLengthLte.js.map +1 -0
  86. package/lib/internal/_stringLengthLte.mjs +11 -0
  87. package/lib/internal/_stringLengthLte.mjs.map +1 -0
  88. package/lib/llm.d.ts +54 -1
  89. package/lib/llm.js +5 -0
  90. package/lib/llm.js.map +1 -1
  91. package/lib/llm.mjs +6 -1
  92. package/lib/llm.mjs.map +1 -1
  93. package/lib/re-exports.d.ts +1 -1
  94. package/lib/re-exports.js.map +1 -1
  95. package/native/cmd/ttsc-typia/build.go +2 -0
  96. package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +1 -1
  97. package/native/cmd/ttsc-typia/llm_evaluation_accepts_property_probability_test.go +27 -0
  98. package/native/cmd/ttsc-typia/llm_evaluation_accepts_unselected_source_probability_test.go +26 -0
  99. package/native/cmd/ttsc-typia/llm_evaluation_complete_object_shape_test.go +96 -0
  100. package/native/cmd/ttsc-typia/llm_evaluation_ignores_declaration_probability_without_call_test.go +18 -0
  101. package/native/cmd/ttsc-typia/llm_evaluation_plan_emission_transform_test.go +90 -0
  102. package/native/cmd/ttsc-typia/llm_evaluation_program_scan_dependencies_test.go +69 -0
  103. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_comment_test.go +44 -0
  104. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_refinement_test.go +45 -0
  105. package/native/cmd/ttsc-typia/llm_evaluation_rejects_computed_method_probability_test.go +30 -0
  106. package/native/cmd/ttsc-typia/llm_evaluation_rejects_imported_declaration_probability_test.go +48 -0
  107. package/native/cmd/ttsc-typia/llm_evaluation_rejects_invalid_probability_test.go +208 -0
  108. package/native/cmd/ttsc-typia/llm_evaluation_rejects_refinements_test.go +94 -0
  109. package/native/cmd/ttsc-typia/llm_evaluation_rejects_undecidable_types_test.go +232 -0
  110. package/native/cmd/ttsc-typia/metadata_type_tag_sole_malformed_diagnostic_test.go +94 -0
  111. package/native/cmd/ttsc-typia/random_recursive_min_items_diagnostic_test.go +18 -1
  112. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -2
  113. package/native/cmd/ttsc-typia/transform.go +2 -0
  114. package/native/cmd/ttsc-typia/transform_helpers_test.go +17 -3
  115. package/native/core/context/ITypiaContext.go +4 -0
  116. package/native/core/factories/ExpressionFactory.go +16 -1
  117. package/native/core/factories/IdentifierFactory.go +10 -0
  118. package/native/core/factories/LiteralFactory.go +16 -0
  119. package/native/core/factories/MetadataCommentTagFactory.go +185 -35
  120. package/native/core/factories/MetadataTypeTagFactory.go +97 -24
  121. package/native/core/factories/MetadataTypeTagSchemaFactory.go +5 -0
  122. package/native/core/factories/expression_factory_number_spells_non_finite_values_test.go +69 -0
  123. package/native/core/factories/internal/metadata/IMetadataIteratorProps.go +6 -2
  124. package/native/core/factories/internal/metadata/emplace_metadata_object.go +49 -15
  125. package/native/core/factories/literal_factory_null_survives_objects_test.go +43 -0
  126. package/native/core/factories/metadata_comment_tag_factory_holds_bigint_tags_exact_test.go +168 -0
  127. package/native/core/factories/metadata_comment_tag_factory_reads_javascript_numbers_test.go +158 -0
  128. package/native/core/factories/metadata_comment_tag_factory_string_length_helpers_test.go +55 -0
  129. package/native/core/factories/metadata_type_tag_factory_reports_all_invalid_candidates_test.go +73 -0
  130. package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +1 -3
  131. package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +107 -9
  132. package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +1 -3
  133. package/native/core/programmers/http/HttpFormDataProgrammer.go +41 -2
  134. package/native/core/programmers/http/HttpHeadersProgrammer.go +56 -4
  135. package/native/core/programmers/http/HttpParameterProgrammer.go +1 -3
  136. package/native/core/programmers/http/HttpQueryProgrammer.go +26 -43
  137. package/native/core/programmers/iterate/json_schema_jsDocTags.go +10 -3
  138. package/native/core/programmers/iterate/json_schema_jsdoc_tags_cast_reads_javascript_numbers_test.go +64 -0
  139. package/native/core/programmers/llm/LlmApplicationProgrammer.go +1 -0
  140. package/native/core/programmers/llm/LlmEvaluationProgrammer.go +559 -0
  141. package/native/core/programmers/llm/LlmParametersProgrammer.go +6 -5
  142. package/native/core/programmers/llm/LlmReferenceDescription.go +113 -0
  143. package/native/core/programmers/llm/LlmSchemaProgrammer.go +34 -4
  144. package/native/core/programmers/llm/llm_reference_description_test.go +134 -0
  145. package/native/core/schemas/metadata/MetadataDependency.go +9 -0
  146. package/native/core/utils/NumberUtil.go +195 -0
  147. package/native/core/utils/number_util_rational_keeps_written_value_test.go +62 -0
  148. package/native/core/utils/number_util_reads_javascript_number_grammar_test.go +147 -0
  149. package/native/transform/CallExpressionTransformer.go +1 -0
  150. package/native/transform/FileTransformer.go +5 -0
  151. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations.go +94 -0
  152. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations_test.go +50 -0
  153. package/native/transform/features/llm/LlmEvaluationTransformer.go +59 -0
  154. package/native/transform/features/llm/LlmSchemaTransformer.go +14 -11
  155. package/native/transform/features/llm/llm_transformer_entry_coverage_test.go +29 -27
  156. package/package.json +3 -3
  157. package/src/http.ts +61 -34
  158. package/src/internal/_createLlmEvaluation.ts +678 -0
  159. package/src/internal/_httpFormDataReadBigint.ts +3 -1
  160. package/src/internal/_httpFormDataReadBoolean.ts +3 -1
  161. package/src/internal/_httpFormDataReadNumber.ts +3 -1
  162. package/src/internal/_httpFormDataReadString.ts +10 -1
  163. package/src/internal/_httpHeaderReadBigint.ts +6 -1
  164. package/src/internal/_httpHeaderReadNumber.ts +6 -1
  165. package/src/internal/_httpParameterReadBigint.ts +3 -0
  166. package/src/internal/_httpParameterReadNumber.ts +3 -0
  167. package/src/internal/_httpParameterReadString.ts +12 -2
  168. package/src/internal/_httpQueryReadBigint.ts +7 -1
  169. package/src/internal/_httpQueryReadBoolean.ts +3 -1
  170. package/src/internal/_httpQueryReadNumber.ts +7 -1
  171. package/src/internal/_httpQueryReadString.ts +10 -1
  172. package/src/internal/_randomBigint.ts +111 -3
  173. package/src/internal/_randomInteger.ts +31 -16
  174. package/src/internal/_randomNumber.ts +23 -12
  175. package/src/internal/_stringLengthGte.ts +6 -0
  176. package/src/internal/_stringLengthLte.ts +6 -0
  177. package/src/llm.ts +64 -0
  178. package/src/re-exports.ts +1 -0
@@ -1,10 +1,19 @@
1
+ /**
2
+ * Reads one form field as a string.
3
+ *
4
+ * The text `"null"` spells `null` only where the property's type admits `null`;
5
+ * elsewhere it is the string `"null"` (#2450). The emitter passes `false` for a
6
+ * string whose type does not admit `null` and omits the argument otherwise, so
7
+ * code emitted before the parameter existed keeps its reading.
8
+ */
1
9
  export const _httpFormDataReadString = (
2
10
  input: string | File | null,
11
+ nullable: boolean = true,
3
12
  ): string | null | undefined =>
4
13
  input instanceof File
5
14
  ? (input as any)
6
15
  : input === null
7
16
  ? undefined
8
- : input === "null"
17
+ : nullable === true && input === "null"
9
18
  ? null
10
19
  : input;
@@ -1,5 +1,10 @@
1
1
  export const _httpHeaderReadBigint = (value: string | undefined) =>
2
- value !== undefined ? toBigint(value) : undefined;
2
+ // A blank header, or a blank element of a header list, is absent: `BigInt("")`
3
+ // is 0n, which let validators accept an empty header as a real zero (#2448).
4
+ value !== undefined && isBlank(value) === false ? toBigint(value) : undefined;
5
+
6
+ const isBlank = (value: string): boolean =>
7
+ typeof value === "string" && value.trim().length === 0;
3
8
 
4
9
  const toBigint = (str: string): bigint | string => {
5
10
  try {
@@ -1,5 +1,10 @@
1
1
  export const _httpHeaderReadNumber = (value: string | undefined) =>
2
- value !== undefined ? toNumber(value) : undefined;
2
+ // A blank header, or a blank element of a header list, is absent: `Number("")`
3
+ // is 0, which let validators accept an empty header as a real zero (#2448).
4
+ value !== undefined && isBlank(value) === false ? toNumber(value) : undefined;
5
+
6
+ const isBlank = (value: string): boolean =>
7
+ typeof value === "string" && value.trim().length === 0;
3
8
 
4
9
  const toNumber = (str: string): number | string => {
5
10
  const value: number = Number(str);
@@ -2,6 +2,9 @@ export const _httpParameterReadBigint = (value: string) =>
2
2
  value !== "null" ? toBigint(value) : null;
3
3
 
4
4
  const toBigint = (str: string): bigint | string => {
5
+ // Blank text stays text, so the assertion rejects it: `BigInt(" ")` is 0n,
6
+ // which read a blank path segment as a real zero (#2448).
7
+ if (str.trim().length === 0) return str;
5
8
  try {
6
9
  return BigInt(str);
7
10
  } catch {
@@ -2,6 +2,9 @@ export const _httpParameterReadNumber = (value: string) =>
2
2
  value !== "null" ? toNumber(value) : null;
3
3
 
4
4
  const toNumber = (str: string): number | string => {
5
+ // Blank text stays text, so the assertion rejects it: `Number(" ")` is 0,
6
+ // which read a blank path segment as a real zero (#2448).
7
+ if (str.trim().length === 0) return str;
5
8
  const value: number = Number(str);
6
9
  return isNaN(value) ? str : value;
7
10
  };
@@ -1,2 +1,12 @@
1
- export const _httpParameterReadString = (value: string) =>
2
- value !== "null" ? value : null;
1
+ /**
2
+ * Reads one path parameter as a string.
3
+ *
4
+ * The text `"null"` spells `null` only where the parameter's type admits
5
+ * `null`; elsewhere it is the string `"null"` (#2450). The emitter passes
6
+ * `false` for a string whose type does not admit `null` and omits the argument
7
+ * otherwise, so code emitted before the parameter existed keeps its reading.
8
+ */
9
+ export const _httpParameterReadString = (
10
+ value: string,
11
+ nullable: boolean = true,
12
+ ) => (nullable === true && value === "null" ? null : value);
@@ -1,7 +1,13 @@
1
1
  export const _httpQueryReadBigint = (
2
2
  str: string | null,
3
3
  ): bigint | null | undefined =>
4
- !!str?.length ? (str === "null" ? null : (toBigint(str) as any)) : undefined;
4
+ // Blank text is absent, as the empty string always was: `BigInt(" ")` is 0n,
5
+ // which would read a whitespace value as a real zero (#2448).
6
+ typeof str === "string" && str.trim().length !== 0
7
+ ? str === "null"
8
+ ? null
9
+ : (toBigint(str) as any)
10
+ : undefined;
5
11
 
6
12
  const toBigint = (str: string): bigint | string => {
7
13
  try {
@@ -1,7 +1,9 @@
1
1
  export const _httpQueryReadBoolean = (
2
2
  str: string | null,
3
3
  ): boolean | null | undefined =>
4
- str === null
4
+ // `undefined` is as absent as `null`, which the contract returns; a
5
+ // stand-in reader that answers `undefined` must not throw on `.length`.
6
+ str === null || str === undefined
5
7
  ? undefined
6
8
  : str === "null"
7
9
  ? null
@@ -1,7 +1,13 @@
1
1
  export const _httpQueryReadNumber = (
2
2
  str: string | null,
3
3
  ): number | null | undefined =>
4
- !!str?.length ? (str === "null" ? null : (toNumber(str) as any)) : undefined;
4
+ // Blank text is absent, as the empty string always was: `Number(" ")` is 0,
5
+ // which would read a whitespace value as a real zero (#2448).
6
+ typeof str === "string" && str.trim().length !== 0
7
+ ? str === "null"
8
+ ? null
9
+ : (toNumber(str) as any)
10
+ : undefined;
5
11
 
6
12
  const toNumber = (str: string): number | string => {
7
13
  const value: number = Number(str);
@@ -1,4 +1,13 @@
1
+ /**
2
+ * Reads one query value as a string.
3
+ *
4
+ * The text `"null"` spells `null` only where the property's type admits `null`;
5
+ * elsewhere it is the string `"null"` (#2450). The emitter passes `false` for a
6
+ * string whose type does not admit `null` and omits the argument otherwise, so
7
+ * code emitted before the parameter existed keeps its reading.
8
+ */
1
9
  export const _httpQueryReadString = (
2
10
  str: string | null,
11
+ nullable: boolean = true,
3
12
  ): string | null | undefined =>
4
- str === null ? undefined : str === "null" ? null : str;
13
+ str === null ? undefined : nullable === true && str === "null" ? null : str;
@@ -1,6 +1,114 @@
1
1
  import { OpenApi } from "@typia/interface";
2
2
 
3
- import { _randomInteger } from "./_randomInteger";
3
+ import { _decimalIntegerStep } from "./_decimal";
4
4
 
5
- export const _randomBigint = (props: OpenApi.IJsonSchema.IInteger): bigint =>
6
- BigInt(_randomInteger(props));
5
+ /**
6
+ * Generates a random `bigint` satisfying an integer schema.
7
+ *
8
+ * The schema carries its bounds and step as numbers, but the value is a
9
+ * `bigint`, so the draw runs on integers. Drawing through doubles rounded every
10
+ * value past 2^53, and it checked `multipleOf` against a double's shortest
11
+ * decimal text rather than the integer `BigInt` makes of it, so `random`
12
+ * returned values the validator rejects, or gave up on a range that holds one
13
+ * (#2457). An integral bound or step is read as the integer the double holds,
14
+ * which is the integer the validator compares with.
15
+ */
16
+ export const _randomBigint = (schema: OpenApi.IJsonSchema.IInteger): bigint => {
17
+ const lower: bigint | null = boundary(
18
+ schema.minimum,
19
+ schema.exclusiveMinimum,
20
+ "lower",
21
+ );
22
+ const upper: bigint | null = boundary(
23
+ schema.maximum,
24
+ schema.exclusiveMaximum,
25
+ "upper",
26
+ );
27
+ const minimum: bigint =
28
+ lower ?? (upper === null ? BigInt(0) : upper - BigInt(100));
29
+ const maximum: bigint =
30
+ upper ?? (lower === null ? BigInt(100) : lower + BigInt(100));
31
+ if (minimum > maximum)
32
+ throw new Error("Minimum value is greater than maximum value.");
33
+ if (schema.multipleOf === undefined) return between(minimum, maximum);
34
+
35
+ const step: bigint | null = integerStep(schema.multipleOf);
36
+ if (step === null || step <= BigInt(0))
37
+ throw new Error("The multipleOf value must be a positive finite number.");
38
+ const first: bigint = ceilDivide(minimum, step);
39
+ const last: bigint = floorDivide(maximum, step);
40
+ if (first > last)
41
+ throw new Error("The range does not contain a multipleOf value.");
42
+ return between(first, last) * step;
43
+ };
44
+
45
+ /**
46
+ * Reads one side's inclusive integer bound.
47
+ *
48
+ * `-Infinity` below or `Infinity` above excludes no integer, so it is no bound
49
+ * at all; `Infinity` below or `-Infinity` above excludes every integer.
50
+ */
51
+ const boundary = (
52
+ inclusive: number | undefined,
53
+ exclusive: number | undefined,
54
+ side: "lower" | "upper",
55
+ ): bigint | null => {
56
+ const candidates: bigint[] = [];
57
+ for (const [value, open] of [
58
+ [inclusive, false],
59
+ [exclusive, true],
60
+ ] as const) {
61
+ if (value === undefined) continue;
62
+ if (Number.isFinite(value) === false) {
63
+ if (value === (side === "lower" ? -Infinity : Infinity)) continue;
64
+ throw new Error("Numeric range has no finite value.");
65
+ }
66
+ candidates.push(
67
+ side === "lower"
68
+ ? open
69
+ ? BigInt(Math.floor(value)) + BigInt(1)
70
+ : BigInt(Math.ceil(value))
71
+ : open
72
+ ? BigInt(Math.ceil(value)) - BigInt(1)
73
+ : BigInt(Math.floor(value)),
74
+ );
75
+ }
76
+ if (candidates.length === 0) return null;
77
+ return candidates.reduce((x, y) =>
78
+ side === "lower" ? (x > y ? x : y) : x < y ? x : y,
79
+ );
80
+ };
81
+
82
+ /**
83
+ * The smallest positive integer a `multipleOf` divides.
84
+ *
85
+ * An integral step is the integer its double holds; a fractional one, such as
86
+ * `1.5`, steps by its smallest integer multiple (`3`).
87
+ */
88
+ const integerStep = (multipleOf: number): bigint | null => {
89
+ if (Number.isFinite(multipleOf) === false) return null;
90
+ if (Number.isInteger(multipleOf)) return BigInt(multipleOf);
91
+ return _decimalIntegerStep(multipleOf)?.coefficient ?? null;
92
+ };
93
+
94
+ const ceilDivide = (x: bigint, y: bigint): bigint => {
95
+ const quotient: bigint = x / y;
96
+ return x % y > BigInt(0) ? quotient + BigInt(1) : quotient;
97
+ };
98
+
99
+ const floorDivide = (x: bigint, y: bigint): bigint => {
100
+ const quotient: bigint = x / y;
101
+ return x % y < BigInt(0) ? quotient - BigInt(1) : quotient;
102
+ };
103
+
104
+ /** Draws an integer in `[minimum, maximum]`, scaling one 53-bit sample. */
105
+ const between = (minimum: bigint, maximum: bigint): bigint => {
106
+ const scale: bigint = BigInt(1) << BigInt(53);
107
+ const sample: bigint = BigInt(
108
+ Math.min(
109
+ Number(scale - BigInt(1)),
110
+ Math.floor(Math.max(0, Math.random()) * Number(scale)),
111
+ ),
112
+ );
113
+ return minimum + ((maximum - minimum + BigInt(1)) * sample) / scale;
114
+ };
@@ -35,14 +35,12 @@ const scalar = (props: { minimum: number; maximum: number }): number => {
35
35
  const getLowerBoundary = (
36
36
  schema: OpenApi.IJsonSchema.IInteger,
37
37
  ): IBoundary | null => {
38
- const inclusive: IBoundary | null =
39
- schema.minimum === undefined
40
- ? null
41
- : { value: schema.minimum, exclusive: false };
42
- const exclusive: IBoundary | null =
43
- schema.exclusiveMinimum === undefined
44
- ? null
45
- : { value: schema.exclusiveMinimum, exclusive: true };
38
+ const inclusive: IBoundary | null = boundary(schema.minimum, false, "lower");
39
+ const exclusive: IBoundary | null = boundary(
40
+ schema.exclusiveMinimum,
41
+ true,
42
+ "lower",
43
+ );
46
44
  const selected: IBoundary | null = selectBoundary(
47
45
  inclusive,
48
46
  exclusive,
@@ -60,14 +58,12 @@ const getLowerBoundary = (
60
58
  const getUpperBoundary = (
61
59
  schema: OpenApi.IJsonSchema.IInteger,
62
60
  ): IBoundary | null => {
63
- const inclusive: IBoundary | null =
64
- schema.maximum === undefined
65
- ? null
66
- : { value: schema.maximum, exclusive: false };
67
- const exclusive: IBoundary | null =
68
- schema.exclusiveMaximum === undefined
69
- ? null
70
- : { value: schema.exclusiveMaximum, exclusive: true };
61
+ const inclusive: IBoundary | null = boundary(schema.maximum, false, "upper");
62
+ const exclusive: IBoundary | null = boundary(
63
+ schema.exclusiveMaximum,
64
+ true,
65
+ "upper",
66
+ );
71
67
  const selected: IBoundary | null = selectBoundary(
72
68
  inclusive,
73
69
  exclusive,
@@ -82,6 +78,25 @@ const getUpperBoundary = (
82
78
  };
83
79
  };
84
80
 
81
+ /**
82
+ * Reads one bound, which may be infinite.
83
+ *
84
+ * A type tag built from an overflowing literal (`Maximum<1e400>`) carries an
85
+ * infinite bound (#2452). `-Infinity` below or `Infinity` above excludes no
86
+ * finite number, so it is no bound at all; `Infinity` below or `-Infinity`
87
+ * above excludes every finite number, so no value can be generated.
88
+ */
89
+ const boundary = (
90
+ value: number | undefined,
91
+ exclusive: boolean,
92
+ side: "lower" | "upper",
93
+ ): IBoundary | null => {
94
+ if (value === undefined) return null;
95
+ if (Number.isFinite(value)) return { value, exclusive };
96
+ if (value === (side === "lower" ? -Infinity : Infinity)) return null;
97
+ throw new Error("Numeric range has no finite value.");
98
+ };
99
+
85
100
  const selectBoundary = (
86
101
  x: IBoundary | null,
87
102
  y: IBoundary | null,
@@ -57,12 +57,8 @@ const getLowerBoundary = (
57
57
  schema: OpenApi.IJsonSchema.INumber,
58
58
  ): IBoundary | null =>
59
59
  selectBoundary(
60
- schema.minimum === undefined
61
- ? null
62
- : { value: schema.minimum, exclusive: false },
63
- schema.exclusiveMinimum === undefined
64
- ? null
65
- : { value: schema.exclusiveMinimum, exclusive: true },
60
+ boundary(schema.minimum, false, "lower"),
61
+ boundary(schema.exclusiveMinimum, true, "lower"),
66
62
  Math.max,
67
63
  );
68
64
 
@@ -70,15 +66,30 @@ const getUpperBoundary = (
70
66
  schema: OpenApi.IJsonSchema.INumber,
71
67
  ): IBoundary | null =>
72
68
  selectBoundary(
73
- schema.maximum === undefined
74
- ? null
75
- : { value: schema.maximum, exclusive: false },
76
- schema.exclusiveMaximum === undefined
77
- ? null
78
- : { value: schema.exclusiveMaximum, exclusive: true },
69
+ boundary(schema.maximum, false, "upper"),
70
+ boundary(schema.exclusiveMaximum, true, "upper"),
79
71
  Math.min,
80
72
  );
81
73
 
74
+ /**
75
+ * Reads one bound, which may be infinite.
76
+ *
77
+ * A type tag built from an overflowing literal (`Maximum<1e400>`) carries an
78
+ * infinite bound (#2452). `-Infinity` below or `Infinity` above excludes no
79
+ * finite number, so it is no bound at all; `Infinity` below or `-Infinity`
80
+ * above excludes every finite number, so no value can be generated.
81
+ */
82
+ const boundary = (
83
+ value: number | undefined,
84
+ exclusive: boolean,
85
+ side: "lower" | "upper",
86
+ ): IBoundary | null => {
87
+ if (value === undefined) return null;
88
+ if (Number.isFinite(value)) return { value, exclusive };
89
+ if (value === (side === "lower" ? -Infinity : Infinity)) return null;
90
+ throw new Error("Numeric range has no finite value.");
91
+ };
92
+
82
93
  const selectBoundary = (
83
94
  x: IBoundary | null,
84
95
  y: IBoundary | null,
@@ -0,0 +1,6 @@
1
+ export const _stringLengthGte = (value: string, length: number): boolean => {
2
+ let count: number = 0;
3
+ if (length <= count) return true;
4
+ for (const _ch of value) if (length <= ++count) return true;
5
+ return false;
6
+ };
@@ -0,0 +1,6 @@
1
+ export const _stringLengthLte = (value: string, length: number): boolean => {
2
+ let count: number = 0;
3
+ if (!(count <= length)) return false;
4
+ for (const _ch of value) if (!(++count <= length)) return false;
5
+ return true;
6
+ };
package/src/llm.ts CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  IJsonParseResult,
3
3
  ILlmApplication,
4
4
  ILlmController,
5
+ ILlmEvaluation,
5
6
  ILlmSchema,
6
7
  ILlmStructuredOutput,
7
8
  } from "@typia/interface";
@@ -201,6 +202,69 @@ export function structuredOutput(): never {
201
202
  NoTransformConfigurationError("llm.structuredOutput");
202
203
  }
203
204
 
205
+ /* -----------------------------------------------------------
206
+ EVALUATION
207
+ ----------------------------------------------------------- */
208
+ /**
209
+ * Creates LLM evaluation questions.
210
+ *
211
+ * @danger You must configure the generic argument `T`
212
+ */
213
+ export function evaluation(): never;
214
+
215
+ /**
216
+ * Creates LLM evaluation questions from TypeScript object type.
217
+ *
218
+ * Generates {@link ILlmEvaluation} for evaluation models, which answer typed
219
+ * questions about a shared state with probabilities instead of generating text:
220
+ * TypeSafe's Jev natively, and OpenAI, Anthropic, and Google through Vercel AI
221
+ * SDK's `experimental_evaluate()`.
222
+ *
223
+ * Every leaf property of `T` becomes one question, and its JSDoc description
224
+ * becomes the question text:
225
+ *
226
+ * - `boolean` → boolean question
227
+ * - String enum or string literal union → choice question
228
+ * - Numeric enum or numeric literal union → score question
229
+ * - Array of a string literal union or string enum → one boolean question per
230
+ * member
231
+ * - Nested object → flattened, one question per leaf
232
+ *
233
+ * Types an evaluation model cannot answer, such as `string`, `number`, optional
234
+ * properties, or a leaf without a JSDoc description, are compile errors. Use
235
+ * `tags.Probability<N>` or `@probability N` to set decision thresholds and
236
+ * acceptance minimums. Once one choice, score, or set member declares a
237
+ * requirement, every member must declare one or inherit the property's
238
+ * `@probability` default. A nested object's own JSDoc description is not sent
239
+ * to the model; only the leaves' descriptions become question text. Other
240
+ * validation refinements that the answer decoder cannot enforce are compile
241
+ * errors.
242
+ *
243
+ * This feature is experimental. It follows Vercel AI SDK's evaluation model
244
+ * specification, which is itself experimental and may change in patch
245
+ * releases.
246
+ *
247
+ * Workflow:
248
+ *
249
+ * 1. Pass {@link ILlmEvaluation.questions} to the evaluation model
250
+ * 2. Receive the answer map keyed by the same question IDs
251
+ * 3. Use {@link ILlmEvaluation.decode} to fold the answers back into `T`; pass the
252
+ * model's declared rounding precision when available
253
+ *
254
+ * Related functions:
255
+ *
256
+ * - {@link structuredOutput} — Structured output generated as text by an LLM
257
+ *
258
+ * @template T Target decision type (object with static properties)
259
+ * @returns LLM evaluation questions with a checked answer decoder
260
+ */
261
+ export function evaluation<T extends Record<string, any>>(): ILlmEvaluation<T>;
262
+
263
+ /** @internal */
264
+ export function evaluation(): never {
265
+ NoTransformConfigurationError("llm.evaluation");
266
+ }
267
+
204
268
  /* -----------------------------------------------------------
205
269
  RAW SCHEMAS
206
270
  ----------------------------------------------------------- */
package/src/re-exports.ts CHANGED
@@ -25,6 +25,7 @@ export type {
25
25
  ILlmApplication,
26
26
  ILlmFunction,
27
27
  ILlmStructuredOutput,
28
+ ILlmEvaluation,
28
29
  ILlmSchema,
29
30
  // reflect
30
31
  IMetadataSchema,