typia 14.0.6 → 15.0.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 (72) hide show
  1. package/README.md +3 -0
  2. package/lib/internal/_createLlmEvaluation.d.ts +1 -0
  3. package/lib/internal/_createLlmEvaluation.js +486 -0
  4. package/lib/internal/_createLlmEvaluation.js.map +1 -0
  5. package/lib/internal/_createLlmEvaluation.mjs +382 -0
  6. package/lib/internal/_createLlmEvaluation.mjs.map +1 -0
  7. package/lib/internal/_stringLengthGte.d.ts +1 -0
  8. package/lib/internal/_stringLengthGte.js +14 -0
  9. package/lib/internal/_stringLengthGte.js.map +1 -0
  10. package/lib/internal/_stringLengthGte.mjs +11 -0
  11. package/lib/internal/_stringLengthGte.mjs.map +1 -0
  12. package/lib/internal/_stringLengthLte.d.ts +1 -0
  13. package/lib/internal/_stringLengthLte.js +14 -0
  14. package/lib/internal/_stringLengthLte.js.map +1 -0
  15. package/lib/internal/_stringLengthLte.mjs +11 -0
  16. package/lib/internal/_stringLengthLte.mjs.map +1 -0
  17. package/lib/llm.d.ts +54 -1
  18. package/lib/llm.js +5 -0
  19. package/lib/llm.js.map +1 -1
  20. package/lib/llm.mjs +6 -1
  21. package/lib/llm.mjs.map +1 -1
  22. package/lib/re-exports.d.ts +1 -1
  23. package/lib/re-exports.js.map +1 -1
  24. package/native/cmd/ttsc-typia/build.go +2 -0
  25. package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +1 -1
  26. package/native/cmd/ttsc-typia/llm_evaluation_accepts_property_probability_test.go +27 -0
  27. package/native/cmd/ttsc-typia/llm_evaluation_accepts_unselected_source_probability_test.go +26 -0
  28. package/native/cmd/ttsc-typia/llm_evaluation_complete_object_shape_test.go +96 -0
  29. package/native/cmd/ttsc-typia/llm_evaluation_ignores_declaration_probability_without_call_test.go +18 -0
  30. package/native/cmd/ttsc-typia/llm_evaluation_plan_emission_transform_test.go +90 -0
  31. package/native/cmd/ttsc-typia/llm_evaluation_program_scan_dependencies_test.go +69 -0
  32. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_comment_test.go +44 -0
  33. package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_refinement_test.go +45 -0
  34. package/native/cmd/ttsc-typia/llm_evaluation_rejects_computed_method_probability_test.go +30 -0
  35. package/native/cmd/ttsc-typia/llm_evaluation_rejects_imported_declaration_probability_test.go +48 -0
  36. package/native/cmd/ttsc-typia/llm_evaluation_rejects_invalid_probability_test.go +199 -0
  37. package/native/cmd/ttsc-typia/llm_evaluation_rejects_refinements_test.go +94 -0
  38. package/native/cmd/ttsc-typia/llm_evaluation_rejects_undecidable_types_test.go +232 -0
  39. package/native/cmd/ttsc-typia/metadata_type_tag_sole_malformed_diagnostic_test.go +94 -0
  40. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -2
  41. package/native/cmd/ttsc-typia/transform.go +2 -0
  42. package/native/cmd/ttsc-typia/transform_helpers_test.go +17 -3
  43. package/native/core/context/ITypiaContext.go +4 -0
  44. package/native/core/factories/IdentifierFactory.go +10 -0
  45. package/native/core/factories/LiteralFactory.go +16 -0
  46. package/native/core/factories/MetadataCommentTagFactory.go +12 -10
  47. package/native/core/factories/MetadataTypeTagFactory.go +97 -24
  48. package/native/core/factories/MetadataTypeTagSchemaFactory.go +5 -0
  49. package/native/core/factories/internal/metadata/IMetadataIteratorProps.go +6 -2
  50. package/native/core/factories/internal/metadata/emplace_metadata_object.go +49 -15
  51. package/native/core/factories/literal_factory_null_survives_objects_test.go +43 -0
  52. package/native/core/factories/metadata_comment_tag_factory_string_length_helpers_test.go +55 -0
  53. package/native/core/factories/metadata_type_tag_factory_reports_all_invalid_candidates_test.go +73 -0
  54. package/native/core/programmers/llm/LlmApplicationProgrammer.go +1 -0
  55. package/native/core/programmers/llm/LlmEvaluationProgrammer.go +555 -0
  56. package/native/core/programmers/llm/LlmParametersProgrammer.go +6 -5
  57. package/native/core/programmers/llm/LlmReferenceDescription.go +113 -0
  58. package/native/core/programmers/llm/llm_reference_description_test.go +134 -0
  59. package/native/core/schemas/metadata/MetadataDependency.go +9 -0
  60. package/native/transform/CallExpressionTransformer.go +1 -0
  61. package/native/transform/FileTransformer.go +5 -0
  62. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations.go +94 -0
  63. package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations_test.go +50 -0
  64. package/native/transform/features/llm/LlmEvaluationTransformer.go +59 -0
  65. package/native/transform/features/llm/LlmSchemaTransformer.go +14 -11
  66. package/native/transform/features/llm/llm_transformer_entry_coverage_test.go +29 -27
  67. package/package.json +3 -3
  68. package/src/internal/_createLlmEvaluation.ts +678 -0
  69. package/src/internal/_stringLengthGte.ts +6 -0
  70. package/src/internal/_stringLengthLte.ts +6 -0
  71. package/src/llm.ts +64 -0
  72. package/src/re-exports.ts +1 -0
