typia 13.1.1 → 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 (515) 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 +60 -6
  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/type_arguments_precondition_test.go +70 -0
  368. package/native/core/factories/metadata_comment_tag_factory_coverage_test.go +39 -0
  369. package/native/core/factories/metadata_comment_tag_factory_exclusivity_matches_interface_test.go +84 -0
  370. package/native/core/factories/metadata_type_tag_factory_accepts_legal_tag_combinations_test.go +60 -0
  371. package/native/core/factories/metadata_type_tag_factory_declarations_test.go +86 -0
  372. package/native/core/factories/metadata_type_tag_factory_keeps_bool_form_exclusivity_test.go +38 -0
  373. package/native/core/factories/metadata_type_tag_factory_rejects_cross_kind_exclusive_tags_test.go +65 -0
  374. package/native/core/factories/metadata_type_tag_factory_rejects_duplicated_array_form_tags_test.go +41 -0
  375. package/native/core/factories/numeric_range_factory_enforces_64bit_bounds_test.go +69 -0
  376. package/native/core/factories/protobuf_recovery_ownership_test.go +64 -0
  377. package/native/core/programmers/IsProgrammer.go +15 -1
  378. package/native/core/programmers/RandomProgrammer.go +51 -14
  379. package/native/core/programmers/compare/CompareEqualProgrammer.go +393 -5
  380. package/native/core/programmers/compare/CompareLessProgrammer.go +4 -2
  381. package/native/core/programmers/functional/FunctionalAssertFunctionProgrammer.go +4 -6
  382. package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +5 -13
  383. package/native/core/programmers/functional/FunctionalAssertReturnProgrammer.go +6 -14
  384. package/native/core/programmers/functional/FunctionalIsFunctionProgrammer.go +4 -6
  385. package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +49 -14
  386. package/native/core/programmers/functional/FunctionalIsReturnProgrammer.go +5 -13
  387. package/native/core/programmers/functional/FunctionalValidateFunctionProgrammer.go +4 -6
  388. package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +5 -13
  389. package/native/core/programmers/functional/FunctionalValidateReturnProgrammer.go +5 -13
  390. package/native/core/programmers/functional/internal/FunctionalGeneralProgrammer.go +4 -17
  391. package/native/core/programmers/helpers/CloneJoiner.go +32 -0
  392. package/native/core/programmers/helpers/NotationJoiner.go +86 -28
  393. package/native/core/programmers/helpers/StringifyJoinder.go +32 -1
  394. package/native/core/programmers/helpers/UnionExplorer.go +203 -61
  395. package/native/core/programmers/helpers/joiner_branch_coverage_test.go +5 -3
  396. package/native/core/programmers/helpers/union_explorer_coverage_test.go +1 -1
  397. package/native/core/programmers/internal/CheckerProgrammer.go +100 -48
  398. package/native/core/programmers/iterate/check_template.go +344 -32
  399. package/native/core/programmers/iterate/json_schema_discriminator.go +36 -10
  400. package/native/core/programmers/iterate/json_schema_discriminator_declaration_syntax_test.go +205 -0
  401. package/native/core/programmers/iterate/openapi_v3_downgrader.go +641 -0
  402. package/native/core/programmers/iterate/openapi_v3_downgrader_boolean_default_test.go +95 -0
  403. package/native/core/programmers/iterate/openapi_v3_downgrader_test.go +123 -0
  404. package/native/core/programmers/iterate/template_interpolation_tags_test.go +40 -8
  405. package/native/core/programmers/iterate/template_runtime_pattern.go +52 -7
  406. package/native/core/programmers/json/JsonApplicationProgrammer.go +45 -11
  407. package/native/core/programmers/json/JsonSchemasProgrammer.go +12 -2
  408. package/native/core/programmers/llm/LlmApplicationProgrammer.go +12 -10
  409. package/native/core/programmers/llm/LlmSchemaProgrammer.go +23 -6
  410. package/native/core/programmers/llm/llm_reference_codec_test.go +24 -0
  411. package/native/core/programmers/notations/NotationGeneralProgrammer.go +183 -67
  412. package/native/core/programmers/notations/notation_general_helpers_test.go +1 -3
  413. package/native/core/programmers/notations/notation_general_programmer_pascal_multiword_test.go +72 -0
  414. package/native/core/programmers/notations/notation_general_programmer_underscore_boundary_test.go +68 -0
  415. package/native/core/programmers/plain/PlainClassifyProgrammer.go +23 -15
  416. package/native/core/programmers/plain/PlainCloneProgrammer.go +20 -7
  417. package/native/core/programmers/plain/PlainPruneProgrammer.go +19 -5
  418. package/native/core/programmers/plain/plain_tuple_seed_recovery_ownership_test.go +25 -0
  419. package/native/core/programmers/protobuf/ProtobufDecodeProgrammer.go +37 -28
  420. package/native/core/programmers/protobuf/ProtobufMessageProgrammer.go +40 -21
  421. package/native/core/programmers/protobuf/protobuf_programmer_helper_coverage_test.go +26 -0
  422. package/native/core/programmers/random_programmer_length_argument_test.go +53 -0
  423. package/native/core/schemas/metadata/MetadataCollection.go +270 -20
  424. package/native/core/schemas/metadata/MetadataDependency.go +388 -0
  425. package/native/core/schemas/metadata/MetadataObjectType.go +17 -4
  426. package/native/core/schemas/metadata/metadata_collection_generic_argument_dot_test.go +122 -0
  427. package/native/core/schemas/metadata/metadata_collection_name_allocation_test.go +147 -0
  428. package/native/core/schemas/metadata/metadata_collection_openapi_name_cascade_test.go +55 -0
  429. package/native/core/schemas/metadata/metadata_collection_openapi_name_test.go +68 -0
  430. package/native/core/utils/PatternUtil.go +13 -0
  431. package/native/core/utils/PromiseTypeFactory.go +59 -0
  432. package/native/core/utils/ProtobufNameEncoder.go +8 -0
  433. package/native/core/utils/promise_type_factory_semantics_test.go +118 -0
  434. package/native/go.mod +9 -1
  435. package/native/transform/CallExpressionTransformer.go +12 -0
  436. package/native/transform/features/json/JsonApplicationTransformer.go +1 -1
  437. package/native/transform/features/json/JsonSchemaTransformer.go +1 -1
  438. package/native/transform/features/json/JsonSchemasTransformer.go +5 -4
  439. package/package.json +16 -4
  440. package/src/executable/FileSystemIdentity.ts +189 -0
  441. package/src/executable/TypiaGenerateWizard.ts +377 -110
  442. package/src/functional.ts +30 -60
  443. package/src/internal/_ProtobufReader.ts +129 -43
  444. package/src/internal/_createStandardSchema.ts +15 -1
  445. package/src/internal/_decimal.ts +69 -0
  446. package/src/internal/_httpQueryParseURLSearchParams.ts +24 -2
  447. package/src/internal/_isFormatByte.ts +2 -5
  448. package/src/internal/_isFormatDate.ts +15 -2
  449. package/src/internal/_isFormatDateTime.ts +28 -2
  450. package/src/internal/_isFormatIri.ts +5 -2
  451. package/src/internal/_isFormatIriReference.ts +11 -3
  452. package/src/internal/_isFormatUriReference.ts +1 -1
  453. package/src/internal/_isMultipleOf.ts +8 -0
  454. package/src/internal/_isTypeFloat.ts +1 -1
  455. package/src/internal/_isTypeInt64.ts +1 -0
  456. package/src/internal/_isTypeInt64Bigint.ts +12 -0
  457. package/src/internal/_isTypeUint64.ts +1 -0
  458. package/src/internal/_isTypeUint64Bigint.ts +7 -0
  459. package/src/internal/_isUniqueItems.ts +134 -132
  460. package/src/internal/_notationAny.ts +9 -4
  461. package/src/internal/_notationAssign.ts +20 -0
  462. package/src/internal/_notationCamel.ts +31 -10
  463. package/src/internal/_notationKebab.ts +11 -0
  464. package/src/internal/_notationKeyCollision.ts +9 -0
  465. package/src/internal/_notationPascal.ts +19 -6
  466. package/src/internal/_notationSnake.ts +24 -21
  467. package/src/internal/_plainCloneAny.ts +208 -33
  468. package/src/internal/_randomArray.ts +13 -4
  469. package/src/internal/_randomFormatByte.ts +4 -1
  470. package/src/internal/_randomFormatDate.ts +17 -12
  471. package/src/internal/_randomFormatDatetime.ts +15 -10
  472. package/src/internal/_randomFormatDuration.ts +16 -14
  473. package/src/internal/_randomFormatEmail.ts +8 -2
  474. package/src/internal/_randomFormatHostname.ts +48 -1
  475. package/src/internal/_randomFormatIdnEmail.ts +18 -2
  476. package/src/internal/_randomFormatIdnHostname.ts +34 -2
  477. package/src/internal/_randomFormatIpv4.ts +3 -2
  478. package/src/internal/_randomFormatIpv6.ts +3 -2
  479. package/src/internal/_randomFormatIri.ts +3 -1
  480. package/src/internal/_randomFormatIriReference.ts +3 -1
  481. package/src/internal/_randomFormatJsonPointer.ts +8 -2
  482. package/src/internal/_randomFormatPassword.ts +11 -6
  483. package/src/internal/_randomFormatRegex.ts +4 -1
  484. package/src/internal/_randomFormatRelativeJsonPointer.ts +13 -6
  485. package/src/internal/_randomFormatTime.ts +13 -10
  486. package/src/internal/_randomFormatUri.ts +3 -1
  487. package/src/internal/_randomFormatUriReference.ts +3 -1
  488. package/src/internal/_randomFormatUriTemplate.ts +3 -1
  489. package/src/internal/_randomFormatUrl.ts +25 -2
  490. package/src/internal/_randomFormatUuid.ts +10 -6
  491. package/src/internal/_randomInteger.ts +87 -40
  492. package/src/internal/_randomMultiple.ts +245 -0
  493. package/src/internal/_randomNumber.ts +72 -55
  494. package/src/internal/_randomPattern.ts +26 -4
  495. package/src/internal/_randomStringLength.ts +72 -0
  496. package/src/internal/_stringLength.ts +5 -0
  497. package/src/internal/_validateReport.ts +5 -1
  498. package/src/internal/private/__notationRename.ts +24 -0
  499. package/src/json.ts +2 -2
  500. package/src/module.ts +4 -6
  501. package/src/notations.ts +20 -4
  502. package/lib/internal/private/__notationCapitalize.d.ts +0 -1
  503. package/lib/internal/private/__notationCapitalize.js +0 -6
  504. package/lib/internal/private/__notationCapitalize.js.map +0 -1
  505. package/lib/internal/private/__notationCapitalize.mjs +0 -6
  506. package/lib/internal/private/__notationCapitalize.mjs.map +0 -1
  507. package/lib/internal/private/__notationUnsnake.d.ts +0 -4
  508. package/lib/internal/private/__notationUnsnake.js +0 -26
  509. package/lib/internal/private/__notationUnsnake.js.map +0 -1
  510. package/lib/internal/private/__notationUnsnake.mjs +0 -15
  511. package/lib/internal/private/__notationUnsnake.mjs.map +0 -1
  512. package/native/cmd/ttsc-typia/plugin_options_missing_config_test.go +0 -26
  513. package/native/cmd/ttsc-typia/plugin_options_undefined_false_test.go +0 -36
  514. package/src/internal/private/__notationCapitalize.ts +0 -2
  515. package/src/internal/private/__notationUnsnake.ts +0 -24
