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,309 @@
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+ )
10
+
11
+ // TestCreateAssertErrorFactoryArity verifies that the declared arity of created
12
+ // assert functions agrees with the emitted one (#2328).
13
+ //
14
+ // Every `create*Assert*` factory emits `(input, errorFactory = <create-time
15
+ // factory>) => ...`, but the declarations returned `(input) => T`. A pointwise
16
+ // hand-off such as `rows.map(parseUser)` therefore type-checked while
17
+ // `Array#map` handed the element index to `errorFactory`. The declared surface
18
+ // has to name that parameter, without breaking the documented
19
+ // `AssertionGuard<T>` annotation or an ordinary one-parameter callback
20
+ // position.
21
+ //
22
+ // 1. Type-check a fixture that overrides `errorFactory` at call time on every
23
+ // member of the family, and that pins the `.map` hand-off as an error while
24
+ // the adjacent one-parameter controls still compile.
25
+ // 2. Transform that same fixture and require each member's emitted function to
26
+ // carry the parameter, with factories outside the family as the controls
27
+ // that must not.
28
+ // 3. Transform a runtime fixture, execute it, and require the call-time factory
29
+ // to build the error while a numeric second argument falls back to the
30
+ // ordinary type-guard error.
31
+ func TestCreateAssertErrorFactoryArity(t *testing.T) {
32
+ surface := compareEqualCoverProject(t, "create-assert-error-factory-", createAssertErrorFactorySurfaceSource)
33
+ ttscTypiaTestTypecheck(t, surface)
34
+ createAssertErrorFactoryAssertEmittedArity(t, compareEqualCoverTransform(t, surface))
35
+
36
+ project := compareEqualCoverProject(t, "create-assert-error-factory-runtime-", createAssertErrorFactoryRuntimeSource)
37
+ ttscTypiaTestTypecheck(t, project)
38
+ js := compareEqualCoverTransform(t, project)
39
+ if !strings.Contains(js, "(input, errorFactory)") {
40
+ t.Fatalf("emitted factory lost its errorFactory parameter:\n%s", js)
41
+ }
42
+
43
+ node, err := exec.LookPath("node")
44
+ if err != nil {
45
+ t.Skip("node executable not found")
46
+ }
47
+ runtimeDir := filepath.Join(project, "runtime")
48
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
49
+ t.Fatalf("mkdir runtime dir: %v", err)
50
+ }
51
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
52
+ if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(ttscTypiaTestRewriteCommonJS(t, js)), 0o644); err != nil {
53
+ t.Fatalf("write runtime module: %v", err)
54
+ }
55
+ runner := filepath.Join(runtimeDir, "run.cjs")
56
+ if err := os.WriteFile(runner, []byte(createAssertErrorFactoryRuntimeRunner), 0o644); err != nil {
57
+ t.Fatalf("write runtime runner: %v", err)
58
+ }
59
+ cmd := exec.Command(node, runner)
60
+ cmd.Dir = runtimeDir
61
+ if output, err := cmd.CombinedOutput(); err != nil {
62
+ t.Fatalf("created assert error factory runtime cases failed: %v\n%s", err, output)
63
+ }
64
+ }
65
+
66
+ // createAssertErrorFactoryAssertEmittedArity requires each member of the family
67
+ // to emit the parameter its declaration now names, and each control not to.
68
+ //
69
+ // The declaration and the emit are written on opposite sides of the codebase,
70
+ // so a declaration test alone can over-promise: dropping `Guardian.Parameter`
71
+ // from one programmer would leave the type claiming a parameter the function no
72
+ // longer takes. The emitted body of each member is what settles it.
73
+ func createAssertErrorFactoryAssertEmittedArity(t *testing.T, js string) {
74
+ t.Helper()
75
+ starts := make([]int, len(createAssertErrorFactoryMembers))
76
+ for i, name := range createAssertErrorFactoryMembers {
77
+ // The CommonJS prologue lists every export on one `void 0` line, so the
78
+ // real assignment is the last occurrence, never the first.
79
+ index := strings.LastIndex(js, "exports."+name+" = ")
80
+ if index < 0 {
81
+ t.Fatalf("emit has no assignment for %s:\n%s", name, js)
82
+ }
83
+ starts[i] = index
84
+ }
85
+ for i, name := range createAssertErrorFactoryMembers {
86
+ end := strings.LastIndex(js, "exports."+createAssertErrorFactorySentinel+" = ")
87
+ if i+1 < len(createAssertErrorFactoryMembers) {
88
+ end = starts[i+1]
89
+ }
90
+ if starts[i] >= end {
91
+ t.Fatalf("emitted members are out of source order at %s", name)
92
+ }
93
+ segment := js[starts[i]:end]
94
+ // The returned function is the public one. Every composed member also
95
+ // builds a private `__assert` that takes the parameter, so matching the
96
+ // parameter list anywhere in the segment would keep passing after the
97
+ // returned arrow lost it.
98
+ carries := strings.Contains(segment, "return (input, errorFactory)")
99
+ if strings.HasPrefix(name, "m") && carries == false {
100
+ t.Fatalf("%s lost its errorFactory parameter:\n%s", name, segment)
101
+ }
102
+ if strings.HasPrefix(name, "n") && strings.Contains(segment, "errorFactory") {
103
+ t.Fatalf("%s gained an errorFactory parameter it does not declare:\n%s", name, segment)
104
+ }
105
+ }
106
+ }
107
+
108
+ // createAssertErrorFactoryMembers lists the emitted fixture exports in source
109
+ // order: `m*` is the whole family whose emitted function takes `errorFactory`,
110
+ // `n*` are factories that must not grow one.
111
+ var createAssertErrorFactoryMembers = []string{
112
+ "m01", "m02", "m03", "m04", "m05", "m06", "m07", "m08", "m09",
113
+ "m10", "m11", "m12", "m13", "m14", "m15", "m16", "m17", "m18",
114
+ "n01", "n02", "n03",
115
+ }
116
+
117
+ const createAssertErrorFactorySentinel = "zzz"
118
+
119
+ // createAssertErrorFactorySurfaceSource is type-checked and transformed, but
120
+ // never executed: the http, protobuf and notation members pull runtime helpers
121
+ // this package stubs only for the emit it runs, so the executed fixture stays
122
+ // on the module family.
123
+ const createAssertErrorFactorySurfaceSource = `import { StandardSchemaV1 } from "@standard-schema/spec";
124
+ import typia, { AssertionGuard, TypeGuardError } from "typia";
125
+
126
+ interface User {
127
+ id: number;
128
+ }
129
+ interface StringUser {
130
+ id: string;
131
+ }
132
+ interface SnakeUser {
133
+ user_id: string;
134
+ }
135
+
136
+ type ErrorFactory = (props: TypeGuardError.IProps) => Error;
137
+ type UserGuard = (
138
+ input: unknown,
139
+ errorFactory?: undefined | ErrorFactory,
140
+ ) => asserts input is User;
141
+
142
+ type Assert<T extends true> = T;
143
+ type Equal<X, Y> =
144
+ (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
145
+ ? true
146
+ : false;
147
+
148
+ const factory: ErrorFactory = (props) =>
149
+ Object.assign(new Error("call-time"), { path: props.path });
150
+
151
+ const assertUser = typia.createAssert<User>();
152
+ const assertUserEquals = typia.createAssertEquals<User>();
153
+ const guardUser = typia.createAssertGuard<User>();
154
+ const guardUserEquals = typia.createAssertGuardEquals<User>();
155
+ const jsonParse = typia.json.createAssertParse<User>();
156
+ const jsonStringify = typia.json.createAssertStringify<User>();
157
+ const httpFormData = typia.http.createAssertFormData<StringUser>();
158
+ const httpQuery = typia.http.createAssertQuery<StringUser>();
159
+ const httpHeaders = typia.http.createAssertHeaders<StringUser>();
160
+ const notationCamel = typia.notations.createAssertCamel<SnakeUser>();
161
+ const notationPascal = typia.notations.createAssertPascal<SnakeUser>();
162
+ const notationSnake = typia.notations.createAssertSnake<SnakeUser>();
163
+ const notationKebab = typia.notations.createAssertKebab<SnakeUser>();
164
+ const plainClone = typia.plain.createAssertClone<User>();
165
+ const plainPrune = typia.plain.createAssertPrune<User>();
166
+ const plainClassify = typia.plain.createAssertClassify<User>();
167
+ const protobufDecode = typia.protobuf.createAssertDecode<User>();
168
+ const protobufEncode = typia.protobuf.createAssertEncode<User>();
169
+
170
+ // typia's own declaration of the guard factories, not a local alias: the guard
171
+ // family is the one place where a user annotation could hide a reverted change.
172
+ export type GuardCases = [
173
+ Assert<Equal<typeof guardUser, UserGuard>>,
174
+ Assert<Equal<typeof guardUserEquals, UserGuard>>,
175
+ ];
176
+
177
+ const annotatedGuard: UserGuard = guardUser;
178
+ const annotatedGuardEquals: UserGuard = guardUserEquals;
179
+
180
+ // Every call below is a compile-time assertion that the family member declares
181
+ // the call-time override the emit gives it.
182
+ export const overrides = (
183
+ raw: unknown,
184
+ text: string,
185
+ user: User,
186
+ snake: SnakeUser,
187
+ form: FormData,
188
+ headers: Record<string, string | string[] | undefined>,
189
+ bytes: Uint8Array,
190
+ ): void => {
191
+ assertUser(raw, factory);
192
+ assertUserEquals(raw, factory);
193
+ annotatedGuard(raw, factory);
194
+ annotatedGuardEquals(raw, factory);
195
+ jsonParse(text, factory);
196
+ jsonStringify(user, factory);
197
+ httpFormData(form, factory);
198
+ httpQuery(text, factory);
199
+ httpHeaders(headers, factory);
200
+ notationCamel(snake, factory);
201
+ notationPascal(snake, factory);
202
+ notationSnake(snake, factory);
203
+ notationKebab(snake, factory);
204
+ plainClone(raw, factory);
205
+ plainPrune(raw, factory);
206
+ plainClassify(raw, factory);
207
+ protobufDecode(bytes, factory);
208
+ protobufEncode(user, factory);
209
+ };
210
+
211
+ // The narrowing contract of the guard family survives the extra parameter, and
212
+ // the documented one-parameter annotation still accepts the created guard.
213
+ export const documented: AssertionGuard<User> = typia.createAssertGuard<User>();
214
+ export const narrowed = (raw: unknown): number => {
215
+ annotatedGuard(raw);
216
+ return raw.id;
217
+ };
218
+
219
+ declare const rows: unknown[];
220
+
221
+ // @ts-expect-error Array#map hands the element index to errorFactory.
222
+ export const mappedAssert = rows.map(assertUser);
223
+ // @ts-expect-error the guard family carries the same hazard.
224
+ export const mappedGuard = rows.map(guardUser);
225
+
226
+ // Adjacent one-axis controls that must keep compiling.
227
+ export const mappedExplicit = rows.map((row) => assertUser(row));
228
+ type Parser = (input: unknown) => User;
229
+ export const parser: Parser = assertUser;
230
+ declare function takesParser(parse: (input: unknown) => User): User;
231
+ export const parsed = takesParser(assertUser);
232
+ export const standard: StandardSchemaV1<User, User> = typia.createValidate<User>();
233
+
234
+ // The emitted-arity census. Order is load-bearing: the assertion slices the
235
+ // emit between consecutive assignments, and ` + "`zzz`" + ` closes the last one.
236
+ export const m01 = typia.createAssert<User>();
237
+ export const m02 = typia.createAssertEquals<User>();
238
+ export const m03 = typia.createAssertGuard<User>();
239
+ export const m04 = typia.createAssertGuardEquals<User>();
240
+ export const m05 = typia.json.createAssertParse<User>();
241
+ export const m06 = typia.json.createAssertStringify<User>();
242
+ export const m07 = typia.http.createAssertFormData<StringUser>();
243
+ export const m08 = typia.http.createAssertQuery<StringUser>();
244
+ export const m09 = typia.http.createAssertHeaders<StringUser>();
245
+ export const m10 = typia.notations.createAssertCamel<SnakeUser>();
246
+ export const m11 = typia.notations.createAssertPascal<SnakeUser>();
247
+ export const m12 = typia.notations.createAssertSnake<SnakeUser>();
248
+ export const m13 = typia.notations.createAssertKebab<SnakeUser>();
249
+ export const m14 = typia.plain.createAssertClone<User>();
250
+ export const m15 = typia.plain.createAssertPrune<User>();
251
+ export const m16 = typia.plain.createAssertClassify<User>();
252
+ export const m17 = typia.protobuf.createAssertDecode<User>();
253
+ export const m18 = typia.protobuf.createAssertEncode<User>();
254
+ export const n01 = typia.createIs<User>();
255
+ export const n02 = typia.json.createIsParse<User>();
256
+ export const n03 = typia.plain.createClone<User>();
257
+ export const zzz = 0;
258
+ `
259
+
260
+ const createAssertErrorFactoryRuntimeSource = `import typia, { TypeGuardError } from "typia";
261
+
262
+ interface User {
263
+ id: number;
264
+ }
265
+
266
+ export const assertUser = typia.createAssert<User>();
267
+ export const assertUserEquals = typia.createAssertEquals<User>();
268
+ export const withOverride = (
269
+ input: unknown,
270
+ errorFactory: (props: TypeGuardError.IProps) => Error,
271
+ ): User => assertUser(input, errorFactory);
272
+ `
273
+
274
+ const createAssertErrorFactoryRuntimeRunner = `const mod = require("./main.cjs");
275
+
276
+ const expect = (label, actual, expected) => {
277
+ if (actual !== expected) throw new Error(label + ": expected " + expected + ", got " + actual);
278
+ };
279
+
280
+ const capture = (task) => {
281
+ try {
282
+ task();
283
+ } catch (exp) {
284
+ return exp;
285
+ }
286
+ throw new Error("expected the assertion to throw");
287
+ };
288
+
289
+ expect("valid input passes", 1, mod.assertUser({ id: 1 }).id);
290
+
291
+ // A pointwise hand-off fills errorFactory with the element index. Both the
292
+ // falsy 0 and a truthy index must reach the ordinary type-guard error.
293
+ for (const index of [0, 1, 2]) {
294
+ const error = capture(() => mod.assertUser({ id: "bad" }, index));
295
+ expect("index " + index + " expected", "number", error.expected);
296
+ expect("index " + index + " path", "$input.id", error.path);
297
+ expect("index " + index + " method", "typia.createAssert", error.method);
298
+ }
299
+
300
+ // The declared parameter is real: a callable factory still wins.
301
+ const custom = capture(() =>
302
+ mod.withOverride({ id: "bad" }, (props) => Object.assign(new Error("call-time"), props)),
303
+ );
304
+ expect("call-time factory message", "call-time", custom.message);
305
+ expect("call-time factory path", "$input.id", custom.path);
306
+
307
+ const equals = capture(() => mod.assertUserEquals({ id: 1, extra: true }, 4));
308
+ expect("equals surplus expected", "undefined", equals.expected);
309
+ `
@@ -0,0 +1,216 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "os"
6
+ "os/exec"
7
+ "path/filepath"
8
+ "strings"
9
+ "testing"
10
+ )
11
+
12
+ // TestDefaultLibrarySpoofNativeIdentityTransform keeps a declaration package out
13
+ // of the runtime-native authority even when its file is named like a TypeScript
14
+ // default library (#2200).
15
+ //
16
+ // Runtime-native identity admits a global whose constructor a default library
17
+ // provides, so how "default library" is decided is the whole boundary. `lib.d.ts`
18
+ // is an ordinary published file name, so a base-name test makes that authority
19
+ // claimable by any package a project pulls in through `typeRoots` — the forged
20
+ // declarations below are a full-member copy of the DOM `File` and `Blob`,
21
+ // including their `declare var` constructor bindings, and nothing but the
22
+ // containing directory distinguishes them from the real thing.
23
+ //
24
+ // 1. Publish `lib.dom.d.ts` and `lib.es5.d.ts` from a fixture `@types` package
25
+ // that declares global File and Blob with their constructors.
26
+ // 2. Transform validators for those globals with no DOM library and no Node
27
+ // types loaded, so the forged package is their only declaration source.
28
+ // 3. Require the emit to keep the forged members instead of an `instanceof`.
29
+ // 4. Execute the validators in Node against the forged structural values and
30
+ // against the real runtime instances, requiring an exact case count.
31
+ func TestDefaultLibrarySpoofNativeIdentityTransform(t *testing.T) {
32
+ project := defaultLibrarySpoofNativeIdentityProject(t)
33
+ js, errText, code := ttscTypiaTestCapture(func() int {
34
+ return runTransform([]string{
35
+ "--cwd", project,
36
+ "--tsconfig", "tsconfig.json",
37
+ "--file", "src/input.ts",
38
+ "--output", "js",
39
+ })
40
+ })
41
+ if code != 0 {
42
+ t.Fatalf("default library spoof transform failed: code=%d stderr=\n%s", code, errText)
43
+ }
44
+
45
+ failures := []string{}
46
+ for _, native := range []string{"instanceof File", "instanceof Blob"} {
47
+ if strings.Contains(js, native) {
48
+ failures = append(failures, fmt.Sprintf("a lib.*.d.ts named package declaration was promoted to %q", native))
49
+ }
50
+ }
51
+ for _, member := range []string{"spoofBlobBrand", "spoofFileBrand"} {
52
+ if !strings.Contains(js, member) {
53
+ failures = append(failures, fmt.Sprintf("emit dropped forged declaration member %q", member))
54
+ }
55
+ }
56
+
57
+ output, runtimeErr := defaultLibrarySpoofNativeIdentityRun(t, project, js)
58
+ if runtimeErr != nil {
59
+ failures = append(failures, fmt.Sprintf("runtime matrix failed: %v\n%s", runtimeErr, output))
60
+ }
61
+ if expected := "RAN 6 SPOOF CASES"; !strings.Contains(output, expected) {
62
+ failures = append(failures, fmt.Sprintf("spoof runner did not report %q; got:\n%s", expected, output))
63
+ }
64
+ if len(failures) != 0 {
65
+ t.Fatalf("default library spoof mismatches:\n%s\n\nemit:\n%s", strings.Join(failures, "\n"), js)
66
+ }
67
+ }
68
+
69
+ func defaultLibrarySpoofNativeIdentityProject(t *testing.T) string {
70
+ t.Helper()
71
+ root := ttscTypiaTestRepoRoot(t)
72
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
73
+ if err := os.MkdirAll(base, 0o755); err != nil {
74
+ t.Fatalf("mkdir temp base: %v", err)
75
+ }
76
+ dir, err := os.MkdirTemp(base, "default-library-spoof-native-identity-")
77
+ if err != nil {
78
+ t.Fatalf("create temp fixture: %v", err)
79
+ }
80
+ t.Cleanup(func() {
81
+ _ = os.RemoveAll(dir)
82
+ })
83
+ for name, content := range map[string]string{
84
+ "tsconfig.json": defaultLibrarySpoofNativeIdentityTSConfig,
85
+ "node_modules/@types/spoof-lib/package.json": defaultLibrarySpoofNativeIdentityPackageJSON,
86
+ "node_modules/@types/spoof-lib/lib.dom.d.ts": defaultLibrarySpoofNativeIdentityDeclarations,
87
+ "node_modules/@types/spoof-lib/lib.es5.d.ts": defaultLibrarySpoofNativeIdentityExtraDeclarations,
88
+ "src/input.ts": defaultLibrarySpoofNativeIdentitySource,
89
+ } {
90
+ path := filepath.Join(dir, filepath.FromSlash(name))
91
+ if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
92
+ t.Fatalf("mkdir fixture path %s: %v", filepath.Dir(path), err)
93
+ }
94
+ if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
95
+ t.Fatalf("write fixture file %s: %v", path, err)
96
+ }
97
+ }
98
+ return dir
99
+ }
100
+
101
+ func defaultLibrarySpoofNativeIdentityRun(t *testing.T, project string, js string) (string, error) {
102
+ t.Helper()
103
+ node, err := exec.LookPath("node")
104
+ if err != nil {
105
+ t.Skip("node executable not found")
106
+ return "", nil
107
+ }
108
+ runtimeDir := filepath.Join(project, "runtime")
109
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
110
+ t.Fatalf("mkdir runtime dir: %v", err)
111
+ }
112
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
113
+ for name, content := range map[string]string{
114
+ "input.cjs": ttscTypiaTestRewriteCommonJS(t, js),
115
+ "run.cjs": defaultLibrarySpoofNativeIdentityRuntimeRunner,
116
+ } {
117
+ if err := os.WriteFile(filepath.Join(runtimeDir, name), []byte(content), 0o644); err != nil {
118
+ t.Fatalf("write runtime file %s: %v", name, err)
119
+ }
120
+ }
121
+ cmd := exec.Command(node, filepath.Join(runtimeDir, "run.cjs"))
122
+ cmd.Dir = runtimeDir
123
+ output, err := cmd.CombinedOutput()
124
+ return string(output), err
125
+ }
126
+
127
+ const defaultLibrarySpoofNativeIdentityTSConfig = `{
128
+ "compilerOptions": {
129
+ "target": "ES2022",
130
+ "module": "commonjs",
131
+ "moduleResolution": "bundler",
132
+ "ignoreDeprecations": "6.0",
133
+ "lib": ["ES2022"],
134
+ "types": ["spoof-lib"],
135
+ "esModuleInterop": true,
136
+ "strict": true,
137
+ "skipLibCheck": true
138
+ },
139
+ "include": ["src"]
140
+ }
141
+ `
142
+
143
+ const defaultLibrarySpoofNativeIdentityPackageJSON = `{
144
+ "name": "@types/spoof-lib",
145
+ "version": "1.0.0",
146
+ "types": "lib.dom.d.ts"
147
+ }
148
+ `
149
+
150
+ const defaultLibrarySpoofNativeIdentityDeclarations = `/// <reference path="./lib.es5.d.ts" />
151
+
152
+ interface Blob {
153
+ readonly size: number;
154
+ readonly type: string;
155
+ spoofBlobBrand: string;
156
+ }
157
+ declare var Blob: {
158
+ prototype: Blob;
159
+ new (parts?: unknown[], options?: unknown): Blob;
160
+ };
161
+ `
162
+
163
+ const defaultLibrarySpoofNativeIdentityExtraDeclarations = `interface File extends Blob {
164
+ readonly lastModified: number;
165
+ readonly name: string;
166
+ readonly webkitRelativePath: string;
167
+ spoofFileBrand: string;
168
+ }
169
+ declare var File: {
170
+ prototype: File;
171
+ new (parts: unknown[], name: string, options?: unknown): File;
172
+ };
173
+ `
174
+
175
+ const defaultLibrarySpoofNativeIdentitySource = `import typia from "typia";
176
+
177
+ export const createdIsBlob = typia.createIs<Blob>();
178
+ export const createdIsFile = typia.createIs<File>();
179
+ `
180
+
181
+ const defaultLibrarySpoofNativeIdentityRuntimeRunner = `const validators = require("./input.cjs");
182
+
183
+ let ran = 0;
184
+ const failures = [];
185
+ const eq = (name, actual, expected) => {
186
+ ran += 1;
187
+ if (actual !== expected) {
188
+ failures.push(name + ": expected " + expected + " but got " + actual);
189
+ }
190
+ };
191
+
192
+ const spoofBlob = {
193
+ size: 1,
194
+ type: "text/plain",
195
+ spoofBlobBrand: "spoof",
196
+ };
197
+ const spoofFile = {
198
+ ...spoofBlob,
199
+ lastModified: 0,
200
+ name: "x.txt",
201
+ webkitRelativePath: "",
202
+ spoofFileBrand: "spoof",
203
+ };
204
+
205
+ eq("spoof Blob structural", validators.createdIsBlob(spoofBlob), true);
206
+ eq("spoof Blob rejects runtime instance", validators.createdIsBlob(new Blob(["x"])), false);
207
+ eq("spoof Blob missing brand", validators.createdIsBlob({ size: 1, type: "text/plain" }), false);
208
+ eq("spoof File structural", validators.createdIsFile(spoofFile), true);
209
+ eq("spoof File rejects runtime instance", validators.createdIsFile(new File(["x"], "x.txt")), false);
210
+ eq("spoof File missing brand", validators.createdIsFile({ ...spoofFile, spoofFileBrand: undefined }), false);
211
+
212
+ console.log("RAN " + ran + " SPOOF CASES");
213
+ if (failures.length !== 0) {
214
+ throw new Error("MISMATCHES:\n" + failures.join("\n"));
215
+ }
216
+ `