typia 13.1.19 → 13.2.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 (169) 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/internal/_ProtobufReader.d.ts +18 -3
  11. package/lib/internal/_ProtobufReader.js +39 -11
  12. package/lib/internal/_ProtobufReader.js.map +1 -1
  13. package/lib/internal/_ProtobufReader.mjs +37 -10
  14. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  15. package/lib/internal/_jsonStringifyArray.d.ts +1 -0
  16. package/lib/internal/_jsonStringifyArray.js +48 -0
  17. package/lib/internal/_jsonStringifyArray.js.map +1 -0
  18. package/lib/internal/_jsonStringifyArray.mjs +40 -0
  19. package/lib/internal/_jsonStringifyArray.mjs.map +1 -0
  20. package/lib/internal/_jsonStringifyElement.d.ts +1 -0
  21. package/lib/internal/_jsonStringifyElement.js +23 -0
  22. package/lib/internal/_jsonStringifyElement.js.map +1 -0
  23. package/lib/internal/_jsonStringifyElement.mjs +23 -0
  24. package/lib/internal/_jsonStringifyElement.mjs.map +1 -0
  25. package/lib/internal/_jsonStringifyProperty.d.ts +1 -0
  26. package/lib/internal/_jsonStringifyProperty.js +31 -0
  27. package/lib/internal/_jsonStringifyProperty.js.map +1 -0
  28. package/lib/internal/_jsonStringifyProperty.mjs +31 -0
  29. package/lib/internal/_jsonStringifyProperty.mjs.map +1 -0
  30. package/lib/internal/_llmApplicationFinalize.js +1 -1
  31. package/lib/internal/_llmApplicationFinalize.js.map +1 -1
  32. package/lib/internal/_llmApplicationFinalize.mjs +1 -1
  33. package/lib/internal/_llmApplicationFinalize.mjs.map +1 -1
  34. package/lib/internal/_randomFormatByte.js +24 -1
  35. package/lib/internal/_randomFormatByte.js.map +1 -1
  36. package/lib/internal/_randomFormatByte.mjs +20 -2
  37. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  38. package/lib/internal/_randomFormatDate.d.ts +3 -6
  39. package/lib/internal/_randomFormatDate.js +2 -10
  40. package/lib/internal/_randomFormatDate.js.map +1 -1
  41. package/lib/internal/_randomFormatDate.mjs +2 -6
  42. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  43. package/lib/internal/_randomFormatDatetime.d.ts +3 -6
  44. package/lib/internal/_randomFormatDatetime.js +25 -8
  45. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  46. package/lib/internal/_randomFormatDatetime.mjs +17 -7
  47. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  48. package/lib/internal/_randomFormatDuration.js +23 -15
  49. package/lib/internal/_randomFormatDuration.js.map +1 -1
  50. package/lib/internal/_randomFormatDuration.mjs +23 -15
  51. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  52. package/lib/internal/_randomFormatIpv4.js +31 -1
  53. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  54. package/lib/internal/_randomFormatIpv4.mjs +23 -2
  55. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  56. package/lib/internal/_randomFormatIpv6.js +57 -1
  57. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  58. package/lib/internal/_randomFormatIpv6.mjs +45 -2
  59. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  60. package/lib/internal/_randomFormatJsonPointer.js +14 -2
  61. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  62. package/lib/internal/_randomFormatJsonPointer.mjs +13 -3
  63. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  64. package/lib/internal/_randomFormatRegex.js +14 -1
  65. package/lib/internal/_randomFormatRegex.js.map +1 -1
  66. package/lib/internal/_randomFormatRegex.mjs +14 -2
  67. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  68. package/lib/internal/_randomFormatRelativeJsonPointer.js +19 -5
  69. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  70. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +21 -6
  71. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  72. package/lib/internal/_randomFormatTime.js +33 -7
  73. package/lib/internal/_randomFormatTime.js.map +1 -1
  74. package/lib/internal/_randomFormatTime.mjs +37 -5
  75. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  76. package/lib/internal/_randomPattern.js.map +1 -1
  77. package/lib/internal/_randomPattern.mjs.map +1 -1
  78. package/lib/internal/_randomStringLength.d.ts +41 -10
  79. package/lib/internal/_randomStringLength.js +49 -13
  80. package/lib/internal/_randomStringLength.js.map +1 -1
  81. package/lib/internal/_randomStringLength.mjs +48 -13
  82. package/lib/internal/_randomStringLength.mjs.map +1 -1
  83. package/lib/internal/private/__notationRename.js.map +1 -1
  84. package/lib/internal/private/__notationRename.mjs.map +1 -1
  85. package/lib/internal/private/__randomComposition.d.ts +23 -0
  86. package/lib/internal/private/__randomComposition.js +48 -0
  87. package/lib/internal/private/__randomComposition.js.map +1 -0
  88. package/lib/internal/private/__randomComposition.mjs +54 -0
  89. package/lib/internal/private/__randomComposition.mjs.map +1 -0
  90. package/lib/internal/private/__randomEpoch.d.ts +19 -0
  91. package/lib/internal/private/__randomEpoch.js +31 -0
  92. package/lib/internal/private/__randomEpoch.js.map +1 -0
  93. package/lib/internal/private/__randomEpoch.mjs +28 -0
  94. package/lib/internal/private/__randomEpoch.mjs.map +1 -0
  95. package/native/cmd/ttsc-typia/build.go +3 -0
  96. package/native/cmd/ttsc-typia/callable_interface_function_semantics_transform_test.go +331 -0
  97. package/native/cmd/ttsc-typia/callable_type_literal_boundaries_transform_test.go +1184 -0
  98. package/native/cmd/ttsc-typia/compare_functional_union_membership_transform_test.go +434 -0
  99. package/native/cmd/ttsc-typia/compare_template_literal_union_transform_test.go +241 -0
  100. package/native/cmd/ttsc-typia/default_library_spoof_native_identity_transform_test.go +216 -0
  101. package/native/cmd/ttsc-typia/json_schema_dynamic_key_determinism_transform_test.go +246 -0
  102. package/native/cmd/ttsc-typia/json_stringify_contextual_undefined_transform_test.go +556 -0
  103. package/native/cmd/ttsc-typia/lib_replacement_native_identity_transform_test.go +277 -0
  104. package/native/cmd/ttsc-typia/native_named_intersection_union_transform_test.go +390 -0
  105. package/native/cmd/ttsc-typia/node_buffer_native_exports_is_transform_test.go +526 -0
  106. package/native/cmd/ttsc-typia/package_declaration_native_identity_is_transform_test.go +293 -0
  107. package/native/cmd/ttsc-typia/protobuf_diagnostic_code_transform_test.go +167 -0
  108. package/native/cmd/ttsc-typia/symbol_index_domain_transform_test.go +316 -0
  109. package/native/cmd/ttsc-typia/transform.go +23 -0
  110. package/native/cmd/ttsc-typia/transform_helpers_test.go +77 -2
  111. package/native/cmd/ttsc-typia/user_global_native_identity_transform_test.go +484 -0
  112. package/native/core/factories/ProtobufFactory.go +6 -1
  113. package/native/core/factories/internal/metadata/MetadataHelper.go +185 -30
  114. package/native/core/factories/internal/metadata/emplace_metadata_object.go +25 -0
  115. package/native/core/factories/internal/metadata/iterate_metadata_function.go +1 -1
  116. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +103 -23
  117. package/native/core/factories/internal/metadata/iterate_metadata_map.go +3 -7
  118. package/native/core/factories/internal/metadata/iterate_metadata_native.go +32 -14
  119. package/native/core/factories/internal/metadata/iterate_metadata_set.go +3 -7
  120. package/native/core/programmers/compare/CompareEqualProgrammer.go +27 -13
  121. package/native/core/programmers/helpers/FunctionProgrammer.go +6 -13
  122. package/native/core/programmers/helpers/StringifyJoinder.go +129 -50
  123. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +116 -120
  124. package/native/core/programmers/iterate/iterate_check_coverage_test.go +76 -158
  125. package/native/core/programmers/iterate/iterate_utility_coverage_test.go +231 -270
  126. package/native/core/programmers/iterate/json_schema_object.go +49 -7
  127. package/native/core/programmers/iterate/json_schema_pattern_property_order_test.go +44 -0
  128. package/native/core/programmers/iterate/openapi_v3_downgrader.go +34 -1
  129. package/native/core/programmers/iterate/template_runtime_pattern.go +11 -0
  130. package/native/core/programmers/json/JsonStringifyProgrammer.go +47 -6
  131. package/native/core/programmers/llm/LlmApplicationProgrammer.go +9 -1
  132. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +1 -1
  133. package/native/core/schemas/metadata/MetadataCollection.go +0 -9
  134. package/native/core/schemas/metadata/MetadataDefaultLibrary.go +81 -0
  135. package/native/core/schemas/metadata/MetadataObjectType.go +7 -18
  136. package/native/go.mod +4 -4
  137. package/native/transform/features/protobuf/ProtobufMessageTransformer.go +1 -1
  138. package/package.json +3 -7
  139. package/src/executable/FileSystemIdentity.ts +33 -0
  140. package/src/executable/TypiaGenerateWizard.ts +18 -12
  141. package/src/internal/_ProtobufReader.ts +40 -11
  142. package/src/internal/_jsonStringifyArray.ts +50 -0
  143. package/src/internal/_jsonStringifyElement.ts +19 -0
  144. package/src/internal/_jsonStringifyProperty.ts +30 -0
  145. package/src/internal/_llmApplicationFinalize.ts +6 -1
  146. package/src/internal/_randomFormatByte.ts +30 -3
  147. package/src/internal/_randomFormatDate.ts +4 -20
  148. package/src/internal/_randomFormatDatetime.ts +34 -20
  149. package/src/internal/_randomFormatDuration.ts +19 -4
  150. package/src/internal/_randomFormatIpv4.ts +43 -3
  151. package/src/internal/_randomFormatIpv6.ts +67 -3
  152. package/src/internal/_randomFormatJsonPointer.ts +23 -3
  153. package/src/internal/_randomFormatRegex.ts +21 -3
  154. package/src/internal/_randomFormatRelativeJsonPointer.ts +23 -10
  155. package/src/internal/_randomFormatTime.ts +45 -12
  156. package/src/internal/_randomPattern.ts +4 -1
  157. package/src/internal/_randomStringLength.ts +61 -17
  158. package/src/internal/private/__notationRename.ts +1 -4
  159. package/src/internal/private/__randomComposition.ts +50 -0
  160. package/src/internal/private/__randomEpoch.ts +34 -0
  161. package/native/adapter/visit.go +0 -173
  162. package/native/adapter/visit_property_chain_edges_test.go +0 -129
  163. package/native/core/programmers/helpers/disable_function_programmer_declare.go +0 -10
  164. package/native/core/programmers/iterate/check_union_array_like.go +0 -422
  165. package/native/core/programmers/iterate/prune_object_properties.go +0 -105
  166. package/native/core/programmers/iterate/stringify_dynamic_properties.go +0 -219
  167. package/native/core/programmers/iterate/stringify_native.go +0 -14
  168. package/native/core/programmers/iterate/stringify_regular_properties.go +0 -112
  169. package/native/core/schemas/metadata/MetadataApplication.go +0 -41