@@ -0,0 +1,64 @@
1
+ package factories
2
+
3
+ import (
4
+ "slices"
5
+ "testing"
6
+
7
+ schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
8
+ )
9
+
10
+ // TestProtobufEmplacerRecoveryOwnership verifies unexpected panics stay visible.
11
+ //
12
+ // Unsupported metadata is diagnosed before emission, but an invariant failure
13
+ // inside the Protobuf emplacer must not be converted into a successful semantic
14
+ // result by a blanket recover.
15
+ //
16
+ // 1. Verify unsupported metadata remains an ordinary diagnostic.
17
+ // 2. Build a static object with an impossible empty semantic schema.
18
+ // 3. Require the panic to escape the post-validation emplacement pass.
19
+ func TestProtobufEmplacerRecoveryOwnership(t *testing.T) {
20
+ unsupported := schemametadata.MetadataSchema_initialize()
21
+ unsupported.Any = true
22
+ errors := protobufFactory_validate()(struct {
23
+ Metadata *schemametadata.MetadataSchema
24
+ Explore MetadataFactory_IExplore
25
+ Top *schemametadata.MetadataSchema
26
+ }{
27
+ Metadata: unsupported,
28
+ Explore: MetadataFactory_IExplore{Top: true},
29
+ Top: unsupported,
30
+ })
31
+ if !slices.Contains(errors, "does not support any type") {
32
+ t.Fatalf("unsupported any fallback mismatch: %v", errors)
33
+ }
34
+
35
+ key := MetadataFactory.SoleLiteral("value")
36
+ dynamicKey := schemametadata.MetadataSchema_initialize()
37
+ dynamicKey.Atomics = append(dynamicKey.Atomics, schemametadata.MetadataAtomic_create(schemametadata.MetadataAtomic{Type: "string"}))
38
+ dynamic := schemametadata.MetadataObjectType_create(schemametadata.MetadataObjectType{
39
+ Name: "BrokenMap",
40
+ Properties: []*schemametadata.MetadataProperty{
41
+ schemametadata.MetadataProperty_create(schemametadata.MetadataProperty{
42
+ Key: dynamicKey,
43
+ Value: schemametadata.MetadataSchema_initialize(),
44
+ }),
45
+ },
46
+ })
47
+ value := schemametadata.MetadataSchema_initialize()
48
+ value.Objects = append(value.Objects, schemametadata.MetadataObject_create(schemametadata.MetadataObject{Type: dynamic}))
49
+ object := schemametadata.MetadataObjectType_create(schemametadata.MetadataObjectType{
50
+ Name: "Broken",
51
+ Properties: []*schemametadata.MetadataProperty{
52
+ schemametadata.MetadataProperty_create(schemametadata.MetadataProperty{
53
+ Key: key,
54
+ Value: value,
55
+ }),
56
+ },
57
+ })
58
+ defer func() {
59
+ if recover() == nil {
60
+ t.Fatal("unexpected Protobuf emplacer panic was swallowed")
61
+ }
62
+ }()
63
+ protobufFactory_emplaceObjects([]*schemametadata.MetadataObjectType{object})
64
+ }
@@ -18,6 +18,7 @@ var IsProgrammer = isProgrammerNamespace{}
18
18
 
