typia 13.3.0 → 14.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 (84) hide show
  1. package/lib/internal/_createStandardSchema.d.ts +1 -2
  2. package/lib/internal/_createStandardSchema.js.map +1 -1
  3. package/lib/internal/_createStandardSchema.mjs.map +1 -1
  4. package/lib/internal/_randomPattern.js +20 -3
  5. package/lib/internal/_randomPattern.js.map +1 -1
  6. package/lib/internal/_randomPattern.mjs +5 -1
  7. package/lib/internal/_randomPattern.mjs.map +1 -1
  8. package/lib/internal/_randomStringLength.js +9 -2
  9. package/lib/internal/_randomStringLength.js.map +1 -1
  10. package/lib/internal/_randomStringLength.mjs +3 -1
  11. package/lib/internal/_randomStringLength.mjs.map +1 -1
  12. package/lib/module.d.ts +1 -2
  13. package/lib/module.js.map +1 -1
  14. package/lib/module.mjs.map +1 -1
  15. package/lib/re-exports.d.ts +1 -1
  16. package/lib/re-exports.js.map +1 -1
  17. package/lib/transform.mjs +1 -1
  18. package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +5 -2
  19. package/native/cmd/ttsc-typia/dependency_collector_virtual_scheme_test.go +52 -0
  20. package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +206 -0
  21. package/native/cmd/ttsc-typia/notation_kebab_case_transform_test.go +2 -2
  22. package/native/cmd/ttsc-typia/project_catalog_transform_coverage_test.go +84 -85
  23. package/native/cmd/ttsc-typia/project_dependencies_callee_argument_transform_test.go +177 -0
  24. package/native/cmd/ttsc-typia/project_dependencies_callee_barrel_transform_test.go +115 -0
  25. package/native/cmd/ttsc-typia/project_dependencies_callee_inference_transform_test.go +285 -0
  26. package/native/cmd/ttsc-typia/project_dependencies_callee_shape_transform_test.go +117 -0
  27. package/native/cmd/ttsc-typia/project_dependencies_callee_untransformed_barrel_transform_test.go +121 -0
  28. package/native/cmd/ttsc-typia/project_dependencies_complete_diagnostic_transform_test.go +116 -0
  29. package/native/cmd/ttsc-typia/project_dependencies_complete_envelope_transform_test.go +115 -0
  30. package/native/cmd/ttsc-typia/project_dependencies_complete_inferred_type_transform_test.go +127 -0
  31. package/native/cmd/ttsc-typia/project_dependencies_complete_replaced_library_transform_test.go +153 -0
  32. package/native/cmd/ttsc-typia/project_dependencies_complete_untouched_reprint_transform_test.go +155 -0
  33. package/native/cmd/ttsc-typia/project_dependencies_computed_key_transform_test.go +218 -0
  34. package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +6 -5
  35. package/native/cmd/ttsc-typia/project_dependencies_enum_member_value_transform_test.go +131 -0
  36. package/native/cmd/ttsc-typia/project_dependencies_inferred_declaration_transform_test.go +159 -0
  37. package/native/cmd/ttsc-typia/project_dependencies_jsdoc_typedef_transform_test.go +134 -0
  38. package/native/cmd/ttsc-typia/project_dependencies_named_tuple_member_transform_test.go +123 -0
  39. package/native/cmd/ttsc-typia/project_dependencies_qualified_barrel_transform_test.go +141 -0
  40. package/native/cmd/ttsc-typia/project_dependencies_type_parameter_default_transform_test.go +127 -0
  41. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -1
  42. package/native/cmd/ttsc-typia/transform.go +195 -21
  43. package/native/cmd/ttsc-typia/transform_helpers_test.go +12 -0
  44. package/native/core/factories/MetadataCommentTagFactory.go +96 -27
  45. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +2 -2
  46. package/native/core/factories/metadata_comment_tag_factory_rejects_out_of_range_integer_test.go +124 -0
  47. package/native/core/programmers/AssertProgrammer.go +20 -6
  48. package/native/core/programmers/RandomProgrammer.go +78 -6
  49. package/native/core/programmers/ValidateProgrammer.go +21 -6
  50. package/native/core/programmers/helpers/RandomJoiner.go +8 -1
  51. package/native/core/programmers/iterate/check_dynamic_properties.go +177 -3
  52. package/native/core/programmers/iterate/check_object.go +12 -1
  53. package/native/core/schemas/metadata/MetadataDependency.go +613 -30
  54. package/native/transform/CallExpressionTransformer.go +16 -1
  55. package/package.json +4 -14
  56. package/src/internal/_createStandardSchema.ts +1 -2
  57. package/src/internal/_randomPattern.ts +18 -3
  58. package/src/internal/_randomStringLength.ts +9 -2
  59. package/src/module.ts +6 -2
  60. package/src/re-exports.ts +13 -0
  61. package/lib/executable/FileSystemIdentity.d.ts +0 -44
  62. package/lib/executable/FileSystemIdentity.js +0 -213
  63. package/lib/executable/FileSystemIdentity.js.map +0 -1
  64. package/lib/executable/FileSystemIdentity.mjs +0 -133
  65. package/lib/executable/FileSystemIdentity.mjs.map +0 -1
  66. package/lib/executable/TypiaGenerateWizard.d.ts +0 -9
  67. package/lib/executable/TypiaGenerateWizard.js +0 -852
  68. package/lib/executable/TypiaGenerateWizard.js.map +0 -1
  69. package/lib/executable/TypiaGenerateWizard.mjs +0 -618
  70. package/lib/executable/TypiaGenerateWizard.mjs.map +0 -1
  71. package/lib/executable/generate/ttsc.d.ts +0 -1
  72. package/lib/executable/generate/ttsc.js +0 -53
  73. package/lib/executable/generate/ttsc.js.map +0 -1
  74. package/lib/executable/generate/ttsc.mjs +0 -37
  75. package/lib/executable/generate/ttsc.mjs.map +0 -1
  76. package/lib/executable/typia.d.ts +0 -2
  77. package/lib/executable/typia.js +0 -84
  78. package/lib/executable/typia.js.map +0 -1
  79. package/lib/executable/typia.mjs +0 -60
  80. package/lib/executable/typia.mjs.map +0 -1
  81. package/src/executable/FileSystemIdentity.ts +0 -222
  82. package/src/executable/TypiaGenerateWizard.ts +0 -1133
  83. package/src/executable/generate/ttsc.ts +0 -70
  84. package/src/executable/typia.ts +0 -80
