@typecad/cuttlefish 0.1.0-alpha.1

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 (377) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/api/board-types.d.ts +1 -0
  4. package/dist/api/board-types.js +4 -0
  5. package/dist/api/capabilities.d.ts +12 -0
  6. package/dist/api/capabilities.js +1 -0
  7. package/dist/api/config.d.ts +120 -0
  8. package/dist/api/config.js +7 -0
  9. package/dist/api/index.d.ts +5 -0
  10. package/dist/api/index.js +2 -0
  11. package/dist/api/schema/builder.d.ts +14 -0
  12. package/dist/api/schema/builder.js +15 -0
  13. package/dist/api/schema/index.d.ts +2 -0
  14. package/dist/api/schema/index.js +1 -0
  15. package/dist/api/schema/types.d.ts +257 -0
  16. package/dist/api/schema/types.js +4 -0
  17. package/dist/api/shared/async-runtime-static.d.ts +8 -0
  18. package/dist/api/shared/async-runtime-static.js +201 -0
  19. package/dist/api/shared/async-types.d.ts +42 -0
  20. package/dist/api/shared/async-types.js +8 -0
  21. package/dist/api/shared/board-resolver.d.ts +12 -0
  22. package/dist/api/shared/board-resolver.js +7 -0
  23. package/dist/api/shared/cpp-type-ir.d.ts +229 -0
  24. package/dist/api/shared/cpp-type-ir.js +672 -0
  25. package/dist/api/shared/display-adapter.d.ts +12 -0
  26. package/dist/api/shared/display-adapter.js +145 -0
  27. package/dist/api/shared/display-adapters/eink-mono.d.ts +2 -0
  28. package/dist/api/shared/display-adapters/eink-mono.js +53 -0
  29. package/dist/api/shared/display-adapters/sdl.d.ts +2 -0
  30. package/dist/api/shared/display-adapters/sdl.js +452 -0
  31. package/dist/api/shared/display-adapters/ssd1309.d.ts +2 -0
  32. package/dist/api/shared/display-adapters/ssd1309.js +136 -0
  33. package/dist/api/shared/display-adapters/st7796.d.ts +2 -0
  34. package/dist/api/shared/display-adapters/st7796.js +132 -0
  35. package/dist/api/shared/display-capabilities.d.ts +45 -0
  36. package/dist/api/shared/display-capabilities.js +54 -0
  37. package/dist/api/shared/display-op-ir.d.ts +62 -0
  38. package/dist/api/shared/display-op-ir.js +19 -0
  39. package/dist/api/shared/display-profile.d.ts +265 -0
  40. package/dist/api/shared/display-profile.js +338 -0
  41. package/dist/api/shared/graphics-strategy.d.ts +29 -0
  42. package/dist/api/shared/graphics-strategy.js +11 -0
  43. package/dist/api/shared/hal-op-ir.d.ts +393 -0
  44. package/dist/api/shared/hal-op-ir.js +18 -0
  45. package/dist/api/shared/index.d.ts +26 -0
  46. package/dist/api/shared/index.js +21 -0
  47. package/dist/api/shared/ir-core.d.ts +363 -0
  48. package/dist/api/shared/ir-core.js +8 -0
  49. package/dist/api/shared/ir-declarations.d.ts +201 -0
  50. package/dist/api/shared/ir-declarations.js +26 -0
  51. package/dist/api/shared/ir.d.ts +85 -0
  52. package/dist/api/shared/ir.js +13 -0
  53. package/dist/api/shared/platform-strategy.d.ts +402 -0
  54. package/dist/api/shared/platform-strategy.js +14 -0
  55. package/dist/api/shared/polyfill-helper-registry.d.ts +11 -0
  56. package/dist/api/shared/polyfill-helper-registry.js +86 -0
  57. package/dist/api/shared/polyfill-types.d.ts +33 -0
  58. package/dist/api/shared/polyfill-types.js +76 -0
  59. package/dist/api/shared/promise-runtime.d.ts +10 -0
  60. package/dist/api/shared/promise-runtime.js +244 -0
  61. package/dist/api/shared/snprintf-types.d.ts +29 -0
  62. package/dist/api/shared/snprintf-types.js +8 -0
  63. package/dist/api/shared/string-method-registry.d.ts +53 -0
  64. package/dist/api/shared/string-method-registry.js +168 -0
  65. package/dist/api/shared/toolchain-types.d.ts +63 -0
  66. package/dist/api/shared/toolchain-types.js +71 -0
  67. package/dist/api/shared/types.d.ts +50 -0
  68. package/dist/api/shared/types.js +6 -0
  69. package/dist/ast/parse.d.ts +2 -0
  70. package/dist/ast/parse.js +4 -0
  71. package/dist/cache.d.ts +26 -0
  72. package/dist/cache.js +95 -0
  73. package/dist/cli-utils.d.ts +37 -0
  74. package/dist/cli-utils.js +250 -0
  75. package/dist/cli.d.ts +2 -0
  76. package/dist/cli.js +635 -0
  77. package/dist/config-loader.d.ts +78 -0
  78. package/dist/config-loader.js +508 -0
  79. package/dist/config-schema.d.ts +233 -0
  80. package/dist/config-schema.js +83 -0
  81. package/dist/create/board-checklist.d.ts +2 -0
  82. package/dist/create/board-checklist.js +52 -0
  83. package/dist/create/board-codegen.d.ts +9 -0
  84. package/dist/create/board-codegen.js +238 -0
  85. package/dist/create/board-generators.d.ts +12 -0
  86. package/dist/create/board-generators.js +652 -0
  87. package/dist/create/board-spec.d.ts +640 -0
  88. package/dist/create/board-spec.js +215 -0
  89. package/dist/create/eslint-rules-template.d.ts +2 -0
  90. package/dist/create/eslint-rules-template.js +672 -0
  91. package/dist/create/index.d.ts +11 -0
  92. package/dist/create/index.js +8 -0
  93. package/dist/create/init-scaffold.d.ts +27 -0
  94. package/dist/create/init-scaffold.js +150 -0
  95. package/dist/create/init-templates.d.ts +24 -0
  96. package/dist/create/init-templates.js +379 -0
  97. package/dist/create/init-wizard.d.ts +8 -0
  98. package/dist/create/init-wizard.js +168 -0
  99. package/dist/debug/breakpoint-loader.d.ts +24 -0
  100. package/dist/debug/breakpoint-loader.js +137 -0
  101. package/dist/debug/index.d.ts +3 -0
  102. package/dist/debug/index.js +7 -0
  103. package/dist/debug/preprocessor.d.ts +9 -0
  104. package/dist/debug/preprocessor.js +214 -0
  105. package/dist/debug/types.d.ts +32 -0
  106. package/dist/debug/types.js +6 -0
  107. package/dist/diagnostics/diagnostics-report.d.ts +51 -0
  108. package/dist/diagnostics/diagnostics-report.js +333 -0
  109. package/dist/diagnostics/json-schema.d.ts +138 -0
  110. package/dist/diagnostics/json-schema.js +27 -0
  111. package/dist/diagnostics/md-writer.d.ts +10 -0
  112. package/dist/diagnostics/md-writer.js +336 -0
  113. package/dist/diagnostics/mermaid-builder.d.ts +65 -0
  114. package/dist/diagnostics/mermaid-builder.js +681 -0
  115. package/dist/emit/cpp-emitter.d.ts +6 -0
  116. package/dist/emit/cpp-emitter.js +48 -0
  117. package/dist/emit/emitters/class-emitter.d.ts +2 -0
  118. package/dist/emit/emitters/class-emitter.js +523 -0
  119. package/dist/emit/emitters/emitter-context.d.ts +174 -0
  120. package/dist/emit/emitters/emitter-context.js +1 -0
  121. package/dist/emit/emitters/entrypoint-synthesizer.d.ts +2 -0
  122. package/dist/emit/emitters/entrypoint-synthesizer.js +175 -0
  123. package/dist/emit/emitters/function-emitter-impl.d.ts +19 -0
  124. package/dist/emit/emitters/function-emitter-impl.js +428 -0
  125. package/dist/emit/emitters/line-appender.d.ts +15 -0
  126. package/dist/emit/emitters/line-appender.js +344 -0
  127. package/dist/emit/emitters/namespace-emitter.d.ts +2 -0
  128. package/dist/emit/emitters/namespace-emitter.js +324 -0
  129. package/dist/emit/emitters/output-finalizer.d.ts +4 -0
  130. package/dist/emit/emitters/output-finalizer.js +267 -0
  131. package/dist/emit/emitters/setup.d.ts +3 -0
  132. package/dist/emit/emitters/setup.js +851 -0
  133. package/dist/emit/emitters/top-level-prep.d.ts +2 -0
  134. package/dist/emit/emitters/top-level-prep.js +706 -0
  135. package/dist/emit/emitters/type-decl-emitter.d.ts +2 -0
  136. package/dist/emit/emitters/type-decl-emitter.js +251 -0
  137. package/dist/emit/emitters/ui-emitter.d.ts +21 -0
  138. package/dist/emit/emitters/ui-emitter.js +564 -0
  139. package/dist/emit/enum-emitter.d.ts +1 -0
  140. package/dist/emit/enum-emitter.js +1 -0
  141. package/dist/emit/expression-renderer.d.ts +283 -0
  142. package/dist/emit/expression-renderer.js +1477 -0
  143. package/dist/emit/native-helpers-emitter.d.ts +11 -0
  144. package/dist/emit/native-helpers-emitter.js +34 -0
  145. package/dist/emit/route-hal-op.d.ts +5 -0
  146. package/dist/emit/route-hal-op.js +13 -0
  147. package/dist/emit/snprintf-helpers.d.ts +17 -0
  148. package/dist/emit/snprintf-helpers.js +462 -0
  149. package/dist/emit/statement-renderer.d.ts +189 -0
  150. package/dist/emit/statement-renderer.js +948 -0
  151. package/dist/emit/utils/async-state-machine.d.ts +42 -0
  152. package/dist/emit/utils/async-state-machine.js +343 -0
  153. package/dist/emit/utils/comment-helpers.d.ts +20 -0
  154. package/dist/emit/utils/comment-helpers.js +31 -0
  155. package/dist/emit/utils/cpp-helpers.d.ts +47 -0
  156. package/dist/emit/utils/cpp-helpers.js +85 -0
  157. package/dist/emit/utils/include-resolver.d.ts +58 -0
  158. package/dist/emit/utils/include-resolver.js +155 -0
  159. package/dist/emit/utils/index.d.ts +8 -0
  160. package/dist/emit/utils/index.js +12 -0
  161. package/dist/emit/utils/type-inference.d.ts +159 -0
  162. package/dist/emit/utils/type-inference.js +559 -0
  163. package/dist/eslint-check.d.ts +10 -0
  164. package/dist/eslint-check.js +102 -0
  165. package/dist/framework-package.d.ts +10 -0
  166. package/dist/framework-package.js +58 -0
  167. package/dist/framework-registry.d.ts +39 -0
  168. package/dist/framework-registry.js +30 -0
  169. package/dist/incremental-cache.d.ts +116 -0
  170. package/dist/incremental-cache.js +335 -0
  171. package/dist/ir/adc-range-validation.d.ts +11 -0
  172. package/dist/ir/adc-range-validation.js +250 -0
  173. package/dist/ir/ast-node-utils.d.ts +8 -0
  174. package/dist/ir/ast-node-utils.js +32 -0
  175. package/dist/ir/board-pin-utils.d.ts +13 -0
  176. package/dist/ir/board-pin-utils.js +65 -0
  177. package/dist/ir/board-resolver.d.ts +36 -0
  178. package/dist/ir/board-resolver.js +437 -0
  179. package/dist/ir/build-ir-state.d.ts +167 -0
  180. package/dist/ir/build-ir-state.js +306 -0
  181. package/dist/ir/build-ir.d.ts +2 -0
  182. package/dist/ir/build-ir.js +808 -0
  183. package/dist/ir/call-graph.d.ts +35 -0
  184. package/dist/ir/call-graph.js +194 -0
  185. package/dist/ir/compile-time-only.d.ts +2 -0
  186. package/dist/ir/compile-time-only.js +16 -0
  187. package/dist/ir/declaration-builders.d.ts +9 -0
  188. package/dist/ir/declaration-builders.js +608 -0
  189. package/dist/ir/entry-points.d.ts +30 -0
  190. package/dist/ir/entry-points.js +191 -0
  191. package/dist/ir/expression-to-ir.d.ts +5 -0
  192. package/dist/ir/expression-to-ir.js +2249 -0
  193. package/dist/ir/extract-property-chain.d.ts +10 -0
  194. package/dist/ir/extract-property-chain.js +30 -0
  195. package/dist/ir/feature-prescan.d.ts +3 -0
  196. package/dist/ir/feature-prescan.js +43 -0
  197. package/dist/ir/feature-registry.d.ts +30 -0
  198. package/dist/ir/feature-registry.js +816 -0
  199. package/dist/ir/filter.d.ts +7 -0
  200. package/dist/ir/filter.js +85 -0
  201. package/dist/ir/function-builder.d.ts +19 -0
  202. package/dist/ir/function-builder.js +670 -0
  203. package/dist/ir/hal/hal-emitter.d.ts +62 -0
  204. package/dist/ir/hal/hal-emitter.js +735 -0
  205. package/dist/ir/hal/hal-parser.d.ts +61 -0
  206. package/dist/ir/hal/hal-parser.js +473 -0
  207. package/dist/ir/hal/hal-plugins.d.ts +34 -0
  208. package/dist/ir/hal/hal-plugins.js +706 -0
  209. package/dist/ir/hal-resolver.d.ts +5 -0
  210. package/dist/ir/hal-resolver.js +5 -0
  211. package/dist/ir/heap-analysis.d.ts +8 -0
  212. package/dist/ir/heap-analysis.js +350 -0
  213. package/dist/ir/heap-array-validation.d.ts +24 -0
  214. package/dist/ir/heap-array-validation.js +29 -0
  215. package/dist/ir/identifier-collector.d.ts +18 -0
  216. package/dist/ir/identifier-collector.js +439 -0
  217. package/dist/ir/interrupt-analysis.d.ts +39 -0
  218. package/dist/ir/interrupt-analysis.js +467 -0
  219. package/dist/ir/memory-budget-validation.d.ts +10 -0
  220. package/dist/ir/memory-budget-validation.js +86 -0
  221. package/dist/ir/namespace-builder.d.ts +7 -0
  222. package/dist/ir/namespace-builder.js +152 -0
  223. package/dist/ir/ownership-analysis.d.ts +9 -0
  224. package/dist/ir/ownership-analysis.js +1207 -0
  225. package/dist/ir/peripheral-ownership.d.ts +3 -0
  226. package/dist/ir/peripheral-ownership.js +152 -0
  227. package/dist/ir/peripheral-symbols.d.ts +7 -0
  228. package/dist/ir/peripheral-symbols.js +57 -0
  229. package/dist/ir/peripheral-usage.d.ts +54 -0
  230. package/dist/ir/peripheral-usage.js +691 -0
  231. package/dist/ir/peripheral-validation.d.ts +8 -0
  232. package/dist/ir/peripheral-validation.js +77 -0
  233. package/dist/ir/pin-alias-conflict.d.ts +4 -0
  234. package/dist/ir/pin-alias-conflict.js +34 -0
  235. package/dist/ir/pin-capability-validation.d.ts +6 -0
  236. package/dist/ir/pin-capability-validation.js +413 -0
  237. package/dist/ir/pin-mode-validation.d.ts +10 -0
  238. package/dist/ir/pin-mode-validation.js +301 -0
  239. package/dist/ir/pin-safety.d.ts +11 -0
  240. package/dist/ir/pin-safety.js +58 -0
  241. package/dist/ir/program-analysis.d.ts +44 -0
  242. package/dist/ir/program-analysis.js +589 -0
  243. package/dist/ir/pulldown-validation.d.ts +7 -0
  244. package/dist/ir/pulldown-validation.js +49 -0
  245. package/dist/ir/pwm-timer-sharing.d.ts +4 -0
  246. package/dist/ir/pwm-timer-sharing.js +93 -0
  247. package/dist/ir/reachability.d.ts +68 -0
  248. package/dist/ir/reachability.js +224 -0
  249. package/dist/ir/register-decorators.d.ts +6 -0
  250. package/dist/ir/register-decorators.js +49 -0
  251. package/dist/ir/render-expr.d.ts +4 -0
  252. package/dist/ir/render-expr.js +127 -0
  253. package/dist/ir/resource-analysis.d.ts +19 -0
  254. package/dist/ir/resource-analysis.js +153 -0
  255. package/dist/ir/statement-to-ir.d.ts +23 -0
  256. package/dist/ir/statement-to-ir.js +349 -0
  257. package/dist/ir/symbol-table.d.ts +68 -0
  258. package/dist/ir/symbol-table.js +179 -0
  259. package/dist/ir/symbol-types.d.ts +56 -0
  260. package/dist/ir/symbol-types.js +107 -0
  261. package/dist/ir/timer0-pwm-timing-conflict.d.ts +4 -0
  262. package/dist/ir/timer0-pwm-timing-conflict.js +71 -0
  263. package/dist/ir/timing-validation.d.ts +7 -0
  264. package/dist/ir/timing-validation.js +95 -0
  265. package/dist/ir/transformers/array-methods.d.ts +8 -0
  266. package/dist/ir/transformers/array-methods.js +493 -0
  267. package/dist/ir/transformers/call-statement.d.ts +5 -0
  268. package/dist/ir/transformers/call-statement.js +758 -0
  269. package/dist/ir/transformers/callback-context-registry.d.ts +20 -0
  270. package/dist/ir/transformers/callback-context-registry.js +55 -0
  271. package/dist/ir/transformers/canvas-lowering.d.ts +42 -0
  272. package/dist/ir/transformers/canvas-lowering.js +249 -0
  273. package/dist/ir/transformers/control-flow.d.ts +8 -0
  274. package/dist/ir/transformers/control-flow.js +508 -0
  275. package/dist/ir/transformers/expressions.d.ts +7 -0
  276. package/dist/ir/transformers/expressions.js +406 -0
  277. package/dist/ir/transformers/hal-call-resolver.d.ts +29 -0
  278. package/dist/ir/transformers/hal-call-resolver.js +274 -0
  279. package/dist/ir/transformers/hal-emit-helpers.d.ts +14 -0
  280. package/dist/ir/transformers/hal-emit-helpers.js +63 -0
  281. package/dist/ir/transformers/namespace-methods.d.ts +20 -0
  282. package/dist/ir/transformers/namespace-methods.js +110 -0
  283. package/dist/ir/transformers/register-assignment.d.ts +5 -0
  284. package/dist/ir/transformers/register-assignment.js +56 -0
  285. package/dist/ir/transformers/ui-call-resolver.d.ts +149 -0
  286. package/dist/ir/transformers/ui-call-resolver.js +1136 -0
  287. package/dist/ir/transformers/ui-callback-lowering.d.ts +62 -0
  288. package/dist/ir/transformers/ui-callback-lowering.js +623 -0
  289. package/dist/ir/transformers/ui-mount.d.ts +20 -0
  290. package/dist/ir/transformers/ui-mount.js +35 -0
  291. package/dist/ir/transformers/ui-reactive.d.ts +68 -0
  292. package/dist/ir/transformers/ui-reactive.js +129 -0
  293. package/dist/ir/transformers/variables.d.ts +14 -0
  294. package/dist/ir/transformers/variables.js +1045 -0
  295. package/dist/ir/try-catch-validation.d.ts +26 -0
  296. package/dist/ir/try-catch-validation.js +128 -0
  297. package/dist/ir/type-resolution.d.ts +31 -0
  298. package/dist/ir/type-resolution.js +977 -0
  299. package/dist/ir/ui-element-auto-wire.d.ts +50 -0
  300. package/dist/ir/ui-element-auto-wire.js +218 -0
  301. package/dist/ir/unit-suspicion-validation.d.ts +12 -0
  302. package/dist/ir/unit-suspicion-validation.js +296 -0
  303. package/dist/ir/utils/walk-ir.d.ts +6 -0
  304. package/dist/ir/utils/walk-ir.js +162 -0
  305. package/dist/ir/validation-orchestrator.d.ts +4 -0
  306. package/dist/ir/validation-orchestrator.js +45 -0
  307. package/dist/libdef/base-class-resolver.d.ts +23 -0
  308. package/dist/libdef/base-class-resolver.js +50 -0
  309. package/dist/libdef/cpp-to-decl.d.ts +34 -0
  310. package/dist/libdef/cpp-to-decl.js +584 -0
  311. package/dist/libdef/header-parser.d.ts +53 -0
  312. package/dist/libdef/header-parser.js +269 -0
  313. package/dist/libdef/registry.d.ts +10 -0
  314. package/dist/libdef/registry.js +142 -0
  315. package/dist/mapping/peripheral-names.d.ts +23 -0
  316. package/dist/mapping/peripheral-names.js +63 -0
  317. package/dist/mapping/source-map.d.ts +46 -0
  318. package/dist/mapping/source-map.js +207 -0
  319. package/dist/orchestrator/dts-generator.d.ts +17 -0
  320. package/dist/orchestrator/dts-generator.js +83 -0
  321. package/dist/orchestrator/graph-builder.d.ts +18 -0
  322. package/dist/orchestrator/graph-builder.js +218 -0
  323. package/dist/orchestrator/semantic-facts-verifier.d.ts +38 -0
  324. package/dist/orchestrator/semantic-facts-verifier.js +121 -0
  325. package/dist/orchestrator/semantic-facts.d.ts +141 -0
  326. package/dist/orchestrator/semantic-facts.js +652 -0
  327. package/dist/orchestrator/type-checker.d.ts +39 -0
  328. package/dist/orchestrator/type-checker.js +760 -0
  329. package/dist/platform/async-runtime.d.ts +8 -0
  330. package/dist/platform/async-runtime.js +26 -0
  331. package/dist/platform/generic-strategy.d.ts +101 -0
  332. package/dist/platform/generic-strategy.js +289 -0
  333. package/dist/platform/index.d.ts +4 -0
  334. package/dist/platform/index.js +9 -0
  335. package/dist/platform/registry.d.ts +21 -0
  336. package/dist/platform/registry.js +42 -0
  337. package/dist/platform/toolchain.d.ts +4 -0
  338. package/dist/platform/toolchain.js +43 -0
  339. package/dist/preview/client.d.ts +1 -0
  340. package/dist/preview/client.js +137 -0
  341. package/dist/preview/server.d.ts +5 -0
  342. package/dist/preview/server.js +199 -0
  343. package/dist/profiler/index.d.ts +28 -0
  344. package/dist/profiler/index.js +28 -0
  345. package/dist/profiler/profiler.d.ts +95 -0
  346. package/dist/profiler/profiler.js +338 -0
  347. package/dist/profiler/types.d.ts +87 -0
  348. package/dist/profiler/types.js +12 -0
  349. package/dist/stores/display-profile-store.d.ts +16 -0
  350. package/dist/stores/display-profile-store.js +48 -0
  351. package/dist/stores/theme-store.d.ts +13 -0
  352. package/dist/stores/theme-store.js +30 -0
  353. package/dist/testing.d.ts +45 -0
  354. package/dist/testing.js +47 -0
  355. package/dist/transpile/resolution.d.ts +29 -0
  356. package/dist/transpile/resolution.js +282 -0
  357. package/dist/transpile.d.ts +3 -0
  358. package/dist/transpile.js +722 -0
  359. package/dist/types.d.ts +217 -0
  360. package/dist/types.js +1 -0
  361. package/dist/ui/ui-bridge.d.ts +4 -0
  362. package/dist/ui/ui-bridge.js +34 -0
  363. package/dist/ui-hook.d.ts +84 -0
  364. package/dist/ui-hook.js +45 -0
  365. package/dist/utils/cli.d.ts +3 -0
  366. package/dist/utils/cli.js +463 -0
  367. package/dist/utils/fs.d.ts +4 -0
  368. package/dist/utils/fs.js +23 -0
  369. package/dist/utils/logger.d.ts +2 -0
  370. package/dist/utils/logger.js +8 -0
  371. package/dist/utils/strings.d.ts +35 -0
  372. package/dist/utils/strings.js +142 -0
  373. package/dist/utils/ui.d.ts +66 -0
  374. package/dist/utils/ui.js +149 -0
  375. package/dist/watch.d.ts +35 -0
  376. package/dist/watch.js +111 -0
  377. package/package.json +127 -0