19
19
  type IsProgrammer_CONFIG_IOptions struct {
20
20
  Numeric *bool
21
+ Finite *bool
21
22
  Undefined *bool
22
23
  Object func(props IsProgrammer_CONFIG_IOptions_ObjectProps) *shimast.Node
23
24
  }
@@ -182,6 +183,7 @@ func (isProgrammerNamespace) Decompose(props IsProgrammer_DecomposeProps) native
182
183
  f := nativecontext.EmitFactoryOf(isProgrammer_factory, props.Context.Emit)
183
184
  options := &IsProgrammer_CONFIG_IOptions{
184
185
  Numeric: props.Context.Options.Numeric,
186
+ Finite: props.Context.Options.Finite,
185
187
  Object: func(v IsProgrammer_CONFIG_IOptions_ObjectProps) *shimast.Node {
186
188
  return nativeiterate.Check_object(nativeiterate.Check_objectProps{
187
189
  Config: nativeiterate.Check_object_IConfig{
@@ -397,8 +399,20 @@ func isProgrammer_binary(left *shimast.Expression, operator shimast.Kind, right
397
399
  )
398
400
  }
399
401
 
402
+ // isProgrammer_option_numeric reports whether the number leaf gate must be
403
+ // emitted at all. It opens on `finite` as well as `numeric` so that `finite:true`
404
+ // alone rejects NaN and Infinity, matching how assert/validate open the same gate
405
+ // via OptionPredicator.Numeric (which is likewise finite || numeric) and the
406
+ // documented independence of the two flags (samchon/typia#2196). The gate only
407
+ // decides whether check_number emits a guard; check_number's own inner selection
408
+ // then picks Number.isFinite for `finite` or !Number.isNaN for `numeric`.
400
409
  func isProgrammer_option_numeric(options *IsProgrammer_CONFIG_IOptions) bool {
401
- return options != nil && options.Numeric != nil && *options.Numeric
410
+ if options == nil {
411
+ return false
412
+ }
413
+ finite := options.Finite != nil && *options.Finite
414
+ numeric := options.Numeric != nil && *options.Numeric
415
+ return finite || numeric
402
416
  }
403
417
 
404
418
  func isProgrammer_option_undefined(options *IsProgrammer_CONFIG_IOptions) bool {
@@ -615,27 +615,36 @@ type randomProgrammer_composedAtomic struct {
615
615
  func randomProgrammer_compose_atomic(atomicType string, schema nativeiterate.JsonSchema, emit *shimprinter.EmitContext) randomProgrammer_composedAtomic {
616
616
  f := nativecontext.EmitFactoryOf(randomProgrammer_factory, emit)
617
617
  if atomicType == "string" {
618
+ // A string leaf that also carries a length tag needs the bounds forwarded
619
+ // to the format and pattern generators; only the plain-string fall-through
620
+ // used to receive the full schema, so a format or pattern combined with
621
+ // minLength/maxLength was generated at the wrong length and failed its own
622
+ // validator (issue #2189).
623
+ lengthArgs := randomProgrammer_length_argument(schema, emit)
618
624
  if raw, ok := schema["format"].(string); ok && raw != "" {
619
625
  if raw == "date-time" {
620
- return randomProgrammer_composedAtomic{Method: "datetime", Internal: "randomFormatDatetime"}
626
+ return randomProgrammer_composedAtomic{Method: "datetime", Internal: "randomFormatDatetime", Arguments: lengthArgs}
621
627
  }
622
628
  method := randomProgrammer_format_method(raw)
623
629
  return randomProgrammer_composedAtomic{
624
- Method: method,
625
- Internal: "randomFormat" + randomProgrammer_format_pascal(raw),
630
+ Method: method,
631
+ Internal: "randomFormat" + randomProgrammer_format_pascal(raw),
632
+ Arguments: lengthArgs,
626
633
  }
627
634
  }
628
635
  if pattern, ok := schema["pattern"].(string); ok && pattern != "" {
636
+ arguments := []*shimast.Node{
637
+ f.NewNewExpression(
638
+ f.NewIdentifier("RegExp"),
639
+ nil,
640
+ f.NewNodeList([]*shimast.Node{f.NewStringLiteral(pattern, shimast.TokenFlagsNone)}),
641
+ ),
642
+ }
643
+ arguments = append(arguments, lengthArgs...)
629
644
  return randomProgrammer_composedAtomic{
630
- Method: "pattern",
631
- Internal: "randomPattern",
632
- Arguments: []*shimast.Node{
633
- f.NewNewExpression(
634
- f.NewIdentifier("RegExp"),
635
- nil,
636
- f.NewNodeList([]*shimast.Node{f.NewStringLiteral(pattern, shimast.TokenFlagsNone)}),
637
- ),
638
- },
645
+ Method: "pattern",
646
+ Internal: "randomPattern",
647
+ Arguments: arguments,
639
648
  }
640
649
  }
641
650
  } else if atomicType == "number" {
@@ -659,6 +668,24 @@ func randomProgrammer_compose_atomic(atomicType string, schema nativeiterate.Jso
659
668
  }
660
669
  }
661
670
 
671
+ // randomProgrammer_length_argument forwards the minLength/maxLength bounds of a
672
+ // string leaf to the format and pattern generators as a
673
+ // `{ minLength?, maxLength? }` object literal, or nil when the leaf carries no
674
+ // length tag so the format-only and pattern-only emission stays byte-identical.
675
+ func randomProgrammer_length_argument(schema nativeiterate.JsonSchema, emit *shimprinter.EmitContext) []*shimast.Node {
676
+ length := map[string]any{}
677
+ if value, ok := schema["minLength"]; ok {
678
+ length["minLength"] = value
679
+ }
680
+ if value, ok := schema["maxLength"]; ok {
681
+ length["maxLength"] = value
682
+ }
683
+ if len(length) == 0 {
684
+ return nil
685
+ }
686
+ return []*shimast.Node{nativefactories.LiteralFactory.Write(length, emit)}
687
+ }
688
+
662
689
  func randomProgrammer_decode_template(props struct {
663
690
  Context nativecontext.ITypiaContext
664
691
  Functor *nativehelpers.FunctionProgrammer
@@ -1407,6 +1434,16 @@ func randomProgrammer_is_typed_array(name string) bool {
1407
1434
  }
1408
1435
  }
1409
1436
 
1437
+ // randomProgrammer_typed_array_range reports the type tag and range a TypedArray's
1438
+ // elements are generated from.
1439
+ //
1440
+ // These bounds are a generation hint, not a validation gate, and they are the one
1441
+ // copy of the 64-bit bound that is deliberately inexact. They become `minimum` and
1442
+ // `maximum` comment tags on a number-typed JSON schema, and `number` cannot
1443
+ // represent 2**63 - 1 or 2**64 - 1 -- both arrive rounded up to the next power of
1444
+ // two. That costs nothing here: the generator only picks a value from the range,
1445
+ // and the TypedArray constructor wraps whatever it is handed. Validation owns
1446
+ // exactness instead, in _isTypeInt64Bigint and its siblings.
1410
1447
  func randomProgrammer_typed_array_range(name string) (string, string, string) {
1411
1448
  switch name {
1412
1449
  case "Uint8Array", "Uint8ClampedArray":
@@ -1424,9 +1461,9 @@ func randomProgrammer_typed_array_range(name string) (string, string, string) {
1424
1461
  case "Int32Array":
1425
1462
  return "int32", "-2147483648", "2147483647"
1426
1463
  case "BigInt64Array":
1427
- return "uint64", "-9223372036854775808", "9223372036854775807"
1464
+ return "int64", "-9223372036854775808", "9223372036854775807"
1428
1465
  case "Float32Array":
1429
- return "float", "-1.175494351e38", "3.4028235e38"
1466
+ return "float", "-3.4028235e38", "3.4028235e38"
1430
1467
  default:
1431
1468
  return "double", fmt.Sprint(math.SmallestNonzeroFloat64), fmt.Sprint(math.MaxFloat64)
1432
1469
  }
@@ -34,6 +34,10 @@ type compareEqualProgrammerGenerator struct {
34
34
  Config CompareEqualProgrammer_IConfig
35
35
  Recursive bool
36
36
  Counter int
37
+ // Member-resolution checkers (`_ui<index>`) emitted on demand for the object
38
+ // unions that need the is-match ladder, keyed by the object's collection index.
39
+ Matchers []string
40
+ MatcherIndex map[int]bool
37
41
  }
38
42
 
39
43
  var compareEqualProgrammer_factory = shimast.NewNodeFactory(shimast.NodeFactoryHooks{})
@@ -71,8 +75,9 @@ func (compareEqualProgrammerNamespace) Write(props CompareEqualProgrammer_IProps
71
75
  }
72
76
 
73
77
  generator := &compareEqualProgrammerGenerator{
74
- Config: props.Config,
75
- Recursive: nativeinternal.FeatureProgrammer.CollectionRecursive(collection),
78
+ Config: props.Config,
79
+ Recursive: nativeinternal.FeatureProgrammer.CollectionRecursive(collection),
80
+ MatcherIndex: map[int]bool{},
76
81
  }
77
82
  body := generator.schema(result.Data, "x", "y")
78
83
  statements := []string{}
@@ -89,6 +94,12 @@ func (compareEqualProgrammerNamespace) Write(props CompareEqualProgrammer_IProps
89
94
  statements = append(statements, generator.tupleFunction(tuple))
90
95
  }
91
96
  }
97
+ // The member matchers are collected last because every generation step above
98
+ // may request one. They are `const` arrow functions in the same scope as the
99
+ // `_eo`/`_ea`/`_et` helpers and are only ever called after this IIFE returns,
100
+ // so declaring them at the end is free of temporal-dead-zone hazards — the
101
+ // same placement `is` uses for the `_io` checkers it appends after `_cu`.
102
+ statements = append(statements, generator.Matchers...)
92
103
  if generator.Recursive {
93
104
  statements = append(statements, "return (x, y) => { const _vctx = {}; return "+body+"; };")
94
105
  } else {
@@ -155,8 +166,28 @@ func (g *compareEqualProgrammerGenerator) schema(metadata *schemametadata.Metada
155
166
  for _, array := range metadata.Arrays {
156
167
  branches = append(branches, g.array(array, x, y))
157
168
  }
158
- for _, object := range metadata.Objects {
159
- branches = append(branches, g.objectCall(object.Type, x, y))
169
+ // A union of two or more object types must discriminate: route each operand
170
+ // to exactly one member and compare within that single member. A flat OR of
171
+ // member comparators lets a wrong member's comparator match spuriously — its
172
+ // literal discriminant is satisfied by the always-present `x[k] === y[k]`
173
+ // branch and its absent payload keys compare `undefined === undefined`. The
174
+ // discrimination reuses the shared UnionPredicator specialization the sibling
175
+ // programmers (is/clone/classify/...) route through, so `equals` agrees with
176
+ // `is` on which member a value is. A union no discriminant can split (every
177
+ // distinguishing key optional, e.g. `{ a?: number } | { b?: string }`) routes
178
+ // through the first-is-match ladder instead — never a flat OR, which admits
179
+ // the same spurious match through absent keys comparing
180
+ // `undefined === undefined` (issue #2225).
181
+ if len(metadata.Objects) >= 2 {
182
+ expr := g.objectUnion(metadata.Objects, x, y)
183
+ if guard := g.notNatives(metadata.Natives, x, y); guard != "" {
184
+ expr = g.and(guard, expr)
185
+ }
186
+ branches = append(branches, expr)
187
+ } else {
188
+ for _, object := range metadata.Objects {
189
+ branches = append(branches, g.objectFlatBranch(object.Type, metadata.Natives, x, y))
190
+ }
160
191
  }
161
192
  for _, alias := range metadata.Aliases {
162
193
  branches = append(branches, g.schema(alias.Type.Value, x, y))
@@ -233,7 +264,27 @@ func (g *compareEqualProgrammerGenerator) tupleInline(tuple *schemametadata.Meta
233
264
  g.same(g.access(x, "length"), g.access(y, "length")),
234
265
  }
235
266
  if rest == nil {
236
- checks = append(checks, g.same(g.access(x, "length"), strconv.Itoa(fixed)))
267
+ // An omitted optional trailing element makes the tuple's length a range
268
+ // [required, fixed] — exactly the gate `is` emits. A hard `=== fixed`
269
+ // rejects a value `is` accepts and breaks reflexivity of `equals`; the
270
+ // per-element `x[i] === y[i]` prefix already treats both-absent as equal,
271
+ // so only the length gate needs the range. A fully-required tuple keeps
272
+ // its byte-identical `x.length === fixed`.
273
+ required := 0
274
+ allRequired := true
275
+ for i := 0; i < fixed; i++ {
276
+ if tuple.Elements[i].Optional {
277
+ allRequired = false
278
+ } else {
279
+ required++
280
+ }
281
+ }
282
+ if allRequired {
283
+ checks = append(checks, g.same(g.access(x, "length"), strconv.Itoa(fixed)))
284
+ } else {
285
+ length := g.access(x, "length")
286
+ checks = append(checks, fmt.Sprintf("%d <= %s && %d >= %s", required, length, fixed, length))
287
+ }
237
288
  } else {
238
289
  checks = append(checks, fmt.Sprintf("%s.length >= %d", g.wrap(x), fixed))
239
290
  }
@@ -256,6 +307,328 @@ func (g *compareEqualProgrammerGenerator) objectCall(object *schemametadata.Meta
256
307
  return fmt.Sprintf("_eo%d(%s, %s)", object.Index, g.wrap(x), g.wrap(y))
257
308
  }
258
309
 
310
+ // objectFlatBranch renders one member of an object union as a guarded member
311
+ // comparator (the pre-discrimination form). It is used for a single-object
312
+ // "union" and as the fallback for a union no supported predicate can split.
313
+ func (g *compareEqualProgrammerGenerator) objectFlatBranch(object *schemametadata.MetadataObjectType, natives []*schemametadata.MetadataNative, x string, y string) string {
314
+ // Guard the object branch against the sibling native instances. `_eo` admits
315
+ // any `typeof === "object" && !Array.isArray` value, so a native (a Date is
316
+ // an object) would be compared by the object's declared keys, which the
317
+ // native lacks — two different Dates then look equal on their absent keys and
318
+ // the OR wrongly accepts. Excluding what a native branch owns makes the arms
319
+ // mutually exclusive, matching the clone/classify ladder whose object arm is
320
+ // unreachable once a native arm matches.
321
+ call := g.objectCall(object, x, y)
322
+ if guard := g.notNatives(natives, x, y); guard != "" {
323
+ call = g.and(guard, call)
324
+ }
325
+ return call
326
+ }
327
+
328
+ // objectUnion renders a discriminated comparison for a union of two or more
329
+ // object types. It mirrors the is/clone/classify discrimination: each operand is
330
+ // routed to exactly one member, and only when both land on the same member does
331
+ // that member's comparator run. This replaces the flat OR whose wrong-member
332
+ // comparator could match spuriously.
333
+ //
334
+ // Routing prefers the shared UnionPredicator discriminants (issue #2214). When
335
+ // no discriminant splits the members — every distinguishing key is optional, so
336
+ // UnionPredicator yields no specialization, or more than one member is left
337
+ // unspecialized — routing falls back to the first-is-match ladder that
338
+ // clone/classify/prune reach through Decode_union_object (issue #2225). There is
339
+ // no flat-OR fallback: the flat OR is the defect both issues describe.
340
+ func (g *compareEqualProgrammerGenerator) objectUnion(objects []*schemametadata.MetadataObject, x string, y string) string {
341
+ types := make([]*schemametadata.MetadataObjectType, 0, len(objects))
342
+ for _, object := range objects {
343
+ types = append(types, object.Type)
344
+ }
345
+ ladder, ok := g.discriminantLadder(types)
346
+ if ok == false {
347
+ ladder = g.matchLadder(types)
348
+ }
349
+
350
+ tag := g.local("utag")
351
+ tx := g.local("utx")
352
+ // Dispatch: with the shared member index, run only that member's comparator.
353
+ dispatch := "false"
354
+ for i := len(types) - 1; i >= 0; i-- {
355
+ dispatch = fmt.Sprintf("%s === %d ? %s : %s", tx, types[i].Index, g.objectCall(types[i], "x", "y"), dispatch)
356
+ }
357
+ body := fmt.Sprintf(
358
+ "((x, y) => { const %s = (v) => (%s) ? (%s) : -1; const %s = %s(x); return %s !== -1 && %s === %s(y) && (%s); })(%s, %s)",
359
+ tag, g.isObject("v"), ladder, tx, tag, tx, tx, tag, dispatch, g.wrap(x), g.wrap(y),
360
+ )
361
+ return body
362
+ }
363
+
364
+ // discriminantLadder renders the routing ternary from the shared UnionPredicator
365
+ // specialization: `<discriminant of member i> ? <index of member i> : ...`,
366
+ // ending in the lone unspecialized member (the unconditional else the
367
+ // discriminant ladder leaves) or -1 for "no member". It reports ok=false when
368
+ // the members carry no usable discriminant, when more than one member is left
369
+ // unspecialized, or when a discriminant value cannot be rendered as a check —
370
+ // the caller then routes by is-match instead.
371
+ func (g *compareEqualProgrammerGenerator) discriminantLadder(types []*schemametadata.MetadataObjectType) (string, bool) {
372
+ specs := nativehelpers.UnionPredicator.Object(types)
373
+ if len(specs) == 0 {
374
+ return "", false
375
+ }
376
+ specialized := map[*schemametadata.MetadataObjectType]bool{}
377
+ for _, spec := range specs {
378
+ specialized[spec.Object] = true
379
+ }
380
+ remained := []*schemametadata.MetadataObjectType{}
381
+ for _, object := range types {
382
+ if specialized[object] == false {
383
+ remained = append(remained, object)
384
+ }
385
+ }
386
+ if len(remained) > 1 {
387
+ return "", false
388
+ }
389
+ fallback := "-1"
390
+ if len(remained) == 1 {
391
+ fallback = strconv.Itoa(remained[0].Index)
392
+ }
393
+ ladder := fallback
394
+ for i := len(specs) - 1; i >= 0; i-- {
395
+ check, ok := g.discriminant(specs[i], "v")
396
+ if ok == false {
397
+ return "", false
398
+ }
399
+ ladder = fmt.Sprintf("%s ? %d : %s", check, specs[i].Object.Index, ladder)
400
+ }
401
+ return ladder, true
402
+ }
403
+
404
+ // matchLadder renders the routing ternary for a union no discriminant splits:
405
+ // the first member the value is-matches wins, exactly as `clone`/`classify`/
406
+ // `prune` resolve membership through Decode_union_object's `if (_io0(input))
407
+ // return ...; if (_io1(input)) ...` ladder. A value matching no member yields
408
+ // -1, which makes `equals` false rather than letting a wrong member's comparator
409
+ // decide.
410
+ func (g *compareEqualProgrammerGenerator) matchLadder(types []*schemametadata.MetadataObjectType) string {
411
+ calls := make([]string, 0, len(types))
412
+ for _, object := range types {
413
+ // Declared in member order so the emitted matchers read in the same order
414
+ // as the ladder that calls them; the ladder itself is folded back to front.
415
+ calls = append(calls, g.matchCall(object, "v"))
416
+ }
417
+ ladder := "-1"
418
+ for i := len(types) - 1; i >= 0; i-- {
419
+ ladder = fmt.Sprintf("%s ? %d : %s", calls[i], types[i].Index, ladder)
420
+ }
421
+ return ladder
422
+ }
423
+
424
+ // matchCall returns a call to the member's `_ui<index>` matcher, declaring the
425
+ // matcher on first request. The index is registered before the body is rendered
426
+ // so a recursive member refers to its own matcher instead of recursing forever
427
+ // at generation time.
428
+ func (g *compareEqualProgrammerGenerator) matchCall(object *schemametadata.MetadataObjectType, v string) string {
429
+ name := fmt.Sprintf("_ui%d", object.Index)
430
+ if g.MatcherIndex[object.Index] == false {
431
+ g.MatcherIndex[object.Index] = true
432
+ g.Matchers = append(g.Matchers, fmt.Sprintf("const %s = (v) => %s;", name, g.matchObject(object, "v")))
433
+ }
434
+ return fmt.Sprintf("%s(%s)", name, g.wrap(v))
435
+ }
436
+
437
+ // matchObject renders the structural is-check of one object member: every
438
+ // declared regular key must hold a value of its declared type (an optional key
439
+ // may be absent), and every extra key a dynamic index signature declares must
440
+ // hold a value of the signature's type. It mirrors the `_io` checkers `is`
441
+ // emits, at the abstraction level the rest of this programmer works at — shape
442
+ // and typeof, not the value constraints (`typia.tags.*`, template patterns)
443
+ // `compare` deliberately ignores.
444
+ func (g *compareEqualProgrammerGenerator) matchObject(object *schemametadata.MetadataObjectType, v string) string {
445
+ checks := []string{}
446
+ regularKeys := []string{}
447
+ dynamic := []*schemametadata.MetadataProperty{}
448
+ for _, property := range object.Properties {
449
+ if compareProgrammer_isMethod(property) {
450
+ continue // methods carry no comparable data, so they do not route either
451
+ }
452
+ if sole := property.Key.GetSoleLiteral(); sole != nil {
453
+ regularKeys = append(regularKeys, *sole)
454
+ checks = append(checks, g.matchSlot(property.Value, g.property(v, *sole)))
455
+ } else {
456
+ dynamic = append(dynamic, property)
457
+ }
458
+ }
459
+ if len(dynamic) != 0 {
460
+ key := g.local("key")
461
+ regularCheck := compareEqualProgrammer_regularKeyCheck(regularKeys)
462
+ conditions := []string{}
463
+ for _, property := range dynamic {
464
+ conditions = append(conditions, g.and(g.dynamicKey(property.Key, key), g.matchSlot(property.Value, g.index(v, key))))
465
+ }
466
+ checks = append(checks, fmt.Sprintf("Object.keys(%s).every((%s) => %s)", g.wrap(v), key, g.or(regularCheck(key), g.or(conditions...))))
467
+ }
468
+ return g.and(checks...)
469
+ }
470
+
471
+ // matchSlot renders the is-check of a value slot — an object property or a tuple
472
+ // element — allowing the slot to be absent when it is optional.
473
+ func (g *compareEqualProgrammerGenerator) matchSlot(metadata *schemametadata.MetadataSchema, v string) string {
474
+ check := g.match(metadata, v)
475
+ if metadata != nil && metadata.IsRequired() == false {
476
+ return g.or(g.same(v, "undefined"), check)
477
+ }
478
+ return check
479
+ }
480
+
481
+ // match renders the structural is-check of one metadata schema as the OR of its
482
+ // buckets, the same bucket walk `schema` compares over. An unconstrained bucket
483
+ // (anything the compare feature already rejects, or a bucket carrying no shape
484
+ // to test) renders as "true", which keeps the ladder's first-match order the
485
+ // deciding factor exactly as it is in `is`.
486
+ func (g *compareEqualProgrammerGenerator) match(metadata *schemametadata.MetadataSchema, v string) string {
487
+ if metadata == nil {
488
+ return "true"
489
+ }
490
+ metadata = schemametadata.MetadataSchema_unalias(metadata)
491
+ if metadata.Any {
492
+ return "true"
493
+ }
494
+ branches := []string{}
495
+ if metadata.Nullable {
496
+ branches = append(branches, g.same(v, "null"))
497
+ }
498
+ for _, constant := range metadata.Constants {
499
+ for _, value := range constant.Values {
500
+ branches = append(branches, g.same(v, compareEqualProgrammer_literal(value.Value, constant.Type)))
501
+ }
502
+ }
503
+ for _, atomic := range metadata.Atomics {
504
+ branches = append(branches, g.typeof(v, atomic.Type))
505
+ }
506
+ if len(metadata.Templates) != 0 {
507
+ branches = append(branches, g.typeof(v, "string"))
508
+ }
509
+ if len(metadata.Functions) != 0 {
510
+ branches = append(branches, g.typeof(v, "function"))
511
+ }
512
+ for _, native := range metadata.Natives {
513
+ branches = append(branches, g.instanceof(v, native.Name))
514
+ }
515
+ for _, tuple := range metadata.Tuples {
516
+ branches = append(branches, g.matchTuple(tuple.Type, v))
517
+ }
518
+ for _, array := range metadata.Arrays {
519
+ elem := g.local("elem")
520
+ branches = append(branches, g.and(g.isArray(v), fmt.Sprintf("%s.every((%s) => %s)", g.wrap(v), elem, g.match(array.Type.Value, elem))))
521
+ }
522
+ if len(metadata.Objects) != 0 {
523
+ calls := []string{}
524
+ for _, object := range metadata.Objects {
525
+ calls = append(calls, g.matchCall(object.Type, v))
526
+ }
527
+ branches = append(branches, g.and(g.isObject(v), g.or(calls...)))
528
+ }
529
+ for _, alias := range metadata.Aliases {
530
+ branches = append(branches, g.match(alias.Type.Value, v))
531
+ }
532
+ if metadata.Escaped != nil {
533
+ branches = append(branches, g.match(metadata.Escaped.Original, v))
534
+ }
535
+ if metadata.Rest != nil {
536
+ branches = append(branches, g.match(metadata.Rest, v))
537
+ }
538
+ if len(branches) == 0 {
539
+ return "true"
540
+ }
541
+ return g.or(branches...)
542
+ }
543
+
544
+ // matchTuple renders the is-check of a tuple: the array gate, the length range
545
+ // an omitted optional trailing element makes legal (the same range `tupleInline`
546
+ // compares over), and each element's own check.
547
+ func (g *compareEqualProgrammerGenerator) matchTuple(tuple *schemametadata.MetadataTupleType, v string) string {
548
+ fixed := len(tuple.Elements)
549
+ var rest *schemametadata.MetadataSchema
550
+ if fixed != 0 && tuple.Elements[fixed-1].Rest != nil {
551
+ rest = tuple.Elements[fixed-1].Rest
552
+ fixed--
553
+ }
554
+ checks := []string{g.isArray(v)}
555
+ length := g.access(v, "length")
556
+ if rest == nil {
557
+ required := 0
558
+ allRequired := true
559
+ for i := 0; i < fixed; i++ {
560
+ if tuple.Elements[i].Optional {
561
+ allRequired = false
562
+ } else {
563
+ required++
564
+ }
565
+ }
566
+ if allRequired {
567
+ checks = append(checks, g.same(length, strconv.Itoa(fixed)))
568
+ } else {
569
+ checks = append(checks, fmt.Sprintf("%d <= %s && %d >= %s", required, length, fixed, length))
570
+ }
571
+ } else {
572
+ checks = append(checks, fmt.Sprintf("%s >= %d", length, fixed))
573
+ }
574
+ for i := 0; i < fixed; i++ {
575
+ checks = append(checks, g.matchSlot(tuple.Elements[i], g.index(v, strconv.Itoa(i))))
576
+ }
577
+ if rest != nil {
578
+ elem := g.local("elem")
579
+ checks = append(checks, fmt.Sprintf("%s.slice(%d).every((%s) => %s)", g.wrap(v), fixed, elem, g.match(rest, elem)))
580
+ }
581
+ return g.and(checks...)
582
+ }
583
+
584
+ // discriminant renders the routing predicate for one specialized union member,
585
+ // matching how `is` decides membership: presence (`v[key] !== undefined`) for a
586
+ // key unique to this member, or a value check (literal equality for constants,
587
+ // typeof for atomics/templates) for a shared key whose value distinguishes it.
588
+ // It returns ok=false for any discriminant value it cannot render as such a
589
+ // check, so the caller falls back rather than emit a weaker predicate.
590
+ func (g *compareEqualProgrammerGenerator) discriminant(spec nativehelpers.UnionPredicator_ISpecialized, v string) (string, bool) {
591
+ sole := spec.Property.Key.GetSoleLiteral()
592
+ if sole == nil {
593
+ return "", false
594
+ }
595
+ access := g.property(v, *sole)
596
+ if spec.Neighbor == false {
597
+ return fmt.Sprintf("%s !== undefined", g.wrap(access)), true
598
+ }
599
+ meta := schemametadata.MetadataSchema_unalias(spec.Property.Value)
600
+ if meta == nil || meta.Any {
601
+ return "", false
602
+ }
603
+ if len(meta.Objects) != 0 || len(meta.Arrays) != 0 || len(meta.Tuples) != 0 ||
604
+ len(meta.Natives) != 0 || len(meta.Sets) != 0 || len(meta.Maps) != 0 ||
605
+ len(meta.Aliases) != 0 || len(meta.Functions) != 0 || meta.Escaped != nil || meta.Rest != nil {
606
+ return "", false
607
+ }
608
+ checks := []string{}
609
+ if meta.Nullable {
610
+ // A nullable discriminant (e.g. `type: "a" | null`) routes a null value to
611
+ // this member exactly as `is` does, so `equals(null-arm, null-arm)` stays
612
+ // reflexive rather than falling through to no member.
613
+ checks = append(checks, g.same(access, "null"))
614
+ }
615
+ for _, constant := range meta.Constants {
616
+ for _, value := range constant.Values {
617
+ checks = append(checks, g.same(access, compareEqualProgrammer_literal(value.Value, constant.Type)))
618
+ }
619
+ }
620
+ for _, atomic := range meta.Atomics {
621
+ checks = append(checks, g.typeof(access, atomic.Type))
622
+ }
623
+ if len(meta.Templates) != 0 {
624
+ checks = append(checks, g.typeof(access, "string"))
625
+ }
626
+ if len(checks) == 0 {
627
+ return "", false
628
+ }
629
+ return g.or(checks...), true
630
+ }
631
+
259
632
  func (g *compareEqualProgrammerGenerator) arrayCall(array *schemametadata.MetadataArrayType, x string, y string) string {
260
633
  index := 0
261
634
  if array.Index != nil {
@@ -409,6 +782,21 @@ func (g *compareEqualProgrammerGenerator) objectGuard(x string, y string) string
409
782
  return g.and(g.isObject(x), g.isObject(y))
410
783
  }
411
784
 
785
+ // notNatives builds "neither x nor y is one of the union's native instances",
786
+ // so the object branch never claims a value a native branch owns. Empty when
787
+ // the union declares no native, keeping the object-only output unchanged.
788
+ func (g *compareEqualProgrammerGenerator) notNatives(natives []*schemametadata.MetadataNative, x string, y string) string {
789
+ if len(natives) == 0 {
790
+ return ""
791
+ }
792
+ checks := []string{}
793
+ for _, native := range natives {
794
+ checks = append(checks, "!"+g.wrap(g.instanceof(x, native.Name)))
795
+ checks = append(checks, "!"+g.wrap(g.instanceof(y, native.Name)))
796
+ }
797
+ return g.and(checks...)
798
+ }
799
+
412
800
  func (g *compareEqualProgrammerGenerator) isObject(input string) string {
413
801
  return fmt.Sprintf("typeof %s === \"object\" && %s !== null && !Array.isArray(%s)", g.wrap(input), g.wrap(input), g.wrap(input))
414
802
  }
@@ -219,9 +219,11 @@ func (g *compareLessProgrammerGenerator) core(metadata *schemametadata.MetadataS
219
219
  }
220
220
 
221
221
  // primitive renders the scalar three-way comparator (works for number, string,
222
- // boolean and bigint via the relational operators).
222
+ // boolean and bigint via the relational operators). Self-inequality detects NaN
223
+ // without coercing other scalar types and places it after every ordinary number.
223
224
  func (g *compareLessProgrammerGenerator) primitive(x string, y string) string {
224
- return fmt.Sprintf("(%s < %s ? -1 : %s > %s ? 1 : 0)", g.wrap(x), g.wrap(y), g.wrap(x), g.wrap(y))
225
+ return fmt.Sprintf("(%s !== %s ? (%s !== %s ? 0 : 1) : %s !== %s ? -1 : %s < %s ? -1 : %s > %s ? 1 : 0)",
226
+ g.wrap(x), g.wrap(x), g.wrap(y), g.wrap(y), g.wrap(y), g.wrap(y), g.wrap(x), g.wrap(y), g.wrap(x), g.wrap(y))
225
227
  }
226
228
 
227
229
  func (g *compareLessProgrammerGenerator) native(name string, x string, y string) string {