@@ -0,0 +1,218 @@
1
+ package main
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ // TestProjectDependenciesComputedKeyTransform verifies a computed member key
11
+ // reports the file that decides the name, and withholds the declaration when
12
+ // that name is borrowed from a file the written surface cannot enumerate.
13
+ //
14
+ // `interface Doc { [Kind.A]: number }` emits `input.alpha`, so the enum
15
+ // member's value is read into the validator exactly the way an `enum` member's
16
+ // own value is — and the checker interns the resolved key as a bare string
17
+ // literal with no symbol to follow, so neither the declaration's written type
18
+ // nor the type graph names `kind.ts`. Renaming `Kind.A` changed the generated
19
+ // validator with no reported edge, which is invisible while a file keeps the
20
+ // reference closure and serves a stale validator once it is declared complete
21
+ // (samchon/typia#2126, samchon/typia#2357).
22
+ //
23
+ // 1. Build a project where `a.ts` validates `Doc`, whose only key is
24
+ // `[Kind.A]` reached through a barrel, and where `b.ts` validates `Spare`,
25
+ // whose key is a constant that borrows its value from a third file.
26
+ // 2. Run project transform mode and decode the JSON envelope.
27
+ // 3. Assert `dependencies["src/a.ts"]` contains `src/kind.ts` and the
28
+ // `src/barrel.ts` the reference traveled, and that `a.ts` is declared
29
+ // complete so the narrowed bound is the one that carries them.
30
+ // 4. Assert it omits `src/unused.ts`, a sibling export the reference never
31
+ // traverses.
32
+ // 5. Assert `b.ts` is withheld: `const BORROWED = VALUE` takes its value from
33
+ // a file no written key names, which is the same answer an enum member
34
+ // borrowing a value gets.
35
+ // 6. Assert `c.ts` stays declared: `["gamma"]` is written where it is used, so
36
+ // treating every computed key as unbounded would cost narrowing for a name
37
+ // no other file can decide.
38
+ // 7. Assert `d.ts` stays declared AND reports `src/keyconst.ts`: a bare name
39
+ // whose constant fixes its own value is the bounded twin of `b.ts`, and it
40
+ // is the only case that pins both halves of the bare-name branch.
41
+ func TestProjectDependenciesComputedKeyTransform(t *testing.T) {
42
+ project := projectDependenciesComputedKeyProject(t)
43
+ out, errText, code := ttscTypiaTestCapture(func() int {
44
+ return runTransform([]string{
45
+ "--cwd", project,
46
+ "--tsconfig", "tsconfig.json",
47
+ "--output", "ts",
48
+ })
49
+ })
50
+ if code != 0 {
51
+ t.Fatalf("project transform failed: code=%d stderr=\n%s", code, errText)
52
+ }
53
+ var envelope struct {
54
+ Dependencies map[string][]string `json:"dependencies"`
55
+ DependenciesComplete []string `json:"dependenciesComplete"`
56
+ }
57
+ if err := json.Unmarshal([]byte(out), &envelope); err != nil {
58
+ t.Fatalf("decode envelope: %v\n%s", err, out)
59
+ }
60
+ entries := envelope.Dependencies["src/a.ts"]
61
+ found := map[string]bool{}
62
+ for _, entry := range entries {
63
+ found[entry] = true
64
+ }
65
+ if !found["src/kind.ts"] {
66
+ t.Fatalf("dependencies of src/a.ts must contain src/kind.ts, whose enum member decides the emitted key: %v", entries)
67
+ }
68
+ if !found["src/barrel.ts"] {
69
+ t.Fatalf("dependencies of src/a.ts must contain src/barrel.ts, which selects the enum the key reads: %v", entries)
70
+ }
71
+ if found["src/unused.ts"] {
72
+ t.Fatalf("dependencies of src/a.ts must not contain src/unused.ts, a sibling the reference never traverses: %v", entries)
73
+ }
74
+ declared := map[string]bool{}
75
+ for _, key := range envelope.DependenciesComplete {
76
+ declared[key] = true
77
+ }
78
+ if !declared["src/a.ts"] {
79
+ t.Fatalf("src/a.ts must be declared complete, so the reported entry is the whole bound: %v", envelope.DependenciesComplete)
80
+ }
81
+ if declared["src/b.ts"] {
82
+ t.Fatalf("a key whose constant borrows its value from another file is not bounded by any written name, so src/b.ts must be withheld: %v", envelope.DependenciesComplete)
83
+ }
84
+ if !declared["src/c.ts"] {
85
+ t.Fatalf("a computed key written as a literal names no other file and must stay declared: %v", envelope.DependenciesComplete)
86
+ }
87
+ if !declared["src/d.ts"] {
88
+ t.Fatalf("a key whose constant fixes its own value is bounded and must stay declared: %v", envelope.DependenciesComplete)
89
+ }
90
+ bare := map[string]bool{}
91
+ for _, entry := range envelope.Dependencies["src/d.ts"] {
92
+ bare[entry] = true
93
+ }
94
+ if !bare["src/keyconst.ts"] {
95
+ t.Fatalf("dependencies of src/d.ts must contain src/keyconst.ts, whose constant decides the emitted key: %v", envelope.Dependencies["src/d.ts"])
96
+ }
97
+ }
98
+
99
+ func projectDependenciesComputedKeyProject(t *testing.T) string {
100
+ t.Helper()
101
+ root := ttscTypiaTestRepoRoot(t)
102
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
103
+ if err := os.MkdirAll(base, 0o755); err != nil {
104
+ t.Fatalf("mkdir temp base: %v", err)
105
+ }
106
+ dir, err := os.MkdirTemp(base, "project-dependencies-computed-key-")
107
+ if err != nil {
108
+ t.Fatalf("create temp fixture: %v", err)
109
+ }
110
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
111
+ src := filepath.Join(dir, "src")
112
+ if err := os.MkdirAll(src, 0o755); err != nil {
113
+ t.Fatalf("mkdir fixture src: %v", err)
114
+ }
115
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(projectDependenciesEnvelopeTSConfig), 0o644); err != nil {
116
+ t.Fatalf("write tsconfig: %v", err)
117
+ }
118
+ for name, body := range map[string]string{
119
+ "a.ts": projectDependenciesComputedKeySourceA,
120
+ "b.ts": projectDependenciesComputedKeySourceB,
121
+ "c.ts": projectDependenciesComputedKeySourceC,
122
+ "d.ts": projectDependenciesComputedKeySourceD,
123
+ "doc.ts": projectDependenciesComputedKeySourceDoc,
124
+ "spare.ts": projectDependenciesComputedKeySourceSpare,
125
+ "plain.ts": projectDependenciesComputedKeySourcePlain,
126
+ "bare.ts": projectDependenciesComputedKeySourceBare,
127
+ "keyconst.ts": projectDependenciesComputedKeySourceKeyConst,
128
+ "barrel.ts": projectDependenciesComputedKeySourceBarrel,
129
+ "kind.ts": projectDependenciesComputedKeySourceKind,
130
+ "unused.ts": projectDependenciesComputedKeySourceUnused,
131
+ "borrow.ts": projectDependenciesComputedKeySourceBorrow,
132
+ "value.ts": projectDependenciesComputedKeySourceValue,
133
+ } {
134
+ if err := os.WriteFile(filepath.Join(src, name), []byte(body), 0o644); err != nil {
135
+ t.Fatalf("write %s: %v", name, err)
136
+ }
137
+ }
138
+ return dir
139
+ }
140
+
141
+ const projectDependenciesComputedKeySourceA = `import typia from "typia";
142
+
143
+ import { Doc } from "./doc";
144
+
145
+ export const check = (input: unknown) => typia.is<Doc>(input);
146
+ `
147
+
148
+ const projectDependenciesComputedKeySourceB = `import typia from "typia";
149
+
150
+ import { Spare } from "./spare";
151
+
152
+ export const check = (input: unknown) => typia.is<Spare>(input);
153
+ `
154
+
155
+ const projectDependenciesComputedKeySourceC = `import typia from "typia";
156
+
157
+ import { Plain } from "./plain";
158
+
159
+ export const check = (input: unknown) => typia.is<Plain>(input);
160
+ `
161
+
162
+ const projectDependenciesComputedKeySourcePlain = `export interface Plain {
163
+ ["gamma"]: number;
164
+ }
165
+ `
166
+
167
+ const projectDependenciesComputedKeySourceD = `import typia from "typia";
168
+
169
+ import { Bare } from "./bare";
170
+
171
+ export const check = (input: unknown) => typia.is<Bare>(input);
172
+ `
173
+
174
+ const projectDependenciesComputedKeySourceBare = `import { KEY } from "./keyconst";
175
+
176
+ export interface Bare {
177
+ [KEY]: number;
178
+ }
179
+ `
180
+
181
+ const projectDependenciesComputedKeySourceKeyConst = `export const KEY = "epsilon";
182
+ `
183
+
184
+ const projectDependenciesComputedKeySourceDoc = `import { Kind } from "./barrel";
185
+
186
+ export interface Doc {
187
+ [Kind.A]: number;
188
+ }
189
+ `
190
+
191
+ const projectDependenciesComputedKeySourceSpare = `import { BORROWED } from "./borrow";
192
+
193
+ export interface Spare {
194
+ [BORROWED]: number;
195
+ }
196
+ `
197
+
198
+ const projectDependenciesComputedKeySourceBarrel = `export { Kind } from "./kind";
199
+ export { Unused } from "./unused";
200
+ `
201
+
202
+ const projectDependenciesComputedKeySourceKind = `export enum Kind {
203
+ A = "alpha",
204
+ }
205
+ `
206
+
207
+ const projectDependenciesComputedKeySourceUnused = `export enum Unused {
208
+ B = "beta",
209
+ }
210
+ `
211
+
212
+ const projectDependenciesComputedKeySourceBorrow = `import { VALUE } from "./value";
213
+
214
+ export const BORROWED = VALUE;
215
+ `
216
+
217
+ const projectDependenciesComputedKeySourceValue = `export const VALUE = "delta";
218
+ `
@@ -25,8 +25,12 @@ import (
25
25
  // analysis touches real default libraries.
26
26
  // 2. Run project transform mode and decode the JSON envelope.
27
27
  // 3. Assert `dependencies["src/a.ts"]` contains `src/lib.custom.d.ts`.
28
- // 4. Assert no compiler-owned default library (virtual `bundled:///` URI or
29
- // any value outside the project) leaks into the entry.
28
+ // 4. Assert no compiler-owned default library leaks into the entry. Under this
29
+ // fixture they are the program's virtual `bundled:///` sources, so the URI
30
+ // shape is what proves the classification still excludes them. Being outside
31
+ // the project is not evidence of one: the envelope reports a `node_modules`
32
+ // declaration file like any other, and the files that decide a callee's
33
+ // typia identity are exactly such files.
30
34
  func TestProjectDependenciesCustomLibNameTransform(t *testing.T) {
31
35
  project := projectDependenciesCustomLibNameProject(t)
32
36
  out, errText, code := ttscTypiaTestCapture(func() int {
@@ -56,9 +60,6 @@ func TestProjectDependenciesCustomLibNameTransform(t *testing.T) {
56
60
  if strings.Contains(entry, "://") {
57
61
  t.Fatalf("dependencies must exclude virtual URI sources, got %q in %v", entry, entries)
58
62
  }
59
- if filepath.IsAbs(filepath.FromSlash(entry)) || strings.HasPrefix(entry, "../") {
60
- t.Fatalf("dependencies must not report files outside the project, got %q in %v", entry, entries)
61
- }
62
63
  }
63
64
  if !found["src/lib.custom.d.ts"] {
64
65
  t.Fatalf("dependencies of src/a.ts must contain the project-owned src/lib.custom.d.ts: %v", entries)
@@ -0,0 +1,131 @@
1
+ package main
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+ )
10
+
11
+ // TestProjectDependenciesEnumMemberValueTransform verifies an enum whose member
12
+ // borrows its value from another file withholds the completeness declaration,
13
+ // while an enum that writes its own values keeps it.
14
+ //
15
+ // An enum member's value is read straight into the generated validator, so
16
+ // `Kind.A === input` becomes `"x" === input` and changes the moment the value
17
+ // changes. When the member writes a literal — including the negative form, which
18
+ // TypeScript reads as one constant — that value is written here and no other
19
+ // file can decide it. When it borrows one (`A = Other.X`), the value lives
20
+ // somewhere the type graph never names: the checker hands the analysis the
21
+ // resolved literal, not the reference that produced it (samchon/typia#2357).
22
+ //
23
+ // 1. Build a project with `plain.ts`, whose enum writes a string and a negative
24
+ // number, and `kind.ts`, whose enum takes a member value from `other.ts`.
25
+ // 2. Run project transform mode and decode the JSON envelope.
26
+ // 3. Assert both callers transformed into a literal comparison, so both enums
27
+ // really did reach the validator.
28
+ // 4. Assert the caller of the self-contained enum is declared complete and the
29
+ // caller of the borrowing enum is not.
30
+ func TestProjectDependenciesEnumMemberValueTransform(t *testing.T) {
31
+ project := projectDependenciesEnumMemberValueProject(t)
32
+ out, errText, code := ttscTypiaTestCapture(func() int {
33
+ return runTransform([]string{
34
+ "--cwd", project,
35
+ "--tsconfig", "tsconfig.json",
36
+ "--output", "ts",
37
+ })
38
+ })
39
+ if code != 0 {
40
+ t.Fatalf("project transform failed: code=%d stderr=\n%s", code, errText)
41
+ }
42
+ var envelope struct {
43
+ TypeScript map[string]string `json:"typescript"`
44
+ Dependencies map[string][]string `json:"dependencies"`
45
+ DependenciesComplete []string `json:"dependenciesComplete"`
46
+ }
47
+ if err := json.Unmarshal([]byte(out), &envelope); err != nil {
48
+ t.Fatalf("decode envelope: %v\n%s", err, out)
49
+ }
50
+ if text := envelope.TypeScript["src/own.ts"]; !strings.Contains(text, `"a" === input`) || !strings.Contains(text, "-1 === input") {
51
+ t.Fatalf("src/own.ts must compare against both written member values, got:\n%s", text)
52
+ }
53
+ if text := envelope.TypeScript["src/borrowed.ts"]; !strings.Contains(text, `"x" === input`) {
54
+ t.Fatalf("src/borrowed.ts must compare against the borrowed member value, got:\n%s", text)
55
+ }
56
+ declared := map[string]bool{}
57
+ for _, key := range envelope.DependenciesComplete {
58
+ declared[key] = true
59
+ }
60
+ if !declared["src/own.ts"] {
61
+ t.Fatalf("an enum that writes its own member values bounds them and must be declared complete: %v", envelope.DependenciesComplete)
62
+ }
63
+ if declared["src/borrowed.ts"] {
64
+ t.Fatalf("an enum member that borrows its value must withhold the declaration: %v", envelope.DependenciesComplete)
65
+ }
66
+ }
67
+
68
+ func projectDependenciesEnumMemberValueProject(t *testing.T) string {
69
+ t.Helper()
70
+ root := ttscTypiaTestRepoRoot(t)
71
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
72
+ if err := os.MkdirAll(base, 0o755); err != nil {
73
+ t.Fatalf("mkdir temp base: %v", err)
74
+ }
75
+ dir, err := os.MkdirTemp(base, "project-dependencies-enum-member-value-")
76
+ if err != nil {
77
+ t.Fatalf("create temp fixture: %v", err)
78
+ }
79
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
80
+ src := filepath.Join(dir, "src")
81
+ if err := os.MkdirAll(src, 0o755); err != nil {
82
+ t.Fatalf("mkdir fixture src: %v", err)
83
+ }
84
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(projectDependenciesEnvelopeTSConfig), 0o644); err != nil {
85
+ t.Fatalf("write tsconfig: %v", err)
86
+ }
87
+ for name, body := range map[string]string{
88
+ "own.ts": projectDependenciesEnumMemberValueSourceOwn,
89
+ "borrowed.ts": projectDependenciesEnumMemberValueSourceBorrowed,
90
+ "plain.ts": projectDependenciesEnumMemberValueSourcePlain,
91
+ "kind.ts": projectDependenciesEnumMemberValueSourceKind,
92
+ "other.ts": projectDependenciesEnumMemberValueSourceOther,
93
+ } {
94
+ if err := os.WriteFile(filepath.Join(src, name), []byte(body), 0o644); err != nil {
95
+ t.Fatalf("write %s: %v", name, err)
96
+ }
97
+ }
98
+ return dir
99
+ }
100
+
101
+ const projectDependenciesEnumMemberValueSourceOwn = `import typia from "typia";
102
+
103
+ import { Plain } from "./plain";
104
+
105
+ export const check = (input: unknown) => typia.is<Plain>(input);
106
+ `
107
+
108
+ const projectDependenciesEnumMemberValueSourceBorrowed = `import typia from "typia";
109
+
110
+ import { Kind } from "./kind";
111
+
112
+ export const check = (input: unknown) => typia.is<Kind>(input);
113
+ `
114
+
115
+ const projectDependenciesEnumMemberValueSourcePlain = `export enum Plain {
116
+ Text = "a",
117
+ Negative = -1,
118
+ }
119
+ `
120
+
121
+ const projectDependenciesEnumMemberValueSourceKind = `import { Other } from "./other";
122
+
123
+ export enum Kind {
124
+ Borrowed = Other.Value,
125
+ }
126
+ `
127
+
128
+ const projectDependenciesEnumMemberValueSourceOther = `export enum Other {
129
+ Value = "x",
130
+ }
131
+ `
@@ -0,0 +1,159 @@
1
+ package main
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+ )
10
+
11
+ // TestProjectDependenciesInferredDeclarationTransform verifies a validated type
12
+ // that reaches a declaration with no written annotation withholds the
13
+ // completeness declaration, while its annotated twin keeps it.
14
+ //
15
+ // The written surface exists because the checker erases an alias of an
16
+ // intrinsic: `type Id = string` interns as the bare intrinsic and leaves no
17
+ // symbol for the type graph to follow, so only the syntax naming the alias can
18
+ // register its file (samchon/typia#2126). A `const` with an annotation has that
19
+ // syntax. A `const` typed by its initializer alone does not, and recovering it
20
+ // means following type inference over arbitrary expressions -- a call's return
21
+ // type, an overload's selection, a contextually typed parameter -- which is
22
+ // exactly the unbounded problem a typia call with no written type argument has.
23
+ // Both get the same answer rather than a partial walk that would leave the file
24
+ // declared on an incomplete list (samchon/typia#2357).
25
+ //
26
+ // 1. Build a project where `cfg.ts` exports one annotated constant, one
27
+ // inferred constant of the same shape, and one destructured binding, and
28
+ // three callers validate `typeof` each.
29
+ // 2. Run project transform mode and decode the JSON envelope.
30
+ // 3. Assert every caller transformed, so the set differs only in where the
31
+ // type was written.
32
+ // 4. Assert the annotated caller is declared complete and names the
33
+ // annotation's own file, and that the inferred caller is withheld while
34
+ // keeping what it did report.
35
+ // 5. Assert the destructured caller is withheld too. A binding element is a
36
+ // declaration kind the predicate names nowhere, so it answers through the
37
+ // default -- which is what pins that the default is "withhold".
38
+ func TestProjectDependenciesInferredDeclarationTransform(t *testing.T) {
39
+ project := projectDependenciesInferredDeclarationProject(t)
40
+ out, errText, code := ttscTypiaTestCapture(func() int {
41
+ return runTransform([]string{
42
+ "--cwd", project,
43
+ "--tsconfig", "tsconfig.json",
44
+ "--output", "ts",
45
+ })
46
+ })
47
+ if code != 0 {
48
+ t.Fatalf("project transform failed: code=%d stderr=\n%s", code, errText)
49
+ }
50
+ var envelope struct {
51
+ TypeScript map[string]string `json:"typescript"`
52
+ Dependencies map[string][]string `json:"dependencies"`
53
+ DependenciesComplete []string `json:"dependenciesComplete"`
54
+ }
55
+ if err := json.Unmarshal([]byte(out), &envelope); err != nil {
56
+ t.Fatalf("decode envelope: %v\n%s", err, out)
57
+ }
58
+ for _, key := range []string{"src/annotated.ts", "src/inferred.ts", "src/destructured.ts"} {
59
+ if text := envelope.TypeScript[key]; !strings.Contains(text, "typeof input") {
60
+ t.Fatalf("%s must have been transformed into a generated validator, got:\n%s", key, text)
61
+ }
62
+ }
63
+ declared := map[string]bool{}
64
+ for _, key := range envelope.DependenciesComplete {
65
+ declared[key] = true
66
+ }
67
+ if !declared["src/annotated.ts"] {
68
+ t.Fatalf("a validated type written as an annotation bounds its inputs and must be declared complete: %v", envelope.DependenciesComplete)
69
+ }
70
+ found := map[string]bool{}
71
+ for _, entry := range envelope.Dependencies["src/annotated.ts"] {
72
+ found[entry] = true
73
+ }
74
+ if !found["src/shape.ts"] {
75
+ t.Fatalf("the annotated constant's own annotation file must be reported: %v", envelope.Dependencies["src/annotated.ts"])
76
+ }
77
+ if declared["src/inferred.ts"] {
78
+ t.Fatalf("a validated type that reaches a declaration typed by its initializer alone must be withheld: %v", envelope.DependenciesComplete)
79
+ }
80
+ if len(envelope.Dependencies["src/inferred.ts"]) == 0 {
81
+ t.Fatalf("withholding the declaration must not strip what src/inferred.ts did report: %v", envelope.Dependencies)
82
+ }
83
+ if declared["src/destructured.ts"] {
84
+ t.Fatalf("a declaration kind the predicate names nowhere must answer through the default and withhold: %v", envelope.DependenciesComplete)
85
+ }
86
+ }
87
+
88
+ func projectDependenciesInferredDeclarationProject(t *testing.T) string {
89
+ t.Helper()
90
+ root := ttscTypiaTestRepoRoot(t)
91
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
92
+ if err := os.MkdirAll(base, 0o755); err != nil {
93
+ t.Fatalf("mkdir temp base: %v", err)
94
+ }
95
+ dir, err := os.MkdirTemp(base, "project-dependencies-inferred-declaration-")
96
+ if err != nil {
97
+ t.Fatalf("create temp fixture: %v", err)
98
+ }
99
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
100
+ src := filepath.Join(dir, "src")
101
+ if err := os.MkdirAll(src, 0o755); err != nil {
102
+ t.Fatalf("mkdir fixture src: %v", err)
103
+ }
104
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(projectDependenciesEnvelopeTSConfig), 0o644); err != nil {
105
+ t.Fatalf("write tsconfig: %v", err)
106
+ }
107
+ for name, body := range map[string]string{
108
+ "annotated.ts": projectDependenciesInferredDeclarationSourceAnnotated,
109
+ "inferred.ts": projectDependenciesInferredDeclarationSourceInferred,
110
+ "destructured.ts": projectDependenciesInferredDeclarationSourceDestructured,
111
+ "cfg.ts": projectDependenciesInferredDeclarationSourceCfg,
112
+ "shape.ts": projectDependenciesInferredDeclarationSourceShape,
113
+ "id.ts": projectDependenciesInferredDeclarationSourceId,
114
+ } {
115
+ if err := os.WriteFile(filepath.Join(src, name), []byte(body), 0o644); err != nil {
116
+ t.Fatalf("write %s: %v", name, err)
117
+ }
118
+ }
119
+ return dir
120
+ }
121
+
122
+ const projectDependenciesInferredDeclarationSourceAnnotated = `import typia from "typia";
123
+
124
+ import { written } from "./cfg";
125
+
126
+ export const check = (input: unknown) => typia.is<typeof written>(input);
127
+ `
128
+
129
+ const projectDependenciesInferredDeclarationSourceInferred = `import typia from "typia";
130
+
131
+ import { guessed } from "./cfg";
132
+
133
+ export const check = (input: unknown) => typia.is<typeof guessed>(input);
134
+ `
135
+
136
+ const projectDependenciesInferredDeclarationSourceDestructured = `import typia from "typia";
137
+
138
+ import { picked } from "./cfg";
139
+
140
+ export const check = (input: unknown) => typia.is<typeof picked>(input);
141
+ `
142
+
143
+ const projectDependenciesInferredDeclarationSourceCfg = `import { Id } from "./id";
144
+ import { Shape } from "./shape";
145
+
146
+ export const written: Shape = { id: "w" };
147
+
148
+ export const guessed = { id: "g" as Id };
149
+
150
+ export const { id: picked } = written;
151
+ `
152
+
153
+ const projectDependenciesInferredDeclarationSourceShape = `export interface Shape {
154
+ id: string;
155
+ }
156
+ `
157
+
158
+ const projectDependenciesInferredDeclarationSourceId = `export type Id = string;
159
+ `
@@ -0,0 +1,134 @@
1
+ package main
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ // TestProjectDependenciesJsDocTypedefTransform verifies an `allowJs` project
11
+ // whose type is written as a JSDoc typedef reports the file behind a
12
+ // `@property` tag and still declares the consumer complete.
13
+ //
14
+ // A JSDoc typedef reaches the walk as a `JSTypeAliasDeclaration`, so its whole
15
+ // node is surfaced and every reference written inside it -- including the
16
+ // `import("./id").Id` a `@property` tag names -- resolves from there. The tags
17
+ // themselves never arrive at the boundedness predicate, so this is what pins
18
+ // that they do not need to: were a property enumeration to start handing tags
19
+ // over, the default would withhold and this file would stop being declared
20
+ // (samchon/typia#2357).
21
+ //
22
+ // 1. Build an `allowJs` project where `main.ts` validates a typedef declared
23
+ // in `doc.js`, whose `@property` tag names a typedef in `id.js`.
24
+ // 2. Run project transform mode and decode the JSON envelope.
25
+ // 3. Assert `dependencies["src/main.ts"]` carries both `src/doc.js` and
26
+ // `src/id.js`.
27
+ // 4. Assert `src/main.ts` is declared complete, so the narrowed bound is the
28
+ // one carrying them.
29
+ func TestProjectDependenciesJsDocTypedefTransform(t *testing.T) {
30
+ project := projectDependenciesJsDocTypedefProject(t)
31
+ out, errText, code := ttscTypiaTestCapture(func() int {
32
+ return runTransform([]string{
33
+ "--cwd", project,
34
+ "--tsconfig", "tsconfig.json",
35
+ "--output", "ts",
36
+ })
37
+ })
38
+ if code != 0 {
39
+ t.Fatalf("project transform failed: code=%d stderr=\n%s", code, errText)
40
+ }
41
+ var envelope struct {
42
+ Dependencies map[string][]string `json:"dependencies"`
43
+ DependenciesComplete []string `json:"dependenciesComplete"`
44
+ }
45
+ if err := json.Unmarshal([]byte(out), &envelope); err != nil {
46
+ t.Fatalf("decode envelope: %v\n%s", err, out)
47
+ }
48
+ entries := envelope.Dependencies["src/main.ts"]
49
+ found := map[string]bool{}
50
+ for _, entry := range entries {
51
+ found[entry] = true
52
+ }
53
+ if !found["src/doc.js"] {
54
+ t.Fatalf("dependencies of src/main.ts must contain the typedef's own file src/doc.js: %v", entries)
55
+ }
56
+ if !found["src/id.js"] {
57
+ t.Fatalf("dependencies of src/main.ts must contain src/id.js, which a @property tag names: %v", entries)
58
+ }
59
+ declared := false
60
+ for _, key := range envelope.DependenciesComplete {
61
+ if key == "src/main.ts" {
62
+ declared = true
63
+ }
64
+ }
65
+ if !declared {
66
+ t.Fatalf("src/main.ts must be declared complete, so the reported entry is the whole bound: %v", envelope.DependenciesComplete)
67
+ }
68
+ }
69
+
70
+ func projectDependenciesJsDocTypedefProject(t *testing.T) string {
71
+ t.Helper()
72
+ root := ttscTypiaTestRepoRoot(t)
73
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
74
+ if err := os.MkdirAll(base, 0o755); err != nil {
75
+ t.Fatalf("mkdir temp base: %v", err)
76
+ }
77
+ dir, err := os.MkdirTemp(base, "project-dependencies-jsdoc-typedef-")
78
+ if err != nil {
79
+ t.Fatalf("create temp fixture: %v", err)
80
+ }
81
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
82
+ src := filepath.Join(dir, "src")
83
+ if err := os.MkdirAll(src, 0o755); err != nil {
84
+ t.Fatalf("mkdir fixture src: %v", err)
85
+ }
86
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(projectDependenciesJsDocTypedefTSConfig), 0o644); err != nil {
87
+ t.Fatalf("write tsconfig: %v", err)
88
+ }
89
+ for name, body := range map[string]string{
90
+ "main.ts": projectDependenciesJsDocTypedefSourceMain,
91
+ "doc.js": projectDependenciesJsDocTypedefSourceDoc,
92
+ "id.js": projectDependenciesJsDocTypedefSourceId,
93
+ } {
94
+ if err := os.WriteFile(filepath.Join(src, name), []byte(body), 0o644); err != nil {
95
+ t.Fatalf("write %s: %v", name, err)
96
+ }
97
+ }
98
+ return dir
99
+ }
100
+
101
+ const projectDependenciesJsDocTypedefTSConfig = `{
102
+ "compilerOptions": {
103
+ "target": "ES2022",
104
+ "module": "commonjs",
105
+ "moduleResolution": "bundler",
106
+ "ignoreDeprecations": "6.0",
107
+ "esModuleInterop": true,
108
+ "strict": true,
109
+ "skipLibCheck": true,
110
+ "allowJs": true,
111
+ "rootDir": "src",
112
+ "outDir": "dist"
113
+ },
114
+ "include": ["src"]
115
+ }
116
+ `
117
+
118
+ const projectDependenciesJsDocTypedefSourceMain = `import typia from "typia";
119
+
120
+ export const check = (input: unknown) => typia.is<import("./doc").Doc>(input);
121
+ `
122
+
123
+ const projectDependenciesJsDocTypedefSourceDoc = `/**
124
+ * @typedef {Object} Doc
125
+ * @property {import("./id").Id} id
126
+ */
127
+
128
+ export const marker = 1;
129
+ `
130
+
131
+ const projectDependenciesJsDocTypedefSourceId = `/** @typedef {string} Id */
132
+
133
+ export const marker = 1;
134
+ `