@@ -0,0 +1,316 @@
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ // TestSymbolIndexDomainTransform verifies a symbol index signature stays out
11
+ // of typia's string-keyed validation and JSON Schema shape (#2240).
12
+ //
13
+ // TypeScript keeps string and symbol index domains distinct, including when a
14
+ // symbol index key is intersected with a nominal brand. This regression pins
15
+ // that boundary through the real transform because treating every checker
16
+ // IndexInfo as a JSON string index makes unrelated Object.keys values inherit a
17
+ // symbol index's value constraint. An ordinary string index and the explicit
18
+ // symbol-member behavior fixed by #2226 are adjacent controls.
19
+ //
20
+ // 1. Compile checker-level keyof assertions for symbol and string indexes.
21
+ // 2. Execute validators over ordinary extras and symbol-valued properties.
22
+ // 3. Compare the symbol-index schema exactly with a plain-object control while
23
+ // requiring a normal string index to retain additionalProperties.
24
+ func TestSymbolIndexDomainTransform(t *testing.T) {
25
+ project := symbolIndexDomainProject(t)
26
+ js := symbolIndexDomainTransform(t, project)
27
+ symbolIndexDomainRunRuntimeCases(t, project, js)
28
+ }
29
+
30
+ func symbolIndexDomainProject(t *testing.T) string {
31
+ t.Helper()
32
+ root := ttscTypiaTestRepoRoot(t)
33
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
34
+ if err := os.MkdirAll(base, 0o755); err != nil {
35
+ t.Fatalf("mkdir temp base: %v", err)
36
+ }
37
+ dir, err := os.MkdirTemp(base, "symbol-index-domain-")
38
+ if err != nil {
39
+ t.Fatalf("create temp fixture: %v", err)
40
+ }
41
+ t.Cleanup(func() {
42
+ _ = os.RemoveAll(dir)
43
+ })
44
+ src := filepath.Join(dir, "src")
45
+ if err := os.MkdirAll(src, 0o755); err != nil {
46
+ t.Fatalf("mkdir fixture src: %v", err)
47
+ }
48
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(symbolIndexDomainTSConfig), 0o644); err != nil {
49
+ t.Fatalf("write tsconfig: %v", err)
50
+ }
51
+ if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(symbolIndexDomainSource), 0o644); err != nil {
52
+ t.Fatalf("write source: %v", err)
53
+ }
54
+ return dir
55
+ }
56
+
57
+ func symbolIndexDomainTransform(t *testing.T, project string) string {
58
+ t.Helper()
59
+ out, errText, code := ttscTypiaTestCapture(func() int {
60
+ return runTransform([]string{
61
+ "--cwd", project,
62
+ "--tsconfig", "tsconfig.json",
63
+ "--file", "src/main.ts",
64
+ "--output", "js",
65
+ })
66
+ })
67
+ if code != 0 {
68
+ t.Fatalf("symbol index domain transform failed: code=%d stderr=\n%s", code, errText)
69
+ }
70
+ return out
71
+ }
72
+
73
+ func symbolIndexDomainRunRuntimeCases(t *testing.T, project string, js string) {
74
+ t.Helper()
75
+ node, err := exec.LookPath("node")
76
+ if err != nil {
77
+ t.Skip("node executable not found")
78
+ }
79
+ runtimeDir := filepath.Join(project, "runtime")
80
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
81
+ t.Fatalf("mkdir runtime dir: %v", err)
82
+ }
83
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
84
+ runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
85
+ if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
86
+ t.Fatalf("write runtime module: %v", err)
87
+ }
88
+ runner := filepath.Join(runtimeDir, "run.cjs")
89
+ if err := os.WriteFile(runner, []byte(symbolIndexDomainRuntimeRunner), 0o644); err != nil {
90
+ t.Fatalf("write runtime runner: %v", err)
91
+ }
92
+ cmd := exec.Command(node, runner)
93
+ cmd.Dir = runtimeDir
94
+ if output, err := cmd.CombinedOutput(); err != nil {
95
+ t.Fatalf("symbol index domain runtime cases failed: %v\n%s", err, output)
96
+ }
97
+ }
98
+
99
+ const symbolIndexDomainTSConfig = `{
100
+ "compilerOptions": {
101
+ "target": "ES2022",
102
+ "module": "commonjs",
103
+ "moduleResolution": "bundler",
104
+ "ignoreDeprecations": "6.0",
105
+ "types": ["*"],
106
+ "esModuleInterop": true,
107
+ "strict": true,
108
+ "skipLibCheck": true
109
+ },
110
+ "include": ["src"]
111
+ }
112
+ `
113
+
114
+ const symbolIndexDomainSource = `import typia from "typia";
115
+
116
+ declare const explicitSymbol: unique symbol;
117
+
118
+ interface SymbolIndex {
119
+ name: string;
120
+ [key: symbol]: number;
121
+ }
122
+
123
+ type BrandedSymbol = symbol & {
124
+ readonly __brand: unique symbol;
125
+ };
126
+
127
+ interface BrandedSymbolIndex {
128
+ name: string;
129
+ [key: BrandedSymbol]: number;
130
+ }
131
+
132
+ interface PlainObject {
133
+ name: string;
134
+ }
135
+
136
+ interface StringIndex {
137
+ name: string;
138
+ [key: string]: string;
139
+ }
140
+
141
+ interface ExplicitSymbolMember {
142
+ name: string;
143
+ [explicitSymbol]: number;
144
+ }
145
+
146
+ type Assert<T extends true> = T;
147
+ type _SymbolIndexHasNoStringDomain = Assert<
148
+ string extends keyof SymbolIndex ? false : true
149
+ >;
150
+ type _SymbolIndexHasNoNumberDomain = Assert<
151
+ number extends keyof SymbolIndex ? false : true
152
+ >;
153
+ type _SymbolIndexHasSymbolDomain = Assert<
154
+ symbol extends keyof SymbolIndex ? true : false
155
+ >;
156
+ type _BrandedSymbolIndexHasNoStringDomain = Assert<
157
+ string extends keyof BrandedSymbolIndex ? false : true
158
+ >;
159
+ type _BrandedSymbolIndexHasNoNumberDomain = Assert<
160
+ number extends keyof BrandedSymbolIndex ? false : true
161
+ >;
162
+ type _BrandedSymbolIndexHasBrandedDomain = Assert<
163
+ BrandedSymbol extends keyof BrandedSymbolIndex ? true : false
164
+ >;
165
+ type _StringIndexHasStringDomain = Assert<
166
+ string extends keyof StringIndex ? true : false
167
+ >;
168
+ type _StringIndexHasNumberDomain = Assert<
169
+ number extends keyof StringIndex ? true : false
170
+ >;
171
+ type _StringIndexHasNoSymbolDomain = Assert<
172
+ symbol extends keyof StringIndex ? false : true
173
+ >;
174
+ type _ExplicitSymbolMemberIsPresent = Assert<
175
+ typeof explicitSymbol extends keyof ExplicitSymbolMember ? true : false
176
+ >;
177
+
178
+ export const isSymbolIndex = typia.createIs<SymbolIndex>();
179
+ export const isBrandedSymbolIndex =
180
+ typia.createIs<BrandedSymbolIndex>();
181
+ export const isPlainObject = typia.createIs<PlainObject>();
182
+ export const isStringIndex = typia.createIs<StringIndex>();
183
+ export const isExplicitSymbolMember =
184
+ typia.createIs<ExplicitSymbolMember>();
185
+ export const schemas = typia.json.schemas<[
186
+ SymbolIndex,
187
+ BrandedSymbolIndex,
188
+ PlainObject,
189
+ StringIndex,
190
+ ExplicitSymbolMember,
191
+ ]>();
192
+ `
193
+
194
+ const symbolIndexDomainRuntimeRunner = `const mod = require("./main.cjs");
195
+
196
+ const failures = [];
197
+ const expect = (label, actual, expected) => {
198
+ if (actual !== expected) {
199
+ failures.push(
200
+ label +
201
+ ": expected " +
202
+ JSON.stringify(expected) +
203
+ " but got " +
204
+ JSON.stringify(actual),
205
+ );
206
+ }
207
+ };
208
+
209
+ expect("symbol index plain", mod.isSymbolIndex({ name: "x" }), true);
210
+ expect(
211
+ "symbol index ignores a numeric string extra",
212
+ mod.isSymbolIndex({ name: "x", extra: 1 }),
213
+ true,
214
+ );
215
+ expect(
216
+ "symbol index ignores a string extra",
217
+ mod.isSymbolIndex({ name: "x", extra: "unrelated" }),
218
+ true,
219
+ );
220
+ expect(
221
+ "symbol index ignores a matching symbol value",
222
+ mod.isSymbolIndex({ name: "x", [Symbol("key")]: 1 }),
223
+ true,
224
+ );
225
+ expect(
226
+ "symbol index ignores a non-matching symbol value",
227
+ mod.isSymbolIndex({ name: "x", [Symbol("key")]: "outside-json-shape" }),
228
+ true,
229
+ );
230
+ expect("symbol index validates named properties", mod.isSymbolIndex({ name: 1 }), false);
231
+
232
+ expect(
233
+ "branded symbol index plain",
234
+ mod.isBrandedSymbolIndex({ name: "x" }),
235
+ true,
236
+ );
237
+ expect(
238
+ "branded symbol index ignores a string extra",
239
+ mod.isBrandedSymbolIndex({ name: "x", extra: "unrelated" }),
240
+ true,
241
+ );
242
+ expect(
243
+ "branded symbol index ignores a matching symbol value",
244
+ mod.isBrandedSymbolIndex({ name: "x", [Symbol("key")]: 1 }),
245
+ true,
246
+ );
247
+ expect(
248
+ "branded symbol index ignores a non-matching symbol value",
249
+ mod.isBrandedSymbolIndex({ name: "x", [Symbol("key")]: "outside-json-shape" }),
250
+ true,
251
+ );
252
+ expect(
253
+ "branded symbol index validates named properties",
254
+ mod.isBrandedSymbolIndex({ name: 1 }),
255
+ false,
256
+ );
257
+
258
+ expect("plain object ignores a string extra", mod.isPlainObject({ name: "x", extra: 1 }), true);
259
+ expect("plain object validates named properties", mod.isPlainObject({ name: 1 }), false);
260
+
261
+ expect("string index accepts matching extra", mod.isStringIndex({ name: "x", extra: "ok" }), true);
262
+ expect("string index rejects mismatching extra", mod.isStringIndex({ name: "x", extra: 1 }), false);
263
+
264
+ expect(
265
+ "explicit symbol member remains outside the JSON shape",
266
+ mod.isExplicitSymbolMember({ name: "x", [Symbol("member")]: "ignored" }),
267
+ true,
268
+ );
269
+ expect(
270
+ "explicit symbol member validates named properties",
271
+ mod.isExplicitSymbolMember({ name: 1 }),
272
+ false,
273
+ );
274
+
275
+ const schemas = mod.schemas.components.schemas;
276
+ const plain = {
277
+ type: "object",
278
+ properties: { name: { type: "string" } },
279
+ required: ["name"],
280
+ additionalProperties: false,
281
+ };
282
+ const stringIndex = {
283
+ type: "object",
284
+ properties: { name: { type: "string" } },
285
+ required: ["name"],
286
+ additionalProperties: { type: "string" },
287
+ };
288
+ expect(
289
+ "plain object exact schema",
290
+ JSON.stringify(schemas.PlainObject),
291
+ JSON.stringify(plain),
292
+ );
293
+ expect(
294
+ "symbol index exact schema",
295
+ JSON.stringify(schemas.SymbolIndex),
296
+ JSON.stringify(plain),
297
+ );
298
+ expect(
299
+ "branded symbol index exact schema",
300
+ JSON.stringify(schemas.BrandedSymbolIndex),
301
+ JSON.stringify(plain),
302
+ );
303
+ expect(
304
+ "explicit symbol member exact schema",
305
+ JSON.stringify(schemas.ExplicitSymbolMember),
306
+ JSON.stringify(plain),
307
+ );
308
+ expect(
309
+ "string index exact schema",
310
+ JSON.stringify(schemas.StringIndex),
311
+ JSON.stringify(stringIndex),
312
+ );
313
+ if (failures.length !== 0) {
314
+ throw new Error("MISMATCHES:\n" + failures.join("\n"));
315
+ }
316
+ `
@@ -80,6 +80,8 @@ func runTransform(args []string) int {
80
80
  return 2
81
81
  }
