typia 13.1.0 → 13.1.19

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 (516) hide show
  1. package/README.md +3 -0
  2. package/lib/_virtual/_rolldown/runtime.mjs +1 -5
  3. package/lib/executable/FileSystemIdentity.d.ts +21 -0
  4. package/lib/executable/FileSystemIdentity.js +183 -0
  5. package/lib/executable/FileSystemIdentity.js.map +1 -0
  6. package/lib/executable/FileSystemIdentity.mjs +129 -0
  7. package/lib/executable/FileSystemIdentity.mjs.map +1 -0
  8. package/lib/executable/TypiaGenerateWizard.js +264 -104
  9. package/lib/executable/TypiaGenerateWizard.js.map +1 -1
  10. package/lib/executable/TypiaGenerateWizard.mjs +233 -93
  11. package/lib/executable/TypiaGenerateWizard.mjs.map +1 -1
  12. package/lib/functional.d.ts +15 -12
  13. package/lib/functional.js.map +1 -1
  14. package/lib/functional.mjs.map +1 -1
  15. package/lib/internal/_ProtobufReader.d.ts +17 -0
  16. package/lib/internal/_ProtobufReader.js +117 -45
  17. package/lib/internal/_ProtobufReader.js.map +1 -1
  18. package/lib/internal/_ProtobufReader.mjs +108 -39
  19. package/lib/internal/_ProtobufReader.mjs.map +1 -1
  20. package/lib/internal/_createStandardSchema.js +18 -1
  21. package/lib/internal/_createStandardSchema.js.map +1 -1
  22. package/lib/internal/_createStandardSchema.mjs +12 -1
  23. package/lib/internal/_createStandardSchema.mjs.map +1 -1
  24. package/lib/internal/_decimal.d.ts +14 -0
  25. package/lib/internal/_decimal.js +61 -0
  26. package/lib/internal/_decimal.js.map +1 -0
  27. package/lib/internal/_decimal.mjs +49 -0
  28. package/lib/internal/_decimal.mjs.map +1 -0
  29. package/lib/internal/_httpQueryParseURLSearchParams.js +23 -2
  30. package/lib/internal/_httpQueryParseURLSearchParams.js.map +1 -1
  31. package/lib/internal/_httpQueryParseURLSearchParams.mjs +20 -2
  32. package/lib/internal/_httpQueryParseURLSearchParams.mjs.map +1 -1
  33. package/lib/internal/_isFormatByte.js +2 -5
  34. package/lib/internal/_isFormatByte.js.map +1 -1
  35. package/lib/internal/_isFormatByte.mjs +2 -5
  36. package/lib/internal/_isFormatByte.mjs.map +1 -1
  37. package/lib/internal/_isFormatDate.js +15 -2
  38. package/lib/internal/_isFormatDate.js.map +1 -1
  39. package/lib/internal/_isFormatDate.mjs +22 -2
  40. package/lib/internal/_isFormatDate.mjs.map +1 -1
  41. package/lib/internal/_isFormatDateTime.js +21 -2
  42. package/lib/internal/_isFormatDateTime.js.map +1 -1
  43. package/lib/internal/_isFormatDateTime.mjs +13 -2
  44. package/lib/internal/_isFormatDateTime.mjs.map +1 -1
  45. package/lib/internal/_isFormatIri.js +3 -2
  46. package/lib/internal/_isFormatIri.js.map +1 -1
  47. package/lib/internal/_isFormatIri.mjs +3 -2
  48. package/lib/internal/_isFormatIri.mjs.map +1 -1
  49. package/lib/internal/_isFormatIriReference.js +10 -2
  50. package/lib/internal/_isFormatIriReference.js.map +1 -1
  51. package/lib/internal/_isFormatIriReference.mjs +9 -2
  52. package/lib/internal/_isFormatIriReference.mjs.map +1 -1
  53. package/lib/internal/_isFormatUriReference.js +1 -1
  54. package/lib/internal/_isFormatUriReference.js.map +1 -1
  55. package/lib/internal/_isFormatUriReference.mjs +1 -1
  56. package/lib/internal/_isFormatUriReference.mjs.map +1 -1
  57. package/lib/internal/_isMultipleOf.d.ts +1 -0
  58. package/lib/internal/_isMultipleOf.js +13 -0
  59. package/lib/internal/_isMultipleOf.js.map +1 -0
  60. package/lib/internal/_isMultipleOf.mjs +12 -0
  61. package/lib/internal/_isMultipleOf.mjs.map +1 -0
  62. package/lib/internal/_isTypeFloat.js +1 -1
  63. package/lib/internal/_isTypeFloat.js.map +1 -1
  64. package/lib/internal/_isTypeFloat.mjs +1 -1
  65. package/lib/internal/_isTypeFloat.mjs.map +1 -1
  66. package/lib/internal/_isTypeInt64.js +1 -0
  67. package/lib/internal/_isTypeInt64.js.map +1 -1
  68. package/lib/internal/_isTypeInt64.mjs.map +1 -1
  69. package/lib/internal/_isTypeInt64Bigint.d.ts +1 -0
  70. package/lib/internal/_isTypeInt64Bigint.js +15 -0
  71. package/lib/internal/_isTypeInt64Bigint.js.map +1 -0
  72. package/lib/internal/_isTypeInt64Bigint.mjs +8 -0
  73. package/lib/internal/_isTypeInt64Bigint.mjs.map +1 -0
  74. package/lib/internal/_isTypeUint64.js +1 -0
  75. package/lib/internal/_isTypeUint64.js.map +1 -1
  76. package/lib/internal/_isTypeUint64.mjs.map +1 -1
  77. package/lib/internal/_isTypeUint64Bigint.d.ts +1 -0
  78. package/lib/internal/_isTypeUint64Bigint.js +10 -0
  79. package/lib/internal/_isTypeUint64Bigint.js.map +1 -0
  80. package/lib/internal/_isTypeUint64Bigint.mjs +8 -0
  81. package/lib/internal/_isTypeUint64Bigint.mjs.map +1 -0
  82. package/lib/internal/_isUniqueItems.js +96 -109
  83. package/lib/internal/_isUniqueItems.js.map +1 -1
  84. package/lib/internal/_isUniqueItems.mjs +62 -50
  85. package/lib/internal/_isUniqueItems.mjs.map +1 -1
  86. package/lib/internal/_notationAny.js +8 -1
  87. package/lib/internal/_notationAny.js.map +1 -1
  88. package/lib/internal/_notationAny.mjs +7 -1
  89. package/lib/internal/_notationAny.mjs.map +1 -1
  90. package/lib/internal/_notationAssign.d.ts +1 -0
  91. package/lib/internal/_notationAssign.js +18 -0
  92. package/lib/internal/_notationAssign.js.map +1 -0
  93. package/lib/internal/_notationAssign.mjs +17 -0
  94. package/lib/internal/_notationAssign.mjs.map +1 -0
  95. package/lib/internal/_notationCamel.js +30 -9
  96. package/lib/internal/_notationCamel.js.map +1 -1
  97. package/lib/internal/_notationCamel.mjs +13 -5
  98. package/lib/internal/_notationCamel.mjs.map +1 -1
  99. package/lib/internal/_notationKebab.d.ts +1 -0
  100. package/lib/internal/_notationKebab.js +15 -0
  101. package/lib/internal/_notationKebab.js.map +1 -0
  102. package/lib/internal/_notationKebab.mjs +15 -0
  103. package/lib/internal/_notationKebab.mjs.map +1 -0
  104. package/lib/internal/_notationKeyCollision.d.ts +1 -0
  105. package/lib/internal/_notationKeyCollision.js +8 -0
  106. package/lib/internal/_notationKeyCollision.js.map +1 -0
  107. package/lib/internal/_notationKeyCollision.mjs +8 -0
  108. package/lib/internal/_notationKeyCollision.mjs.map +1 -0
  109. package/lib/internal/_notationPascal.js +20 -5
  110. package/lib/internal/_notationPascal.js.map +1 -1
  111. package/lib/internal/_notationPascal.mjs +10 -5
  112. package/lib/internal/_notationPascal.mjs.map +1 -1
  113. package/lib/internal/_notationSnake.js +25 -22
  114. package/lib/internal/_notationSnake.js.map +1 -1
  115. package/lib/internal/_notationSnake.mjs +11 -11
  116. package/lib/internal/_notationSnake.mjs.map +1 -1
  117. package/lib/internal/_plainCloneAny.js +174 -38
  118. package/lib/internal/_plainCloneAny.js.map +1 -1
  119. package/lib/internal/_plainCloneAny.mjs +126 -22
  120. package/lib/internal/_plainCloneAny.mjs.map +1 -1
  121. package/lib/internal/_randomArray.d.ts +1 -1
  122. package/lib/internal/_randomArray.js +11 -4
  123. package/lib/internal/_randomArray.js.map +1 -1
  124. package/lib/internal/_randomArray.mjs +9 -3
  125. package/lib/internal/_randomArray.mjs.map +1 -1
  126. package/lib/internal/_randomFormatByte.d.ts +2 -1
  127. package/lib/internal/_randomFormatByte.js +2 -1
  128. package/lib/internal/_randomFormatByte.js.map +1 -1
  129. package/lib/internal/_randomFormatByte.mjs +2 -1
  130. package/lib/internal/_randomFormatByte.mjs.map +1 -1
  131. package/lib/internal/_randomFormatDate.d.ts +2 -0
  132. package/lib/internal/_randomFormatDate.js +3 -2
  133. package/lib/internal/_randomFormatDate.js.map +1 -1
  134. package/lib/internal/_randomFormatDate.mjs +3 -2
  135. package/lib/internal/_randomFormatDate.mjs.map +1 -1
  136. package/lib/internal/_randomFormatDatetime.d.ts +2 -0
  137. package/lib/internal/_randomFormatDatetime.js +3 -2
  138. package/lib/internal/_randomFormatDatetime.js.map +1 -1
  139. package/lib/internal/_randomFormatDatetime.mjs +3 -2
  140. package/lib/internal/_randomFormatDatetime.mjs.map +1 -1
  141. package/lib/internal/_randomFormatDuration.d.ts +2 -1
  142. package/lib/internal/_randomFormatDuration.js +3 -2
  143. package/lib/internal/_randomFormatDuration.js.map +1 -1
  144. package/lib/internal/_randomFormatDuration.mjs +3 -2
  145. package/lib/internal/_randomFormatDuration.mjs.map +1 -1
  146. package/lib/internal/_randomFormatEmail.d.ts +2 -1
  147. package/lib/internal/_randomFormatEmail.js +8 -1
  148. package/lib/internal/_randomFormatEmail.js.map +1 -1
  149. package/lib/internal/_randomFormatEmail.mjs +5 -1
  150. package/lib/internal/_randomFormatEmail.mjs.map +1 -1
  151. package/lib/internal/_randomFormatHostname.d.ts +8 -1
  152. package/lib/internal/_randomFormatHostname.js +45 -2
  153. package/lib/internal/_randomFormatHostname.js.map +1 -1
  154. package/lib/internal/_randomFormatHostname.mjs +38 -2
  155. package/lib/internal/_randomFormatHostname.mjs.map +1 -1
  156. package/lib/internal/_randomFormatIdnEmail.d.ts +2 -1
  157. package/lib/internal/_randomFormatIdnEmail.js +16 -2
  158. package/lib/internal/_randomFormatIdnEmail.js.map +1 -1
  159. package/lib/internal/_randomFormatIdnEmail.mjs +11 -2
  160. package/lib/internal/_randomFormatIdnEmail.mjs.map +1 -1
  161. package/lib/internal/_randomFormatIdnHostname.d.ts +2 -1
  162. package/lib/internal/_randomFormatIdnHostname.js +26 -1
  163. package/lib/internal/_randomFormatIdnHostname.js.map +1 -1
  164. package/lib/internal/_randomFormatIdnHostname.mjs +25 -2
  165. package/lib/internal/_randomFormatIdnHostname.mjs.map +1 -1
  166. package/lib/internal/_randomFormatIpv4.d.ts +2 -1
  167. package/lib/internal/_randomFormatIpv4.js +2 -1
  168. package/lib/internal/_randomFormatIpv4.js.map +1 -1
  169. package/lib/internal/_randomFormatIpv4.mjs +2 -1
  170. package/lib/internal/_randomFormatIpv4.mjs.map +1 -1
  171. package/lib/internal/_randomFormatIpv6.d.ts +2 -1
  172. package/lib/internal/_randomFormatIpv6.js +2 -1
  173. package/lib/internal/_randomFormatIpv6.js.map +1 -1
  174. package/lib/internal/_randomFormatIpv6.mjs +2 -1
  175. package/lib/internal/_randomFormatIpv6.mjs.map +1 -1
  176. package/lib/internal/_randomFormatIri.d.ts +2 -1
  177. package/lib/internal/_randomFormatIri.js +1 -1
  178. package/lib/internal/_randomFormatIri.js.map +1 -1
  179. package/lib/internal/_randomFormatIri.mjs +1 -1
  180. package/lib/internal/_randomFormatIri.mjs.map +1 -1
  181. package/lib/internal/_randomFormatIriReference.d.ts +2 -1
  182. package/lib/internal/_randomFormatIriReference.js +1 -1
  183. package/lib/internal/_randomFormatIriReference.js.map +1 -1
  184. package/lib/internal/_randomFormatIriReference.mjs +1 -1
  185. package/lib/internal/_randomFormatIriReference.mjs.map +1 -1
  186. package/lib/internal/_randomFormatJsonPointer.d.ts +2 -1
  187. package/lib/internal/_randomFormatJsonPointer.js +8 -1
  188. package/lib/internal/_randomFormatJsonPointer.js.map +1 -1
  189. package/lib/internal/_randomFormatJsonPointer.mjs +5 -1
  190. package/lib/internal/_randomFormatJsonPointer.mjs.map +1 -1
  191. package/lib/internal/_randomFormatPassword.d.ts +2 -1
  192. package/lib/internal/_randomFormatPassword.js +7 -5
  193. package/lib/internal/_randomFormatPassword.js.map +1 -1
  194. package/lib/internal/_randomFormatPassword.mjs +5 -1
  195. package/lib/internal/_randomFormatPassword.mjs.map +1 -1
  196. package/lib/internal/_randomFormatRegex.d.ts +2 -1
  197. package/lib/internal/_randomFormatRegex.js +2 -1
  198. package/lib/internal/_randomFormatRegex.js.map +1 -1
  199. package/lib/internal/_randomFormatRegex.mjs +2 -1
  200. package/lib/internal/_randomFormatRegex.mjs.map +1 -1
  201. package/lib/internal/_randomFormatRelativeJsonPointer.d.ts +2 -1
  202. package/lib/internal/_randomFormatRelativeJsonPointer.js +3 -2
  203. package/lib/internal/_randomFormatRelativeJsonPointer.js.map +1 -1
  204. package/lib/internal/_randomFormatRelativeJsonPointer.mjs +3 -2
  205. package/lib/internal/_randomFormatRelativeJsonPointer.mjs.map +1 -1
  206. package/lib/internal/_randomFormatTime.d.ts +2 -1
  207. package/lib/internal/_randomFormatTime.js +3 -2
  208. package/lib/internal/_randomFormatTime.js.map +1 -1
  209. package/lib/internal/_randomFormatTime.mjs +3 -2
  210. package/lib/internal/_randomFormatTime.mjs.map +1 -1
  211. package/lib/internal/_randomFormatUri.d.ts +2 -1
  212. package/lib/internal/_randomFormatUri.js +1 -1
  213. package/lib/internal/_randomFormatUri.js.map +1 -1
  214. package/lib/internal/_randomFormatUri.mjs +1 -1
  215. package/lib/internal/_randomFormatUri.mjs.map +1 -1
  216. package/lib/internal/_randomFormatUriReference.d.ts +2 -1
  217. package/lib/internal/_randomFormatUriReference.js +1 -1
  218. package/lib/internal/_randomFormatUriReference.js.map +1 -1
  219. package/lib/internal/_randomFormatUriReference.mjs +1 -1
  220. package/lib/internal/_randomFormatUriReference.mjs.map +1 -1
  221. package/lib/internal/_randomFormatUriTemplate.d.ts +2 -1
  222. package/lib/internal/_randomFormatUriTemplate.js +1 -1
  223. package/lib/internal/_randomFormatUriTemplate.js.map +1 -1
  224. package/lib/internal/_randomFormatUriTemplate.mjs +1 -1
  225. package/lib/internal/_randomFormatUriTemplate.mjs.map +1 -1
  226. package/lib/internal/_randomFormatUrl.d.ts +2 -1
  227. package/lib/internal/_randomFormatUrl.js +21 -1
  228. package/lib/internal/_randomFormatUrl.js.map +1 -1
  229. package/lib/internal/_randomFormatUrl.mjs +18 -1
  230. package/lib/internal/_randomFormatUrl.mjs.map +1 -1
  231. package/lib/internal/_randomFormatUuid.d.ts +2 -1
  232. package/lib/internal/_randomFormatUuid.js +3 -2
  233. package/lib/internal/_randomFormatUuid.js.map +1 -1
  234. package/lib/internal/_randomFormatUuid.mjs +3 -2
  235. package/lib/internal/_randomFormatUuid.mjs.map +1 -1
  236. package/lib/internal/_randomInteger.js +59 -28
  237. package/lib/internal/_randomInteger.js.map +1 -1
  238. package/lib/internal/_randomInteger.mjs +56 -16
  239. package/lib/internal/_randomInteger.mjs.map +1 -1
  240. package/lib/internal/_randomMultiple.d.ts +8 -0
  241. package/lib/internal/_randomMultiple.js +168 -0
  242. package/lib/internal/_randomMultiple.js.map +1 -0
  243. package/lib/internal/_randomMultiple.mjs +158 -0
  244. package/lib/internal/_randomMultiple.mjs.map +1 -0
  245. package/lib/internal/_randomNumber.js +42 -42
  246. package/lib/internal/_randomNumber.js.map +1 -1
  247. package/lib/internal/_randomNumber.mjs +41 -27
  248. package/lib/internal/_randomNumber.mjs.map +1 -1
  249. package/lib/internal/_randomPattern.d.ts +2 -1
  250. package/lib/internal/_randomPattern.js +19 -4
  251. package/lib/internal/_randomPattern.js.map +1 -1
  252. package/lib/internal/_randomPattern.mjs +10 -4
  253. package/lib/internal/_randomPattern.mjs.map +1 -1
  254. package/lib/internal/_randomStringLength.d.ts +33 -0
  255. package/lib/internal/_randomStringLength.js +48 -0
  256. package/lib/internal/_randomStringLength.js.map +1 -0
  257. package/lib/internal/_randomStringLength.mjs +44 -0
  258. package/lib/internal/_randomStringLength.mjs.map +1 -0
  259. package/lib/internal/_stringLength.d.ts +1 -0
  260. package/lib/internal/_stringLength.js +11 -0
  261. package/lib/internal/_stringLength.js.map +1 -0
  262. package/lib/internal/_stringLength.mjs +10 -0
  263. package/lib/internal/_stringLength.mjs.map +1 -0
  264. package/lib/internal/_validateReport.js +4 -1
  265. package/lib/internal/_validateReport.js.map +1 -1
  266. package/lib/internal/_validateReport.mjs +2 -1
  267. package/lib/internal/_validateReport.mjs.map +1 -1
  268. package/lib/internal/private/__notationRename.d.ts +14 -0
  269. package/lib/internal/private/__notationRename.js +25 -0
  270. package/lib/internal/private/__notationRename.js.map +1 -0
  271. package/lib/internal/private/__notationRename.mjs +24 -0
  272. package/lib/internal/private/__notationRename.mjs.map +1 -0
  273. package/lib/json.d.ts +2 -2
  274. package/lib/json.mjs.map +1 -1
  275. package/lib/module.d.ts +2 -2
  276. package/lib/module.js.map +1 -1
  277. package/lib/module.mjs.map +1 -1
  278. package/lib/notations.d.ts +20 -4
  279. package/lib/notations.js.map +1 -1
  280. package/lib/notations.mjs.map +1 -1
  281. package/native/adapter/plugin_options.go +117 -0
  282. package/native/adapter/plugin_options_payload_matrix_test.go +181 -0
  283. package/native/cmd/ttsc-typia/any_array_type_tags_transform_test.go +63 -9
  284. package/native/cmd/ttsc-typia/assert_guard_factory_contract_test.go +152 -0
  285. package/native/cmd/ttsc-typia/build.go +81 -64
  286. package/native/cmd/ttsc-typia/build_no_emit_preserves_analysis_options_test.go +67 -0
  287. package/native/cmd/ttsc-typia/build_no_emit_transform_diagnostics_test.go +138 -0
  288. package/native/cmd/ttsc-typia/build_plugin_options_come_from_payload_test.go +48 -0
  289. package/native/cmd/ttsc-typia/build_transactional_emit_success_test.go +81 -0
  290. package/native/cmd/ttsc-typia/build_transform_failure_atomicity_test.go +138 -0
  291. package/native/cmd/ttsc-typia/command_routes_and_diagnostics_coverage_test.go +3 -1
  292. package/native/cmd/ttsc-typia/compare_less_nan_transform_test.go +98 -0
  293. package/native/cmd/ttsc-typia/compare_native_object_overmatch_transform_test.go +161 -0
  294. package/native/cmd/ttsc-typia/compare_nondiscriminable_union_transform_test.go +343 -0
  295. package/native/cmd/ttsc-typia/compare_union_discrimination_transform_test.go +289 -0
  296. package/native/cmd/ttsc-typia/escaped_property_key_path_transform_test.go +193 -0
  297. package/native/cmd/ttsc-typia/finite_option_number_leaf_transform_test.go +240 -0
  298. package/native/cmd/ttsc-typia/functional_promised_type_transform_test.go +220 -0
  299. package/native/cmd/ttsc-typia/functional_receiver_transform_test.go +232 -0
  300. package/native/cmd/ttsc-typia/is_object_function_member_transform_test.go +205 -0
  301. package/native/cmd/ttsc-typia/json_application_alias_function_validation_transform_test.go +151 -0
  302. package/native/cmd/ttsc-typia/json_is_stringify_finite_number_transform_test.go +198 -0
  303. package/native/cmd/ttsc-typia/json_stringify_special_key_transform_test.go +238 -0
  304. package/native/cmd/ttsc-typia/main_wasm.go +21 -2
  305. package/native/cmd/ttsc-typia/native_collection_identity_is_transform_test.go +234 -0
  306. package/native/cmd/ttsc-typia/native_generic_name_guard_is_transform_test.go +194 -0
  307. package/native/cmd/ttsc-typia/native_name_collision_is_transform_test.go +204 -0
  308. package/native/cmd/ttsc-typia/non_trailing_rest_tuple_transform_test.go +23 -11
  309. package/native/cmd/ttsc-typia/notation_dynamic_keys_transform_test.go +286 -0
  310. package/native/cmd/ttsc-typia/notation_kebab_case_transform_test.go +1 -1
  311. package/native/cmd/ttsc-typia/notation_literal_collision_transform_test.go +164 -0
  312. package/native/cmd/ttsc-typia/notation_pascal_case_transform_test.go +230 -0
  313. package/native/cmd/ttsc-typia/notation_unicode_key_transform_test.go +309 -0
  314. package/native/cmd/ttsc-typia/pattern_line_terminator_escape_transform_test.go +224 -0
  315. package/native/cmd/ttsc-typia/plain_prune_union_object_overmatch_transform_test.go +219 -0
  316. package/native/cmd/ttsc-typia/plugin_options_payload_helpers_test.go +181 -0
  317. package/native/cmd/ttsc-typia/private_field_filter_is_transform_test.go +278 -0
  318. package/native/cmd/ttsc-typia/project_catalog_transform_coverage_test.go +73 -27
  319. package/native/cmd/ttsc-typia/project_dependencies_barrel_reexport_transform_test.go +120 -0
  320. package/native/cmd/ttsc-typia/project_dependencies_collapsed_alias_transform_test.go +134 -0
  321. package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +135 -0
  322. package/native/cmd/ttsc-typia/project_dependencies_default_barrel_transform_test.go +114 -0
  323. package/native/cmd/ttsc-typia/project_dependencies_empty_heritage_transform_test.go +100 -0
  324. package/native/cmd/ttsc-typia/project_dependencies_envelope_transform_test.go +148 -0
  325. package/native/cmd/ttsc-typia/project_dependencies_index_signature_alias_transform_test.go +139 -0
  326. package/native/cmd/ttsc-typia/project_dependencies_local_reexport_transform_test.go +122 -0
  327. package/native/cmd/ttsc-typia/project_dependencies_signature_alias_transform_test.go +125 -0
  328. package/native/cmd/ttsc-typia/project_dependencies_star_barrel_transform_test.go +112 -0
  329. package/native/cmd/ttsc-typia/project_reference_graph_envelope_transform_test.go +190 -0
  330. package/native/cmd/ttsc-typia/protobuf_is_encode_finite_number_transform_test.go +98 -0
  331. package/native/cmd/ttsc-typia/protobuf_sequence_field_numbers_transform_test.go +52 -22
  332. package/native/cmd/ttsc-typia/symbol_key_member_filter_transform_test.go +279 -0
  333. package/native/cmd/ttsc-typia/template_interpolation_type_tags_transform_test.go +86 -23
  334. package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -1
  335. package/native/cmd/ttsc-typia/transform.go +228 -39
  336. package/native/cmd/ttsc-typia/{transform_declaration_source_produces_no_js_test.go → transform_declaration_source_produces_no_javascript_test.go} +10 -2
  337. package/native/cmd/ttsc-typia/transform_fixtures_emit_coverage_test.go +21 -4
  338. package/native/cmd/ttsc-typia/transform_helpers_test.go +159 -1
  339. package/native/cmd/ttsc-typia/transform_plugin_options_come_from_payload_test.go +43 -0
  340. package/native/cmd/ttsc-typia/transform_single_file_failure_atomicity_test.go +114 -0
  341. package/native/cmd/ttsc-typia/transform_single_file_failure_writes_no_stdout_test.go +43 -0
  342. package/native/cmd/ttsc-typia/transform_single_file_js_distinguishes_same_basename_sources_test.go +81 -0
  343. package/native/cmd/ttsc-typia/transform_single_file_js_empty_emit_reports_no_output_test.go +100 -0
  344. package/native/cmd/ttsc-typia/transform_single_file_js_locates_output_across_layouts_test.go +160 -0
  345. package/native/cmd/ttsc-typia/transform_single_file_success_publishes_artifact_test.go +54 -0
  346. package/native/cmd/ttsc-typia/transform_wasm_host_argv_reports_diagnostics_test.go +39 -0
  347. package/native/cmd/ttsc-typia/tuple_optional_compare_clone_transform_test.go +227 -0
  348. package/native/core/factories/FormatCheatSheet.go +40 -7
  349. package/native/core/factories/IdentifierFactory.go +131 -4
  350. package/native/core/factories/MetadataCommentTagFactory.go +83 -40
  351. package/native/core/factories/MetadataTypeTagFactory.go +13 -1
  352. package/native/core/factories/NumericRangeFactory.go +60 -17
  353. package/native/core/factories/ProtobufFactory.go +7 -4
  354. package/native/core/factories/factory_utility_coverage_test.go +8 -2
  355. package/native/core/factories/format_alias_resolves_to_cheat_sheet_test.go +57 -0
  356. package/native/core/factories/format_alias_table_targets_the_cheat_sheet_test.go +44 -0
  357. package/native/core/factories/identifier_factory_postfix_escapes_every_key_test.go +147 -0
  358. package/native/core/factories/identifier_factory_postfix_survives_every_code_point_test.go +86 -0
  359. package/native/core/factories/internal/metadata/MetadataHelper.go +134 -7
  360. package/native/core/factories/internal/metadata/emplace_metadata_object.go +116 -8
  361. package/native/core/factories/internal/metadata/iterate_metadata.go +6 -0
  362. package/native/core/factories/internal/metadata/iterate_metadata_function.go +4 -11
  363. package/native/core/factories/internal/metadata/iterate_metadata_intersection.go +8 -6
  364. package/native/core/factories/internal/metadata/iterate_metadata_map.go +9 -0
  365. package/native/core/factories/internal/metadata/iterate_metadata_native.go +27 -2
  366. package/native/core/factories/internal/metadata/iterate_metadata_set.go +9 -0
  367. package/native/core/factories/internal/metadata/js_doc_link_text_test.go +69 -0
  368. package/native/core/factories/internal/metadata/type_arguments_precondition_test.go +70 -0
  369. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +39 -0
  370. package/native/core/factories/metadata_comment_tag_factory_exclusivity_matches_interface_test.go +84 -0
  371. package/native/core/factories/metadata_type_tag_factory_accepts_legal_tag_combinations_test.go +60 -0
  372. package/native/core/factories/metadata_type_tag_factory_declarations_test.go +86 -0
  373. package/native/core/factories/metadata_type_tag_factory_keeps_bool_form_exclusivity_test.go +38 -0
  374. package/native/core/factories/metadata_type_tag_factory_rejects_cross_kind_exclusive_tags_test.go +65 -0
  375. package/native/core/factories/metadata_type_tag_factory_rejects_duplicated_array_form_tags_test.go +41 -0
  376. package/native/core/factories/numeric_range_factory_enforces_64bit_bounds_test.go +69 -0
  377. package/native/core/factories/protobuf_recovery_ownership_test.go +64 -0
  378. package/native/core/programmers/IsProgrammer.go +15 -1
  379. package/native/core/programmers/RandomProgrammer.go +51 -14
  380. package/native/core/programmers/compare/CompareEqualProgrammer.go +393 -5
  381. package/native/core/programmers/compare/CompareLessProgrammer.go +4 -2
  382. package/native/core/programmers/functional/FunctionalAssertFunctionProgrammer.go +4 -6
  383. package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +5 -13
  384. package/native/core/programmers/functional/FunctionalAssertReturnProgrammer.go +6 -14
  385. package/native/core/programmers/functional/FunctionalIsFunctionProgrammer.go +4 -6
  386. package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +49 -14
  387. package/native/core/programmers/functional/FunctionalIsReturnProgrammer.go +5 -13
  388. package/native/core/programmers/functional/FunctionalValidateFunctionProgrammer.go +4 -6
  389. package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +5 -13
  390. package/native/core/programmers/functional/FunctionalValidateReturnProgrammer.go +5 -13
  391. package/native/core/programmers/functional/internal/FunctionalGeneralProgrammer.go +4 -17
  392. package/native/core/programmers/helpers/CloneJoiner.go +32 -0
  393. package/native/core/programmers/helpers/NotationJoiner.go +86 -28
  394. package/native/core/programmers/helpers/StringifyJoinder.go +32 -1
  395. package/native/core/programmers/helpers/UnionExplorer.go +203 -61
  396. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +5 -3
  397. package/native/core/programmers/helpers/union_explorer_coverage_test.go +1 -1
  398. package/native/core/programmers/internal/CheckerProgrammer.go +100 -48
  399. package/native/core/programmers/iterate/check_template.go +344 -32
  400. package/native/core/programmers/iterate/json_schema_discriminator.go +36 -10
  401. package/native/core/programmers/iterate/json_schema_discriminator_declaration_syntax_test.go +205 -0
  402. package/native/core/programmers/iterate/openapi_v3_downgrader.go +641 -0
  403. package/native/core/programmers/iterate/openapi_v3_downgrader_boolean_default_test.go +95 -0
  404. package/native/core/programmers/iterate/openapi_v3_downgrader_test.go +123 -0
  405. package/native/core/programmers/iterate/template_interpolation_tags_test.go +40 -8
  406. package/native/core/programmers/iterate/template_runtime_pattern.go +52 -7
  407. package/native/core/programmers/json/JsonApplicationProgrammer.go +45 -11
  408. package/native/core/programmers/json/JsonSchemasProgrammer.go +12 -2
  409. package/native/core/programmers/llm/LlmApplicationProgrammer.go +12 -10
  410. package/native/core/programmers/llm/LlmSchemaProgrammer.go +23 -6
  411. package/native/core/programmers/llm/llm_reference_codec_test.go +24 -0
  412. package/native/core/programmers/notations/NotationGeneralProgrammer.go +183 -67
  413. package/native/core/programmers/notations/notation_general_helpers_test.go +1 -3
  414. package/native/core/programmers/notations/notation_general_programmer_pascal_multiword_test.go +72 -0
  415. package/native/core/programmers/notations/notation_general_programmer_underscore_boundary_test.go +68 -0
  416. package/native/core/programmers/plain/PlainClassifyProgrammer.go +23 -15
  417. package/native/core/programmers/plain/PlainCloneProgrammer.go +20 -7
  418. package/native/core/programmers/plain/PlainPruneProgrammer.go +19 -5
  419. package/native/core/programmers/plain/plain_tuple_seed_recovery_ownership_test.go +25 -0
  420. package/native/core/programmers/protobuf/ProtobufDecodeProgrammer.go +37 -28
  421. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +40 -21
  422. package/native/core/programmers/protobuf/protobuf_programmer_helper_coverage_test.go +26 -0
  423. package/native/core/programmers/random_programmer_length_argument_test.go +53 -0
  424. package/native/core/schemas/metadata/MetadataCollection.go +270 -20
  425. package/native/core/schemas/metadata/MetadataDependency.go +388 -0
  426. package/native/core/schemas/metadata/MetadataObjectType.go +17 -4
  427. package/native/core/schemas/metadata/metadata_collection_generic_argument_dot_test.go +122 -0
  428. package/native/core/schemas/metadata/metadata_collection_name_allocation_test.go +147 -0
  429. package/native/core/schemas/metadata/metadata_collection_openapi_name_cascade_test.go +55 -0
  430. package/native/core/schemas/metadata/metadata_collection_openapi_name_test.go +68 -0
  431. package/native/core/utils/PatternUtil.go +13 -0
  432. package/native/core/utils/PromiseTypeFactory.go +59 -0
  433. package/native/core/utils/ProtobufNameEncoder.go +8 -0
  434. package/native/core/utils/promise_type_factory_semantics_test.go +118 -0
  435. package/native/go.mod +9 -1
  436. package/native/transform/CallExpressionTransformer.go +12 -0
  437. package/native/transform/features/json/JsonApplicationTransformer.go +1 -1
  438. package/native/transform/features/json/JsonSchemaTransformer.go +1 -1
  439. package/native/transform/features/json/JsonSchemasTransformer.go +5 -4
  440. package/package.json +16 -4
  441. package/src/executable/FileSystemIdentity.ts +189 -0
  442. package/src/executable/TypiaGenerateWizard.ts +377 -110
  443. package/src/functional.ts +30 -60
  444. package/src/internal/_ProtobufReader.ts +129 -43
  445. package/src/internal/_createStandardSchema.ts +15 -1
  446. package/src/internal/_decimal.ts +69 -0
  447. package/src/internal/_httpQueryParseURLSearchParams.ts +24 -2
  448. package/src/internal/_isFormatByte.ts +2 -5
  449. package/src/internal/_isFormatDate.ts +15 -2
  450. package/src/internal/_isFormatDateTime.ts +28 -2
  451. package/src/internal/_isFormatIri.ts +5 -2
  452. package/src/internal/_isFormatIriReference.ts +11 -3
  453. package/src/internal/_isFormatUriReference.ts +1 -1
  454. package/src/internal/_isMultipleOf.ts +8 -0
  455. package/src/internal/_isTypeFloat.ts +1 -1
  456. package/src/internal/_isTypeInt64.ts +1 -0
  457. package/src/internal/_isTypeInt64Bigint.ts +12 -0
  458. package/src/internal/_isTypeUint64.ts +1 -0
  459. package/src/internal/_isTypeUint64Bigint.ts +7 -0
  460. package/src/internal/_isUniqueItems.ts +134 -132
  461. package/src/internal/_notationAny.ts +9 -4
  462. package/src/internal/_notationAssign.ts +20 -0
  463. package/src/internal/_notationCamel.ts +31 -10
  464. package/src/internal/_notationKebab.ts +11 -0
  465. package/src/internal/_notationKeyCollision.ts +9 -0
  466. package/src/internal/_notationPascal.ts +19 -6
  467. package/src/internal/_notationSnake.ts +24 -21
  468. package/src/internal/_plainCloneAny.ts +208 -33
  469. package/src/internal/_randomArray.ts +13 -4
  470. package/src/internal/_randomFormatByte.ts +4 -1
  471. package/src/internal/_randomFormatDate.ts +17 -12
  472. package/src/internal/_randomFormatDatetime.ts +15 -10
  473. package/src/internal/_randomFormatDuration.ts +16 -14
  474. package/src/internal/_randomFormatEmail.ts +8 -2
  475. package/src/internal/_randomFormatHostname.ts +48 -1
  476. package/src/internal/_randomFormatIdnEmail.ts +18 -2
  477. package/src/internal/_randomFormatIdnHostname.ts +34 -2
  478. package/src/internal/_randomFormatIpv4.ts +3 -2
  479. package/src/internal/_randomFormatIpv6.ts +3 -2
  480. package/src/internal/_randomFormatIri.ts +3 -1
  481. package/src/internal/_randomFormatIriReference.ts +3 -1
  482. package/src/internal/_randomFormatJsonPointer.ts +8 -2
  483. package/src/internal/_randomFormatPassword.ts +11 -6
  484. package/src/internal/_randomFormatRegex.ts +4 -1
  485. package/src/internal/_randomFormatRelativeJsonPointer.ts +13 -6
  486. package/src/internal/_randomFormatTime.ts +13 -10
  487. package/src/internal/_randomFormatUri.ts +3 -1
  488. package/src/internal/_randomFormatUriReference.ts +3 -1
  489. package/src/internal/_randomFormatUriTemplate.ts +3 -1
  490. package/src/internal/_randomFormatUrl.ts +25 -2
  491. package/src/internal/_randomFormatUuid.ts +10 -6
  492. package/src/internal/_randomInteger.ts +87 -40
  493. package/src/internal/_randomMultiple.ts +245 -0
  494. package/src/internal/_randomNumber.ts +72 -55
  495. package/src/internal/_randomPattern.ts +26 -4
  496. package/src/internal/_randomStringLength.ts +72 -0
  497. package/src/internal/_stringLength.ts +5 -0
  498. package/src/internal/_validateReport.ts +5 -1
  499. package/src/internal/private/__notationRename.ts +24 -0
  500. package/src/json.ts +2 -2
  501. package/src/module.ts +4 -6
  502. package/src/notations.ts +20 -4
  503. package/lib/internal/private/__notationCapitalize.d.ts +0 -1
  504. package/lib/internal/private/__notationCapitalize.js +0 -6
  505. package/lib/internal/private/__notationCapitalize.js.map +0 -1
  506. package/lib/internal/private/__notationCapitalize.mjs +0 -6
  507. package/lib/internal/private/__notationCapitalize.mjs.map +0 -1
  508. package/lib/internal/private/__notationUnsnake.d.ts +0 -4
  509. package/lib/internal/private/__notationUnsnake.js +0 -26
  510. package/lib/internal/private/__notationUnsnake.js.map +0 -1
  511. package/lib/internal/private/__notationUnsnake.mjs +0 -15
  512. package/lib/internal/private/__notationUnsnake.mjs.map +0 -1
  513. package/native/cmd/ttsc-typia/plugin_options_missing_config_test.go +0 -26
  514. package/native/cmd/ttsc-typia/plugin_options_undefined_false_test.go +0 -36
  515. package/src/internal/private/__notationCapitalize.ts +0 -2
  516. package/src/internal/private/__notationUnsnake.ts +0 -24