@@ -0,0 +1,113 @@
1
+ package llm
2
+
3
+ import (
4
+ "strings"
5
+
6
+ nativeiterate "github.com/samchon/typia/packages/typia/native/core/programmers/iterate"
7
+ )
8
+
9
+ // llmReferenceDescription_root describes a parameters root that was reached
10
+ // through `$ref`, the way `LlmSchemaConverter.parameters` does with
11
+ // `JsonDescriptor.cascade({ escape: true })`: the type's own description, then
12
+ // each described namespace parent quoted, or `Current Type: {@link Name}` when
13
+ // the type carries none (samchon/typia#2405). A root that is not a reference
14
+ // keeps `own`.
15
+ func llmReferenceDescription_root(
16
+ schema nativeiterate.JsonSchema,
17
+ components *nativeiterate.OpenApi_IComponents,
18
+ own *string,
19
+ ) *string {
20
+ ref, ok := schema["$ref"].(string)
21
+ if ok == false {
22
+ return own
23
+ }
24
+ key, ok := llmReferenceDescription_key(ref)
25
+ if ok == false {
26
+ return own
27
+ }
28
+ return llmReferenceDescription_cascade(key, components, own)
29
+ }
30
+
31
+ // llmReferenceDescription_cascade ports `JsonDescriptor.cascade` with
32
+ // `escape: true`.
33
+ func llmReferenceDescription_cascade(
34
+ key string,
35
+ components *nativeiterate.OpenApi_IComponents,
36
+ own *string,
37
+ ) *string {
38
+ type parent struct {
39
+ key string
40
+ description *string
41
+ }
42
+ accessors := strings.Split(key, ".")
43
+ parents := []parent{}
44
+ for i := len(accessors); i >= 1; i-- {
45
+ current := strings.Join(accessors[:i], ".")
46
+ var description *string
47
+ if components != nil && components.Schemas != nil {
48
+ if target, found := components.Schemas[current]; found {
49
+ if text, ok := target["description"].(string); ok {
50
+ description = &text
51
+ }
52
+ }
53
+ }
54
+ // the type itself always stays; a parent only when it is described
55
+ if i == len(accessors) || (description != nil && *description != "") {
56
+ parents = append(parents, parent{key: current, description: description})
57
+ }
58
+ }
59
+ if (own == nil || *own == "") && len(parents) == 0 {
60
+ return nil
61
+ }
62
+ parts := []string{}
63
+ if own != nil && *own != "" {
64
+ parts = append(parts, *own)
65
+ }
66
+ for i, p := range parents {
67
+ if p.description == nil {
68
+ parts = append(parts, "Current Type: {@link "+p.key+"}")
69
+ continue
70
+ }
71
+ role := "parent"
72
+ if i == 0 {
73
+ role = "current"
74
+ }
75
+ lines := strings.Split(*p.description, "\n")
76
+ for j, line := range lines {
77
+ lines[j] = "> " + line
78
+ }
79
+ parts = append(parts, "Description of the "+role+" {@link "+p.key+"} type:\n\n"+strings.Join(lines, "\n"))
80
+ }
81
+ output := strings.Join(parts, "\n\n------------------------------\n\n")
82
+ return &output
83
+ }
84
+
85
+ // llmReferenceDescription_key reads the component key of a
86
+ // `#/components/schemas/` reference. Native references carry the raw key, the
87
+ // one `components.schemas` is indexed by; `LlmReference.readOpenApi` decodes
88
+ // the escaped form of the same key in an emitted document.
89
+ func llmReferenceDescription_key(ref string) (string, bool) {
90
+ const prefix = "#/components/schemas/"
91
+ if strings.HasPrefix(ref, prefix) == false {
92
+ return "", false
93
+ }
94
+ return strings.TrimPrefix(ref, prefix), true
95
+ }
96
+
97
+ // llmReferenceDescription_assign sets the cascaded root description on a
98
+ // converted parameters object, removing it when the cascade yields none.
99
+ func llmReferenceDescription_assign(
100
+ output map[string]any,
101
+ schema nativeiterate.JsonSchema,
102
+ components *nativeiterate.OpenApi_IComponents,
103
+ ) {
104
+ var own *string
105
+ if text, ok := output["description"].(string); ok {
106
+ own = &text
107
+ }
108
+ if description := llmReferenceDescription_root(schema, components, own); description != nil {
109
+ output["description"] = *description
110
+ } else {
111
+ delete(output, "description")
112
+ }
113
+ }
@@ -0,0 +1,134 @@
1
+ package llm
2
+
3
+ import (
4
+ "testing"
5
+
6
+ nativeiterate "github.com/samchon/typia/packages/typia/native/core/programmers/iterate"
7
+ )
8
+
9
+ // TestLlmReferenceDescription locks the root description of a parameters
10
+ // object reached through `$ref` to `JsonDescriptor.cascade({ escape: true })`,
11
+ // the description `LlmSchemaConverter.parameters` writes for the same
12
+ // collection (samchon/typia#2405).
13
+ func TestLlmReferenceDescription(t *testing.T) {
14
+ t.Parallel()
15
+ const separator = "\n\n------------------------------\n\n"
16
+ text := func(value string) *string { return &value }
17
+ components := &nativeiterate.OpenApi_IComponents{
18
+ Schemas: map[string]nativeiterate.JsonSchema{
19
+ "IPlain": {"type": "object"},
20
+ "IMember": {"type": "object", "description": "Member.\nSecond line."},
21
+ "IMember.ICreate": {"type": "object", "description": "Creation."},
22
+ "IMember.IBare": {"type": "object"},
23
+ "IMember.Deep": {"type": "object"},
24
+ "IMember.Deep.ILeaf": {"type": "object"},
25
+ "IMember.IEmpty": {"type": "object", "description": ""},
26
+ "INamespaceless.IItem": {"type": "object"},
27
+ },
28
+ }
29
+ cases := []struct {
30
+ name string
31
+ schema nativeiterate.JsonSchema
32
+ own *string
33
+ expected *string
34
+ }{
35
+ {
36
+ name: "undescribed",
37
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IPlain"},
38
+ expected: text("Current Type: {@link IPlain}"),
39
+ },
40
+ {
41
+ name: "described",
42
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IMember"},
43
+ own: text("Member.\nSecond line."),
44
+ expected: text("Member.\nSecond line." + separator +
45
+ "Description of the current {@link IMember} type:\n\n> Member.\n> Second line."),
46
+ },
47
+ {
48
+ name: "described child of a described parent",
49
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IMember.ICreate"},
50
+ own: text("Creation."),
51
+ expected: text("Creation." + separator +
52
+ "Description of the current {@link IMember.ICreate} type:\n\n> Creation." + separator +
53
+ "Description of the parent {@link IMember} type:\n\n> Member.\n> Second line."),
54
+ },
55
+ {
56
+ name: "undescribed child of a described parent",
57
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IMember.IBare"},
58
+ expected: text("Current Type: {@link IMember.IBare}" + separator +
59
+ "Description of the parent {@link IMember} type:\n\n> Member.\n> Second line."),
60
+ },
61
+ {
62
+ name: "undescribed middle parent is skipped",
63
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IMember.Deep.ILeaf"},
64
+ expected: text("Current Type: {@link IMember.Deep.ILeaf}" + separator +
65
+ "Description of the parent {@link IMember} type:\n\n> Member.\n> Second line."),
66
+ },
67
+ {
68
+ name: "empty own description renders quoted",
69
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/IMember.IEmpty"},
70
+ own: text(""),
71
+ expected: text("Description of the current {@link IMember.IEmpty} type:\n\n> " + separator +
72
+ "Description of the parent {@link IMember} type:\n\n> Member.\n> Second line."),
73
+ },
74
+ {
75
+ name: "parent missing from components",
76
+ schema: nativeiterate.JsonSchema{"$ref": "#/components/schemas/INamespaceless.IItem"},
77
+ expected: text("Current Type: {@link INamespaceless.IItem}"),
78
+ },
79
+ {
80
+ name: "inline object keeps its own description",
81
+ schema: nativeiterate.JsonSchema{"type": "object"},
82
+ own: text("Inline."),
83
+ expected: text("Inline."),
84
+ },
85
+ {
86
+ name: "inline object without description",
87
+ schema: nativeiterate.JsonSchema{"type": "object"},
88
+ },
89
+ {
90
+ name: "foreign reference keeps its own description",
91
+ schema: nativeiterate.JsonSchema{"$ref": "#/$defs/IPlain"},
92
+ own: text("Own."),
93
+ expected: text("Own."),
94
+ },
95
+ }
96
+ for _, c := range cases {
97
+ actual := llmReferenceDescription_root(c.schema, components, c.own)
98
+ if (actual == nil) != (c.expected == nil) || (actual != nil && *actual != *c.expected) {
99
+ t.Errorf("%s:\nexpected %s\nactual %s", c.name, llmReferenceDescriptionTest_show(c.expected), llmReferenceDescriptionTest_show(actual))
100
+ }
101
+ }
102
+ }
103
+
104
+ // TestLlmReferenceDescriptionAssign locks that the parameters object loses a
105
+ // stale description when the cascade yields none, and gains the cascade
106
+ // otherwise.
107
+ func TestLlmReferenceDescriptionAssign(t *testing.T) {
108
+ t.Parallel()
109
+ components := &nativeiterate.OpenApi_IComponents{
110
+ Schemas: map[string]nativeiterate.JsonSchema{"IPlain": {"type": "object"}},
111
+ }
112
+ output := map[string]any{"type": "object"}
113
+ llmReferenceDescription_assign(output, nativeiterate.JsonSchema{"$ref": "#/components/schemas/IPlain"}, components)
114
+ if output["description"] != "Current Type: {@link IPlain}" {
115
+ t.Fatalf("reference root: got %#v", output["description"])
116
+ }
117
+ inline := map[string]any{"type": "object", "description": ""}
118
+ llmReferenceDescription_assign(inline, nativeiterate.JsonSchema{"type": "object"}, components)
119
+ if value, ok := inline["description"]; ok == false || value != "" {
120
+ t.Fatalf("inline root must keep its own description: got %#v", inline)
121
+ }
122
+ bare := map[string]any{"type": "object"}
123
+ llmReferenceDescription_assign(bare, nativeiterate.JsonSchema{"type": "object"}, components)
124
+ if _, ok := bare["description"]; ok {
125
+ t.Fatalf("inline root without description must stay undescribed: got %#v", bare)
126
+ }
127
+ }
128
+
129
+ func llmReferenceDescriptionTest_show(value *string) string {
130
+ if value == nil {
131
+ return "<nil>"
132
+ }
133
+ return "\"" + *value + "\""
134
+ }
@@ -91,6 +91,15 @@ func MetadataDependency_active(checker *nativechecker.Checker) bool {
91
91
  return metadataDependency_listener(checker).active()
92
92
  }
