typia 13.1.19 → 13.3.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 (235) hide show
  1. package/lib/executable/FileSystemIdentity.d.ts +23 -0
  2. package/lib/executable/FileSystemIdentity.js +30 -0
  3. package/lib/executable/FileSystemIdentity.js.map +1 -1
  4. package/lib/executable/FileSystemIdentity.mjs +4 -0
  5. package/lib/executable/FileSystemIdentity.mjs.map +1 -1
  6. package/lib/executable/TypiaGenerateWizard.js +15 -9
  7. package/lib/executable/TypiaGenerateWizard.js.map +1 -1
  8. package/lib/executable/TypiaGenerateWizard.mjs +11 -7
  9. package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
  10. package/lib/http.d.ts +3 -3
  11. package/lib/http.js.map +1 -1
  12. package/lib/http.mjs.map +1 -1
  13. package/lib/internal/_ProtobufReader.d.ts +18 -3
  14. package/lib/internal/_ProtobufReader.js +39 -11
  15. package/lib/internal/_ProtobufReader.js.map +1 -1
  16. package/lib/internal/_ProtobufReader.mjs +37 -10
  17. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  18. package/lib/internal/_assertGuard.js +13 -3
  19. package/lib/internal/_assertGuard.js.map +1 -1
  20. package/lib/internal/_assertGuard.mjs +4 -2
  21. package/lib/internal/_assertGuard.mjs.map +1 -1
  22. package/lib/internal/_isFormatIdnHostname.js +5 -1
  23. package/lib/internal/_isFormatIdnHostname.js.map +1 -1
  24. package/lib/internal/_isFormatIdnHostname.mjs +1 -1
  25. package/lib/internal/_isFormatIdnHostname.mjs.map +1 -1
  26. package/lib/internal/_isFormatTime.js +19 -2
  27. package/lib/internal/_isFormatTime.js.map +1 -1
  28. package/lib/internal/_isFormatTime.mjs +9 -2
  29. package/lib/internal/_isFormatTime.mjs.map +1 -1
  30. package/lib/internal/_jsonStringifyArray.d.ts +1 -0
  31. package/lib/internal/_jsonStringifyArray.js +48 -0
  32. package/lib/internal/_jsonStringifyArray.js.map +1 -0
  33. package/lib/internal/_jsonStringifyArray.mjs +40 -0
  34. package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
  35. package/lib/internal/_jsonStringifyElement.d.ts +1 -0
  36. package/lib/internal/_jsonStringifyElement.js +23 -0
  37. package/lib/internal/_jsonStringifyElement.js.map +1 -0
  38. package/lib/internal/_jsonStringifyElement.mjs +23 -0
  39. package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
  40. package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
  41. package/lib/internal/_jsonStringifyProperty.js +31 -0
  42. package/lib/internal/_jsonStringifyProperty.js.map +1 -0
  43. package/lib/internal/_jsonStringifyProperty.mjs +31 -0
  44. package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
  45. package/lib/internal/_llmApplicationFinalize.js +1 -1
  46. package/lib/internal/_llmApplicationFinalize.js.map +1 -1
  47. package/lib/internal/_llmApplicationFinalize.mjs +1 -1
  48. package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
  49. package/lib/internal/_randomArray.js +37 -4
  50. package/lib/internal/_randomArray.js.map +1 -1
  51. package/lib/internal/_randomArray.mjs +16 -3
  52. package/lib/internal/_randomArray.mjs.map +1 -1
  53. package/lib/internal/_randomFormatByte.js +28 -2
  54. package/lib/internal/_randomFormatByte.js.map +1 -1
  55. package/lib/internal/_randomFormatByte.mjs +22 -3
  56. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  57. package/lib/internal/_randomFormatDate.d.ts +3 -6
  58. package/lib/internal/_randomFormatDate.js +2 -10
  59. package/lib/internal/_randomFormatDate.js.map +1 -1
  60. package/lib/internal/_randomFormatDate.mjs +2 -6
  61. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  62. package/lib/internal/_randomFormatDatetime.d.ts +3 -6
  63. package/lib/internal/_randomFormatDatetime.js +25 -8
  64. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  65. package/lib/internal/_randomFormatDatetime.mjs +17 -7
  66. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  67. package/lib/internal/_randomFormatDuration.js +23 -15
  68. package/lib/internal/_randomFormatDuration.js.map +1 -1
  69. package/lib/internal/_randomFormatDuration.mjs +23 -15
  70. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  71. package/lib/internal/_randomFormatHostname.d.ts +2 -2
  72. package/lib/internal/_randomFormatHostname.js +2 -2
  73. package/lib/internal/_randomFormatHostname.mjs +2 -2
  74. package/lib/internal/_randomFormatHostname.mjs.map +1 -1
  75. package/lib/internal/_randomFormatIdnHostname.js +9 -10
  76. package/lib/internal/_randomFormatIdnHostname.js.map +1 -1
  77. package/lib/internal/_randomFormatIdnHostname.mjs +3 -4
  78. package/lib/internal/_randomFormatIdnHostname.mjs.map +1 -1
  79. package/lib/internal/_randomFormatIpv4.js +31 -1
  80. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  81. package/lib/internal/_randomFormatIpv4.mjs +23 -2
  82. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  83. package/lib/internal/_randomFormatIpv6.js +57 -1
  84. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  85. package/lib/internal/_randomFormatIpv6.mjs +45 -2
  86. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  87. package/lib/internal/_randomFormatJsonPointer.js +14 -2
  88. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  89. package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
  90. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  91. package/lib/internal/_randomFormatRegex.js +15 -2
  92. package/lib/internal/_randomFormatRegex.js.map +1 -1
  93. package/lib/internal/_randomFormatRegex.mjs +14 -3
  94. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  95. package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
  96. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  97. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
  98. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  99. package/lib/internal/_randomFormatTime.js +38 -7
  100. package/lib/internal/_randomFormatTime.js.map +1 -1
  101. package/lib/internal/_randomFormatTime.mjs +40 -5
  102. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  103. package/lib/internal/_randomPattern.js.map +1 -1
  104. package/lib/internal/_randomPattern.mjs.map +1 -1
  105. package/lib/internal/_randomStringLength.d.ts +41 -10
  106. package/lib/internal/_randomStringLength.js +49 -13
  107. package/lib/internal/_randomStringLength.js.map +1 -1
  108. package/lib/internal/_randomStringLength.mjs +48 -13
  109. package/lib/internal/_randomStringLength.mjs.map +1 -1
  110. package/lib/internal/private/__notationRename.js.map +1 -1
  111. package/lib/internal/private/__notationRename.mjs.map +1 -1
  112. package/lib/internal/private/__randomComposition.d.ts +31 -0
  113. package/lib/internal/private/__randomComposition.js +68 -0
  114. package/lib/internal/private/__randomComposition.js.map +1 -0
  115. package/lib/internal/private/__randomComposition.mjs +71 -0
  116. package/lib/internal/private/__randomComposition.mjs.map +1 -0
  117. package/lib/internal/private/__randomEpoch.d.ts +19 -0
  118. package/lib/internal/private/__randomEpoch.js +31 -0
  119. package/lib/internal/private/__randomEpoch.js.map +1 -0
  120. package/lib/internal/private/__randomEpoch.mjs +28 -0
  121. package/lib/internal/private/__randomEpoch.mjs.map +1 -0
  122. package/lib/json.d.ts +2 -2
  123. package/lib/json.js.map +1 -1
  124. package/lib/json.mjs.map +1 -1
  125. package/lib/module.d.ts +28 -13
  126. package/lib/module.js.map +1 -1
  127. package/lib/module.mjs.map +1 -1
  128. package/lib/notations.d.ts +4 -4
  129. package/lib/notations.js.map +1 -1
  130. package/lib/notations.mjs.map +1 -1
  131. package/lib/plain.d.ts +3 -3
  132. package/lib/plain.js.map +1 -1
  133. package/lib/plain.mjs.map +1 -1
  134. package/lib/protobuf.d.ts +2 -2
  135. package/lib/protobuf.js.map +1 -1
  136. package/lib/protobuf.mjs.map +1 -1
  137. package/native/cmd/ttsc-typia/assert_guard_factory_contract_test.go +17 -4
  138. package/native/cmd/ttsc-typia/build.go +3 -0
  139. package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
  140. package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
  141. package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
  142. package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
  143. package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +309 -0
  144. package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
  145. package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
  146. package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
  147. package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
  148. package/native/cmd/ttsc-typia/local_function_named_like_typia_operation_transform_test.go +185 -0
  149. package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
  150. package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
  151. package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
  152. package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
  153. package/native/cmd/ttsc-typia/recursive_conditional_alias_name_transform_test.go +307 -0
  154. package/native/cmd/ttsc-typia/shadowed_typia_module_declaration_diagnostic_test.go +152 -0
  155. package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
  156. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +1 -3
  157. package/native/cmd/ttsc-typia/transform.go +23 -0
  158. package/native/cmd/ttsc-typia/transform_helpers_test.go +166 -25
  159. package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
  160. package/native/core/factories/FormatCheatSheet.go +2 -2
  161. package/native/core/factories/MetadataCommentTagFactory.go +26 -11
  162. package/native/core/factories/ProtobufFactory.go +6 -1
  163. package/native/core/factories/factory_utility_coverage_test.go +896 -907
  164. package/native/core/factories/internal/metadata/MetadataHelper.go +190 -58
  165. package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
  166. package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
  167. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
  168. package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
  169. package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
  170. package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
  171. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +2 -2
  172. package/native/core/programmers/RandomProgrammer.go +5 -2
  173. package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
  174. package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
  175. package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
  176. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
  177. package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
  178. package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
  179. package/native/core/programmers/iterate/json_schema_object.go +49 -7
  180. package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
  181. package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
  182. package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
  183. package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
  184. package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
  185. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
  186. package/native/core/schemas/metadata/MetadataCollection.go +47 -14
  187. package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
  188. package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
  189. package/native/go.mod +4 -4
  190. package/native/transform/CallExpressionTransformer.go +167 -0
  191. package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
  192. package/package.json +3 -7
  193. package/src/executable/FileSystemIdentity.ts +33 -0
  194. package/src/executable/TypiaGenerateWizard.ts +18 -12
  195. package/src/http.ts +18 -4
  196. package/src/internal/_ProtobufReader.ts +40 -11
  197. package/src/internal/_assertGuard.ts +13 -2
  198. package/src/internal/_isFormatIdnHostname.ts +5 -1
  199. package/src/internal/_isFormatTime.ts +19 -2
  200. package/src/internal/_jsonStringifyArray.ts +50 -0
  201. package/src/internal/_jsonStringifyElement.ts +19 -0
  202. package/src/internal/_jsonStringifyProperty.ts +30 -0
  203. package/src/internal/_llmApplicationFinalize.ts +6 -1
  204. package/src/internal/_randomArray.ts +42 -6
  205. package/src/internal/_randomFormatByte.ts +36 -4
  206. package/src/internal/_randomFormatDate.ts +4 -20
  207. package/src/internal/_randomFormatDatetime.ts +34 -20
  208. package/src/internal/_randomFormatDuration.ts +19 -4
  209. package/src/internal/_randomFormatHostname.ts +2 -2
  210. package/src/internal/_randomFormatIdnHostname.ts +8 -9
  211. package/src/internal/_randomFormatIpv4.ts +43 -3
  212. package/src/internal/_randomFormatIpv6.ts +67 -3
  213. package/src/internal/_randomFormatJsonPointer.ts +23 -3
  214. package/src/internal/_randomFormatRegex.ts +22 -6
  215. package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
  216. package/src/internal/_randomFormatTime.ts +50 -12
  217. package/src/internal/_randomPattern.ts +4 -1
  218. package/src/internal/_randomStringLength.ts +61 -17
  219. package/src/internal/private/__notationRename.ts +1 -4
  220. package/src/internal/private/__randomComposition.ts +74 -0
  221. package/src/internal/private/__randomEpoch.ts +34 -0
  222. package/src/json.ts +16 -4
  223. package/src/module.ts +56 -22
  224. package/src/notations.ts +16 -4
  225. package/src/plain.ts +12 -3
  226. package/src/protobuf.ts +16 -4
  227. package/native/adapter/visit.go +0 -173
  228. package/native/adapter/visit_property_chain_edges_test.go +0 -129
  229. package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
  230. package/native/core/programmers/iterate/check_union_array_like.go +0 -422
  231. package/native/core/programmers/iterate/prune_object_properties.go +0 -105
  232. package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
  233. package/native/core/programmers/iterate/stringify_native.go +0 -14
  234. package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
  235. package/native/core/schemas/metadata/MetadataApplication.go +0 -41
