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
@@ -9,6 +9,7 @@ import (
9
9
  "path/filepath"
10
10
  "sort"
11
11
  "strings"
12
+ "sync"
12
13
 
13
14
  shimast "github.com/microsoft/typescript-go/shim/ast"
14
15
  shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
@@ -86,6 +87,7 @@ func runTransform(args []string) int {
86
87
  transformDiags := []typiaTransformDiagnostic{}
87
88
  transformOptions := pluginOptions.TransformOptions()
88
89
  extras := nativecontext.ITypiaContext_Extras{
90
+ Shared: &sync.Map{},
89
91
  AddDiagnostic: func(diag *nativecontext.ITypiaDiagnostic) int {
90
92
  transformDiags = append(transformDiags, typiaTransformDiagnosticFrom(diag))
91
93
  return len(transformDiags)
@@ -155,6 +155,8 @@ func ttscTypiaTestRewriteCommonJS(t *testing.T, js string) string {
155
155
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_functionalTypeGuardErrorFactory")`, `require("./functional-error-stub.cjs")`)
156
156
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_accessExpressionAsString")`, `require("./access-expression-stub.cjs")`)
157
157
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_stringLength")`, `require("./string-length-stub.cjs")`)
158
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_stringLengthGte")`, `require("./string-length-stub.cjs")`)
159
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_stringLengthLte")`, `require("./string-length-stub.cjs")`)
158
160
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyArray")`, `require("./json-stringify-array-stub.cjs")`)
159
161
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyProperty")`, `require("./json-stringify-property-stub.cjs")`)
160
162
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyElement")`, `require("./json-stringify-element-stub.cjs")`)
@@ -292,14 +294,26 @@ const ttscTypiaTestRandomStringStub = `module.exports._randomString = (props) =>
292
294
  };
293
295
  `
294
296
 
295
- // A double for packages/typia/src/internal/_stringLength.ts: the string
296
- // iterator walks code points, so a surrogate pair counts once, which is what
297
- // `MinLength` and `MaxLength` now mean.
297
+ // Doubles for the string-length helpers. The string iterator walks code points,
298
+ // so a surrogate pair counts once; the comparisons stop as soon as their
299
+ // boundary determines the answer.
298
300
  const ttscTypiaTestStringLengthStub = `module.exports._stringLength = (value) => {
299
301
  let count = 0;
300
302
  for (const _ of value) ++count;
301
303
  return count;
302
304
  };
305
+ module.exports._stringLengthGte = (value, length) => {
306
+ let count = 0;
307
+ if (length <= count) return true;
308
+ for (const _ of value) if (length <= ++count) return true;
309
+ return false;
310
+ };
311
+ module.exports._stringLengthLte = (value, length) => {
312
+ let count = 0;
313
+ if (!(count <= length)) return false;
314
+ for (const _ of value) if (!(++count <= length)) return false;
315
+ return true;
316
+ };
303
317
  `
304
318
 
305
319
  const ttscTypiaTestAccessExpressionStub = `const reserved = new Set([
@@ -1,6 +1,8 @@
1
1
  package context
2
2
 
3
3
  import (
4
+ "sync"
5
+
4
6
  shimast "github.com/microsoft/typescript-go/shim/ast"
5
7
  shimchecker "github.com/microsoft/typescript-go/shim/checker"
6
8
  shimcore "github.com/microsoft/typescript-go/shim/core"
@@ -21,10 +23,12 @@ type ITypiaContext struct {
21
23
  Emit *shimprinter.EmitContext
22
24
  Importer *ImportProgrammer
23
25
  Extras ITypiaContext_Extras
26
+ Shared *sync.Map
24
27
  }
25
28
 
26
29
  type ITypiaContext_Extras struct {
27
30
  AddDiagnostic func(diag *ITypiaDiagnostic) int
31
+ Shared *sync.Map
28
32
  }
29
33
 
30
34
  type ITypiaDiagnostic struct {
@@ -57,7 +57,22 @@ var expressionFactory_factory = shimast.NewNodeFactory(shimast.NodeFactoryHooks{
57
57
  func (expressionFactoryNamespace) Number(value any, emit ...*shimprinter.EmitContext) *shimast.Node {
58
58
  f := nativecontext.EmitFactoryOf(expressionFactory_factory, emit...)
59
59
  text, numeric := expressionFactory_number_text(value)
60
- if numeric < 0 {
60
+ // Go spells the non-finite floats `NaN`, `+Inf`, and `-Inf`. Only the first
61
+ // happens to be JavaScript; `+Inf` evaluates an undeclared `Inf` and throws a
62
+ // ReferenceError when the emitted function first runs (samchon/typia#2452).
63
+ // Spell them as the globals, as TypeScript's own factory does.
64
+ if math.IsNaN(numeric) {
65
+ return f.NewIdentifier("NaN")
66
+ }
67
+ if math.IsInf(numeric, 0) {
68
+ if numeric < 0 {
69
+ return f.NewPrefixUnaryExpression(shimast.KindMinusToken, f.NewIdentifier("Infinity"))
70
+ }
71
+ return f.NewIdentifier("Infinity")
72
+ }
73
+ // Negative zero takes the same negation as every negative value; its text
74
+ // `-0` is not a numeric literal on its own.
75
+ if numeric < 0 || (numeric == 0 && math.Signbit(numeric)) {
61
76
  return f.NewPrefixUnaryExpression(
62
77
  shimast.KindMinusToken,
63
78
  f.NewNumericLiteral(expressionFactory_number_abs_text(numeric), shimast.TokenFlagsNone),
@@ -94,6 +94,16 @@ func (identifierFactoryNamespace) Postfix(str string) string {
94
94
  return identifierFactory_source("[" + identifierFactory_json(str) + "]")
95
95
  }
96
96
 
97
+ // PathPostfix returns the accessor text `_accessExpressionAsString` builds at
98
+ // runtime for the same key: `.key` for an identifier, `["key"]` otherwise. It
99
+ // is the path text itself, not a JavaScript literal that spells it.
100
+ func (identifierFactoryNamespace) PathPostfix(str string) string {
101
+ if identifierFactory_variable(str) {
102
+ return "." + str
103
+ }
104
+ return "[" + identifierFactory_json(str) + "]"
105
+ }
106
+
97
107
  // identifierFactory_json renders `str` as JSON text, matching JSON.stringify so
98
108
  // that the path this lands in is the one _accessExpressionAsString builds for
99
109
  // the same key at runtime, and so JSON.parse in _createStandardSchema reads the
@@ -18,6 +18,19 @@ type literalFactoryNamespace struct{}
18
18
 
19
19
  var LiteralFactory = literalFactoryNamespace{}
20
20
 
21
+ // LiteralFactory_Null is an explicit JSON `null` value.
22
+ //
23
+ // Object writers treat a Go `nil` value as absent and skip it, which is what
24
+ // most schema builders mean by it, so a real `null`, such as the value of
25
+ // `tags.Example<null>`, needs its own marker to survive into the emitted
26
+ // literal and into encoding/json output (samchon/typia#2403).
27
+ type LiteralFactory_Null struct{}
28
+
29
+ // MarshalJSON writes the marker as JSON `null`.
30
+ func (LiteralFactory_Null) MarshalJSON() ([]byte, error) {
31
+ return []byte("null"), nil
32
+ }
33
+
21
34
  // LiteralFactory_OrderedObject is an object literal whose property order is
22
35
  // fixed by Keys rather than inferred from a Go map's (unordered) iteration or
23
36
  // from propertyRank sorting. Use it for objects whose insertion order is
@@ -71,6 +84,9 @@ func (literalFactoryNamespace) Write(input any, emit ...*shimprinter.EmitContext
71
84
  if input == nil {
72
85
  return f.NewKeywordExpression(shimast.KindNullKeyword)
73
86
  }
87
+ if _, ok := input.(LiteralFactory_Null); ok {
88
+ return f.NewKeywordExpression(shimast.KindNullKeyword)
89
+ }
74
90
  if node, ok := input.(*shimast.Node); ok {
75
91
  if node.Kind == shimast.KindArrowFunction || node.Kind == shimast.KindCallExpression || node.Kind == shimast.KindIdentifier {
76
92
  return node
@@ -2,10 +2,12 @@ package factories
2
2
 
3
3
  import (
4
4
  "math"
5
+ "math/big"
5
6
  "strconv"
6
7
  "strings"
7
8
 
8
9
  schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
10
+ nativeutils "github.com/samchon/typia/packages/typia/native/core/utils"
9
11
  )
10
12
 
11
13
  type metadataCommentTagFactoryNamespace struct{}
@@ -51,6 +53,22 @@ func (metadataCommentTagFactoryNamespace) Analyze(props struct {
51
53
  continue
52
54
  }
53
55
  for key, value := range tagger {
56
+ // An empty arm names a target the tag's value cannot be stated for; see
57
+ // metadataCommentTagFactory_bigint. It is an error only where that target
58
+ // occurs, and the other arms still apply to theirs.
59
+ if value != nil && len(value) == 0 {
60
+ for _, atomic := range props.Metadata.Atomics {
61
+ if atomic.Type == key {
62
+ text := ""
63
+ if len(tag.Text) != 0 {
64
+ text = tag.Text[0].Text
65
+ }
66
+ report(key + " value " + strings.TrimSpace(text) + " is not an int64 integer that a number represents exactly")
67
+ break
68
+ }
69
+ }
70
+ continue
71
+ }
54
72
  filtered := []schemametadata.IMetadataTypeTag{}
55
73
  for _, elem := range value {
56
74
  filtered = append(filtered, elem)
@@ -216,11 +234,12 @@ func (metadataCommentTagFactoryNamespace) Get(props struct {
216
234
  // The rule: a template may name only a helper that every `typia` inside the
217
235
  // caret range already ships. `isTypeInt8` and its siblings satisfy it --
218
236
  // `@typia/interface` 13.0.0 named them and `typia` 13.0.0 shipped them. The
219
- // four this file and `Type.ts` now name do not: `_stringLength`, `_isMultipleOf`
220
- // (both first published in 13.1.19), `_isTypeInt64Bigint`, and
221
- // `_isTypeUint64Bigint` (13.1.19). They are safe only because the release that
222
- // carries them is a major, where the caret cannot reach a `typia` that predates
223
- // them. A minor or patch release of this tree reopens #2330.
237
+ // helpers this file and the tag declarations now name do not:
238
+ // `_stringLengthGte`, `_stringLengthLte`, `_isMultipleOf`,
239
+ // `_isTypeInt64Bigint`, and `_isTypeUint64Bigint`. They are safe only because
240
+ // the release that carries them is a major, where the caret cannot reach a
241
+ // `typia` that predates them. A minor or patch release of this tree reopens
242
+ // #2330.
224
243
  //
225
244
  // Nothing here can enforce that; the release version is the maintainer's, and a
226
245
  // campaign pull request never assigns one. This comment is the record.
@@ -229,37 +248,37 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
229
248
  Report func(msg string) any
230
249
  Value string
231
250
  }) metadataCommentTagFactory_TagRecord {
232
- value := metadataCommentTagFactory_parse_integer(struct {
251
+ value := metadataCommentTagFactory_value(metadataCommentTagFactory_parse_integer(struct {
233
252
  Report func(msg string) any
234
253
  Unsigned bool
235
254
  Value string
236
- }{Report: props.Report, Value: props.Value, Unsigned: true})
255
+ }{Report: props.Report, Value: props.Value, Unsigned: true}))
237
256
  return metadataCommentTagFactory_TagRecord{"array": {
238
- {Name: "MinItems<" + props.Value + ">", Target: "array", Kind: "minItems", Value: value, Validate: props.Value + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minItems"), Schema: map[string]any{"minItems": value}},
239
- {Name: "MaxItems<" + props.Value + ">", Target: "array", Kind: "maxItems", Value: value, Validate: "$input.length <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxItems"), Schema: map[string]any{"maxItems": value}},
257
+ {Name: "MinItems<" + props.Value + ">", Target: "array", Kind: "minItems", Value: value, Validate: metadataCommentTagFactory_splice(props.Value) + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minItems"), Schema: map[string]any{"minItems": value}},
258
+ {Name: "MaxItems<" + props.Value + ">", Target: "array", Kind: "maxItems", Value: value, Validate: "$input.length <= " + metadataCommentTagFactory_splice(props.Value), Exclusive: metadataCommentTagFactory_exclusive("maxItems"), Schema: map[string]any{"maxItems": value}},
240
259
  }}
241
260
  },
242
261
  "minItems": func(props struct {
243
262
  Report func(msg string) any
244
263
  Value string
245
264
  }) metadataCommentTagFactory_TagRecord {
246
- value := metadataCommentTagFactory_parse_integer(struct {
265
+ value := metadataCommentTagFactory_value(metadataCommentTagFactory_parse_integer(struct {
247
266
  Report func(msg string) any
248
267
  Unsigned bool
249
268
  Value string
250
- }{Report: props.Report, Value: props.Value, Unsigned: true})
251
- return metadataCommentTagFactory_TagRecord{"array": {{Name: "MinItems<" + props.Value + ">", Target: "array", Kind: "minItems", Value: value, Validate: props.Value + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minItems"), Schema: map[string]any{"minItems": value}}}}
269
+ }{Report: props.Report, Value: props.Value, Unsigned: true}))
270
+ return metadataCommentTagFactory_TagRecord{"array": {{Name: "MinItems<" + props.Value + ">", Target: "array", Kind: "minItems", Value: value, Validate: metadataCommentTagFactory_splice(props.Value) + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minItems"), Schema: map[string]any{"minItems": value}}}}
252
271
  },
253
272
  "maxItems": func(props struct {
254
273
  Report func(msg string) any
255
274
  Value string
256
275
  }) metadataCommentTagFactory_TagRecord {
257
- value := metadataCommentTagFactory_parse_integer(struct {
276
+ value := metadataCommentTagFactory_value(metadataCommentTagFactory_parse_integer(struct {
258
277
  Report func(msg string) any
259
278
  Unsigned bool
260
279
  Value string
261
- }{Report: props.Report, Value: props.Value, Unsigned: true})
262
- return metadataCommentTagFactory_TagRecord{"array": {{Name: "MaxItems<" + props.Value + ">", Target: "array", Kind: "maxItems", Value: value, Validate: "$input.length <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxItems"), Schema: map[string]any{"maxItems": value}}}}
280
+ }{Report: props.Report, Value: props.Value, Unsigned: true}))
281
+ return metadataCommentTagFactory_TagRecord{"array": {{Name: "MaxItems<" + props.Value + ">", Target: "array", Kind: "maxItems", Value: value, Validate: "$input.length <= " + metadataCommentTagFactory_splice(props.Value), Exclusive: metadataCommentTagFactory_exclusive("maxItems"), Schema: map[string]any{"maxItems": value}}}}
263
282
  },
264
283
  "uniqueItems": func(props struct {
265
284
  Report func(msg string) any
@@ -272,25 +291,25 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
272
291
  Report func(msg string) any
273
292
  Value string
274
293
  }) metadataCommentTagFactory_TagRecord {
275
- return metadataCommentTagFactory_numeric(props, "Minimum", "minimum", props.Value+" <= $input", props.Value+" <= $input")
294
+ return metadataCommentTagFactory_numeric(props, "Minimum", "minimum", metadataCommentTagFactory_splice(props.Value)+" <= $input", metadataCommentTagFactory_splice_integer(props.Value)+" <= $input")
276
295
  },
277
296
  "maximum": func(props struct {
278
297
  Report func(msg string) any
279
298
  Value string
280
299
  }) metadataCommentTagFactory_TagRecord {
281
- return metadataCommentTagFactory_numeric(props, "Maximum", "maximum", "$input <= "+props.Value, "$input <= "+props.Value)
300
+ return metadataCommentTagFactory_numeric(props, "Maximum", "maximum", "$input <= "+metadataCommentTagFactory_splice(props.Value), "$input <= "+metadataCommentTagFactory_splice_integer(props.Value))
282
301
  },
283
302
  "exclusiveMinimum": func(props struct {
284
303
  Report func(msg string) any
285
304
  Value string
286
305
  }) metadataCommentTagFactory_TagRecord {
287
- return metadataCommentTagFactory_numeric(props, "ExclusiveMinimum", "exclusiveMinimum", props.Value+" < $input", props.Value+" < $input")
306
+ return metadataCommentTagFactory_numeric(props, "ExclusiveMinimum", "exclusiveMinimum", metadataCommentTagFactory_splice(props.Value)+" < $input", metadataCommentTagFactory_splice_integer(props.Value)+" < $input")
288
307
  },
289
308
  "exclusiveMaximum": func(props struct {
290
309
  Report func(msg string) any
291
310
  Value string
292
311
  }) metadataCommentTagFactory_TagRecord {
293
- return metadataCommentTagFactory_numeric(props, "ExclusiveMaximum", "exclusiveMaximum", "$input < "+props.Value, "$input < "+props.Value)
312
+ return metadataCommentTagFactory_numeric(props, "ExclusiveMaximum", "exclusiveMaximum", "$input < "+metadataCommentTagFactory_splice(props.Value), "$input < "+metadataCommentTagFactory_splice_integer(props.Value))
294
313
  },
295
314
  "multipleOf": func(props struct {
296
315
  Report func(msg string) any
@@ -302,7 +321,7 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
302
321
  // answers a different question than the `multipleOf` keyword this tag emits.
303
322
  // The bigint arm needs no helper: a bigint remainder is already exact.
304
323
  // `_isMultipleOf` first shipped in 13.1.19; see the doc comment above.
305
- return metadataCommentTagFactory_numeric(props, "MultipleOf", "multipleOf", "$importInternal(\"_isMultipleOf\")($input, "+props.Value+")", "$input % "+props.Value+"n === 0n")
324
+ return metadataCommentTagFactory_numeric(props, "MultipleOf", "multipleOf", "$importInternal(\"_isMultipleOf\")($input, "+metadataCommentTagFactory_splice(props.Value)+")", "$input % "+metadataCommentTagFactory_splice_integer(props.Value)+"n === 0n")
306
325
  },
307
326
  "format": func(props struct {
308
327
  Report func(msg string) any
@@ -331,10 +350,11 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
331
350
  // `$input.length` counts UTF-16 code units, while the `minLength` and
332
351
  // `maxLength` keywords these tags emit count characters, so one astral
333
352
  // character would measure 2 against a schema that measures 1.
334
- // `_stringLength` first shipped in 13.1.19; see the doc comment above.
353
+ // The comparison helpers keep that code-point walk but stop when the
354
+ // declared boundary already determines the answer.
335
355
  return metadataCommentTagFactory_TagRecord{"string": {
336
- {Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: props.Value + " <= $importInternal(\"_stringLength\")($input)", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}},
337
- {Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$importInternal(\"_stringLength\")($input) <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}},
356
+ {Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: "$importInternal(\"_stringLengthGte\")($input, " + metadataCommentTagFactory_splice(props.Value) + ")", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}},
357
+ {Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$importInternal(\"_stringLengthLte\")($input, " + metadataCommentTagFactory_splice(props.Value) + ")", Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}},
338
358
  }}
339
359
  },
340
360
  "minLength": func(props struct {
@@ -342,14 +362,14 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
342
362
  Value string
343
363
  }) metadataCommentTagFactory_TagRecord {
344
364
  value := metadataCommentTagFactory_parse_number(props)
345
- return metadataCommentTagFactory_TagRecord{"string": {{Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: props.Value + " <= $importInternal(\"_stringLength\")($input)", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}}}}
365
+ return metadataCommentTagFactory_TagRecord{"string": {{Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: "$importInternal(\"_stringLengthGte\")($input, " + metadataCommentTagFactory_splice(props.Value) + ")", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}}}}
346
366
  },
347
367
  "maxLength": func(props struct {
348
368
  Report func(msg string) any
349
369
  Value string
350
370
  }) metadataCommentTagFactory_TagRecord {
351
371
  value := metadataCommentTagFactory_parse_number(props)
352
- return metadataCommentTagFactory_TagRecord{"string": {{Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$importInternal(\"_stringLength\")($input) <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}}}}
372
+ return metadataCommentTagFactory_TagRecord{"string": {{Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$importInternal(\"_stringLengthLte\")($input, " + metadataCommentTagFactory_splice(props.Value) + ")", Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}}}}
353
373
  },
354
374
  }
355
375
 
@@ -478,31 +498,161 @@ func metadataCommentTagFactory_numeric(props struct {
478
498
  Value string
479
499
  }, name string, kind string, numberValidate string, bigintValidate string) metadataCommentTagFactory_TagRecord {
480
500
  number := metadataCommentTagFactory_parse_number(props)
481
- integer := metadataCommentTagFactory_parse_integer(struct {
482
- Report func(msg string) any
483
- Unsigned bool
484
- Value string
485
- }{Report: func(string) any { return nil }, Value: props.Value, Unsigned: false})
501
+ if number == nil {
502
+ // Reported as an invalid or non-finite number already; a record would only
503
+ // add "requires number type" on a bigint property, which is not the fault.
504
+ return metadataCommentTagFactory_TagRecord{}
505
+ }
486
506
  exclusive := metadataCommentTagFactory_exclusive(kind)
487
507
  record := metadataCommentTagFactory_TagRecord{
488
508
  "number": {{Name: name + "<" + props.Value + ">", Target: "number", Kind: kind, Value: number, Validate: numberValidate, Exclusive: exclusive, Schema: map[string]any{kind: number}}},
489
509
  }
490
- if integer != nil {
491
- record["bigint"] = []schemametadata.IMetadataTypeTag{{Name: name + "<" + props.Value + "n>", Target: "bigint", Kind: kind, Value: *integer, Validate: bigintValidate, Exclusive: exclusive, Schema: map[string]any{kind: number}}}
510
+ integer, numeric, ok := metadataCommentTagFactory_bigint(props.Value)
511
+ if ok {
512
+ record["bigint"] = []schemametadata.IMetadataTypeTag{{Name: name + "<" + props.Value + "n>", Target: "bigint", Kind: kind, Value: integer, Validate: bigintValidate, Exclusive: exclusive, Schema: map[string]any{kind: number}}}
513
+ } else if numeric {
514
+ // An empty arm: the value bounds a bigint, but not with any value this tag
515
+ // can state. `Analyze` reports it where a bigint occurs, so the bigint part
516
+ // of a `number | bigint` property is never left unconstrained silently.
517
+ record["bigint"] = []schemametadata.IMetadataTypeTag{}
492
518
  }
493
519
  return record
494
520
  }
495
521
 
522
+ // metadataCommentTagFactory_bigint reads a numeric tag's value for its bigint
523
+ // arm.
524
+ //
525
+ // Consumers of that arm hold the value as a double: the bound validators splice
526
+ // a number literal, and the schema `random` draws from is numeric. The written
527
+ // integer survives them only when a double represents it exactly, so that is
528
+ // what the arm admits, within the int64 range its value is carried in
529
+ // (samchon/typia#2352). Reading any integer through a double instead enforced
530
+ // `@minimum 9007199254740993` as 9007199254740992, and let `random` generate
531
+ // values the exact `@multipleOf` check rejects (samchon/typia#2457).
532
+ //
533
+ // numeric reports whether the text writes a finite number at all. One that is
534
+ // no such integer -- `1.5`, `5.0000000000000001`, `9007199254740993`, or
535
+ // `1e-1000001` -- is a bigint bound the tag cannot state, while text that is no
536
+ // finite number has already been reported by the number arm.
537
+ func metadataCommentTagFactory_bigint(text string) (value int64, numeric bool, ok bool) {
538
+ if reading := nativeutils.NumberUtil.Read(text); reading.Numeric == false || reading.Finite == false {
539
+ return 0, false, false
540
+ }
541
+ integer, exact := metadataCommentTagFactory_integer(text)
542
+ if exact == false || integer.IsInt64() == false {
543
+ return 0, true, false
544
+ }
545
+ if _, accuracy := new(big.Float).SetInt(integer).Float64(); accuracy != big.Exact {
546
+ return 0, true, false
547
+ }
548
+ return integer.Int64(), true, true
549
+ }
550
+
551
+ // metadataCommentTagFactory_integer is the integer a finite numeric text
552
+ // writes exactly, if it writes one whose double lies within the int64 range. A
553
+ // few integers just below -2^63 round to it and pass; the bigint record checks
554
+ // the integer itself.
555
+ //
556
+ // Its double, which `NumberUtil.Read` rounds correctly, settles most texts
557
+ // without expanding them. A non-integer double comes only from a non-integer
558
+ // text, and a zero from a text with a non-zero digit is the underflow of a
559
+ // non-integer. A double at 2^63 or above, or below -2^63, is refused too: the
560
+ // int64 texts that round up to 2^63 (from 9223372036854775296) are no doubles,
561
+ // so no bigint record could hold them anyway. `big.Rat` expands only what
562
+ // remains, so a short text such as `@minimum 1e-1000000` costs nothing, on any
563
+ // target.
564
+ func metadataCommentTagFactory_integer(text string) (*big.Int, bool) {
565
+ reading := nativeutils.NumberUtil.Read(text)
566
+ if reading.Numeric == false ||
567
+ reading.Finite == false ||
568
+ reading.Value != math.Trunc(reading.Value) ||
569
+ reading.Value < metadataCommentTagFactory_INT64_MINIMUM ||
570
+ reading.Value >= metadataCommentTagFactory_INT64_EXCLUSIVE_MAXIMUM {
571
+ return nil, false
572
+ }
573
+ if reading.Value == 0 {
574
+ // A zero writes zero only when no digit before its exponent is non-zero;
575
+ // otherwise it underflowed. A radix zero has no `e`, being all zeros.
576
+ mantissa := text
577
+ if index := strings.IndexAny(text, "eE"); index != -1 {
578
+ mantissa = text[:index]
579
+ }
580
+ if strings.ContainsAny(mantissa, "123456789") {
581
+ return nil, false
582
+ }
583
+ return big.NewInt(0), true
584
+ }
585
+ rational, ok := nativeutils.NumberUtil.Rational(text)
586
+ if ok == false || rational.IsInt() == false {
587
+ return nil, false
588
+ }
589
+ return rational.Num(), true
590
+ }
591
+
592
+ // metadataCommentTagFactory_value unwraps a parsed count into the record's
593
+ // value and schema. Storing the pointer itself let every consumer that formats
594
+ // a value print an address: strict LLM schemas described `@minItems 2` as
595
+ // `@minItems 0xc000012345`.
596
+ func metadataCommentTagFactory_value(value *int64) any {
597
+ if value == nil {
598
+ return nil
599
+ }
600
+ return *value
601
+ }
602
+
496
603
  func metadataCommentTagFactory_parse_number(props struct {
497
604
  Report func(msg string) any
498
605
  Value string
499
606
  }) any {
500
- parsed, err := strconv.ParseFloat(props.Value, 64)
501
- if err != nil || math.IsNaN(parsed) {
607
+ reading := nativeutils.NumberUtil.Read(props.Value)
608
+ if reading.Numeric == false {
502
609
  props.Report("invalid number")
503
610
  return nil
504
611
  }
505
- return parsed
612
+ // A JSON Schema keyword such as `minimum` must be a JSON number, and JSON has
613
+ // no spelling for an infinity (samchon/typia#2452).
614
+ if reading.Finite == false {
615
+ props.Report("non-finite number")
616
+ return nil
617
+ }
618
+ return reading.Value
619
+ }
620
+
621
+ // metadataCommentTagFactory_splice respells a numeric tag value for the
622
+ // validator the record splices it into (`16 <= $input`, `$input % 1000n`).
623
+ //
624
+ // The spliced text has to be JavaScript for the value the tag was read as, in
625
+ // both the number and the bigint target. The source spelling need not be:
626
+ // `0x10` happens to be, but `1e3`, `1.0`, `+5`, and `007` are integers whose
627
+ // bigint splice (`1e3n`, `1.0n`, `+5n`, `007n`) is no valid BigInt expression
628
+ // (samchon/typia#2442). An integer spelling keeps its digits as written, so the
629
+ // splice never rounds where the source did not: `Number()` would read
630
+ // `9007199254740993` as ...992, while the bigint `@multipleOf` check appends
631
+ // `n` to the digits and compares exactly.
632
+ // Text that does not read as a finite number is passed through; the parser
633
+ // reports it and nothing is emitted.
634
+ func metadataCommentTagFactory_splice(value string) string {
635
+ if integer, ok := nativeutils.NumberUtil.Integer(value); ok {
636
+ return integer.String()
637
+ }
638
+ if reading := nativeutils.NumberUtil.Read(value); reading.Numeric && reading.Finite {
639
+ return nativeutils.NumberUtil.String(reading.Value)
640
+ }
641
+ return value
642
+ }
643
+
644
+ // metadataCommentTagFactory_splice_integer respells a tag value for a bigint
645
+ // validator: the exact digits of the integer the text writes, whatever its
646
+ // spelling, for every value a bigint record holds. `1.152921504606846976e18`
647
+ // writes 2^60, while its double spells 1152921504606847000, which spliced
648
+ // before an `n` would check a different integer (samchon/typia#2457). Text
649
+ // that writes no integer has no bigint record, and falls back to the number
650
+ // splice.
651
+ func metadataCommentTagFactory_splice_integer(value string) string {
652
+ if integer, ok := metadataCommentTagFactory_integer(value); ok {
653
+ return integer.String()
654
+ }
655
+ return metadataCommentTagFactory_splice(value)
506
656
  }
507
657
 
508
658
  func metadataCommentTagFactory_parse_integer(props struct {