93
93
 
94
+ // MetadataDependency_touchFile reports a source file consulted outside the
95
+ // metadata iterator, so a complete transform dependency list still watches it.
96
+ func MetadataDependency_touchFile(checker *nativechecker.Checker, fileName string) {
97
+ listener := metadataDependency_listener(checker)
98
+ if listener.File != nil {
99
+ listener.File(fileName)
100
+ }
101
+ }
102
+
94
103
  // MetadataDependency_touchType reports the declaration files of a consulted
95
104
  // type: both the structural symbol (interface / class / enum / object literal)
96
105
  // and the type-name symbol (a `type` alias), which differ for aliased types.
@@ -469,6 +469,7 @@ func callExpressionTransformer_createFunctors() map[string]map[string]callExpres
469
469
  "structuredOutput": func() callExpressionTransformerTask {
470
470
  return nativellmtransformers.LlmStructuredOutputTransformer.Transform
471
471
  },
472
+ "evaluation": func() callExpressionTransformerTask { return nativellmtransformers.LlmEvaluationTransformer.Transform },
472
473
  "parameters": func() callExpressionTransformerTask { return nativellmtransformers.LlmParametersTransformer.Transform },
473
474
  "schema": func() callExpressionTransformerTask { return nativellmtransformers.LlmSchemaTransformer.Transform },