@@ -0,0 +1,484 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "os"
6
+ "os/exec"
7
+ "path/filepath"
8
+ "strings"
9
+ "testing"
10
+ )
11
+
12
+ // TestUserGlobalNativeIdentityTransform keeps a user-authored global structural
13
+ // while a runtime-provided global of the same name stays runtime-native (#2200).
14
+ //
15
+ // Winning the checker's global type table proves only that a declaration is
16
+ // global. A project whose sole `File` or `Blob` declaration is its own `declare
17
+ // global` block wins that same lookup, so a resolution-only identity gate erases
18
+ // the user's members, emits `input instanceof File`, and throws `ReferenceError`
19
+ // wherever no runtime supplies that constructor. Native classification therefore
20
+ // has to ask which authority provides the constructor, and it must ask that
21
+ // question without demoting the genuine default-library, Node bare-global, or
22
+ // augmented natives that legitimately answer it.
23
+ //
24
+ // 1. Transform a project whose only File/Blob declarations are user globals in
25
+ // both the interface and the class spelling, one of them carrying its own
26
+ // `declare var` constructor binding, across is/assert/assertGuard/validate/
27
+ // equals/random, direct and factory forms, and alias, nested, intersection,
28
+ // union, and re-exported compositions.
29
+ // 2. Transform that project's json, protobuf, and llm schema surfaces, which a
30
+ // native classification removes from those consumers entirely.
31
+ // 3. Transform a global `type` alias spelling of the same collision in a second
32
+ // project, and near-miss control names in the first.
33
+ // 4. Transform a third project where @types/node provides the runtime bridge
34
+ // and the user contributes only an empty augmentation, requiring every
35
+ // default-library and Node-provided native to keep its `instanceof` check.
36
+ // 5. Execute every emitted validator in Node against structural user values and
37
+ // against the real runtime instances, requiring exact case counts so a
38
+ // dropped branch cannot pass silently.
39
+ func TestUserGlobalNativeIdentityTransform(t *testing.T) {
40
+ project := userGlobalNativeIdentityProject(t)
41
+ aliasProject := userGlobalNativeIdentityAliasProject(t)
42
+ providedProject := userGlobalNativeIdentityProvidedProject(t)
43
+ transform := func(dir string, file string) string {
44
+ t.Helper()
45
+ js, errText, code := ttscTypiaTestCapture(func() int {
46
+ return runTransform([]string{
47
+ "--cwd", dir,
48
+ "--tsconfig", "tsconfig.json",
49
+ "--file", file,
50
+ "--output", "js",
51
+ })
52
+ })
53
+ if code != 0 {
54
+ t.Fatalf("user global native identity transform %s/%s failed: code=%d stderr=\n%s", dir, file, code, errText)
55
+ }
56
+ return js
57
+ }
58
+
59
+ js := transform(project, "src/input.ts")
60
+ schemasJS := transform(project, "src/schemas.ts")
61
+ controlsJS := transform(project, "src/controls.ts")
62
+ aliasJS := transform(aliasProject, "src/input.ts")
63
+ providedJS := transform(providedProject, "src/input.ts")
64
+
65
+ failures := []string{}
66
+ for _, native := range []string{"instanceof File", "instanceof Blob"} {
67
+ for name, emit := range map[string]string{
68
+ "validator emit": js,
69
+ "schema emit": schemasJS,
70
+ "type alias emit": aliasJS,
71
+ "near-miss control": controlsJS,
72
+ } {
73
+ if strings.Contains(emit, native) {
74
+ failures = append(failures, fmt.Sprintf("%s promoted a user-authored global to %q", name, native))
75
+ }
76
+ }
77
+ }
78
+ for _, member := range []string{"userBlobBrand", "userFileBrand"} {
79
+ for name, emit := range map[string]string{
80
+ "validator emit": js,
81
+ "schema emit": schemasJS,
82
+ "type alias emit": aliasJS,
83
+ } {
84
+ if !strings.Contains(emit, member) {
85
+ failures = append(failures, fmt.Sprintf("%s dropped user-declared member %q", name, member))
86
+ }
87
+ }
88
+ }
89
+ for _, member := range []string{"intersectionBrand", "unionControl", "nestedHolder"} {
90
+ if !strings.Contains(js, member) {
91
+ failures = append(failures, fmt.Sprintf("validator emit dropped composition member %q", member))
92
+ }
93
+ }
94
+ for _, member := range []string{"nearMissBrand", "prefixBrand"} {
95
+ if !strings.Contains(controlsJS, member) {
96
+ failures = append(failures, fmt.Sprintf("near-miss control emit dropped member %q", member))
97
+ }
98
+ }
99
+ for _, kept := range []string{
100
+ "instanceof Date",
101
+ "instanceof RegExp",
102
+ "instanceof Uint8Array",
103
+ "instanceof Map",
104
+ "instanceof Set",
105
+ "instanceof WeakMap",
106
+ "instanceof WeakSet",
107
+ "instanceof File",
108
+ "instanceof Blob",
109
+ } {
110
+ if !strings.Contains(providedJS, kept) {
111
+ failures = append(failures, fmt.Sprintf("runtime-provided native lost %q", kept))
112
+ }
113
+ }
114
+
115
+ output, runtimeErr := userGlobalNativeIdentityRun(t, project, js, controlsJS)
116
+ if runtimeErr != nil {
117
+ failures = append(failures, fmt.Sprintf("user global runtime matrix failed: %v\n%s", runtimeErr, output))
118
+ }
119
+ // Counted from the runner's own table, which is the ground truth: 11 rows for
120
+ // the is/assert/assertGuard/validate/equals/random matrix, 15 for the
121
+ // createIs forms across direct, alias, re-export, branded intersection, union,
122
+ // and nested positions, and 2 near-miss name controls. The count is asserted
123
+ // rather than the exit code so a row that silently stops running cannot pass
124
+ // as a row that ran and agreed.
125
+ if expected := "RAN 28 USER GLOBAL CASES"; !strings.Contains(output, expected) {
126
+ failures = append(failures, fmt.Sprintf("user global runner did not report %q; got:\n%s", expected, output))
127
+ }
128
+ providedOutput, providedErr := userGlobalNativeIdentityProvidedRun(t, providedProject, providedJS)
129
+ if providedErr != nil {
130
+ failures = append(failures, fmt.Sprintf("runtime-provided matrix failed: %v\n%s", providedErr, providedOutput))
131
+ }
132
+ if expected := "RAN 18 PROVIDED CASES"; !strings.Contains(providedOutput, expected) {
133
+ failures = append(failures, fmt.Sprintf("provided runner did not report %q; got:\n%s", expected, providedOutput))
134
+ }
135
+
136
+ if len(failures) != 0 {
137
+ t.Fatalf(
138
+ "user global native identity mismatches:\n%s\n\nvalidator emit:\n%s\n\nschema emit:\n%s\n\nalias emit:\n%s\n\ncontrol emit:\n%s\n\nprovided emit:\n%s",
139
+ strings.Join(failures, "\n"),
140
+ js,
141
+ schemasJS,
142
+ aliasJS,
143
+ controlsJS,
144
+ providedJS,
145
+ )
146
+ }
147
+ }
148
+
149
+ func userGlobalNativeIdentityWriteProject(t *testing.T, prefix string, files map[string]string) string {
150
+ t.Helper()
151
+ root := ttscTypiaTestRepoRoot(t)
152
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
153
+ if err := os.MkdirAll(base, 0o755); err != nil {
154
+ t.Fatalf("mkdir temp base: %v", err)
155
+ }
156
+ dir, err := os.MkdirTemp(base, prefix)
157
+ if err != nil {
158
+ t.Fatalf("create temp fixture: %v", err)
159
+ }
160
+ t.Cleanup(func() {
161
+ _ = os.RemoveAll(dir)
162
+ })
163
+ for name, content := range files {
164
+ path := filepath.Join(dir, filepath.FromSlash(name))
165
+ if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
166
+ t.Fatalf("mkdir fixture path %s: %v", filepath.Dir(path), err)
167
+ }
168
+ if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
169
+ t.Fatalf("write fixture file %s: %v", path, err)
170
+ }
171
+ }
172
+ return dir
173
+ }
174
+
175
+ func userGlobalNativeIdentityProject(t *testing.T) string {
176
+ t.Helper()
177
+ return userGlobalNativeIdentityWriteProject(t, "user-global-native-identity-", map[string]string{
178
+ "tsconfig.json": userGlobalNativeIdentityTSConfig,
179
+ "src/globals.d.ts": userGlobalNativeIdentityGlobals,
180
+ "src/reexport.ts": userGlobalNativeIdentityReexport,
181
+ "src/input.ts": userGlobalNativeIdentitySource,
182
+ "src/schemas.ts": userGlobalNativeIdentitySchemaSource,
183
+ "src/controls.ts": userGlobalNativeIdentityControlSource,
184
+ })
185
+ }
186
+
187
+ func userGlobalNativeIdentityAliasProject(t *testing.T) string {
188
+ t.Helper()
189
+ return userGlobalNativeIdentityWriteProject(t, "user-global-native-identity-alias-", map[string]string{
190
+ "tsconfig.json": userGlobalNativeIdentityTSConfig,
191
+ "src/globals.d.ts": userGlobalNativeIdentityAliasGlobals,
192
+ "src/input.ts": userGlobalNativeIdentityAliasSource,
193
+ })
194
+ }
195
+
196
+ func userGlobalNativeIdentityProvidedProject(t *testing.T) string {
197
+ t.Helper()
198
+ return userGlobalNativeIdentityWriteProject(t, "user-global-native-identity-provided-", map[string]string{
199
+ "tsconfig.json": userGlobalNativeIdentityProvidedTSConfig,
200
+ "src/globals.d.ts": userGlobalNativeIdentityProvidedGlobals,
201
+ "src/input.ts": userGlobalNativeIdentityProvidedSource,
202
+ })
203
+ }
204
+
205
+ func userGlobalNativeIdentityRunner(t *testing.T, project string, modules map[string]string) (string, error) {
206
+ t.Helper()
207
+ node, err := exec.LookPath("node")
208
+ if err != nil {
209
+ t.Skip("node executable not found")
210
+ return "", nil
211
+ }
212
+ runtimeDir := filepath.Join(project, "runtime")
213
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
214
+ t.Fatalf("mkdir runtime dir: %v", err)
215
+ }
216
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
217
+ for name, content := range modules {
218
+ if err := os.WriteFile(filepath.Join(runtimeDir, name), []byte(content), 0o644); err != nil {
219
+ t.Fatalf("write runtime file %s: %v", name, err)
220
+ }
221
+ }
222
+ cmd := exec.Command(node, filepath.Join(runtimeDir, "run.cjs"))
223
+ cmd.Dir = runtimeDir
224
+ output, err := cmd.CombinedOutput()
225
+ return string(output), err
226
+ }
227
+
228
+ func userGlobalNativeIdentityRun(t *testing.T, project string, js string, controlsJS string) (string, error) {
229
+ t.Helper()
230
+ return userGlobalNativeIdentityRunner(t, project, map[string]string{
231
+ "input.cjs": ttscTypiaTestRewriteCommonJS(t, js),
232
+ "controls.cjs": ttscTypiaTestRewriteCommonJS(t, controlsJS),
233
+ "run.cjs": userGlobalNativeIdentityRuntimeRunner,
234
+ })
235
+ }
236
+
237
+ func userGlobalNativeIdentityProvidedRun(t *testing.T, project string, js string) (string, error) {
238
+ t.Helper()
239
+ return userGlobalNativeIdentityRunner(t, project, map[string]string{
240
+ "input.cjs": ttscTypiaTestRewriteCommonJS(t, js),
241
+ "run.cjs": userGlobalNativeIdentityProvidedRuntimeRunner,
242
+ })
243
+ }
244
+
245
+ const userGlobalNativeIdentityTSConfig = `{
246
+ "compilerOptions": {
247
+ "target": "ES2022",
248
+ "module": "commonjs",
249
+ "moduleResolution": "bundler",
250
+ "ignoreDeprecations": "6.0",
251
+ "lib": ["ES2022"],
252
+ "types": [],
253
+ "esModuleInterop": true,
254
+ "strict": true,
255
+ "skipLibCheck": true
256
+ },
257
+ "include": ["src"]
258
+ }
259
+ `
260
+
261
+ const userGlobalNativeIdentityProvidedTSConfig = `{
262
+ "compilerOptions": {
263
+ "target": "ES2022",
264
+ "module": "commonjs",
265
+ "moduleResolution": "bundler",
266
+ "ignoreDeprecations": "6.0",
267
+ "lib": ["ES2022"],
268
+ "types": ["node"],
269
+ "esModuleInterop": true,
270
+ "strict": true,
271
+ "skipLibCheck": true
272
+ },
273
+ "include": ["src"]
274
+ }
275
+ `
276
+
277
+ // userGlobalNativeIdentityGlobals is the whole runtime-native declaration set of
278
+ // its project: neither the DOM libraries nor @types/node is loaded, so Blob and
279
+ // File exist only because this file declares them. Blob is the interface-only
280
+ // spelling and File is the class spelling, which additionally gives File a
281
+ // user-owned constructor binding — the one signal a runtime provider would
282
+ // otherwise be recognized by.
283
+ const userGlobalNativeIdentityGlobals = `export {};
284
+
285
+ declare global {
286
+ interface Blob {
287
+ userBlobBrand: string;
288
+ }
289
+ class File {
290
+ userBlobBrand: string;
291
+ userFileBrand: string;
292
+ }
293
+ }
294
+ `
295
+
296
+ const userGlobalNativeIdentityReexport = `export type ReexportedFile = File;
297
+ `
298
+
299
+ const userGlobalNativeIdentitySource = `import typia from "typia";
300
+ import type { ReexportedFile } from "./reexport";
301
+
302
+ type FileAlias = File;
303
+ type BrandedFile = File & { intersectionBrand: string };
304
+ type FileUnion = BrandedFile | { unionControl: boolean };
305
+ type NestedFile = { nestedHolder: File };
306
+
307
+ export const isFile = (input: unknown): boolean => typia.is<File>(input);
308
+ export const assertFile = (input: unknown): File => typia.assert<File>(input);
309
+ export const assertGuardFile = (input: unknown): void => typia.assertGuard<File>(input);
310
+ export const validateFile = (input: unknown) => typia.validate<File>(input);
311
+ export const equalsFile = (input: unknown): boolean => typia.equals<File>(input);
312
+ export const randomBlob = (): Blob => typia.random<Blob>();
313
+
314
+ export const createdIsBlob = typia.createIs<Blob>();
315
+ export const createdIsFile = typia.createIs<File>();
316
+ export const createdIsAlias = typia.createIs<FileAlias>();
317
+ export const createdIsReexported = typia.createIs<ReexportedFile>();
318
+ export const createdIsBranded = typia.createIs<BrandedFile>();
319
+ export const createdIsUnion = typia.createIs<FileUnion>();
320
+ export const createdIsNested = typia.createIs<NestedFile>();
321
+ `
322
+
323
+ const userGlobalNativeIdentitySchemaSource = `import typia from "typia";
324
+
325
+ export const jsonSchema = typia.json.schema<File>();
326
+ export const jsonStringify = typia.json.createStringify<File>();
327
+ export const jsonIsStringify = typia.json.createIsStringify<File>();
328
+ export const protobufMessage = typia.protobuf.message<Blob>();
329
+ export const protobufEncode = typia.protobuf.createIsEncode<Blob>();
330
+ export const llmSchema = typia.llm.schema<File>({});
331
+ `
332
+
333
+ const userGlobalNativeIdentityControlSource = `import typia from "typia";
334
+
335
+ interface FileEntry {
336
+ nearMissBrand: string;
337
+ }
338
+ interface Blobby {
339
+ prefixBrand: string;
340
+ }
341
+
342
+ export const createdIsFileEntry = typia.createIs<FileEntry>();
343
+ export const createdIsBlobby = typia.createIs<Blobby>();
344
+ `
345
+
346
+ // userGlobalNativeIdentityAliasGlobals spells the same collision as a global
347
+ // `type` alias, whose symbol is an anonymous type literal rather than a named
348
+ // declaration. It is the negative twin that proves the classification is decided
349
+ // by declaration provenance rather than by the shape of the declaring node.
350
+ const userGlobalNativeIdentityAliasGlobals = `export {};
351
+
352
+ declare global {
353
+ type Blob = { userBlobBrand: string };
354
+ type File = { userBlobBrand: string; userFileBrand: string };
355
+ }
356
+ `
357
+
358
+ const userGlobalNativeIdentityAliasSource = `import typia from "typia";
359
+
360
+ export const isAliasFile = (input: unknown): boolean => typia.is<File>(input);
361
+ export const createdIsAliasBlob = typia.createIs<Blob>();
362
+ `
363
+
364
+ // userGlobalNativeIdentityProvidedGlobals is the positive control: @types/node
365
+ // bridges the node:buffer constructors to the bare globals, and the user adds
366
+ // only an empty augmentation. Merging a declaration into a runtime-provided
367
+ // global must not change what provides that global.
368
+ const userGlobalNativeIdentityProvidedGlobals = `export {};
369
+
370
+ declare global {
371
+ interface Blob {}
372
+ interface File {}
373
+ }
374
+ `
375
+
376
+ const userGlobalNativeIdentityProvidedSource = `import typia from "typia";
377
+
378
+ export const createdIsDate = typia.createIs<Date>();
379
+ export const createdIsRegExp = typia.createIs<RegExp>();
380
+ export const createdIsBytes = typia.createIs<Uint8Array>();
381
+ export const createdIsMap = typia.createIs<Map<string, number>>();
382
+ export const createdIsSet = typia.createIs<Set<string>>();
383
+ export const createdIsWeakMap = typia.createIs<WeakMap<object, string>>();
384
+ export const createdIsWeakSet = typia.createIs<WeakSet<object>>();
385
+ export const createdIsFile = typia.createIs<File>();
386
+ export const createdIsBlob = typia.createIs<Blob>();
387
+ `
388
+
389
+ const userGlobalNativeIdentityRuntimeRunner = `const validators = require("./input.cjs");
390
+ const controls = require("./controls.cjs");
391
+
392
+ let ran = 0;
393
+ const failures = [];
394
+ const eq = (name, actual, expected) => {
395
+ ran += 1;
396
+ if (actual !== expected) {
397
+ failures.push(name + ": expected " + expected + " but got " + actual);
398
+ }
399
+ };
400
+ const throws = (name, run) => {
401
+ ran += 1;
402
+ try {
403
+ run();
404
+ failures.push(name + ": expected a throw but none happened");
405
+ } catch {}
406
+ };
407
+
408
+ const userBlob = { userBlobBrand: "user" };
409
+ const userFile = { userBlobBrand: "user", userFileBrand: "user" };
410
+ const realBlob = new Blob(["x"]);
411
+ const realFile = new File(["x"], "x.txt");
412
+
413
+ eq("is user File", validators.isFile(userFile), true);
414
+ eq("is real File", validators.isFile(realFile), false);
415
+ eq("assert user File", validators.assertFile(userFile), userFile);
416
+ throws("assert real File", () => validators.assertFile(realFile));
417
+ eq("assertGuard user File", validators.assertGuardFile(userFile), undefined);
418
+ throws("assertGuard real File", () => validators.assertGuardFile(realFile));
419
+ eq("validate user File", validators.validateFile(userFile).success, true);
420
+ eq("validate real File", validators.validateFile(realFile).success, false);
421
+ eq("equals user File", validators.equalsFile(userFile), true);
422
+ eq("equals real File", validators.equalsFile(realFile), false);
423
+ eq("random Blob brand", typeof validators.randomBlob().userBlobBrand, "string");
424
+
425
+ eq("createIs user Blob", validators.createdIsBlob(userBlob), true);
426
+ eq("createIs real Blob", validators.createdIsBlob(realBlob), false);
427
+ eq("createIs user File", validators.createdIsFile(userFile), true);
428
+ eq("createIs real File", validators.createdIsFile(realFile), false);
429
+ eq("alias user File", validators.createdIsAlias(userFile), true);
430
+ eq("alias real File", validators.createdIsAlias(realFile), false);
431
+ eq("re-export user File", validators.createdIsReexported(userFile), true);
432
+ eq("re-export real File", validators.createdIsReexported(realFile), false);
433
+ eq("branded user File", validators.createdIsBranded({ ...userFile, intersectionBrand: "x" }), true);
434
+ eq("branded user File without brand", validators.createdIsBranded(userFile), false);
435
+ eq("union branded arm", validators.createdIsUnion({ ...userFile, intersectionBrand: "x" }), true);
436
+ eq("union control arm", validators.createdIsUnion({ unionControl: true }), true);
437
+ eq("union rejects real File", validators.createdIsUnion(realFile), false);
438
+ eq("nested user File", validators.createdIsNested({ nestedHolder: userFile }), true);
439
+ eq("nested real File", validators.createdIsNested({ nestedHolder: realFile }), false);
440
+
441
+ eq("near-miss FileEntry", controls.createdIsFileEntry({ nearMissBrand: "x" }), true);
442
+ eq("prefix Blobby", controls.createdIsBlobby({ prefixBrand: "x" }), true);
443
+
444
+ console.log("RAN " + ran + " USER GLOBAL CASES");
445
+ if (failures.length !== 0) {
446
+ throw new Error("MISMATCHES:\n" + failures.join("\n"));
447
+ }
448
+ `
449
+
450
+ const userGlobalNativeIdentityProvidedRuntimeRunner = `const validators = require("./input.cjs");
451
+
452
+ let ran = 0;
453
+ const failures = [];
454
+ const eq = (name, actual, expected) => {
455
+ ran += 1;
456
+ if (actual !== expected) {
457
+ failures.push(name + ": expected " + expected + " but got " + actual);
458
+ }
459
+ };
460
+
461
+ eq("Date real", validators.createdIsDate(new Date()), true);
462
+ eq("Date plain", validators.createdIsDate({}), false);
463
+ eq("RegExp real", validators.createdIsRegExp(/x/), true);
464
+ eq("RegExp plain", validators.createdIsRegExp({}), false);
465
+ eq("Uint8Array real", validators.createdIsBytes(new Uint8Array(1)), true);
466
+ eq("Uint8Array plain", validators.createdIsBytes({}), false);
467
+ eq("Map real", validators.createdIsMap(new Map([["x", 1]])), true);
468
+ eq("Map plain", validators.createdIsMap({}), false);
469
+ eq("Set real", validators.createdIsSet(new Set(["x"])), true);
470
+ eq("Set plain", validators.createdIsSet({}), false);
471
+ eq("WeakMap real", validators.createdIsWeakMap(new WeakMap()), true);
472
+ eq("WeakMap plain", validators.createdIsWeakMap({}), false);
473
+ eq("WeakSet real", validators.createdIsWeakSet(new WeakSet()), true);
474
+ eq("WeakSet plain", validators.createdIsWeakSet({}), false);
475
+ eq("File real", validators.createdIsFile(new File(["x"], "x.txt")), true);
476
+ eq("File plain", validators.createdIsFile({ name: "x.txt", size: 1 }), false);
477
+ eq("Blob real", validators.createdIsBlob(new Blob(["x"])), true);
478
+ eq("Blob plain", validators.createdIsBlob({ size: 1, type: "text/plain" }), false);
479
+
480
+ console.log("RAN " + ran + " PROVIDED CASES");
481
+ if (failures.length !== 0) {
482
+ throw new Error("MISMATCHES:\n" + failures.join("\n"));
483
+ }
484
+ `
@@ -45,7 +45,7 @@ var FormatCheatSheet = map[string]string{
45
45
  "email": "/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test($input)",
46
46
  "hostname": "/^(?=.{1,253}\\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\\.?$/i.test($input)",
47
47
  "idn-email": "/^(([^<>()[\\]\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@(([^<>()[\\]\\.,;:\\s@\\\"]+\\.)+[^<>()[\\]\\.,;:\\s@\\\"]{2,})$/i.test($input)",
48
- "idn-hostname": "/^([a-z0-9\\u00a1-\\uffff0-9]+(-[a-z0-9\\u00a1-\\uffff0-9]+)*\\.)+[a-z\\u00a1-\\uffff]{2,}$/i.test($input)",
48
+ "idn-hostname": "/^(?=.{1,253}\\.?$)[a-z0-9\\u00a1-\\uffff](?:[a-z0-9\\u00a1-\\uffff-]{0,61}[a-z0-9\\u00a1-\\uffff])?(?:\\.[a-z0-9\\u00a1-\\uffff](?:[a-z0-9\\u00a1-\\uffff-]{0,61}[a-z0-9\\u00a1-\\uffff])?)*\\.?$/i.test($input)",
49
49
  "iri": `(() => !/[\u0000-\u0020\u007f-\u009f\ud800-\udfff"<>\\^\x60{|}]/u.test($input) && !/%(?![0-9A-Fa-f]{2})/u.test($input) && /^[A-Za-z][A-Za-z0-9+.-]*:/u.test($input))()`,
50
50
  "iri-reference": `(() => { if (/[\u0000-\u0020\u007f-\u009f\ud800-\udfff"<>\\^\x60{|}]/u.test($input) || /%(?![0-9A-Fa-f]{2})/u.test($input)) return false; const colon = $input.indexOf(":"); const boundary = $input.search(/[/?#]/u); return colon === -1 || (boundary !== -1 && boundary < colon) || /^[A-Za-z][A-Za-z0-9+.-]*:/u.test($input); })()`,
51
51
  "ipv4": "/^(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$/.test($input)",
@@ -56,7 +56,7 @@ var FormatCheatSheet = map[string]string{
56
56
  "url": "/^(?:https?|ftp):\\/\\/(?:[^\\s/?#@]+(?::[^\\s/?#@]*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?=.{1,253}(?::\\d{2,5})?(?:\\/[^\\s]*)?$)(?:[a-z0-9\\u00a1-\\uffff](?:[-a-z0-9\\u00a1-\\uffff]{0,61}[a-z0-9\\u00a1-\\uffff])?\\.)+(?:[a-z\\u00a1-\\uffff](?:[-a-z0-9\\u00a1-\\uffff]{0,61}[a-z0-9\\u00a1-\\uffff])))(?::\\d{2,5})?(?:\\/[^\\s]*)?$/iu.test($input)",
57
57
  "date-time": `(() => { const match = /^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])[Tt]((?:[01][0-9]|2[0-3])):([0-5][0-9]):([0-5][0-9]|60)(?:\.[0-9]+)?(?:[Zz]|([+-])((?:[01][0-9]|2[0-3])):([0-5][0-9]))$/.exec($input); if (match === null) return false; const year = Number(match[1]); const month = Number(match[2]); const day = Number(match[3]); if (day > [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1] + (month === 2 && (year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0)) ? 1 : 0)) return false; if (match[6] !== "60") return true; const instant = new Date(0); instant.setUTCFullYear(year, month - 1, day); instant.setUTCHours(Number(match[4]), Number(match[5]), 0, 0); const offset = match[7] === undefined ? 0 : (match[7] === "+" ? 1 : -1) * (Number(match[8]) * 60 + Number(match[9])); instant.setUTCMinutes(instant.getUTCMinutes() - offset); return instant.getUTCHours() === 23 && instant.getUTCMinutes() === 59 && ((instant.getUTCMonth() === 5 && instant.getUTCDate() === 30) || (instant.getUTCMonth() === 11 && instant.getUTCDate() === 31)); })()`,
58
58
  "date": `(() => { const match = /^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/.exec($input); if (match === null) return false; const year = Number(match[1]); const month = Number(match[2]); const day = Number(match[3]); return day <= [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1] + (month === 2 && (year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0)) ? 1 : 0); })()`,
59
- "time": "/^([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\\.[0-9]{1,9})?(Z|[+-]([01][0-9]|2[0-3]):[0-5][0-9])$/i.test($input)",
59
+ "time": `(() => { const match = /^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(?:\.[0-9]+)?(?:[Zz]|([+-])((?:[01][0-9]|2[0-3])):([0-5][0-9]))$/.exec($input); if (match === null) return false; if (match[3] !== "60") return true; const offset = match[4] === undefined ? 0 : (match[4] === "+" ? 1 : -1) * (Number(match[5]) * 60 + Number(match[6])); const minutes = Number(match[1]) * 60 + Number(match[2]) - offset; return ((minutes % 1440) + 1440) % 1440 === 1439; })()`,
60
60
  "duration": "/^P(?!$)((\\d+Y)?(\\d+M)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+S)?)?|(\\d+W)?)$/.test($input)",
61
61
  "json-pointer": "/^(?:\\/(?:[^~/]|~0|~1)*)*$/.test($input)",
62
62
  "relative-json-pointer": "/^(?:0|[1-9][0-9]*)(?:#|(?:\\/(?:[^~/]|~0|~1)*)*)$/.test($input)",
@@ -268,7 +268,7 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
268
268
  Report func(msg string) any
269
269
  Value string
270
270
  }) metadataCommentTagFactory_TagRecord {
271
- return metadataCommentTagFactory_numeric(props, "MultipleOf", "multipleOf", "$importInternal(\"_isMultipleOf\")($input, "+props.Value+")", "$input % "+props.Value+"n === 0n")
271
+ return metadataCommentTagFactory_numeric(props, "MultipleOf", "multipleOf", "$input % "+props.Value+" === 0", "$input % "+props.Value+"n === 0n")
272
272
  },