82
82
  defer prog.Close()
83
+ registerTypiaDefaultLibraryClassifier(prog)
84
+ defer schemametadata.MetadataDefaultLibrary_release(prog.Checker)
83
85
 
84
86
  transformDiags := []typiaTransformDiagnostic{}
85
87
  transformOptions := pluginOptions.TransformOptions()
@@ -122,6 +124,27 @@ func runTransform(args []string) int {
122
124
  })
123
125
  }
124
126
 
127
+ // registerTypiaDefaultLibraryClassifier hands metadata analysis the program's
128
+ // own default-library classification, which runtime-native identity is decided
129
+ // from: a global is the JavaScript built-in only when a runtime authority
130
+ // declares it (#2200). `prog.TSProgram.IsLibFile` is the same oracle the
131
+ // dependency collector above uses, and for the same reason — a default library
132
+ // is not recognizable from its file name under `bundled:///`, `noembed`, or
133
+ // `libReplacement` (#2108).
134
+ //
135
+ // Every program-loading host registers it against the checker whose types the
136
+ // analysis reads, and releases it when that program closes, so no closed
137
+ // program's checker stays reachable from the registry.
138
+ func registerTypiaDefaultLibraryClassifier(prog *driver.Program) {
139
+ if prog == nil || prog.TSProgram == nil {
140
+ return
141
+ }
142
+ program := prog.TSProgram
143
+ schemametadata.MetadataDefaultLibrary_register(prog.Checker, func(source *shimast.SourceFile) bool {
144
+ return source != nil && program.IsLibFile(source)
145
+ })
146
+ }
147
+
125
148
  // runTransformSingle is the single-file counterpart of runTransformProject's