@@ -0,0 +1,286 @@
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ // TestNotationDynamicKeysTransform verifies dynamic key rewriting and collision rejection.
11
+ //
12
+ // Index signatures use the dynamic object-entry branch rather than statically
13
+ // emitted property assignments. That branch must apply the selected rename to
14
+ // every runtime key and reject two source keys that normalize to one destination
15
+ // before either value is silently lost.
16
+ //
17
+ // 1. Transform direct and factory forms of plain/assert/is/validate operations
18
+ // for camel, Pascal, snake, and kebab notation.
19
+ // 2. Require valid dynamic and nested keys to use each selected convention.
20
+ // 3. Require every operation form to throw on a dynamic destination collision.
21
+ func TestNotationDynamicKeysTransform(t *testing.T) {
22
+ project := notationDynamicKeysProject(t)
23
+ out, errText, code := ttscTypiaTestCapture(func() int {
24
+ return runTransform([]string{
25
+ "--cwd", project,
26
+ "--tsconfig", "tsconfig.json",
27
+ "--file", "src/main.ts",
28
+ "--output", "js",
29
+ })
30
+ })
31
+ if code != 0 {
32
+ t.Fatalf("dynamic notation transform failed: code=%d stderr=\n%s", code, errText)
33
+ }
34
+ notationDynamicKeysRunRuntimeCases(t, project, out)
35
+ }
36
+
37
+ func notationDynamicKeysProject(t *testing.T) string {
38
+ t.Helper()
39
+ root := ttscTypiaTestRepoRoot(t)
40
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
41
+ if err := os.MkdirAll(base, 0o755); err != nil {
42
+ t.Fatalf("mkdir temp base: %v", err)
43
+ }
44
+ dir, err := os.MkdirTemp(base, "notation-dynamic-")
45
+ if err != nil {
46
+ t.Fatalf("create temp fixture: %v", err)
47
+ }
48
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
49
+ src := filepath.Join(dir, "src")
50
+ if err := os.MkdirAll(src, 0o755); err != nil {
51
+ t.Fatalf("mkdir fixture src: %v", err)
52
+ }
53
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(notationDynamicKeysTSConfig), 0o644); err != nil {
54
+ t.Fatalf("write tsconfig: %v", err)
55
+ }
56
+ if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(notationDynamicKeysSource), 0o644); err != nil {
57
+ t.Fatalf("write source: %v", err)
58
+ }
59
+ return dir
60
+ }
61
+
62
+ func notationDynamicKeysRunRuntimeCases(t *testing.T, project string, js string) {
63
+ t.Helper()
64
+ node, err := exec.LookPath("node")
65
+ if err != nil {
66
+ t.Skip("node executable not found")
67
+ }
68
+ runtimeDir := filepath.Join(project, "runtime")
69
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
70
+ t.Fatalf("mkdir runtime dir: %v", err)
71
+ }
72
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
73
+ runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
74
+ if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
75
+ t.Fatalf("write runtime module: %v", err)
76
+ }
77
+ runner := filepath.Join(runtimeDir, "run.cjs")
78
+ if err := os.WriteFile(runner, []byte(notationDynamicKeysRuntimeRunner), 0o644); err != nil {
79
+ t.Fatalf("write runtime runner: %v", err)
80
+ }
81
+ cmd := exec.Command(node, runner)
82
+ cmd.Dir = runtimeDir
83
+ output, err := cmd.CombinedOutput()
84
+ if err != nil {
85
+ t.Fatalf("dynamic notation runtime cases failed: %v\n%s", err, output)
86
+ }
87
+ }
88
+
89
+ const notationDynamicKeysTSConfig = `{
90
+ "compilerOptions": {
91
+ "target": "ES2022",
92
+ "module": "commonjs",
93
+ "moduleResolution": "bundler",
94
+ "ignoreDeprecations": "6.0",
95
+ "types": ["*"],
96
+ "esModuleInterop": true,
97
+ "strict": true,
98
+ "skipLibCheck": true
99
+ },
100
+ "include": ["src"]
101
+ }
102
+ `
103
+
104
+ const notationDynamicKeysSource = `import typia from "typia";
105
+
106
+ type UnderscoreRecord = Record<string, { inner_key: string }>;
107
+ type CamelRecord = Record<string, { innerValue: string }>;
108
+ type NumericRecord = Record<number, { innerValue: string }>;
109
+ type TemplateRecord = Record<` + "`item_${string}`" + `, { inner_key: string }>;
110
+ interface SnakeLiteral { "__proto__": { innerValue: string }; }
111
+ interface CamelMixed {
112
+ user_id: { inner_key: string };
113
+ [key: string]: { inner_key: string };
114
+ }
115
+
116
+ export const snakeLiteral = (input: SnakeLiteral) =>
117
+ typia.notations.snake<SnakeLiteral>(input);
118
+ export const mixedCamel = (input: CamelMixed) =>
119
+ typia.notations.camel<CamelMixed>(input);
120
+ export const numericSnake = (input: NumericRecord) =>
121
+ typia.notations.snake<NumericRecord>(input);
122
+ export const templateCamel = (input: TemplateRecord) =>
123
+ typia.notations.camel<TemplateRecord>(input);
124
+
125
+ export const camel = {
126
+ direct: (input: UnderscoreRecord) => typia.notations.camel<UnderscoreRecord>(input),
127
+ create: typia.notations.createCamel<UnderscoreRecord>(),
128
+ assert: (input: unknown) => typia.notations.assertCamel<UnderscoreRecord>(input),
129
+ createAssert: typia.notations.createAssertCamel<UnderscoreRecord>(),
130
+ is: (input: unknown) => typia.notations.isCamel<UnderscoreRecord>(input),
131
+ createIs: typia.notations.createIsCamel<UnderscoreRecord>(),
132
+ validate: (input: unknown) => typia.notations.validateCamel<UnderscoreRecord>(input),
133
+ createValidate: typia.notations.createValidateCamel<UnderscoreRecord>(),
134
+ };
135
+ export const pascal = {
136
+ direct: (input: UnderscoreRecord) => typia.notations.pascal<UnderscoreRecord>(input),
137
+ create: typia.notations.createPascal<UnderscoreRecord>(),
138
+ assert: (input: unknown) => typia.notations.assertPascal<UnderscoreRecord>(input),
139
+ createAssert: typia.notations.createAssertPascal<UnderscoreRecord>(),
140
+ is: (input: unknown) => typia.notations.isPascal<UnderscoreRecord>(input),
141
+ createIs: typia.notations.createIsPascal<UnderscoreRecord>(),
142
+ validate: (input: unknown) => typia.notations.validatePascal<UnderscoreRecord>(input),
143
+ createValidate: typia.notations.createValidatePascal<UnderscoreRecord>(),
144
+ };
145
+ export const snake = {
146
+ direct: (input: CamelRecord) => typia.notations.snake<CamelRecord>(input),
147
+ create: typia.notations.createSnake<CamelRecord>(),
148
+ assert: (input: unknown) => typia.notations.assertSnake<CamelRecord>(input),
149
+ createAssert: typia.notations.createAssertSnake<CamelRecord>(),
150
+ is: (input: unknown) => typia.notations.isSnake<CamelRecord>(input),
151
+ createIs: typia.notations.createIsSnake<CamelRecord>(),
152
+ validate: (input: unknown) => typia.notations.validateSnake<CamelRecord>(input),
153
+ createValidate: typia.notations.createValidateSnake<CamelRecord>(),
154
+ };
155
+ export const kebab = {
156
+ direct: (input: CamelRecord) => typia.notations.kebab<CamelRecord>(input),
157
+ create: typia.notations.createKebab<CamelRecord>(),
158
+ assert: (input: unknown) => typia.notations.assertKebab<CamelRecord>(input),
159
+ createAssert: typia.notations.createAssertKebab<CamelRecord>(),
160
+ is: (input: unknown) => typia.notations.isKebab<CamelRecord>(input),
161
+ createIs: typia.notations.createIsKebab<CamelRecord>(),
162
+ validate: (input: unknown) => typia.notations.validateKebab<CamelRecord>(input),
163
+ createValidate: typia.notations.createValidateKebab<CamelRecord>(),
164
+ };
165
+ `
166
+
167
+ const notationDynamicKeysRuntimeRunner = `const mod = require("./main.cjs");
168
+
169
+ const literalMagic = mod.snakeLiteral(
170
+ Object.fromEntries([["__proto__", { innerValue: "literal" }]]),
171
+ );
172
+ if (
173
+ Object.getPrototypeOf(literalMagic) !== Object.prototype ||
174
+ !Object.hasOwn(literalMagic, "__proto__") ||
175
+ !Object.hasOwn(literalMagic.__proto__, "inner_value")
176
+ ) {
177
+ throw new Error("snake literal __proto__ was not emitted as an own data property");
178
+ }
179
+
180
+ let mixedCollision = null;
181
+ try {
182
+ mod.mixedCamel({
183
+ user_id: { inner_key: "literal" },
184
+ userId: { inner_key: "dynamic" },
185
+ });
186
+ } catch (error) {
187
+ mixedCollision = error;
188
+ }
189
+ if (mixedCollision === null) {
190
+ throw new Error("camel mixed literal/dynamic destination collision was accepted");
191
+ }
192
+ for (const key of ["user_id", "userId", "userId"]) {
193
+ if (!String(mixedCollision.message).includes(JSON.stringify(key))) {
194
+ throw new Error("camel mixed collision omitted " + key + ": " + mixedCollision.message);
195
+ }
196
+ }
197
+
198
+ const numeric = mod.numericSnake({ 7: { innerValue: "numeric" } });
199
+ if (!Object.hasOwn(numeric, "7") || !Object.hasOwn(numeric[7], "inner_value")) {
200
+ throw new Error("snake numeric index key disagreed with its mapped return type");
201
+ }
202
+
203
+ const template = mod.templateCamel({ item_user_id: { inner_key: "template" } });
204
+ if (!Object.hasOwn(template, "itemUserId") || !Object.hasOwn(template.itemUserId, "innerKey")) {
205
+ throw new Error("camel template-literal index key was not converted");
206
+ }
207
+
208
+ const families = [
209
+ {
210
+ name: "camel",
211
+ api: mod.camel,
212
+ valid: { user_id: { inner_key: "u" }, account_name: { inner_key: "a" } },
213
+ expected: [["userId", "innerKey"], ["accountName", "innerKey"]],
214
+ collision: { user_id: { inner_key: "a" }, userId: { inner_key: "b" } },
215
+ collisionKeys: ["user_id", "userId", "userId"],
216
+ },
217
+ {
218
+ name: "pascal",
219
+ api: mod.pascal,
220
+ valid: { user_id: { inner_key: "u" }, account_name: { inner_key: "a" } },
221
+ expected: [["UserId", "InnerKey"], ["AccountName", "InnerKey"]],
222
+ collision: { user_id: { inner_key: "a" }, UserId: { inner_key: "b" } },
223
+ collisionKeys: ["user_id", "UserId", "UserId"],
224
+ },
225
+ {
226
+ name: "snake",
227
+ api: mod.snake,
228
+ valid: Object.fromEntries([
229
+ ["userId", { innerValue: "u" }],
230
+ ["accountName", { innerValue: "a" }],
231
+ ["__proto__", { innerValue: "p" }],
232
+ ]),
233
+ expected: [["user_id", "inner_value"], ["account_name", "inner_value"], ["__proto__", "inner_value"]],
234
+ collision: { userId: { innerValue: "a" }, user_id: { innerValue: "b" } },
235
+ collisionKeys: ["userId", "user_id", "user_id"],
236
+ },
237
+ {
238
+ name: "kebab",
239
+ api: mod.kebab,
240
+ valid: { userId: { innerValue: "u" }, account_name: { innerValue: "a" } },
241
+ expected: [["user-id", "inner-value"], ["account-name", "inner-value"]],
242
+ collision: { userId: { innerValue: "a" }, user_id: { innerValue: "b" } },
243
+ collisionKeys: ["userId", "user_id", "user-id"],
244
+ },
245
+ ];
246
+ const variants = ["direct", "create", "assert", "createAssert", "is", "createIs", "validate", "createValidate"];
247
+
248
+ for (const family of families) {
249
+ for (const variant of variants) {
250
+ const raw = family.api[variant](family.valid);
251
+ const converted = variant === "validate" || variant === "createValidate"
252
+ ? raw.success === true ? raw.data : null
253
+ : raw;
254
+ if (converted === null) {
255
+ throw new Error(family.name + "." + variant + " rejected valid dynamic input");
256
+ }
257
+ if (Object.keys(converted).length !== family.expected.length) {
258
+ throw new Error(family.name + "." + variant + " emitted unexpected keys: " + JSON.stringify(converted));
259
+ }
260
+ for (const [outer, inner] of family.expected) {
261
+ if (
262
+ !Object.hasOwn(converted, outer) ||
263
+ Object.keys(converted[outer]).length !== 1 ||
264
+ !Object.hasOwn(converted[outer], inner)
265
+ ) {
266
+ throw new Error(family.name + "." + variant + " kept an unconverted key: " + JSON.stringify(converted));
267
+ }
268
+ }
269
+
270
+ let collision = null;
271
+ try {
272
+ family.api[variant](family.collision);
273
+ } catch (error) {
274
+ collision = error;
275
+ }
276
+ if (collision === null) {
277
+ throw new Error(family.name + "." + variant + " silently accepted a destination collision");
278
+ }
279
+ for (const key of family.collisionKeys) {
280
+ if (!String(collision.message).includes(JSON.stringify(key))) {
281
+ throw new Error(family.name + "." + variant + " collision omitted " + key + ": " + collision.message);
282
+ }
283
+ }
284
+ }
285
+ }
286
+ `
@@ -36,7 +36,7 @@ func TestNotationKebabCaseTransform(t *testing.T) {
36
36
  if code != 0 {
37
37
  t.Fatalf("kebab notation transform failed: code=%d stderr=\n%s", code, errText)
38
38
  }
39
- for _, key := range []string{`"user-id"`, `"user-name"`, `"_private-value"`, `xmlparser:`, `"inner-value"`} {
39
+ for _, key := range []string{`"user-id"`, `"user-name"`, `"_private-value"`, `"xmlparser"`, `"inner-value"`} {
40
40
  if !strings.Contains(out, key) {
41
41
  t.Fatalf("emitted converter should contain kebab key %s:\n%s", key, out)
42
42
  }
@@ -0,0 +1,164 @@
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ // TestNotationLiteralCollisionTransform verifies static destination collisions are rejected.
11
+ //
12
+ // Literal property metadata exposes every source key during code emission. A
13
+ // converter must reject two distinct literals that normalize to one result
14
+ // instead of emitting duplicate assignments whose last value silently wins.
15
+ //
16
+ // 1. Transform direct and factory plain/assert/is/validate calls for all cases.
17
+ // 2. Give each naming family two literal keys with one normalized destination.
18
+ // 3. Execute every operation and require an error naming both source keys and destination.
19
+ func TestNotationLiteralCollisionTransform(t *testing.T) {
20
+ project := notationLiteralCollisionProject(t)
21
+ out, errText, code := ttscTypiaTestCapture(func() int {
22
+ return runTransform([]string{
23
+ "--cwd", project,
24
+ "--tsconfig", "tsconfig.json",
25
+ "--file", "src/main.ts",
26
+ "--output", "js",
27
+ })
28
+ })
29
+ if code != 0 {
30
+ t.Fatalf("literal collision transform failed: code=%d stderr=\n%s", code, errText)
31
+ }
32
+ notationLiteralCollisionRunRuntimeCases(t, project, out)
33
+ }
34
+
35
+ func notationLiteralCollisionProject(t *testing.T) string {
36
+ t.Helper()
37
+ root := ttscTypiaTestRepoRoot(t)
38
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
39
+ if err := os.MkdirAll(base, 0o755); err != nil {
40
+ t.Fatalf("mkdir temp base: %v", err)
41
+ }
42
+ dir, err := os.MkdirTemp(base, "notation-literal-collision-")
43
+ if err != nil {
44
+ t.Fatalf("create temp fixture: %v", err)
45
+ }
46
+ t.Cleanup(func() { _ = os.RemoveAll(dir) })
47
+ src := filepath.Join(dir, "src")
48
+ if err := os.MkdirAll(src, 0o755); err != nil {
49
+ t.Fatalf("mkdir fixture src: %v", err)
50
+ }
51
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(notationDynamicKeysTSConfig), 0o644); err != nil {
52
+ t.Fatalf("write tsconfig: %v", err)
53
+ }
54
+ if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(notationLiteralCollisionSource), 0o644); err != nil {
55
+ t.Fatalf("write source: %v", err)
56
+ }
57
+ return dir
58
+ }
59
+
60
+ func notationLiteralCollisionRunRuntimeCases(t *testing.T, project string, js string) {
61
+ t.Helper()
62
+ node, err := exec.LookPath("node")
63
+ if err != nil {
64
+ t.Skip("node executable not found")
65
+ }
66
+ runtimeDir := filepath.Join(project, "runtime")
67
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
68
+ t.Fatalf("mkdir runtime dir: %v", err)
69
+ }
70
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
71
+ runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
72
+ if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
73
+ t.Fatalf("write runtime module: %v", err)
74
+ }
75
+ runner := filepath.Join(runtimeDir, "run.cjs")
76
+ if err := os.WriteFile(runner, []byte(notationLiteralCollisionRuntimeRunner), 0o644); err != nil {
77
+ t.Fatalf("write runtime runner: %v", err)
78
+ }
79
+ cmd := exec.Command(node, runner)
80
+ cmd.Dir = runtimeDir
81
+ output, err := cmd.CombinedOutput()
82
+ if err != nil {
83
+ t.Fatalf("literal collision runtime cases failed: %v\n%s", err, output)
84
+ }
85
+ }
86
+
87
+ const notationLiteralCollisionSource = `import typia from "typia";
88
+
89
+ interface CamelCollision { user_id: string; userId: string; }
90
+ interface PascalCollision { user_id: string; UserId: string; }
91
+ interface SnakeCollision { userId: string; user_id: string; }
92
+ interface KebabCollision { userId: string; user_id: string; }
93
+
94
+ export const camel = {
95
+ direct: (input: CamelCollision) => typia.notations.camel<CamelCollision>(input),
96
+ create: typia.notations.createCamel<CamelCollision>(),
97
+ assert: (input: unknown) => typia.notations.assertCamel<CamelCollision>(input),
98
+ createAssert: typia.notations.createAssertCamel<CamelCollision>(),
99
+ is: (input: unknown) => typia.notations.isCamel<CamelCollision>(input),
100
+ createIs: typia.notations.createIsCamel<CamelCollision>(),
101
+ validate: (input: unknown) => typia.notations.validateCamel<CamelCollision>(input),
102
+ createValidate: typia.notations.createValidateCamel<CamelCollision>(),
103
+ };
104
+ export const pascal = {
105
+ direct: (input: PascalCollision) => typia.notations.pascal<PascalCollision>(input),
106
+ create: typia.notations.createPascal<PascalCollision>(),
107
+ assert: (input: unknown) => typia.notations.assertPascal<PascalCollision>(input),
108
+ createAssert: typia.notations.createAssertPascal<PascalCollision>(),
109
+ is: (input: unknown) => typia.notations.isPascal<PascalCollision>(input),
110
+ createIs: typia.notations.createIsPascal<PascalCollision>(),
111
+ validate: (input: unknown) => typia.notations.validatePascal<PascalCollision>(input),
112
+ createValidate: typia.notations.createValidatePascal<PascalCollision>(),
113
+ };
114
+ export const snake = {
115
+ direct: (input: SnakeCollision) => typia.notations.snake<SnakeCollision>(input),
116
+ create: typia.notations.createSnake<SnakeCollision>(),
117
+ assert: (input: unknown) => typia.notations.assertSnake<SnakeCollision>(input),
118
+ createAssert: typia.notations.createAssertSnake<SnakeCollision>(),
119
+ is: (input: unknown) => typia.notations.isSnake<SnakeCollision>(input),
120
+ createIs: typia.notations.createIsSnake<SnakeCollision>(),
121
+ validate: (input: unknown) => typia.notations.validateSnake<SnakeCollision>(input),
122
+ createValidate: typia.notations.createValidateSnake<SnakeCollision>(),
123
+ };
124
+ export const kebab = {
125
+ direct: (input: KebabCollision) => typia.notations.kebab<KebabCollision>(input),
126
+ create: typia.notations.createKebab<KebabCollision>(),
127
+ assert: (input: unknown) => typia.notations.assertKebab<KebabCollision>(input),
128
+ createAssert: typia.notations.createAssertKebab<KebabCollision>(),
129
+ is: (input: unknown) => typia.notations.isKebab<KebabCollision>(input),
130
+ createIs: typia.notations.createIsKebab<KebabCollision>(),
131
+ validate: (input: unknown) => typia.notations.validateKebab<KebabCollision>(input),
132
+ createValidate: typia.notations.createValidateKebab<KebabCollision>(),
133
+ };
134
+ `
135
+
136
+ const notationLiteralCollisionRuntimeRunner = `const mod = require("./main.cjs");
137
+
138
+ const families = [
139
+ { name: "camel", api: mod.camel, input: { user_id: "a", userId: "b" }, expected: ["user_id", "userId", "userId"] },
140
+ { name: "pascal", api: mod.pascal, input: { user_id: "a", UserId: "b" }, expected: ["user_id", "UserId", "UserId"] },
141
+ { name: "snake", api: mod.snake, input: { userId: "a", user_id: "b" }, expected: ["userId", "user_id", "user_id"] },
142
+ { name: "kebab", api: mod.kebab, input: { userId: "a", user_id: "b" }, expected: ["userId", "user_id", "user-id"] },
143
+ ];
144
+ const variants = ["direct", "create", "assert", "createAssert", "is", "createIs", "validate", "createValidate"];
145
+
146
+ for (const family of families) {
147
+ for (const variant of variants) {
148
+ let collision = null;
149
+ try {
150
+ family.api[variant](family.input);
151
+ } catch (error) {
152
+ collision = error;
153
+ }
154
+ if (collision === null) {
155
+ throw new Error(family.name + "." + variant + " silently accepted a literal destination collision");
156
+ }
157
+ for (const key of family.expected) {
158
+ if (!String(collision.message).includes(JSON.stringify(key))) {
159
+ throw new Error(family.name + "." + variant + " collision omitted " + key + ": " + collision.message);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ `
@@ -0,0 +1,230 @@
1
+ package main
2
+
3
+ import (
4
+ "os"
5
+ "os/exec"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+ )
10
+
11
+ // TestNotationPascalCaseTransform verifies PascalCase notation conversion.
12
+ //
13
+ // Issue #2183: `notations.pascal` capitalized each multi-word segment without
14
+ // lowercasing its tail, so an all-caps or mixed-case word kept its inner
15
+ // uppercase characters and `MAX_COUNT` became `MAXCOUNT`. Both the statically
16
+ // emitted converter (Go, one property assignment per known key) and the dynamic
17
+ // converter (runtime `_notationPascal`, one call per index-signature key) must
18
+ // agree with the declared `PascalCase<T>` type — the type-level assertions live
19
+ // in `tests/test-interface/src/typings/test_pascal_case.ts` — or the result type
20
+ // lies about the produced keys and `.MaxCount` reads back `undefined`.
21
+ //
22
+ // 1. Transform a static fixture covering all-caps, mixed-case, leading
23
+ // underscore, single-word (routed through `plain`, tail preserved), and
24
+ // nested keys; require the emitted converter to reference the PascalCase
25
+ // keys and never the un-lowercased `MAXCOUNT` form.
26
+ // 2. Execute the statically emitted converter and assert its runtime keys.
27
+ // 3. Execute the dynamic `Record` converter (runtime `_notationPascal`) over
28
+ // the same all-caps witnesses and assert it produces the identical keys, so
29
+ // the compile-time emit and the runtime helper are proven byte-equal.
30
+ func TestNotationPascalCaseTransform(t *testing.T) {
31
+ project := notationPascalCaseProject(t)
32
+ out, errText, code := ttscTypiaTestCapture(func() int {
33
+ return runTransform([]string{
34
+ "--cwd", project,
35
+ "--tsconfig", "tsconfig.json",
36
+ "--file", "src/main.ts",
37
+ "--output", "js",
38
+ })
39
+ })
40
+ if code != 0 {
41
+ t.Fatalf("pascal notation transform failed: code=%d stderr=\n%s", code, errText)
42
+ }
43
+ for _, key := range []string{"MaxCount", "HttpPort", "UserId", "FoobarBaz", "InnerValue"} {
44
+ if !strings.Contains(out, key) {
45
+ t.Fatalf("emitted converter should contain PascalCase key %q:\n%s", key, out)
46
+ }
47
+ }
48
+ for _, bug := range []string{"MAXCOUNT", "HTTPPORT", "FooBarBaz", "INNERVALUE"} {
49
+ if strings.Contains(out, bug) {
50
+ t.Fatalf("emitted converter must not keep the un-lowercased key %q:\n%s", bug, out)
51
+ }
52
+ }
53
+ notationPascalCaseRunRuntimeCases(t, project, out)
54
+ }
55
+
56
+ func notationPascalCaseProject(t *testing.T) string {
57
+ t.Helper()
58
+ root := ttscTypiaTestRepoRoot(t)
59
+ base := filepath.Join(root, "packages", "typia", "native", ".tmp-ttsc-typia-tests")
60
+ if err := os.MkdirAll(base, 0o755); err != nil {
61
+ t.Fatalf("mkdir temp base: %v", err)
62
+ }
63
+ dir, err := os.MkdirTemp(base, "notation-pascal-")
64
+ if err != nil {
65
+ t.Fatalf("create temp fixture: %v", err)
66
+ }
67
+ t.Cleanup(func() {
68
+ _ = os.RemoveAll(dir)
69
+ })
70
+ src := filepath.Join(dir, "src")
71
+ if err := os.MkdirAll(src, 0o755); err != nil {
72
+ t.Fatalf("mkdir fixture src: %v", err)
73
+ }
74
+ if err := os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte(notationPascalCaseTSConfig), 0o644); err != nil {
75
+ t.Fatalf("write tsconfig: %v", err)
76
+ }
77
+ if err := os.WriteFile(filepath.Join(src, "main.ts"), []byte(notationPascalCaseSource), 0o644); err != nil {
78
+ t.Fatalf("write source: %v", err)
79
+ }
80
+ return dir
81
+ }
82
+
83
+ func notationPascalCaseRunRuntimeCases(t *testing.T, project string, js string) {
84
+ t.Helper()
85
+ node, err := exec.LookPath("node")
86
+ if err != nil {
87
+ t.Skip("node executable not found")
88
+ }
89
+ runtimeDir := filepath.Join(project, "runtime")
90
+ if err := os.MkdirAll(runtimeDir, 0o755); err != nil {
91
+ t.Fatalf("mkdir runtime dir: %v", err)
92
+ }
93
+ ttscTypiaTestWriteCommonRuntimeStubs(t, runtimeDir)
94
+ runtimeJS := ttscTypiaTestRewriteCommonJS(t, js)
95
+ if err := os.WriteFile(filepath.Join(runtimeDir, "main.cjs"), []byte(runtimeJS), 0o644); err != nil {
96
+ t.Fatalf("write runtime module: %v", err)
97
+ }
98
+ runner := filepath.Join(runtimeDir, "run.cjs")
99
+ if err := os.WriteFile(runner, []byte(notationPascalCaseRuntimeRunner), 0o644); err != nil {
100
+ t.Fatalf("write runtime runner: %v", err)
101
+ }
102
+ cmd := exec.Command(node, runner)
103
+ cmd.Dir = runtimeDir
104
+ output, err := cmd.CombinedOutput()
105
+ if err != nil {
106
+ t.Fatalf("pascal notation runtime cases failed: %v\n%s", err, output)
107
+ }
108
+ }
109
+
110
+ const notationPascalCaseTSConfig = `{
111
+ "compilerOptions": {
112
+ "target": "ES2022",
113
+ "module": "commonjs",
114
+ "moduleResolution": "bundler",
115
+ "ignoreDeprecations": "6.0",
116
+ "types": ["*"],
117
+ "esModuleInterop": true,
118
+ "strict": true,
119
+ "skipLibCheck": true
120
+ },
121
+ "include": ["src"]
122
+ }
123
+ `
124
+
125
+ const notationPascalCaseSource = `import typia from "typia";
126
+
127
+ interface SourceRecord {
128
+ MAX_COUNT: number;
129
+ HTTP_PORT: number;
130
+ USER_ID: number;
131
+ fooBar_baz: number;
132
+ _MAX_COUNT: number;
133
+ userID: number;
134
+ ID: number;
135
+ nested: { INNER_VALUE: number };
136
+ }
137
+
138
+ type DynamicRecord = Record<string, { DEEP_VALUE: number }>;
139
+
140
+ export const toPascal = typia.notations.createPascal<SourceRecord>();
141
+ export const isPascal = typia.notations.createIsPascal<SourceRecord>();
142
+ export const assertPascal = typia.notations.createAssertPascal<SourceRecord>();
143
+ export const validatePascal =
144
+ typia.notations.createValidatePascal<SourceRecord>();
145
+ export const toPascalDynamic = typia.notations.createPascal<DynamicRecord>();
146
+ `
147
+
148
+ const notationPascalCaseRuntimeRunner = `const mod = require("./main.cjs");
149
+
150
+ const valid = {
151
+ MAX_COUNT: 1,
152
+ HTTP_PORT: 2,
153
+ USER_ID: 3,
154
+ fooBar_baz: 4,
155
+ _MAX_COUNT: 5,
156
+ userID: 6,
157
+ ID: 7,
158
+ nested: { INNER_VALUE: 8 },
159
+ };
160
+ // Byte-for-byte the key set of PascalCase<SourceRecord>: multi-word tails
161
+ // lowercase (MAX_COUNT -> MaxCount), single words keep their tail through the
162
+ // plain path (userID -> UserID, ID -> ID).
163
+ const expectedKeys = [
164
+ "MaxCount", "HttpPort", "UserId", "FoobarBaz", "_MaxCount", "UserID", "ID", "Nested",
165
+ ];
166
+
167
+ const converted = mod.toPascal(valid);
168
+ const keys = Object.keys(converted).sort();
169
+ if (JSON.stringify(keys) !== JSON.stringify([...expectedKeys].sort())) {
170
+ throw new Error("pascal conversion produced unexpected keys: " + JSON.stringify(keys));
171
+ }
172
+ if (converted.MaxCount !== 1 || converted.HttpPort !== 2 || converted.UserId !== 3) {
173
+ throw new Error("pascal conversion lost multi-word values: " + JSON.stringify(converted));
174
+ }
175
+ if (converted.FoobarBaz !== 4 || converted._MaxCount !== 5) {
176
+ throw new Error("mixed-case/leading-underscore keys converted incorrectly: " + JSON.stringify(converted));
177
+ }
178
+ if (converted.UserID !== 6 || converted.ID !== 7) {
179
+ throw new Error("single-word keys must keep their tail: " + JSON.stringify(converted));
180
+ }
181
+ if (JSON.stringify(Object.keys(converted.Nested)) !== JSON.stringify(["InnerValue"])) {
182
+ throw new Error("nested keys should recurse into PascalCase: " + JSON.stringify(converted.Nested));
183
+ }
184
+
185
+ if (mod.isPascal(valid) === null) {
186
+ throw new Error("isPascal should accept the valid input");
187
+ }
188
+ if (mod.isPascal({ ...valid, MAX_COUNT: "x" }) !== null) {
189
+ throw new Error("isPascal should reject an invalid property type");
190
+ }
191
+ if (mod.assertPascal(valid).MaxCount !== 1) {
192
+ throw new Error("assertPascal should return the converted object");
193
+ }
194
+ let thrown = null;
195
+ try {
196
+ mod.assertPascal({ ...valid, nested: { INNER_VALUE: "x" } });
197
+ } catch (error) {
198
+ thrown = error;
199
+ }
200
+ if (thrown === null) {
201
+ throw new Error("assertPascal should throw on invalid nested input");
202
+ }
203
+
204
+ const success = mod.validatePascal(valid);
205
+ if (success.success !== true || success.data.HttpPort !== 2) {
206
+ throw new Error("validatePascal should succeed with converted data: " + JSON.stringify(success));
207
+ }
208
+ const failure = mod.validatePascal({ ...valid, ID: "x" });
209
+ if (failure.success !== false || failure.errors.length === 0) {
210
+ throw new Error("validatePascal should collect errors for invalid input: " + JSON.stringify(failure));
211
+ }
212
+
213
+ // Dynamic index-signature keys route through the runtime _notationPascal helper
214
+ // rather than statically emitted assignments. Feeding the same all-caps
215
+ // witnesses proves the runtime helper and the compile-time emit agree.
216
+ const dynamic = mod.toPascalDynamic({
217
+ MAX_COUNT: { DEEP_VALUE: 1 },
218
+ HTTP_PORT: { DEEP_VALUE: 2 },
219
+ });
220
+ const dynamicKeys = Object.keys(dynamic).sort();
221
+ if (JSON.stringify(dynamicKeys) !== JSON.stringify(["HttpPort", "MaxCount"])) {
222
+ throw new Error("dynamic pascal keys disagreed with the static emit: " + JSON.stringify(dynamicKeys));
223
+ }
224
+ if (
225
+ !Object.hasOwn(dynamic.MaxCount, "DeepValue") ||
226
+ !Object.hasOwn(dynamic.HttpPort, "DeepValue")
227
+ ) {
228
+ throw new Error("dynamic pascal nested keys were not lowercased: " + JSON.stringify(dynamic));
229
+ }
230
+ `