273
273
  "format": func(props struct {
274
274
  Report func(msg string) any
@@ -292,8 +292,8 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
292
292
  }) metadataCommentTagFactory_TagRecord {
293
293
  value := metadataCommentTagFactory_parse_number(props)
294
294
  return metadataCommentTagFactory_TagRecord{"string": {
295
- {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}},
296
- {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}},
295
+ {Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: props.Value + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}},
296
+ {Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$input.length <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}},
297
297
  }}
298
298
  },
299
299
  "minLength": func(props struct {
@@ -301,14 +301,14 @@ var metadataCommentTagFactory_PARSER = map[string]metadataCommentTagFactory_pars
301
301
  Value string
302
302
  }) metadataCommentTagFactory_TagRecord {
303
303
  value := metadataCommentTagFactory_parse_number(props)
304
- 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}}}}
304
+ return metadataCommentTagFactory_TagRecord{"string": {{Name: "MinLength<" + props.Value + ">", Target: "string", Kind: "minLength", Value: value, Validate: props.Value + " <= $input.length", Exclusive: metadataCommentTagFactory_exclusive("minLength"), Schema: map[string]any{"minLength": value}}}}
305
305
  },
306
306
  "maxLength": func(props struct {
307
307
  Report func(msg string) any
308
308
  Value string
309
309
  }) metadataCommentTagFactory_TagRecord {
310
310
  value := metadataCommentTagFactory_parse_number(props)
311
- 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}}}}
311
+ return metadataCommentTagFactory_TagRecord{"string": {{Name: "MaxLength<" + props.Value + ">", Target: "string", Kind: "maxLength", Value: value, Validate: "$input.length <= " + props.Value, Exclusive: metadataCommentTagFactory_exclusive("maxLength"), Schema: map[string]any{"maxLength": value}}}}
312
312
  },