126
149
  // diagnostic decision: produce the artifact into memory, then publish it only
127
150
  // when typia's analysis reported nothing. Every single-file output mode routes
@@ -6,6 +6,7 @@ import (
6
6
  "os/exec"
7
7
  "path/filepath"
8
8
  "runtime"
9
+ "sort"
9
10
  "strings"
10
11
  "testing"
11
12
  )
@@ -68,6 +69,11 @@ func ttscTypiaTestWriteCommonRuntimeStubs(t *testing.T, runtimeDir string) {
68
69
  "access-expression-stub.cjs": ttscTypiaTestAccessExpressionStub,
69
70
  "string-length-stub.cjs": ttscTypiaTestStringLengthStub,
70
71
  "notation-stub.cjs": ttscTypiaTestNotationStub,
72
+ "json-stringify-array-stub.cjs": ttscTypiaTestJsonStringifyArrayStub,
73
+ "json-stringify-property-stub.cjs": ttscTypiaTestJsonStringifyPropertyStub,
74
+ "json-stringify-element-stub.cjs": ttscTypiaTestJsonStringifyElementStub,
75
+ "json-stringify-tail-stub.cjs": ttscTypiaTestJsonStringifyTailStub,
76
+ "random-string-stub.cjs": ttscTypiaTestRandomStringStub,
71
77
  }