@@ -0,0 +1,977 @@
1
+ import ts from "typescript";
2
+ import { classTypeNames, topLevelClasses, discriminatedUnionVariantNames, activeEnumNames } from "./build-ir-state.js";
3
+ import { getCurrentIrTypeScope } from "./symbol-types.js";
4
+ import { parseCppType, renderCppType, bareType, elementOf, } from "../api/shared/cpp-type-ir.js";
5
+ const DIRECT_CPP_TYPE_MAP = new Map([
6
+ ["int", "int"],
7
+ ["float", "float"],
8
+ ["bool", "bool"],
9
+ ["string", "std::string"],
10
+ ["void", "void"],
11
+ ["double", "double"],
12
+ ["long", "long"],
13
+ ["unsigned", "unsigned int"],
14
+ ["uint8_t", "uint8_t"],
15
+ ["uint16_t", "uint16_t"],
16
+ ["uint32_t", "uint32_t"],
17
+ ["int8_t", "int8_t"],
18
+ ["int16_t", "int16_t"],
19
+ ["int32_t", "int32_t"],
20
+ ["size_t", "size_t"],
21
+ ["Uint8Array", "uint8_t*"],
22
+ ["Uint16Array", "uint16_t*"],
23
+ ["Uint32Array", "uint32_t*"],
24
+ ["Int8Array", "int8_t*"],
25
+ ["Int16Array", "int16_t*"],
26
+ ["Int32Array", "int32_t*"],
27
+ ["Float32Array", "float*"],
28
+ ["Float64Array", "double*"],
29
+ ]);
30
+ const PIN_INTERFACE_TYPE_NAMES = new Set([
31
+ "BasePin", "Pin", "PWMPin", "AnalogPin", "InterruptPin",
32
+ "InterruptOptions",
33
+ "PinMode", "InterruptMode",
34
+ ]);
35
+ const BUS_INTERFACE_TYPE_NAMES = new Set([
36
+ "II2CBus", "ISPIBus", "ISerialPort", "IUART",
37
+ "I2CConfig", "SPIConfig", "UARTConfig",
38
+ "I2CAddress", "UARTStatus", "SPITransferOptions",
39
+ ]);
40
+ const STRATEGY_TYPE_NAMES = new Set([
41
+ "NativeStrategy", "ArduinoStrategy", "BoardStrategy",
42
+ "RuntimePolyfillIR", "PeripheralUsage",
43
+ ]);
44
+ const BOARD_CONSTANT_TYPE_NAMES = new Set([
45
+ "INPUT", "OUTPUT", "INPUT_PULLUP", "INPUT_PULLDOWN",
46
+ "CHANGE", "FALLING", "RISING",
47
+ ]);
48
+ const OWNERSHIP_WRAPPER_TYPE_NAMES = new Set([
49
+ "Owned", "Shared", "Mutable",
50
+ ]);
51
+ export function resolveAliasedTypeNode(node, typeAliases, visited = new Set()) {
52
+ if (!node || !typeAliases) {
53
+ return node;
54
+ }
55
+ if (!ts.isTypeReferenceNode(node) || !ts.isIdentifier(node.typeName)) {
56
+ return node;
57
+ }
58
+ const aliasName = node.typeName.text;
59
+ if (visited.has(aliasName)) {
60
+ return node;
61
+ }
62
+ const aliasNode = typeAliases.get(aliasName);
63
+ if (!aliasNode) {
64
+ return node;
65
+ }
66
+ visited.add(aliasName);
67
+ return resolveAliasedTypeNode(aliasNode, typeAliases, visited);
68
+ }
69
+ function inferNumericCppType(literalText) {
70
+ return /[.eE]/.test(literalText) ? "double" : "int";
71
+ }
72
+ export function getDirectCppType(typeName) {
73
+ const directCppType = DIRECT_CPP_TYPE_MAP.get(typeName);
74
+ return directCppType;
75
+ }
76
+ function isBoardDefinitionTypeName(typeName) {
77
+ return typeName.endsWith("Board") || typeName.endsWith("Definition") ||
78
+ typeName.startsWith("Native");
79
+ }
80
+ function isSerialTypeName(typeName) {
81
+ return typeName === "Serial" || typeName.endsWith("Serial");
82
+ }
83
+ function isPinConstantTypeName(typeName) {
84
+ return /^D\d+$/.test(typeName) ||
85
+ /^A\d+$/.test(typeName) ||
86
+ typeName === "LED" ||
87
+ typeName === "TX" ||
88
+ typeName === "RX" ||
89
+ typeName.startsWith("TX") ||
90
+ typeName.startsWith("RX");
91
+ }
92
+ function isPinImplementationTypeName(typeName) {
93
+ // Framework pin implementation types follow the convention {FRAMEWORK}{Capability}Pin
94
+ // (e.g., AVRDigitalPin, ESP32AnalogPin, STM32PWMPin). Recognized by ALL_CAPS prefix
95
+ // followed by a pin-related suffix, or the Native* prefix for bare-metal strategies.
96
+ return typeName.startsWith("Native") ||
97
+ (/^[A-Z][A-Z0-9]/.test(typeName) && /Pin/.test(typeName));
98
+ }
99
+ function isSharedCompileTimeOnlyTypeName(typeName) {
100
+ return PIN_INTERFACE_TYPE_NAMES.has(typeName) ||
101
+ STRATEGY_TYPE_NAMES.has(typeName) ||
102
+ BOARD_CONSTANT_TYPE_NAMES.has(typeName) ||
103
+ OWNERSHIP_WRAPPER_TYPE_NAMES.has(typeName) ||
104
+ isBoardDefinitionTypeName(typeName) ||
105
+ isSerialTypeName(typeName) ||
106
+ isPinConstantTypeName(typeName) ||
107
+ isPinImplementationTypeName(typeName);
108
+ }
109
+ function isKnownCompileTimeOnlyTypeName(typeName) {
110
+ return BUS_INTERFACE_TYPE_NAMES.has(typeName) || isSharedCompileTimeOnlyTypeName(typeName);
111
+ }
112
+ function normalizeTypeHintForUse(typeHint) {
113
+ if (typeHint === "auto") {
114
+ return "double";
115
+ }
116
+ return typeHint;
117
+ }
118
+ function functionTypeNodeToCppType(node, typeAliases, typeParametersInScope) {
119
+ // Build via CppTypeIR so the function signature is structured, then flatten
120
+ // to the canonical `std::function<R(P...)>` string at the boundary.
121
+ const returnType = normalizeTypeHintForUse(typeNodeToCppType(node.type, typeAliases, typeParametersInScope));
122
+ const params = node.parameters.map((parameter) => normalizeTypeHintForUse(typeNodeToCppType(parameter.type, typeAliases, typeParametersInScope)));
123
+ const ir = {
124
+ kind: "function",
125
+ returnType: parseCppType(returnType),
126
+ params: params.map((p) => parseCppType(p)),
127
+ };
128
+ return renderCppType(ir);
129
+ }
130
+ export function typeNodeToCppType(node, typeAliases, typeParametersInScope) {
131
+ if (!node) {
132
+ return "auto";
133
+ }
134
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
135
+ const typeName = node.typeName.text;
136
+ if (typeParametersInScope && typeParametersInScope.has(typeName)) {
137
+ return typeName;
138
+ }
139
+ }
140
+ // ── Ownership wrapper detection (before alias resolution) ───────────
141
+ // Shared<T>, Mutable<T>, Owned<T> are phantom types that wrap the real type.
142
+ // We must check the ORIGINAL node before alias resolution, because
143
+ // `type Shared<T> = T` would resolve Shared<number> → number, hiding the wrapper.
144
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
145
+ const wrapperName = node.typeName.text;
146
+ if (OWNERSHIP_WRAPPER_TYPE_NAMES.has(wrapperName)) {
147
+ const innerTypeNode = node.typeArguments?.[0];
148
+ return typeNodeToCppType(innerTypeNode, typeAliases, typeParametersInScope);
149
+ }
150
+ }
151
+ const resolvedNode = resolveAliasedTypeNode(node, typeAliases) ?? node;
152
+ // If the resolved node is an object literal type (e.g. type X = { a: number }),
153
+ // return the original type reference name as the C++ struct type.
154
+ if (ts.isTypeLiteralNode(resolvedNode) && ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
155
+ return node.typeName.text;
156
+ }
157
+ // Handle mapped types like { readonly [P in keyof SomeType]: SomeType[P] }
158
+ // These are type-level copies; in C++ they're equivalent to the source type.
159
+ // Resolve to the source type name since C++ doesn't have readonly.
160
+ if (ts.isMappedTypeNode(resolvedNode)) {
161
+ const constraint = resolvedNode.typeParameter?.constraint;
162
+ if (constraint && ts.isTypeOperatorNode(constraint) && constraint.operator === ts.SyntaxKind.KeyOfKeyword) {
163
+ const sourceType = constraint.type;
164
+ if (sourceType && ts.isTypeReferenceNode(sourceType) && ts.isIdentifier(sourceType.typeName)) {
165
+ // The mapped type mirrors the source type; resolve to the source type name
166
+ return sourceType.typeName.text;
167
+ }
168
+ }
169
+ // Generic mapped type fallback: use the outer type reference name
170
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
171
+ return node.typeName.text;
172
+ }
173
+ }
174
+ if (ts.isParenthesizedTypeNode(resolvedNode)) {
175
+ return typeNodeToCppType(resolvedNode.type, typeAliases, typeParametersInScope);
176
+ }
177
+ if (ts.isUnionTypeNode(resolvedNode)) {
178
+ const nonNullTypes = resolvedNode.types.filter(t => {
179
+ return t.kind !== ts.SyntaxKind.NullKeyword && t.kind !== ts.SyntaxKind.UndefinedKeyword;
180
+ });
181
+ if (nonNullTypes.length === 0) {
182
+ return "auto";
183
+ }
184
+ if (nonNullTypes.length === 1) {
185
+ return typeNodeToCppType(nonNullTypes[0], typeAliases, typeParametersInScope);
186
+ }
187
+ const allAreTypeLiterals = nonNullTypes.every(ts.isTypeLiteralNode);
188
+ if (allAreTypeLiterals) {
189
+ const variantNames = discriminatedUnionVariantNames.get(ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) ? node.typeName.text : "");
190
+ if (variantNames) {
191
+ return `std::variant<${variantNames.join(", ")}>`;
192
+ }
193
+ const variantNamesFallback = nonNullTypes.map((_, i) => `_Variant_${i}`);
194
+ return `std::variant<${variantNamesFallback.join(", ")}>`;
195
+ }
196
+ const memberTypes = nonNullTypes
197
+ .map(t => typeNodeToCppType(t, typeAliases, typeParametersInScope))
198
+ .filter((t) => t !== "auto" && t !== undefined);
199
+ const uniqueTypes = [...new Set(memberTypes)];
200
+ if (uniqueTypes.length >= 2) {
201
+ // Build via CppTypeIR.variant so the members are parsed structure, not
202
+ // a hand-joined string. Renders byte-identically to the old form.
203
+ const ir = {
204
+ kind: "variant",
205
+ members: uniqueTypes.map((t) => parseCppType(t)),
206
+ };
207
+ return renderCppType(ir);
208
+ }
209
+ if (uniqueTypes.length === 1) {
210
+ return uniqueTypes[0];
211
+ }
212
+ return "auto";
213
+ }
214
+ if (ts.isArrayTypeNode(resolvedNode)) {
215
+ const elementType = normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.elementType, typeAliases, typeParametersInScope));
216
+ const ir = { kind: "vector", element: parseCppType(elementType) };
217
+ return renderCppType(ir);
218
+ }
219
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "Array") {
220
+ const elementTypeNode = resolvedNode.typeArguments?.[0];
221
+ const elementType = normalizeTypeHintForUse(typeNodeToCppType(elementTypeNode, typeAliases, typeParametersInScope));
222
+ const ir = { kind: "vector", element: parseCppType(elementType) };
223
+ return renderCppType(ir);
224
+ }
225
+ if (ts.isFunctionTypeNode(resolvedNode)) {
226
+ return functionTypeNodeToCppType(resolvedNode, typeAliases, typeParametersInScope);
227
+ }
228
+ if (resolvedNode.kind === ts.SyntaxKind.NumberKeyword) {
229
+ return "double";
230
+ }
231
+ if (resolvedNode.kind === ts.SyntaxKind.BooleanKeyword) {
232
+ return "bool";
233
+ }
234
+ if (resolvedNode.kind === ts.SyntaxKind.StringKeyword) {
235
+ return "std::string";
236
+ }
237
+ if (resolvedNode.kind === ts.SyntaxKind.VoidKeyword) {
238
+ return "void";
239
+ }
240
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName)) {
241
+ const typeName = resolvedNode.typeName.text;
242
+ const directCppType = getDirectCppType(typeName);
243
+ if (directCppType) {
244
+ return directCppType;
245
+ }
246
+ if (isSharedCompileTimeOnlyTypeName(typeName)) {
247
+ return "auto";
248
+ }
249
+ }
250
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "Set") {
251
+ const elementTypeNode = resolvedNode.typeArguments?.[0];
252
+ const elementType = normalizeTypeHintForUse(typeNodeToCppType(elementTypeNode, typeAliases, typeParametersInScope));
253
+ const ir = { kind: "set", element: parseCppType(elementType) };
254
+ return renderCppType(ir);
255
+ }
256
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "ReadonlySet") {
257
+ const elementTypeNode = resolvedNode.typeArguments?.[0];
258
+ const elementType = normalizeTypeHintForUse(typeNodeToCppType(elementTypeNode, typeAliases, typeParametersInScope));
259
+ const ir = { kind: "set", element: parseCppType(elementType) };
260
+ return renderCppType(ir);
261
+ }
262
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "Map") {
263
+ const keyTypeNode = resolvedNode.typeArguments?.[0];
264
+ const valueTypeNode = resolvedNode.typeArguments?.[1];
265
+ const keyType = normalizeTypeHintForUse(typeNodeToCppType(keyTypeNode, typeAliases, typeParametersInScope));
266
+ const valueType = normalizeTypeHintForUse(typeNodeToCppType(valueTypeNode, typeAliases, typeParametersInScope));
267
+ const ir = { kind: "map", key: parseCppType(keyType), value: parseCppType(valueType) };
268
+ return renderCppType(ir);
269
+ }
270
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "ReadonlyMap") {
271
+ const keyTypeNode = resolvedNode.typeArguments?.[0];
272
+ const valueTypeNode = resolvedNode.typeArguments?.[1];
273
+ const keyType = normalizeTypeHintForUse(typeNodeToCppType(keyTypeNode, typeAliases, typeParametersInScope));
274
+ const valueType = normalizeTypeHintForUse(typeNodeToCppType(valueTypeNode, typeAliases, typeParametersInScope));
275
+ const ir = { kind: "map", key: parseCppType(keyType), value: parseCppType(valueType) };
276
+ return renderCppType(ir);
277
+ }
278
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "Record") {
279
+ const keyTypeNode = resolvedNode.typeArguments?.[0];
280
+ const valueTypeNode = resolvedNode.typeArguments?.[1];
281
+ const keyType = normalizeTypeHintForUse(typeNodeToCppType(keyTypeNode, typeAliases, typeParametersInScope));
282
+ const valueType = normalizeTypeHintForUse(typeNodeToCppType(valueTypeNode, typeAliases, typeParametersInScope));
283
+ const ir = { kind: "map", key: parseCppType(keyType), value: parseCppType(valueType) };
284
+ return renderCppType(ir);
285
+ }
286
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName) && resolvedNode.typeName.text === "ReadonlyArray") {
287
+ const elementTypeNode = resolvedNode.typeArguments?.[0];
288
+ const elementType = normalizeTypeHintForUse(typeNodeToCppType(elementTypeNode, typeAliases, typeParametersInScope));
289
+ const ir = { kind: "vector", element: parseCppType(elementType) };
290
+ return renderCppType(ir);
291
+ }
292
+ // Tuple types: [A, B, C] → std::tuple<A, B, C>
293
+ if (ts.isTupleTypeNode(resolvedNode)) {
294
+ const elementTypes = resolvedNode.elements.map((el) => {
295
+ if (ts.isOptionalTypeNode(el)) {
296
+ return normalizeTypeHintForUse(typeNodeToCppType(el.type, typeAliases, typeParametersInScope));
297
+ }
298
+ if (ts.isRestTypeNode(el)) {
299
+ return normalizeTypeHintForUse(typeNodeToCppType(el.type, typeAliases, typeParametersInScope));
300
+ }
301
+ return normalizeTypeHintForUse(typeNodeToCppType(el, typeAliases, typeParametersInScope));
302
+ });
303
+ const ir = { kind: "tuple", elements: elementTypes.map((t) => parseCppType(t)) };
304
+ return renderCppType(ir);
305
+ }
306
+ // User-defined types (interfaces, classes, enums) pass through as their C++ type name.
307
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName)) {
308
+ const typeName = resolvedNode.typeName.text;
309
+ if (typeName === "Partial" && resolvedNode.typeArguments?.length === 1) {
310
+ return normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope));
311
+ }
312
+ if (typeName === "Required" && resolvedNode.typeArguments?.length === 1) {
313
+ return normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope));
314
+ }
315
+ if (typeName === "NonNullable" && resolvedNode.typeArguments?.length === 1) {
316
+ const inner = typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope);
317
+ return (inner || "auto");
318
+ }
319
+ if (typeName === "Readonly" && resolvedNode.typeArguments?.length === 1) {
320
+ return normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope));
321
+ }
322
+ if (typeName === "Pick" && resolvedNode.typeArguments?.length === 2) {
323
+ return normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope));
324
+ }
325
+ if (typeName === "Omit" && resolvedNode.typeArguments?.length === 2) {
326
+ return normalizeTypeHintForUse(typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope));
327
+ }
328
+ if (typeName === "Record" && resolvedNode.typeArguments?.length === 2) {
329
+ const keyType = typeNodeToCppType(resolvedNode.typeArguments[0], typeAliases, typeParametersInScope);
330
+ const valueType = typeNodeToCppType(resolvedNode.typeArguments[1], typeAliases, typeParametersInScope);
331
+ const ir = { kind: "map", key: parseCppType(keyType), value: parseCppType(valueType) };
332
+ return renderCppType(ir);
333
+ }
334
+ if (typeName === "ReturnType" || typeName === "Parameters" || typeName === "ConstructorParameters" || typeName === "InstanceType" || typeName === "Extract" || typeName === "Exclude") {
335
+ return "auto";
336
+ }
337
+ // TypeScript class values are references. Keep that representation consistent
338
+ // across declarations, parameters, returns, fields, and containers so `new X()`
339
+ // is never assigned to a value-typed C++ `X` by accident. Modeled as a
340
+ // `pointer(named(typeName, args?))` so the class-vs-value distinction is
341
+ // structural, not a trailing `*` to be re-parsed.
342
+ if (classTypeNames.has(typeName)) {
343
+ const typeArgs = resolvedNode.typeArguments?.map((arg) => normalizeTypeHintForUse(typeNodeToCppType(arg, typeAliases, typeParametersInScope)));
344
+ const namedIr = {
345
+ kind: "named",
346
+ name: typeName,
347
+ args: typeArgs && typeArgs.length > 0 ? typeArgs.map((t) => parseCppType(t)) : undefined,
348
+ };
349
+ const ir = { kind: "pointer", base: namedIr };
350
+ return renderCppType(ir);
351
+ }
352
+ return resolvedNode.typeName.text;
353
+ }
354
+ if (ts.isIntersectionTypeNode(resolvedNode)) {
355
+ for (const part of resolvedNode.types) {
356
+ const cppType = typeNodeToCppType(part, typeAliases, typeParametersInScope);
357
+ if (cppType && cppType !== "auto" && cppType !== "void") {
358
+ return cppType;
359
+ }
360
+ }
361
+ return "auto";
362
+ }
363
+ if (ts.isLiteralTypeNode(resolvedNode)) {
364
+ if (ts.isStringLiteral(resolvedNode.literal))
365
+ return "std::string";
366
+ if (ts.isNumericLiteral(resolvedNode.literal))
367
+ return "int";
368
+ if (resolvedNode.literal.kind === ts.SyntaxKind.TrueKeyword || resolvedNode.literal.kind === ts.SyntaxKind.FalseKeyword)
369
+ return "bool";
370
+ return "auto";
371
+ }
372
+ // Indexed access types: T[K] — resolve to auto for now since C++ doesn't have this
373
+ if (resolvedNode.kind === ts.SyntaxKind.IndexedAccessType) {
374
+ const indexed = resolvedNode;
375
+ const objectType = typeNodeToCppType(indexed.objectType, typeAliases, typeParametersInScope);
376
+ if (objectType && objectType !== "auto") {
377
+ const indexType = indexed.indexType;
378
+ if (ts.isLiteralTypeNode(indexType) && ts.isStringLiteral(indexType.literal)) {
379
+ return "auto";
380
+ }
381
+ }
382
+ return "auto";
383
+ }
384
+ // Conditional types: T extends U ? X : Y — resolve to true branch optimistically
385
+ if (resolvedNode.kind === ts.SyntaxKind.ConditionalType) {
386
+ const conditional = resolvedNode;
387
+ return typeNodeToCppType(conditional.trueType, typeAliases, typeParametersInScope);
388
+ }
389
+ // Template literal types — no C++ equivalent
390
+ if (resolvedNode.kind === ts.SyntaxKind.TemplateLiteralType ||
391
+ resolvedNode.kind === ts.SyntaxKind.TemplateLiteralTypeSpan) {
392
+ return "auto";
393
+ }
394
+ // keyof T — return auto since C++ doesn't have this concept
395
+ if (ts.isTypeOperatorNode(resolvedNode) && resolvedNode.operator === ts.SyntaxKind.KeyOfKeyword) {
396
+ return "auto";
397
+ }
398
+ return "auto";
399
+ }
400
+ export function resolveFunctionTypeSignature(typeNode, typeAliases) {
401
+ const resolvedNode = resolveAliasedTypeNode(typeNode, typeAliases);
402
+ if (!resolvedNode || !ts.isFunctionTypeNode(resolvedNode)) {
403
+ return undefined;
404
+ }
405
+ return {
406
+ parameterTypes: resolvedNode.parameters.map((parameter) => typeNodeToCppType(parameter.type, typeAliases)),
407
+ returnType: typeNodeToCppType(resolvedNode.type, typeAliases),
408
+ };
409
+ }
410
+ function isStructuredTypeAnnotation(typeNode, typeAliases) {
411
+ const resolvedNode = resolveAliasedTypeNode(typeNode, typeAliases);
412
+ if (!resolvedNode) {
413
+ return false;
414
+ }
415
+ if (ts.isTypeLiteralNode(resolvedNode)) {
416
+ return true;
417
+ }
418
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName)) {
419
+ return resolvedNode.typeName.text === "Record";
420
+ }
421
+ return false;
422
+ }
423
+ function isKnownTypeName(typeName) {
424
+ return isKnownCompileTimeOnlyTypeName(typeName);
425
+ }
426
+ function isKnownCompileTimeType(typeNode, typeAliases) {
427
+ const resolvedNode = resolveAliasedTypeNode(typeNode, typeAliases);
428
+ if (!resolvedNode) {
429
+ return false;
430
+ }
431
+ if (ts.isIntersectionTypeNode(resolvedNode)) {
432
+ return resolvedNode.types.every((part) => isKnownCompileTimeType(part, typeAliases));
433
+ }
434
+ if (ts.isUnionTypeNode(resolvedNode)) {
435
+ return resolvedNode.types.every((part) => isKnownCompileTimeType(part, typeAliases));
436
+ }
437
+ if (ts.isParenthesizedTypeNode(resolvedNode)) {
438
+ return isKnownCompileTimeType(resolvedNode.type, typeAliases);
439
+ }
440
+ if (ts.isTypeReferenceNode(resolvedNode) && ts.isIdentifier(resolvedNode.typeName)) {
441
+ return isKnownTypeName(resolvedNode.typeName.text);
442
+ }
443
+ return false;
444
+ }
445
+ export function inferExprCppType(expr, functionReturnTypes, localVariableTypes, sourceText) {
446
+ if (ts.isAwaitExpression(expr)) {
447
+ return inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
448
+ }
449
+ if (ts.isNonNullExpression(expr) || ts.isParenthesizedExpression(expr)) {
450
+ return inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
451
+ }
452
+ if (ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr)) {
453
+ return inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
454
+ }
455
+ // typeof always produces a string result
456
+ if (ts.isTypeOfExpression(expr)) {
457
+ return "std::string";
458
+ }
459
+ if (ts.isNumericLiteral(expr)) {
460
+ // Use original source text — TypeScript normalizes "2.0" to "2" in expr.text
461
+ const literalText = sourceText
462
+ ? sourceText.substring(expr.pos, expr.end).trim()
463
+ : expr.text;
464
+ return inferNumericCppType(literalText);
465
+ }
466
+ if (ts.isStringLiteral(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
467
+ return "std::string";
468
+ }
469
+ if (ts.isArrayLiteralExpression(expr)) {
470
+ const inferredElementTypes = expr.elements
471
+ .filter((item) => !ts.isSpreadElement(item))
472
+ .map((item) => inferExprCppType(item, functionReturnTypes, localVariableTypes, sourceText))
473
+ .filter((item) => item !== "auto");
474
+ if (inferredElementTypes.length === 0) {
475
+ return "std::vector<int>";
476
+ }
477
+ if (inferredElementTypes.includes("float") || inferredElementTypes.includes("double")) {
478
+ return "std::vector<double>";
479
+ }
480
+ if (inferredElementTypes.includes("std::string")) {
481
+ return "std::vector<std::string>";
482
+ }
483
+ if (inferredElementTypes.includes("bool") && !inferredElementTypes.includes("int")) {
484
+ return "std::vector<bool>";
485
+ }
486
+ if (inferredElementTypes.includes("int") || inferredElementTypes.includes("bool")) {
487
+ return "std::vector<int>";
488
+ }
489
+ const firstElem = inferredElementTypes[0];
490
+ if (firstElem) {
491
+ return `std::vector<${firstElem}>`;
492
+ }
493
+ return "std::vector<int>";
494
+ }
495
+ if (expr.kind === ts.SyntaxKind.TrueKeyword || expr.kind === ts.SyntaxKind.FalseKeyword) {
496
+ return "bool";
497
+ }
498
+ if (ts.isCallExpression(expr)) {
499
+ if (ts.isIdentifier(expr.expression)) {
500
+ const fnReturnType = functionReturnTypes.get(expr.expression.text);
501
+ if (fnReturnType && fnReturnType !== "auto") {
502
+ return fnReturnType;
503
+ }
504
+ }
505
+ if (ts.isPropertyAccessExpression(expr.expression)) {
506
+ if (ts.isIdentifier(expr.expression.expression)) {
507
+ const className = expr.expression.expression.text;
508
+ if (className === "Math") {
509
+ const method = expr.expression.name.text;
510
+ if (["floor", "ceil", "round", "abs", "sqrt", "sin", "cos", "tan", "atan2", "log", "exp", "pow", "fmod"].includes(method)) {
511
+ return "double";
512
+ }
513
+ if (method === "min" || method === "max") {
514
+ const leftType = expr.arguments.length > 0
515
+ ? inferExprCppType(expr.arguments[0], functionReturnTypes, localVariableTypes, sourceText)
516
+ : "auto";
517
+ if (leftType !== "auto")
518
+ return leftType;
519
+ return "int";
520
+ }
521
+ if (method === "random")
522
+ return "double";
523
+ }
524
+ const classDef = topLevelClasses.get(className);
525
+ if (classDef) {
526
+ const method = expr.expression.name.text;
527
+ const classMethod = classDef.methods.find((m) => m.name === method);
528
+ if (classMethod) {
529
+ return classMethod.returnType;
530
+ }
531
+ }
532
+ }
533
+ const receiverType = inferExprCppType(expr.expression.expression, functionReturnTypes, localVariableTypes, sourceText);
534
+ // Peel pointer/const off the receiver to recover the bare class name.
535
+ // Uses the structured bareType() rather than ad-hoc slice/replace.
536
+ const receiverIr = parseCppType(receiverType);
537
+ const receiverClassName = (() => {
538
+ const bare = bareType(receiverIr);
539
+ return bare.kind === "named" ? bare.name : renderCppType(bare);
540
+ })();
541
+ const classDef = topLevelClasses.get(receiverClassName);
542
+ if (classDef) {
543
+ const method = expr.expression.name.text;
544
+ const classMethod = classDef.methods.find((m) => m.name === method);
545
+ if (classMethod) {
546
+ return classMethod.returnType;
547
+ }
548
+ }
549
+ }
550
+ }
551
+ if (ts.isIdentifier(expr)) {
552
+ // Demo #31 Finding C — a bare identifier may resolve to a MODULE-SCOPE
553
+ // (top-level const/let) variable, not just a function local. The prior
554
+ // code consulted `localVariableTypes` only, so a `for (const r of ARR)`
555
+ // over a top-level `const ARR: string[]` resolved `ARR` to "auto" (the
556
+ // for-of element-type inference then couldn't see the vector element
557
+ // type, the loop variable carried `auto`, and because a for-of var has
558
+ // no initializer the snprintf specifier picker couldn't recover the real
559
+ // type — defaulting to `%d` for a `std::string`, tripping g++ -Wformat=
560
+ // and producing garbage at runtime). The fix consults the IR type scope's
561
+ // `globals` map (populated for every top-level decl in variables.ts) as a
562
+ // fallback, matching what `resolveReceiverCppType` in array-methods.ts
563
+ // already does for the string/array-method disambiguation. This is the
564
+ // same lookup shape used at line ~747 for member-access receivers.
565
+ const fromLocals = localVariableTypes.get(expr.text);
566
+ if (fromLocals && fromLocals !== "auto")
567
+ return fromLocals;
568
+ const fromGlobals = getCurrentIrTypeScope()?.globals.get(expr.text);
569
+ if (fromGlobals && fromGlobals !== "auto")
570
+ return fromGlobals;
571
+ return fromLocals ?? "auto";
572
+ }
573
+ if (ts.isParenthesizedExpression(expr)) {
574
+ return inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
575
+ }
576
+ if (ts.isConditionalExpression(expr)) {
577
+ const whenTrueType = inferExprCppType(expr.whenTrue, functionReturnTypes, localVariableTypes, sourceText);
578
+ const whenFalseType = inferExprCppType(expr.whenFalse, functionReturnTypes, localVariableTypes, sourceText);
579
+ if (whenTrueType === "std::string" || whenFalseType === "std::string") {
580
+ return "std::string";
581
+ }
582
+ if (whenTrueType === "float" || whenFalseType === "float" || whenTrueType === "double" || whenFalseType === "double") {
583
+ return "double";
584
+ }
585
+ if ((whenTrueType === "int" || whenTrueType === "bool") && (whenFalseType === "int" || whenFalseType === "bool")) {
586
+ return "int";
587
+ }
588
+ if (whenTrueType === whenFalseType) {
589
+ return whenTrueType;
590
+ }
591
+ return "auto";
592
+ }
593
+ if (ts.isPropertyAccessExpression(expr)) {
594
+ if (expr.name.text === "length") {
595
+ return "int";
596
+ }
597
+ if (ts.isIdentifier(expr.expression)) {
598
+ const objName = expr.expression.text;
599
+ if (activeEnumNames.has(objName)) {
600
+ return objName;
601
+ }
602
+ if (/^[A-Z]/.test(objName)) {
603
+ return "int";
604
+ }
605
+ }
606
+ if (expr.expression.kind === ts.SyntaxKind.ThisKeyword) {
607
+ const fieldKey = `this->${expr.name.text}`;
608
+ const fieldType = getCurrentIrTypeScope()?.classFields.get(fieldKey);
609
+ if (fieldType && fieldType !== "auto")
610
+ return fieldType;
611
+ }
612
+ if (ts.isIdentifier(expr.expression)) {
613
+ // Prefer the caller-supplied local types (e.g. a lambda's param types)
614
+ // before the module-level scope maps, so a callback body like
615
+ // `(n: Node) => n.capacity` resolves `n` -> Node -> capacity -> double.
616
+ // `scope.locals` is the same Map the caller threaded as
617
+ // localVariableTypes, so the prior activeLocalTypes fallback is subsumed.
618
+ const scope = getCurrentIrTypeScope();
619
+ const objType = localVariableTypes.get(expr.expression.text)
620
+ ?? scope?.locals.get(expr.expression.text) ?? scope?.globals.get(expr.expression.text);
621
+ if (objType && objType !== "auto") {
622
+ // Peel pointer to recover the bare class name via the structured IR.
623
+ const className = (() => {
624
+ const bare = bareType(parseCppType(objType));
625
+ return bare.kind === "named" ? bare.name : "";
626
+ })();
627
+ const classDef = topLevelClasses.get(className);
628
+ if (classDef) {
629
+ const field = classDef.fields.find(f => f.name === expr.name.text);
630
+ if (field && field.cppType !== "auto")
631
+ return field.cppType;
632
+ }
633
+ }
634
+ }
635
+ // Handle chained property access: s.player.weaponName
636
+ if (ts.isPropertyAccessExpression(expr.expression)) {
637
+ const receiverType = inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
638
+ if (receiverType && receiverType !== "auto") {
639
+ const className = (() => {
640
+ const bare = bareType(parseCppType(receiverType));
641
+ return bare.kind === "named" ? bare.name : "";
642
+ })();
643
+ const classDef = topLevelClasses.get(className);
644
+ if (classDef) {
645
+ const field = classDef.fields.find(f => f.name === expr.name.text);
646
+ if (field && field.cppType !== "auto")
647
+ return field.cppType;
648
+ }
649
+ }
650
+ }
651
+ return "auto";
652
+ }
653
+ if (ts.isBinaryExpression(expr)) {
654
+ const operator = expr.operatorToken.kind;
655
+ const leftType = inferExprCppType(expr.left, functionReturnTypes, localVariableTypes, sourceText);
656
+ const rightType = inferExprCppType(expr.right, functionReturnTypes, localVariableTypes, sourceText);
657
+ if (operator === ts.SyntaxKind.EqualsEqualsToken ||
658
+ operator === ts.SyntaxKind.EqualsEqualsEqualsToken ||
659
+ operator === ts.SyntaxKind.ExclamationEqualsToken ||
660
+ operator === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
661
+ operator === ts.SyntaxKind.GreaterThanToken ||
662
+ operator === ts.SyntaxKind.GreaterThanEqualsToken ||
663
+ operator === ts.SyntaxKind.LessThanToken ||
664
+ operator === ts.SyntaxKind.LessThanEqualsToken ||
665
+ operator === ts.SyntaxKind.AmpersandAmpersandToken ||
666
+ operator === ts.SyntaxKind.BarBarToken) {
667
+ return "bool";
668
+ }
669
+ if (operator === ts.SyntaxKind.PlusToken && (leftType === "std::string" || rightType === "std::string")) {
670
+ return "std::string";
671
+ }
672
+ if (leftType === "float" || rightType === "float" || leftType === "double" || rightType === "double") {
673
+ return "double";
674
+ }
675
+ if ((leftType === "int" || leftType === "bool" || leftType === "long long" || leftType === "unsigned long long") && (rightType === "int" || rightType === "bool" || rightType === "long long" || rightType === "unsigned long long")) {
676
+ if (leftType === "long long" || rightType === "long long" || leftType === "unsigned long long" || rightType === "unsigned long long") {
677
+ return "long long";
678
+ }
679
+ return "int";
680
+ }
681
+ // Partial type info: if one operand is auto, use the other for arithmetic ops
682
+ if (leftType === "auto" && rightType !== "auto")
683
+ return rightType;
684
+ if (rightType === "auto" && leftType !== "auto")
685
+ return leftType;
686
+ return "auto";
687
+ }
688
+ if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression)) {
689
+ return functionReturnTypes.get(expr.expression.text) ?? "auto";
690
+ }
691
+ if (ts.isNewExpression(expr)) {
692
+ if (ts.isIdentifier(expr.expression)) {
693
+ const ctorName = expr.expression.text;
694
+ const directType = getDirectCppType(ctorName);
695
+ if (directType) {
696
+ return directType;
697
+ }
698
+ // Build the class pointer via structured IR: pointer(named(ctorName, args?)).
699
+ const typeArgs = expr.typeArguments?.map((ta) => ta.getText());
700
+ const namedIr = {
701
+ kind: "named",
702
+ name: ctorName,
703
+ args: typeArgs && typeArgs.length > 0 ? typeArgs.map((t) => parseCppType(t)) : undefined,
704
+ };
705
+ const ir = { kind: "pointer", base: namedIr };
706
+ return renderCppType(ir);
707
+ }
708
+ return "auto";
709
+ }
710
+ if (ts.isElementAccessExpression(expr)) {
711
+ const objectType = inferExprCppType(expr.expression, functionReturnTypes, localVariableTypes, sourceText);
712
+ // Typed array pointers → element types
713
+ if (objectType === "float*")
714
+ return "float";
715
+ if (objectType === "uint8_t*")
716
+ return "int";
717
+ if (objectType === "int16_t*")
718
+ return "int";
719
+ if (objectType === "int32_t*")
720
+ return "int";
721
+ const objectIr = parseCppType(objectType);
722
+ // std::tuple<N> element access → extract Nth type
723
+ if (objectIr.kind === "tuple") {
724
+ const argExpr = expr.argumentExpression;
725
+ if (argExpr && ts.isNumericLiteral(argExpr)) {
726
+ const idx = parseInt(argExpr.text, 10);
727
+ if (idx >= 0 && idx < objectIr.elements.length) {
728
+ return renderCppType(objectIr.elements[idx]);
729
+ }
730
+ }
731
+ return "auto";
732
+ }
733
+ // Element type of vector / staticArray / cArray, or value type of map.
734
+ // Replaces the three duplicated inline parsers (vector / __tc_StaticArray /
735
+ // C-array) with one structured lookup. The uint8_t/int8_t → int and
736
+ // float/double → double promotions are preserved for element access.
737
+ const elemIr = elementOf(objectIr);
738
+ if (elemIr) {
739
+ const elemStr = renderCppType(elemIr);
740
+ if (elemStr === "uint8_t" || elemStr === "int8_t")
741
+ return "int";
742
+ if (elemStr === "float" || elemStr === "double")
743
+ return "double";
744
+ return elemStr;
745
+ }
746
+ // Check local variable declarations for typed array constructors
747
+ if (ts.isIdentifier(expr.expression)) {
748
+ const varName = expr.expression.text;
749
+ const varType = localVariableTypes.get(varName);
750
+ if (varType === "float*")
751
+ return "float";
752
+ }
753
+ return "auto";
754
+ }
755
+ // Handle arrow functions and function expressions — infer return type from body
756
+ if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
757
+ const body = expr.body;
758
+ if (ts.isBlock(body)) {
759
+ const returnTypes = collectReturns(body)
760
+ .filter((item) => item.expression)
761
+ .map((item) => inferExprCppType(item.expression, functionReturnTypes, localVariableTypes, sourceText))
762
+ .filter((item) => item !== "auto");
763
+ if (returnTypes.includes("float") || returnTypes.includes("double")) {
764
+ return "double";
765
+ }
766
+ if (returnTypes.includes("std::string")) {
767
+ return "std::string";
768
+ }
769
+ if (returnTypes.includes("int") || returnTypes.includes("bool")) {
770
+ return "int";
771
+ }
772
+ if (returnTypes.length > 0) {
773
+ return returnTypes[0];
774
+ }
775
+ return "void";
776
+ }
777
+ // Expression body — infer from the expression
778
+ return inferExprCppType(body, functionReturnTypes, localVariableTypes, sourceText);
779
+ }
780
+ return "auto";
781
+ }
782
+ export function resolveDeclarationType(typeNode, initializer, functionReturnTypes, localVariableTypes, typeAliases, sourceText) {
783
+ const explicitType = typeNodeToCppType(typeNode, typeAliases);
784
+ const inferredType = initializer
785
+ ? inferExprCppType(initializer, functionReturnTypes, localVariableTypes, sourceText)
786
+ : "auto";
787
+ let resolvedType;
788
+ if (explicitType === "auto") {
789
+ resolvedType = inferredType;
790
+ }
791
+ else if (explicitType === "int" && (inferredType === "float" || inferredType === "double")) {
792
+ resolvedType = "double";
793
+ }
794
+ else {
795
+ resolvedType = explicitType;
796
+ }
797
+ const canLowerFromStructuredInitializer = isStructuredTypeAnnotation(typeNode, typeAliases) &&
798
+ !!initializer &&
799
+ ts.isObjectLiteralExpression(initializer);
800
+ const isKnownType = isKnownCompileTimeType(typeNode, typeAliases);
801
+ return {
802
+ explicitType,
803
+ inferredType,
804
+ resolvedType,
805
+ canLowerFromStructuredInitializer,
806
+ isKnownCompileTimeType: isKnownType,
807
+ shouldWarnUnmappedType: explicitType === "auto" &&
808
+ inferredType === "auto" &&
809
+ !!typeNode &&
810
+ !canLowerFromStructuredInitializer &&
811
+ !isKnownType,
812
+ };
813
+ }
814
+ /** Collect local variable types from a function body (single-level scan). */
815
+ function collectLocalVarTypes(body, functionReturnTypes, sourceText) {
816
+ const locals = new Map();
817
+ for (const stmt of body.statements) {
818
+ if (ts.isVariableStatement(stmt)) {
819
+ for (const decl of stmt.declarationList.declarations) {
820
+ if (ts.isIdentifier(decl.name) && decl.initializer) {
821
+ const initType = inferExprCppType(decl.initializer, functionReturnTypes, locals, sourceText);
822
+ if (initType !== "auto") {
823
+ locals.set(decl.name.text, initType);
824
+ }
825
+ }
826
+ }
827
+ }
828
+ }
829
+ return locals;
830
+ }
831
+ export function collectReturns(block) {
832
+ const returns = [];
833
+ const walk = (node) => {
834
+ if (ts.isReturnStatement(node)) {
835
+ returns.push(node);
836
+ return;
837
+ }
838
+ node.forEachChild(walk);
839
+ };
840
+ walk(block);
841
+ return returns;
842
+ }
843
+ export function buildFunctionReturnTypeMap(source) {
844
+ const result = new Map();
845
+ const sourceText = source.text;
846
+ const functions = source.statements.filter(ts.isFunctionDeclaration);
847
+ for (let pass = 0; pass < 3; pass++) {
848
+ for (const fn of functions) {
849
+ if (!fn.name || !fn.body) {
850
+ continue;
851
+ }
852
+ if (fn.type) {
853
+ const annotatedType = typeNodeToCppType(fn.type);
854
+ // For generic functions the annotated return type may reference a type
855
+ // parameter (e.g. `function clamp<T>(...): T`). At a call site we can't
856
+ // resolve `T` to a concrete C++ type, so store "auto" — the caller's
857
+ // declaration will then fall back to `auto`/template deduction rather
858
+ // than emitting a literal `T` (which is not a valid C++ type).
859
+ const typeParamNames = new Set((fn.typeParameters ?? []).map(tp => tp.name.text));
860
+ const resolvedAnnotated = typeParamNames.has(annotatedType) ? "auto" : annotatedType;
861
+ if (resolvedAnnotated !== "auto") {
862
+ // Promote int → float when the function body returns float expressions
863
+ if (resolvedAnnotated === "int") {
864
+ const locals = collectLocalVarTypes(fn.body, result, sourceText);
865
+ const returns = collectReturns(fn.body).filter((item) => item.expression);
866
+ const inferredTypes = returns
867
+ .map((item) => inferExprCppType(item.expression, result, locals, sourceText))
868
+ .filter((item) => item !== "auto");
869
+ if (inferredTypes.includes("float") || inferredTypes.includes("double")) {
870
+ result.set(fn.name.text, "double");
871
+ continue;
872
+ }
873
+ // Promote int → long when returning large enum values
874
+ if (returnsLargeEnumValue(fn.body, returns)) {
875
+ result.set(fn.name.text, "long");
876
+ continue;
877
+ }
878
+ }
879
+ result.set(fn.name.text, resolvedAnnotated);
880
+ continue;
881
+ }
882
+ }
883
+ const locals = collectLocalVarTypes(fn.body, result, sourceText);
884
+ const returns = collectReturns(fn.body).filter((item) => item.expression);
885
+ if (returns.length === 0) {
886
+ continue;
887
+ }
888
+ const inferredTypes = returns
889
+ .map((item) => inferExprCppType(item.expression, result, locals, sourceText))
890
+ .filter((item) => item !== "auto");
891
+ if (inferredTypes.length === 0) {
892
+ continue;
893
+ }
894
+ if (inferredTypes.includes("float") || inferredTypes.includes("double")) {
895
+ result.set(fn.name.text, "double");
896
+ }
897
+ else if (inferredTypes.includes("int")) {
898
+ result.set(fn.name.text, "int");
899
+ }
900
+ else if (inferredTypes.includes("bool")) {
901
+ result.set(fn.name.text, "bool");
902
+ }
903
+ else if (inferredTypes.includes("std::string")) {
904
+ result.set(fn.name.text, "std::string");
905
+ }
906
+ else {
907
+ result.set(fn.name.text, inferredTypes[0]);
908
+ }
909
+ }
910
+ }
911
+ return result;
912
+ }
913
+ /**
914
+ * Check if a function body contains enum declarations with values outside the
915
+ * 16-bit signed int range (>32767 or <-32768) and any return expression
916
+ * accesses those enums.
917
+ */
918
+ function returnsLargeEnumValue(body, returns) {
919
+ const largeEnumNames = new Set();
920
+ const walkForEnums = (node) => {
921
+ if (ts.isEnumDeclaration(node) && node.name) {
922
+ for (const member of node.members) {
923
+ let value;
924
+ if (member.initializer && ts.isNumericLiteral(member.initializer)) {
925
+ value = Number(member.initializer.text);
926
+ }
927
+ else if (member.initializer &&
928
+ ts.isPrefixUnaryExpression(member.initializer) &&
929
+ member.initializer.operator === ts.SyntaxKind.MinusToken &&
930
+ ts.isNumericLiteral(member.initializer.operand)) {
931
+ value = -Number(member.initializer.operand.text);
932
+ }
933
+ if (value !== undefined && (value > 32767 || value < -32768)) {
934
+ largeEnumNames.add(node.name.text);
935
+ break;
936
+ }
937
+ }
938
+ }
939
+ node.forEachChild(walkForEnums);
940
+ };
941
+ walkForEnums(body);
942
+ if (largeEnumNames.size === 0)
943
+ return false;
944
+ for (const ret of returns) {
945
+ if (ret.expression &&
946
+ ts.isPropertyAccessExpression(ret.expression) &&
947
+ ts.isIdentifier(ret.expression.expression) &&
948
+ largeEnumNames.has(ret.expression.expression.text)) {
949
+ return true;
950
+ }
951
+ }
952
+ return false;
953
+ }
954
+ export function resolveFunctionReturnType(name, functionReturnTypes) {
955
+ return functionReturnTypes.get(name) ?? "void";
956
+ }
957
+ /**
958
+ * Extract the ownership kind from a TypeScript type node.
959
+ * Detects Shared<T>, Mutable<T>, and Owned<T> wrapper types.
960
+ * Returns undefined if no ownership wrapper is found.
961
+ */
962
+ export function extractOwnershipKindFromTypeNode(node, typeAliases) {
963
+ if (!node)
964
+ return undefined;
965
+ // Check the ORIGINAL node before alias resolution.
966
+ // `type Shared<T> = T` would resolve Shared<number> → number, hiding the wrapper.
967
+ if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
968
+ const wrapperName = node.typeName.text;
969
+ if (wrapperName === 'Shared')
970
+ return 'shared';
971
+ if (wrapperName === 'Mutable')
972
+ return 'mutable';
973
+ if (wrapperName === 'Owned')
974
+ return 'owned';
975
+ }
976
+ return undefined;
977
+ }