474
475
  "parse": func() callExpressionTransformerTask { return nativellmtransformers.LlmParseTransformer.Transform },
@@ -33,6 +33,10 @@ var fileTransformer_factory = shimast.NewNodeFactory(shimast.NodeFactoryHooks{})
33
33
  var fileTransformer_jsDocParsingMode sync.Map
34
34
 
35
35
  func (fileTransformerNamespace) Transform(environments FileTransformer_IEnvironments) func(transformer any) FileTransformer_Type {
36
+ shared := environments.Extras.Shared
37
+ if shared == nil {
38
+ shared = &sync.Map{}
39
+ }
36
40
  return func(transformer any) FileTransformer_Type {
37
41
  return func(file *shimast.SourceFile) *shimast.SourceFile {
38
42
  if file == nil || file.IsDeclarationFile {
@@ -53,6 +57,7 @@ func (fileTransformerNamespace) Transform(environments FileTransformer_IEnvironm
53
57
  Emit: environments.EmitContext,
54
58
  Importer: importer,
55
59
  Extras: environments.Extras,
60
+ Shared: shared,
56
61
  }
57
62
  _ = transformer
58
63
  fileTransformer_checkJsDocParsingMode(context, file)
@@ -0,0 +1,94 @@
1
+ package llm
2
+
3
+ import (
4
+ "fmt"
5
+ "strings"
6
+ "sync"
7
+
8
+ shimast "github.com/microsoft/typescript-go/shim/ast"
9
+ nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
10
+ nativellmprogrammers "github.com/samchon/typia/packages/typia/native/core/programmers/llm"
11
+ )
12
+
13
+ func llmEvaluation_cachedDeclarationProbabilityErrors(context nativecontext.ITypiaContext) []nativellmprogrammers.LlmEvaluationProgrammer_IError {
14
+ if context.Program == nil {
15
+ return nil
16
+ }
17
+ return llmEvaluation_onceDeclarationProbabilityErrors(context.Shared, func() []nativellmprogrammers.LlmEvaluationProgrammer_IError {
18
+ return llmEvaluation_declarationProbabilityErrors(context.Program.SourceFiles())
19
+ })
20
+ }
21
+
22
+ func llmEvaluation_onceDeclarationProbabilityErrors(shared *sync.Map, analyze func() []nativellmprogrammers.LlmEvaluationProgrammer_IError) []nativellmprogrammers.LlmEvaluationProgrammer_IError {
23
+ if shared == nil {
24
+ return analyze()
25
+ }
26
+ cached, _ := shared.LoadOrStore("llm.evaluation.probability.declarations", sync.OnceValue(analyze))
27
+ return cached.(func() []nativellmprogrammers.LlmEvaluationProgrammer_IError)()
28
+ }
29
+
30
+ // Primitive aliases lose their declaration identity when TypeScript resolves
31
+ // them (boolean aliases become the same boolean type). Consequently, no walk
32
+ // of the resolved evaluation type can reliably distinguish a used annotation
33
+ // from an unused one. Validate tag placement syntactically across a program
34
+ // that uses llm.evaluation: only properties and enum members can carry it.
35
+ func llmEvaluation_declarationProbabilityErrors(files []*shimast.SourceFile) []nativellmprogrammers.LlmEvaluationProgrammer_IError {
36
+ errors := []nativellmprogrammers.LlmEvaluationProgrammer_IError{}
37
+ for _, file := range files {
38
+ if file == nil || !strings.Contains(file.Text(), "@probability") {
39
+ continue
40
+ }
41
+ var walk func(*shimast.Node)
42
+ walk = func(node *shimast.Node) {
43
+ if node == nil {
44
+ return
45
+ }
46
+ allowed := node.Kind == shimast.KindPropertySignature ||
47
+ node.Kind == shimast.KindPropertyDeclaration ||
48
+ node.Kind == shimast.KindGetAccessor ||
49
+ node.Kind == shimast.KindSetAccessor ||
50
+ node.Kind == shimast.KindEnumMember
51
+ if !allowed {
52
+ for _, doc := range node.JSDoc(nil) {
53
+ parsed := doc.AsJSDoc()
54
+ if parsed == nil || parsed.Tags == nil {
55
+ continue
56
+ }
57
+ for _, tag := range parsed.Tags.Nodes {
58
+ if tag != nil && tag.TagName() != nil && tag.TagName().Text() == "probability" {
59
+ name := "<anonymous>"
60
+ if identifier := node.Name(); identifier != nil {
61
+ switch identifier.Kind {
62
+ case shimast.KindIdentifier, shimast.KindStringLiteral, shimast.KindNumericLiteral, shimast.KindNoSubstitutionTemplateLiteral:
63
+ name = identifier.Text()
64
+ }
65
+ }
66
+ kind := "declaration"
67
+ switch node.Kind {
68
+ case shimast.KindTypeAliasDeclaration:
69
+ kind = "type alias"
70
+ case shimast.KindInterfaceDeclaration:
71
+ kind = "interface"
72
+ case shimast.KindClassDeclaration, shimast.KindClassExpression:
73
+ kind = "class"
74
+ case shimast.KindEnumDeclaration:
75
+ kind = "enum"
76
+ }
77
+ errors = append(errors, nativellmprogrammers.LlmEvaluationProgrammer_IError{
78
+ Accessor: "$input",
79
+ Message: fmt.Sprintf("LLM evaluation @probability on %s %s in %s is unsupported; put it on a decision property or enum member.", kind, name, file.FileName()),
80
+ })
81
+ break
82
+ }
83
+ }
84
+ }
85
+ }
86
+ node.ForEachChild(func(child *shimast.Node) bool {
87
+ walk(child)
88
+ return false
89
+ })
90
+ }
91
+ walk(file.AsNode())
92
+ }
93
+ return errors
94
+ }
@@ -0,0 +1,50 @@
1
+ package llm
2
+
3
+ import (
4
+ "sync"
5
+ "sync/atomic"
6
+ "testing"
7
+
8
+ nativellmprogrammers "github.com/samchon/typia/packages/typia/native/core/programmers/llm"
9
+ )
10
+
11
+ // TestLlmEvaluationDeclarationProbabilityCache verifies one placement scan
12
+ // runs for every transform invocation sharing a program cache.
13
+ //
14
+ // File callbacks can run concurrently and must receive the same diagnostic
15
+ // result without redoing the program-wide scan. A new program gets a new map.
16
+ //
17
+ // 1. Read the result concurrently through one shared map.
18
+ // 2. Require one calculation and identical diagnostics for every reader.
19
+ // 3. Require a fresh map and an uncached call to calculate independently.
20
+ func TestLlmEvaluationDeclarationProbabilityCache(t *testing.T) {
21
+ var calls atomic.Int32
22
+ analyze := func() []nativellmprogrammers.LlmEvaluationProgrammer_IError {
23
+ calls.Add(1)
24
+ return []nativellmprogrammers.LlmEvaluationProgrammer_IError{{
25
+ Accessor: "$input",
26
+ Message: "unsupported declaration",
27
+ }}
28
+ }
29
+ shared := &sync.Map{}
30
+ var group sync.WaitGroup
31
+ for range 16 {
32
+ group.Add(1)
33
+ go func() {
34
+ defer group.Done()
35
+ errors := llmEvaluation_onceDeclarationProbabilityErrors(shared, analyze)
36
+ if len(errors) != 1 || errors[0].Message != "unsupported declaration" {
37
+ t.Errorf("cached diagnostic changed: %+v", errors)
38
+ }
39
+ }()
40
+ }
41
+ group.Wait()
42
+ if count := calls.Load(); count != 1 {
43
+ t.Fatalf("one program must scan once, got %d scans", count)
44
+ }
45
+ llmEvaluation_onceDeclarationProbabilityErrors(&sync.Map{}, analyze)
46
+ llmEvaluation_onceDeclarationProbabilityErrors(nil, analyze)
47
+ if count := calls.Load(); count != 3 {
48
+ t.Fatalf("fresh and uncached programs must recalculate, got %d scans", count)
49
+ }
50
+ }
@@ -0,0 +1,59 @@
1
+ package llm
2
+
3
+ import (
4
+ shimast "github.com/microsoft/typescript-go/shim/ast"
5
+ nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
6
+ nativellmprogrammers "github.com/samchon/typia/packages/typia/native/core/programmers/llm"
7
+ schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
8
+ nativetransform "github.com/samchon/typia/packages/typia/native/transform/internal"
9
+ )
10
+
11
+ type llmEvaluationTransformerNamespace struct{}
12
+
13
+ var LlmEvaluationTransformer = llmEvaluationTransformerNamespace{}
14
+
15
+ func (llmEvaluationTransformerNamespace) Transform(props nativetransform.ITransformProps) *shimast.Node {
16
+ top, typ, ok := llmTransformer_type_argument(props, "typia.llm.evaluation")
17
+ if ok == false {
18
+ return props.Expression.AsNode()
19
+ }
20
+ if typ != nil && typ.IsTypeParameter() {
21
+ panic(nativetransform.NewTransformerError(nativetransform.TransformerError_IProps{Code: "typia.llm.evaluation", Message: "non-specified generic argument."}))
22
+ }
23
+ metadata := llmTransformer_analyze(llmTransformer_analyzeProps{
24
+ Context: props.Context,
25
+ Type: typ,
26
+ Code: "typia.llm.evaluation",
27
+ Absorb: true,
28
+ StrictObjectMembers: true,
29
+ Validate: func(struct {
30
+ Metadata *schemametadata.MetadataSchema
31
+ Explore nativefactories.MetadataFactory_IExplore
32
+ Top *schemametadata.MetadataSchema
33
+ }) []string {
34
+ return nil
35
+ },
36
+ })
37
+ plan, errors := nativellmprogrammers.LlmEvaluationProgrammer.Compose(metadata)
38
+ errors = append(errors, llmEvaluation_cachedDeclarationProbabilityErrors(props.Context)...)
39
+ // The placement scan depends on every program source, including files with
40
+ // no tag today: adding one later must invalidate a cached successful emit.
41
+ if props.Context.Program != nil && schemametadata.MetadataDependency_active(props.Context.Checker) {
42
+ for _, file := range props.Context.Program.SourceFiles() {
43
+ if file != nil {
44
+ schemametadata.MetadataDependency_touchFile(props.Context.Checker, file.FileName())
45
+ }
46
+ }
47
+ }
48
+ if len(errors) != 0 {
49
+ panic(nativetransform.NewTransformerError(nativetransform.TransformerError_IProps{
50
+ Code: "typia.llm.evaluation",
51
+ Message: nativellmprogrammers.LlmEvaluationProgrammer.Message(errors),
52
+ }))
53
+ }
54
+ return nativellmprogrammers.LlmEvaluationProgrammer.Write(nativellmprogrammers.LlmEvaluationProgrammer_IWriteProps{
55
+ Context: props.Context,
56
+ Metadata: metadata,
57
+ Name: llmTransformer_type_name(top),
58
+ }, plan)
59
+ }
@@ -68,12 +68,13 @@ func (llmSchemaTransformerNamespace) Transform(props nativetransform.ITransformP
68
68
  }
69
69
 
70
70
  type llmTransformer_analyzeProps struct {
71
- Context nativecontext.ITypiaContext
72
- Type *shimchecker.Type
73
- Code string
74
- Absorb bool
75
- Functional bool
76
- Validate func(props struct {
71
+ Context nativecontext.ITypiaContext
72
+ Type *shimchecker.Type
73
+ Code string
74
+ Absorb bool
75
+ Functional bool
76
+ StrictObjectMembers bool
77
+ Validate func(props struct {
77
78
  Metadata *schemametadata.MetadataSchema
78
79
  Explore nativefactories.MetadataFactory_IExplore
79
80
  Top *schemametadata.MetadataSchema
@@ -105,11 +106,13 @@ func llmTransformer_analyze(props llmTransformer_analyzeProps) *schemametadata.M
105
106
  result := nativefactories.MetadataFactory.Analyze(nativefactories.MetadataFactory_IProps{
106
107
  Checker: props.Context.Checker,
107
108
  Options: nativefactories.MetadataFactory_IOptions{
108
- Absorb: props.Absorb,
109
- Escape: true,
110
- Constant: true,
111
- Functional: props.Functional,
112
- Validate: props.Validate,
109
+ Absorb: props.Absorb,
110
+ Escape: true,
111
+ Constant: true,
112
+ Functional: props.Functional,
113
+ Methods: props.StrictObjectMembers,
114
+ StrictObjectMembers: props.StrictObjectMembers,
115
+ Validate: props.Validate,
113
116
  },
114
117
  Components: schemametadata.NewMetadataCollection(&schemametadata.MetadataCollection_IOptions{
115
118
  Replace: schemametadata.MetadataCollection_replace,
@@ -4,9 +4,9 @@
4
4
  package llm
5
5
 
6
6
  import (
7
- "testing"
7
+ "testing"
8
8
 
9
- nativetransform "github.com/samchon/typia/packages/typia/native/transform/internal"
9
+ nativetransform "github.com/samchon/typia/packages/typia/native/transform/internal"
10
10
  )
11
11
 
12
12
  // TestLLMTransformerEntryCoverage exercises LLM transform entrypoints.
@@ -16,33 +16,35 @@ import (
16
16
  // guards. Empty transform props visit those entrypoints and recover their guard
17
17
  // failures deterministically.
18
18
  //
19
- // 1. Visit schema, parameters, application, and structured-output wrappers.
20
- // 2. Visit controller and parse/coerce scalar wrappers.
21
- // 3. Visit create-parse and create-coerce factory wrappers.
22
- // 4. Recover expected guard panics for every wrapper call.
19
+ // 1. Visit schema, parameters, application, structured-output, and evaluation
20
+ // wrappers.
21
+ // 2. Visit controller and parse/coerce scalar wrappers.
22
+ // 3. Visit create-parse and create-coerce factory wrappers.
23
+ // 4. Recover expected guard panics for every wrapper call.
23
24
  func TestLLMTransformerEntryCoverage(t *testing.T) {
24
- props := nativetransform.ITransformProps{}
25
- for _, run := range []func(){
26
- func() { LlmSchemaTransformer.Transform(props) },
27
- func() { LlmParametersTransformer.Transform(props) },
28
- func() { LlmApplicationTransformer.Transform(props) },
29
- func() { LlmStructuredOutputTransformer.Transform(props) },
30
- func() { LlmControllerTransformer.Transform(props) },
31
- func() { LlmParseTransformer.Transform(props) },
32
- func() { LlmCoerceTransformer.Transform(props) },
33
- func() { LlmCreateParseTransformer.Transform(props) },
34
- func() { LlmCreateCoerceTransformer.Transform(props) },
35
- } {
36
- expectLLMPanic(t, run)
37
- }
25
+ props := nativetransform.ITransformProps{}
26
+ for _, run := range []func(){
27
+ func() { LlmSchemaTransformer.Transform(props) },
28
+ func() { LlmParametersTransformer.Transform(props) },
29
+ func() { LlmApplicationTransformer.Transform(props) },
30
+ func() { LlmStructuredOutputTransformer.Transform(props) },
31
+ func() { LlmEvaluationTransformer.Transform(props) },
32
+ func() { LlmControllerTransformer.Transform(props) },
33
+ func() { LlmParseTransformer.Transform(props) },
34
+ func() { LlmCoerceTransformer.Transform(props) },
35
+ func() { LlmCreateParseTransformer.Transform(props) },
36
+ func() { LlmCreateCoerceTransformer.Transform(props) },
37
+ } {
38
+ expectLLMPanic(t, run)
39
+ }
38
40
  }
39
41
 
40
42
  func expectLLMPanic(t *testing.T, run func()) {
41
- t.Helper()
42
- defer func() {
43
- if recover() == nil {
44
- t.Fatal("expected LLM transformer panic")
45
- }
46
- }()
47
- run()
43
+ t.Helper()
44
+ defer func() {
45
+ if recover() == nil {
46
+ t.Fatal("expected LLM transformer panic")
47
+ }
48
+ }()
49
+ run()
48
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typia",
3
- "version": "14.0.6",
3
+ "version": "15.0.0",
4
4
  "description": "Superfast runtime validators with only one line",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -43,8 +43,8 @@
43
43
  "homepage": "https://typia.io",
44
44
  "dependencies": {
45
45
  "randexp": "^0.5.3",
46
- "@typia/interface": "^14.0.6",
47
- "@typia/utils": "^14.0.6"
46
+ "@typia/utils": "^15.0.0",
47
+ "@typia/interface": "^15.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "ttsc": ">=0.19.2"