72
78
  for name, content := range files {
73
79
  if err := os.WriteFile(filepath.Join(runtimeDir, name), []byte(content), 0o644); err != nil {
@@ -85,6 +91,11 @@ func ttscTypiaTestRewriteCommonJS(t *testing.T, js string) string {
85
91
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_functionalTypeGuardErrorFactory")`, `require("./functional-error-stub.cjs")`)
86
92
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_accessExpressionAsString")`, `require("./access-expression-stub.cjs")`)
87
93
  runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_stringLength")`, `require("./string-length-stub.cjs")`)
94
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyArray")`, `require("./json-stringify-array-stub.cjs")`)
95
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyProperty")`, `require("./json-stringify-property-stub.cjs")`)
96
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyElement")`, `require("./json-stringify-element-stub.cjs")`)
97
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_jsonStringifyTail")`, `require("./json-stringify-tail-stub.cjs")`)
98
+ runtimeJS = strings.ReplaceAll(runtimeJS, `require("typia/lib/internal/_randomString")`, `require("./random-string-stub.cjs")`)
88
99
  for _, helper := range []string{"_notationAssign", "_notationCamel", "_notationKebab", "_notationKeyCollision", "_notationPascal", "_notationSnake"} {
89
100
  runtimeJS = strings.ReplaceAll(
90
101
  runtimeJS,
@@ -93,9 +104,29 @@ func ttscTypiaTestRewriteCommonJS(t *testing.T, js string) string {
93
104
  )
94
105
  }
95
106
  for _, needle := range []string{`require("typia")`, `require('typia')`, `from "typia"`, `from 'typia'`, `typia/lib/internal/`} {
96
- if strings.Contains(runtimeJS, needle) {
97
- t.Fatalf("runtime module still contains unresolved typia import %q", needle)
107
+ if !strings.Contains(runtimeJS, needle) {
108
+ continue
98
109
  }
110
+ // Name the modules that are actually unmapped. Reporting only the needle
111
+ // makes every new internal helper look like the same failure and sends the
112
+ // reader hunting through the emit for it.
113
+ if needle == `typia/lib/internal/` {
114
+ unresolved := map[string]bool{}
115
+ for _, part := range strings.Split(runtimeJS, needle)[1:] {
116
+ end := strings.IndexAny(part, "\"')")
117
+ if end < 0 {
118
+ end = len(part)
119
+ }
120
+ unresolved[part[:end]] = true
121
+ }
122
+ names := make([]string, 0, len(unresolved))
123
+ for name := range unresolved {
124
+ names = append(names, name)
125
+ }
126
+ sort.Strings(names)
127
+ t.Fatalf("runtime module has no stub for typia internal helpers: %s", strings.Join(names, ", "))
128
+ }
129
+ t.Fatalf("runtime module still contains unresolved typia import %q", needle)
99
130
  }
100
131
  return runtimeJS
101
132
  }
@@ -142,6 +173,50 @@ const ttscTypiaTestFunctionalErrorStub = `module.exports._functionalTypeGuardErr
142
173
  Object.assign(new Error(props.expected), props);
143
174
  `
144
175
 
176
+ // The two JSON stringify stubs mirror packages/typia/src/internal exactly. They
177
+ // are runtime doubles for the emit these tests execute; the shipped helpers
178
+ // themselves are exercised by the TypeScript suites against the real package.
179
+ const ttscTypiaTestJsonStringifyArrayStub = `module.exports._jsonStringifyArray = (elements, mapper) => {
180
+ const length = Math.min(
181
+ Math.max(Math.trunc(elements.length) || 0, 0),
182
+ Number.MAX_SAFE_INTEGER,
183
+ );
184
+ let output = "";
185
+ for (let i = 0; i < length; ++i) {
186
+ const elem = elements[i];
187
+ const text = elem === undefined ? undefined : mapper(elem, i);
188
+ output += (i === 0 ? "" : ",") + (text === undefined ? "null" : text);
189
+ }
190
+ return output;
191
+ };
192
+ `
193
+
194
+ const ttscTypiaTestJsonStringifyPropertyStub = `module.exports._jsonStringifyProperty = (head, text, tail) =>
195
+ text === undefined ? "" : head + text + tail;
196
+ `
197
+
198
+ const ttscTypiaTestJsonStringifyElementStub = `module.exports._jsonStringifyElement = (text) =>
199
+ text === undefined ? "null" : text;
200
+ `
201
+
202
+ // Deterministic rather than random: these runtimes assert observable behavior
203
+ // of the emitted validators, so a generated string only has to satisfy the
204
+ // declared bounds, and a stable one keeps a failure reproducible.
205
+ const ttscTypiaTestJsonStringifyTailStub = `module.exports._jsonStringifyTail = (str) =>
206
+ str[str.length - 1] === "," ? str.substring(0, str.length - 1) : str;
207
+ `
208
+
209
+ const ttscTypiaTestRandomStringStub = `module.exports._randomString = (props) => {
210
+ const minimum =
211
+ props.minLength !== undefined
212
+ ? props.minLength
213
+ : Math.min(props.maxLength !== undefined ? props.maxLength : 5, 5);
214
+ const maximum = props.maxLength !== undefined ? props.maxLength : minimum + 5;
215
+ const length = Math.max(minimum, Math.min(minimum, maximum));
216
+ return "a".repeat(length);
217
+ };
218
+ `
219
+
145
220
  const ttscTypiaTestStringLengthStub = `module.exports._stringLength = (value) => {
146
221
  let count = 0;
147
222
  for (const _ of value) ++count;