313
313
  }
314
314
 
@@ -407,13 +407,28 @@ func metadataCommentTagFactory_parse_type(props struct {
407
407
  "number": {{Name: "Type<" + strconv.Quote(value) + ">", Target: "number", Kind: "type", Value: value, Validate: validate, Exclusive: metadataCommentTagFactory_exclusive("type"), Schema: numberSchema}},
408
408
  }
409
409
  if value == "int64" || value == "uint64" {
410
- // The bigint form used to emit `true` for int64 and a lower bound only for
411
- // uint64, so `bigint & Type<"int64">` -- the spelling the documentation
412
- // recommends -- certified any magnitude at all. Both now delegate to the
413
- // helper that holds the exact inclusive bound a bigint can represent.
414
- bigintValidate := "$importInternal(\"isTypeUint64Bigint\")($input)"
410
+ // Both checks stay inline, spelled exactly as `Type<"int64">` and
411
+ // `Type<"uint64">` declare them, because `@type int64` and
412
+ // `bigint & Type<"int64">` are two spellings of one constraint.
413
+ //
414
+ // That declaration must not name a runtime helper the way the `number` arms
415
+ // above do. A `$importInternal(...)` in a tag template makes the emitted
416
+ // validator import a `typia/lib/internal/*` module, and the declaration
417
+ // lives in `@typia/interface`, which `typia` depends on through a caret
418
+ // range that only floats upward -- so an older `typia` installs a newer
419
+ // `@typia/interface` and emits an import its own runtime never shipped
420
+ // (#2330). `isTypeInt64` and `isTypeUint64` are safe there because
421
+ // `@typia/interface` 13.0.0 already named them and `typia` 13.0.0 already
422
+ // shipped them; a helper introduced later is not, and inside one major
423
+ // there is no range that prevents the pairing.
424
+ //
425
+ // The bound this leaves unenforced is real: int64 accepts any magnitude and
426
+ // uint64 only rejects negatives. #2338 owns restoring it, and only a major
427
+ // can carry it -- an inline exact comparison would name no helper, but
428
+ // tightening an accepted range rejects data that passes today.
429
+ bigintValidate := "BigInt(0) <= $input"
415
430
  if value == "int64" {
416
- bigintValidate = "$importInternal(\"isTypeInt64Bigint\")($input)"
431
+ bigintValidate = "true"
417
432
  }
418
433
  record["bigint"] = []schemametadata.IMetadataTypeTag{
419
434
  {Name: "Type<" + strconv.Quote(value) + ">", Target: "bigint", Kind: "type", Value: value, Validate: bigintValidate, Exclusive: metadataCommentTagFactory_exclusive("type"), Schema: bigintSchema},
@@ -17,6 +17,11 @@ type protobufFactoryNamespace struct{}
17
17
  var ProtobufFactory = protobufFactoryNamespace{}
18
18
 
19
19
  type ProtobufFactory_IProps struct {
20
+ // Method is the fully qualified typia API the call site invoked, exactly as
21
+ // it must appear in the diagnostic code (`typia.protobuf.encode`). It is the
22
+ // sole source of that code: composing the code here from a shorter spelling
23
+ // let the encode and decode programmers, which already pass the whole call
24
+ // accessor, report `typia.protobuf.typia.protobuf.encode`.
20
25
  Method string
21
26
  Checker *shimchecker.Checker
22
27
  Components *schemametadata.MetadataCollection
@@ -40,7 +45,7 @@ func (protobufFactoryNamespace) Metadata(props ProtobufFactory_IProps) *schemame
40
45
  Code string
41
46
  Errors []nativecontext.TransformerError_MetadataFactory_IError
42
47
  }{
43
- Code: "typia.protobuf." + props.Method,
48
+ Code: props.Method,
44
49
  Errors: protobufFactory_errors(result.Errors),
45
50
  }))
46
51
  }