@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,652 @@
1
+ import ts from "typescript";
2
+ // ---------------------------------------------------------------------------
3
+ // FactStore implementation
4
+ // ---------------------------------------------------------------------------
5
+ function createFactStore() {
6
+ const map = new WeakMap();
7
+ return {
8
+ get(node) {
9
+ return map.get(node);
10
+ },
11
+ has(node) {
12
+ return map.has(node);
13
+ },
14
+ set(node, facts) {
15
+ map.set(node, facts);
16
+ },
17
+ merge(node, partial) {
18
+ const existing = map.get(node);
19
+ if (existing) {
20
+ map.set(node, { ...existing, ...partial });
21
+ }
22
+ else {
23
+ map.set(node, { type: "unknown", ...partial });
24
+ }
25
+ },
26
+ };
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // CanonicalType resolver
30
+ //
31
+ // One function replaces six boolean predicates. Each predicate in
32
+ // type-checker.ts becomes a one-line comparison against canonicalize().
33
+ // ---------------------------------------------------------------------------
34
+ /** Names recognized as typed arrays (Int8Array .. Float64Array, etc.). */
35
+ export const TYPED_ARRAY_NAMES = new Set([
36
+ "Uint8Array",
37
+ "Int8Array",
38
+ "Uint16Array",
39
+ "Int16Array",
40
+ "Uint32Array",
41
+ "Int32Array",
42
+ "Float32Array",
43
+ "Float64Array",
44
+ "BigUint64Array",
45
+ "BigInt64Array",
46
+ ]);
47
+ /** Names recognized as map-like containers. */
48
+ const MAP_NAMES = new Set(["Map", "ReadonlyMap", "Record"]);
49
+ /** Names recognized as set-like containers. */
50
+ const SET_NAMES = new Set(["Set", "ReadonlySet"]);
51
+ function typeToString(checker, type) {
52
+ return checker.typeToString(type);
53
+ }
54
+ /**
55
+ * Resolve whether a type's symbol/alias name (or stringified form) contains
56
+ * any of the given names. Walks union constituents. Mirrors the existing
57
+ * typeHasName() logic so behavior is preserved exactly during migration.
58
+ */
59
+ function typeHasName(checker, type, names) {
60
+ if (type.isUnion()) {
61
+ return type.types.some((t) => typeHasName(checker, t, names));
62
+ }
63
+ const symbolName = type.getSymbol()?.getName();
64
+ const aliasName = type.aliasSymbol?.getName();
65
+ if ((symbolName && names.has(symbolName)) ||
66
+ (aliasName && names.has(aliasName))) {
67
+ return true;
68
+ }
69
+ const text = typeToString(checker, type);
70
+ for (const name of names) {
71
+ if (new RegExp(`\\b${name}\\b`).test(text))
72
+ return true;
73
+ }
74
+ return false;
75
+ }
76
+ /**
77
+ * True iff `type` is an array type (Array<T>, T[], tuple, ReadonlyArray).
78
+ * Preserves the exact behavior of the existing isArrayLikeType() predicate.
79
+ */
80
+ function isArrayLike(checker, type) {
81
+ if (type.isUnion())
82
+ return type.types.some((t) => isArrayLike(checker, t));
83
+ const checkerWithArray = checker;
84
+ if (checkerWithArray.isArrayType?.(type))
85
+ return true;
86
+ if (checker.isTupleType(type))
87
+ return true;
88
+ const text = typeToString(checker, type);
89
+ return /\bReadonlyArray\b|\bArray\b/.test(text) || /\[\]$/.test(text);
90
+ }
91
+ /**
92
+ * Classify a resolved TS type into a canonical category. This is the single
93
+ * source of truth for "what kind of C++ concept does this type lower to?"
94
+ *
95
+ * Categories and their verifier meaning:
96
+ * - concrete categories (primitive, struct, array, ...) — fine.
97
+ * - "any" — the transpiler handles `any` via inference; the verifier treats
98
+ * this as a NON-hazard (it is not `unknown`).
99
+ * - "unknown" — genuinely unclassifiable; the verifier flags this.
100
+ *
101
+ * Unions with a null/undefined constituent (e.g. `Account | null`) are
102
+ * classified by their non-null constituent, because the transpiler erases
103
+ * optionality to the value type. `this` types resolve to the enclosing
104
+ * class/interface, so they classify as struct.
105
+ */
106
+ export function canonicalize(checker, type) {
107
+ const flags = type.flags;
108
+ // Nullable unions (T | null, T | undefined, T | null | undefined): classify
109
+ // by the non-null constituent(s). The transpiler erases optionality. The
110
+ // Null/Undefined flag bits live on the constituents, not the union itself,
111
+ // so we scan the constituents.
112
+ if (type.isUnion()) {
113
+ const hasNullish = type.types.some((t) => (t.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) !== 0);
114
+ if (hasNullish) {
115
+ const nonNull = type.types.filter((t) => (t.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) === 0);
116
+ if (nonNull.length === 1) {
117
+ return canonicalize(checker, nonNull[0]);
118
+ }
119
+ if (nonNull.length > 1) {
120
+ // Multiple non-null constituents (a real discriminated union) — leave
121
+ // as unknown; the transpiler lowers these to std::variant with caveats.
122
+ return "unknown";
123
+ }
124
+ // Only null/undefined — treat as primitive so the verifier doesn't fire.
125
+ return "primitive";
126
+ }
127
+ // Non-nullish union. Two common, lowering-safe shapes appear here as a
128
+ // result of TypeScript control-flow narrowing and both lower to a single
129
+ // primitive C++ type, so they should NOT trip the UNCLASSIFIABLE warning:
130
+ //
131
+ // (1) A narrowed enum — `t.kind` after `if (t.kind === K.A) { continue; }`
132
+ // narrows to `K.B | K.C`. Each constituent is an EnumLiteral of the
133
+ // SAME enum, and the transpiler already lowers any enum member to a
134
+ // single integral type (compared via static_cast<int>).
135
+ // (2) A string-literal union — `op` narrowed to `"+" | "-" | "*" | "/"`,
136
+ // which lowers to a single std::string compared with ==.
137
+ //
138
+ // Coalesce when every non-null constituent canonicalizes to the SAME
139
+ // category — then the union lowers to that one category. Heterogeneous
140
+ // unions (e.g. number | string, or a real object discriminated union)
141
+ // fall through to the per-constituent check below and remain "unknown"
142
+ // (the std::variant case). Demo #22 Finding C.
143
+ if (type.types.length > 1) {
144
+ const categories = new Set();
145
+ for (const t of type.types) {
146
+ categories.add(canonicalize(checker, t));
147
+ }
148
+ if (categories.size === 1) {
149
+ const only = categories.values().next().value;
150
+ if (only === "primitive") {
151
+ return "primitive";
152
+ }
153
+ }
154
+ }
155
+ }
156
+ // `any` — distinct from `unknown`. The transpiler legitimately handles any.
157
+ if (flags & ts.TypeFlags.Any) {
158
+ return "any";
159
+ }
160
+ // `unknown`/`never` — genuinely unclassifiable.
161
+ if (flags & (ts.TypeFlags.Unknown | ts.TypeFlags.Never)) {
162
+ return "unknown";
163
+ }
164
+ // Intersection types (A & B) — common in generated d.ts files (e.g. mixin
165
+ // patterns like `{ kind: "button" } & PressBinding`). They lower to a single
166
+ // struct (the merged field set), so classify as struct. Check each
167
+ // constituent; if any is a container/callable we defer to that, but the
168
+ // overwhelmingly common case is all-object intersections → struct.
169
+ if (flags & ts.TypeFlags.Intersection) {
170
+ const parts = type.types ?? [];
171
+ const partCats = parts.map((t) => canonicalize(checker, t));
172
+ // If every constituent is struct/primitive, the intersection is a struct.
173
+ if (partCats.every((c) => c === "struct" || c === "primitive")) {
174
+ return "struct";
175
+ }
176
+ // If all constituents agree on one non-struct category, inherit it.
177
+ const unique = new Set(partCats);
178
+ if (unique.size === 1)
179
+ return partCats[0];
180
+ return "struct";
181
+ }
182
+ // Primitives.
183
+ if (flags &
184
+ (ts.TypeFlags.NumberLike |
185
+ ts.TypeFlags.StringLike |
186
+ ts.TypeFlags.BooleanLike |
187
+ ts.TypeFlags.BigIntLike |
188
+ ts.TypeFlags.Enum |
189
+ ts.TypeFlags.EnumLiteral |
190
+ ts.TypeFlags.Null |
191
+ ts.TypeFlags.Undefined |
192
+ ts.TypeFlags.Void |
193
+ ts.TypeFlags.Literal)) {
194
+ return "primitive";
195
+ }
196
+ // `this` types and type parameters (<T>) both carry the TypeParameter flag
197
+ // (a `this` type is represented as a constrained type parameter whose
198
+ // constraint is the enclosing class). Resolve to the constraint if bounded;
199
+ // otherwise default to struct, which is the common case for class generics
200
+ // and `this`.
201
+ if (flags & ts.TypeFlags.TypeParameter) {
202
+ const constraint = type.getConstraint?.();
203
+ if (constraint) {
204
+ return canonicalize(checker, constraint);
205
+ }
206
+ return "struct";
207
+ }
208
+ // Containers, checked in specificity order.
209
+ if (typeHasName(checker, type, MAP_NAMES) || /\bstd::map\b/.test(typeToString(checker, type))) {
210
+ return "map";
211
+ }
212
+ if (typeHasName(checker, type, SET_NAMES)) {
213
+ return "set";
214
+ }
215
+ if (typeHasName(checker, type, TYPED_ARRAY_NAMES)) {
216
+ return "typed-array";
217
+ }
218
+ if (isArrayLike(checker, type)) {
219
+ return "array";
220
+ }
221
+ // Functions.
222
+ const symbol = type.getSymbol();
223
+ if (symbol && (symbol.flags & ts.SymbolFlags.Function) !== 0) {
224
+ return "function";
225
+ }
226
+ if (flags & ts.TypeFlags.Object) {
227
+ const sig = type.getCallSignatures();
228
+ if (sig.length > 0 && type.getProperties().length === 0) {
229
+ // Pure callable object type with no other properties.
230
+ return "function";
231
+ }
232
+ }
233
+ // Everything object-like that isn't a known container or callable is a
234
+ // struct (classes, interfaces, object literals, enums-by-shape).
235
+ if (flags & ts.TypeFlags.Object) {
236
+ return "struct";
237
+ }
238
+ return "unknown";
239
+ }
240
+ /**
241
+ * Map a canonicalized type to the concrete C++ type the lowering emits, for
242
+ * the categories where the cppType is deterministic from the TS type alone.
243
+ * Returns undefined when the cppType depends on IR-build context the
244
+ * type-checker does not have (user-defined class/interface names resolve to
245
+ * themselves as struct names but their field layout is a SymbolTable concern;
246
+ * `auto` deduction from complex initializers is an IR-build concern).
247
+ *
248
+ * This populates SemanticFacts.cppType so gate rules can read a concrete type
249
+ * without re-deriving it. Phase 3 of the type-resolution consolidation — see
250
+ * the doc comment on SemanticFacts.cppType for the one-way direction.
251
+ */
252
+ export function cppTypeFromCanonicalType(checker, type, category) {
253
+ switch (category) {
254
+ case "primitive": {
255
+ // number → double (the lowering's default number type), string →
256
+ // std::string, boolean → bool. BigInt and enums share the primitive
257
+ // category but have no single deterministic cppType here (enums lower to
258
+ // their underlying integral width, which depends on member values known
259
+ // only at IR-build time), so they stay undefined.
260
+ const flags = type.flags;
261
+ if (flags & ts.TypeFlags.StringLike)
262
+ return "std::string";
263
+ if (flags & ts.TypeFlags.NumberLike)
264
+ return "double";
265
+ if (flags & ts.TypeFlags.BooleanLike)
266
+ return "bool";
267
+ return undefined;
268
+ }
269
+ case "typed-array": {
270
+ // Map the typed-array name to its element pointer type. The lowering
271
+ // emits these exact pointer types (TYPED_ARRAY_ELEMENT_MAP in
272
+ // build-ir-state); mirroring them here gives gates the concrete storage
273
+ // type without touching the SymbolTable.
274
+ const name = type.getSymbol()?.getName()
275
+ ?? type.aliasSymbol?.getName()
276
+ ?? "";
277
+ switch (name) {
278
+ case "Uint8Array": return "uint8_t*";
279
+ case "Int8Array": return "int8_t*";
280
+ case "Uint16Array": return "uint16_t*";
281
+ case "Int16Array": return "int16_t*";
282
+ case "Uint32Array": return "uint32_t*";
283
+ case "Int32Array": return "int32_t*";
284
+ case "Float32Array": return "float*";
285
+ case "Float64Array": return "double*";
286
+ default: return undefined;
287
+ }
288
+ }
289
+ case "array":
290
+ // std::vector<element>, but the element type depends on the TS element
291
+ // type's own cppType (recursively). Defer to the SymbolTable for the
292
+ // concrete element rather than recursing here; gates that need the
293
+ // container-ness already have the "array" category.
294
+ return undefined;
295
+ case "map":
296
+ case "set":
297
+ // std::map<K,V> / std::set<T>, but the key/value element types are a
298
+ // SymbolTable concern. Same rationale as "array".
299
+ return undefined;
300
+ case "struct": {
301
+ // A user-defined class/interface lowers to its own name (classes as
302
+ // pointers, interfaces as values). The bare name is the cppType prefix;
303
+ // pointer-ness is resolved by the IR build. Return the bare name so a
304
+ // gate can at least see "this is a Foo". Stringification matches the
305
+ // lowering's class/interface naming.
306
+ const name = type.getSymbol()?.getName() ?? type.aliasSymbol?.getName();
307
+ return name;
308
+ }
309
+ case "function":
310
+ case "any":
311
+ case "unknown":
312
+ return undefined;
313
+ }
314
+ }
315
+ // ---------------------------------------------------------------------------
316
+ // buildSemanticFacts — runs the ordered analysis passes.
317
+ //
318
+ // Passes (each produces a slice of the facts; none overwrites another's field):
319
+ // 1. Binding origin pass — tags binding-identifier declaration nodes with
320
+ // their origin (map-value-lookup, array-param, typed-array-param, ...).
321
+ // Covers every binding form, not just identifier VariableDeclarations:
322
+ // destructuring, for-of/in, and catch bindings are included. Reassignment
323
+ // updates the origin to reflect the new initializer.
324
+ // 2. Container-lookup pass — tags container-lookup expression nodes
325
+ // (map.get(k)!, map.at(k), map[k]) with origin "map-value-lookup".
326
+ // The binding-origin pass uses this when classifying initializers.
327
+ //
328
+ // `userFiles` follows the same normalization as runSemanticGates: absolute
329
+ // paths, forward slashes, node_modules/packages excluded.
330
+ // ---------------------------------------------------------------------------
331
+ /**
332
+ * Strip wrapper expressions (parens, non-null, as, type-assertion, satisfies)
333
+ * to reach the underlying expression. Mirrors unwrapExpression() in
334
+ * type-checker.ts so the two layers classify the same nodes.
335
+ */
336
+ function unwrapExpression(expr) {
337
+ let current = expr;
338
+ while (true) {
339
+ if (ts.isParenthesizedExpression(current) ||
340
+ ts.isNonNullExpression(current) ||
341
+ ts.isAsExpression(current) ||
342
+ ts.isTypeAssertionExpression(current)) {
343
+ current = current.expression;
344
+ continue;
345
+ }
346
+ if (ts.isSatisfiesExpression?.(current)) {
347
+ current = current.expression;
348
+ continue;
349
+ }
350
+ return current;
351
+ }
352
+ }
353
+ /** Is `node` a container value lookup (map.get/at, or map[k] on a Map/Record)? */
354
+ function isMapValueLookupExpression(node, checker) {
355
+ const expr = unwrapExpression(node);
356
+ if (ts.isCallExpression(expr)) {
357
+ const callee = unwrapExpression(expr.expression);
358
+ if (ts.isPropertyAccessExpression(callee) &&
359
+ (callee.name.text === "get" || callee.name.text === "at")) {
360
+ return canonicalize(checker, checker.getTypeAtLocation(callee.expression)) === "map";
361
+ }
362
+ }
363
+ if (ts.isElementAccessExpression(expr)) {
364
+ return canonicalize(checker, checker.getTypeAtLocation(expr.expression)) === "map";
365
+ }
366
+ return false;
367
+ }
368
+ /** True iff the resolved type is an object-like value type (the map-value-copy case). */
369
+ function isObjectLikeValueType(type) {
370
+ if (type.isUnion()) {
371
+ return type.types.some((t) => !typeIncludesNullish(t) && isObjectLikeValueType(t));
372
+ }
373
+ // Primitive flag set => not object-like. Mirrors isObjectLikeValueType() in
374
+ // type-checker.ts (NumberLike | StringLike | BooleanLike | BigIntLike |
375
+ // EnumLike | Null | Undefined | Void | Never | Any | Unknown).
376
+ const flags = type.flags;
377
+ const primitiveFlags = ts.TypeFlags.NumberLike |
378
+ ts.TypeFlags.StringLike |
379
+ ts.TypeFlags.BooleanLike |
380
+ ts.TypeFlags.BigIntLike |
381
+ ts.TypeFlags.EnumLike |
382
+ ts.TypeFlags.Null |
383
+ ts.TypeFlags.Undefined |
384
+ ts.TypeFlags.Void |
385
+ ts.TypeFlags.Never |
386
+ ts.TypeFlags.Any |
387
+ ts.TypeFlags.Unknown;
388
+ return (flags & primitiveFlags) === 0;
389
+ }
390
+ /**
391
+ * True iff `type` is the instance type of a `class` declaration (or a union
392
+ * whose non-nullish constituent is). A TypeScript class is a *reference* type,
393
+ * and the transpiler lowers it to a C++ pointer (`C*`, see
394
+ * `ir/type-resolution.ts` `classTypeNames`). That distinction matters for the
395
+ * `TS2CPP_MAP_VALUE_COPY_MUTATION` gate: a `map.get(k)` whose value type is a
396
+ * class returns a *pointer*, so a field write `node.value = v` lowers to
397
+ * `node->value = v` and **persists** through the pointer — it is NOT a value
398
+ * copy the way an `interface`/struct-typed fetch is. Only struct-valued
399
+ * (interface / object-literal) map entries are value copies; class entries are
400
+ * exempt. (Demo #25 Finding A.)
401
+ */
402
+ function isClassInstanceType(type) {
403
+ if (type.isUnion()) {
404
+ return type.types.some((t) => !typeIncludesNullish(t) && isClassInstanceType(t));
405
+ }
406
+ // A class instance type's symbol carries SymbolFlags.Class. Resolve through
407
+ // aliases (e.g. `type Alias = SomeClass`) so an aliased class is still seen
408
+ // as a class.
409
+ let symbol = type.getSymbol();
410
+ if (symbol && symbol.flags & ts.SymbolFlags.TypeAlias) {
411
+ // For an alias, the aliased type is reachable via the checker; fall back to
412
+ // a flag check on the alias target by walking type.aliasSymbol.
413
+ symbol = type.aliasSymbol ?? symbol;
414
+ }
415
+ if (!symbol)
416
+ return false;
417
+ return (symbol.flags & ts.SymbolFlags.Class) !== 0;
418
+ }
419
+ function typeIncludesNullish(type) {
420
+ if (type.isUnion())
421
+ return type.types.some(typeIncludesNullish);
422
+ return (type.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0;
423
+ }
424
+ function isUserFile(filePath, userFileSet) {
425
+ const p = filePath.replace(/\\/g, "/");
426
+ if (!userFileSet.has(p))
427
+ return false;
428
+ if (p.includes("/node_modules/") || p.includes("/packages/"))
429
+ return false;
430
+ return true;
431
+ }
432
+ /**
433
+ * Build the SemanticFacts store for a program by running the analysis passes.
434
+ */
435
+ export function buildSemanticFacts(program, userFiles) {
436
+ const facts = createFactStore();
437
+ const diagnostics = [];
438
+ const checker = program.getTypeChecker();
439
+ const userFileSet = new Set(userFiles.map((f) => f.replace(/\\/g, "/")));
440
+ // Map from binding-declaration identifier node -> origin. Populated by the
441
+ // binding-origin pass, read by BindingResolver.resolveOrigin. Uses a Map
442
+ // (not the WeakMap inside FactStore) so resolveOrigin can look up origins
443
+ // directly by declaration node without going through the read-only store.
444
+ const originByDeclaration = new Map();
445
+ // Walk user files and tag binding declarations with their origin.
446
+ for (const sourceFile of program.getSourceFiles()) {
447
+ if (!isUserFile(sourceFile.fileName, userFileSet))
448
+ continue;
449
+ visitForBindings(sourceFile);
450
+ }
451
+ function recordOrigin(declaration, origin) {
452
+ originByDeclaration.set(declaration, origin);
453
+ // Also set a fact on the declaration node itself, for any consumer that
454
+ // walks declarations directly.
455
+ facts.merge(declaration, { origin });
456
+ }
457
+ /**
458
+ * Record an origin on the declaration node that a use-site identifier's
459
+ * symbol will resolve to. The checker reports a symbol's valueDeclaration
460
+ * as the declarator node (VariableDeclaration for `const x = …`,
461
+ * BindingElement for `const { x } = …`, Parameter for function params), not
462
+ * the identifier inside it — so we record on the declarator, not the name.
463
+ */
464
+ function recordBindingName(bindingName, origin) {
465
+ if (ts.isIdentifier(bindingName)) {
466
+ // For a simple `const x = …`, the declarator is the parent
467
+ // VariableDeclaration / Parameter / etc. (never the identifier itself).
468
+ const declarator = bindingName.parent;
469
+ if (declarator)
470
+ recordOrigin(declarator, origin);
471
+ return;
472
+ }
473
+ // Object/array binding patterns: each BindingElement is its own symbol
474
+ // declaration, so record on each element.
475
+ const walk = (pattern) => {
476
+ pattern.forEachChild((child) => {
477
+ if (ts.isBindingElement(child)) {
478
+ // The BindingElement is the symbol's valueDeclaration.
479
+ recordOrigin(child, origin);
480
+ if (!ts.isIdentifier(child.name))
481
+ walk(child.name);
482
+ }
483
+ else if (ts.isObjectBindingPattern(child) || ts.isArrayBindingPattern(child)) {
484
+ walk(child);
485
+ }
486
+ });
487
+ };
488
+ walk(bindingName);
489
+ }
490
+ function visitForBindings(node) {
491
+ // Function parameters: array / typed-array params get their origin.
492
+ if (isFunctionLikeWithBodyNode(node)) {
493
+ for (const param of node.parameters) {
494
+ const paramType = checker.getTypeAtLocation(param);
495
+ const cat = canonicalize(checker, paramType);
496
+ if (cat === "array") {
497
+ recordBindingName(param.name, "array-param");
498
+ }
499
+ else if (cat === "typed-array") {
500
+ recordBindingName(param.name, "typed-array-param");
501
+ }
502
+ }
503
+ }
504
+ // Variable declarations: classify initializer.
505
+ if (ts.isVariableDeclaration(node) && node.initializer) {
506
+ recordDeclarationOrigin(node.name, node.initializer);
507
+ }
508
+ // Reassignment (task = other) updates the existing declaration's origin
509
+ // to reflect the new value. The symbol resolves back to the original
510
+ // declarator, so we update that node's entry rather than tagging a new one.
511
+ if (ts.isBinaryExpression(node) &&
512
+ isAssignmentOperatorKind(node.operatorToken.kind) &&
513
+ ts.isIdentifier(node.left)) {
514
+ recordReassignmentOrigin(node.left, node.right);
515
+ }
516
+ // for-of / for-in bindings.
517
+ if ((ts.isForOfStatement(node) || ts.isForInStatement(node)) &&
518
+ ts.isVariableDeclarationList(node.initializer)) {
519
+ for (const decl of node.initializer.declarations) {
520
+ if (decl.initializer) {
521
+ recordDeclarationOrigin(decl.name, decl.initializer);
522
+ }
523
+ else {
524
+ recordBindingName(decl.name, "local-binding");
525
+ }
526
+ }
527
+ }
528
+ // catch bindings.
529
+ if (ts.isCatchClause(node) && node.variableDeclaration) {
530
+ recordBindingName(node.variableDeclaration.name, "local-binding");
531
+ }
532
+ ts.forEachChild(node, visitForBindings);
533
+ }
534
+ /**
535
+ * Classify a declaration initializer and tag the declarator's origin. Only
536
+ * called for new bindings (VariableDeclaration, for-of/in). Non-special
537
+ * bindings get no entry, so resolveOrigin returns undefined for them.
538
+ */
539
+ function recordDeclarationOrigin(name, initializer) {
540
+ const init = unwrapExpression(initializer);
541
+ if (isMapValueLookupExpression(init, checker)) {
542
+ // Only struct-typed values count as "map-value copies" — primitive
543
+ // values fetched from a map are not mutated-through, matching the old
544
+ // isObjectLikeValueType gate. A *class*-typed value is also exempt: a TS
545
+ // class is a reference type that lowers to a C++ pointer, so
546
+ // `map.get(k)` returns a pointer and a field write through it persists
547
+ // (it is not a value copy). Only interface / object-literal entries are
548
+ // value copies. (Demo #25 Finding A.)
549
+ const bindingType = checker.getTypeAtLocation(name);
550
+ if (isObjectLikeValueType(bindingType) && !isClassInstanceType(bindingType)) {
551
+ recordBindingName(name, "map-value-lookup");
552
+ return;
553
+ }
554
+ }
555
+ // Otherwise it's a plain local binding — no entry. resolveOrigin returns
556
+ // undefined (meaning "no special origin"), which is correct for the gates.
557
+ }
558
+ /**
559
+ * A reassignment `task = expr` updates the existing declaration's origin to
560
+ * reflect the new value. Resolve the LHS identifier's symbol to its original
561
+ * declarator and overwrite its entry. If the new value isn't a map-value
562
+ * lookup, the origin is cleared (the binding is no longer a copy).
563
+ */
564
+ function recordReassignmentOrigin(left, right) {
565
+ const symbol = checker.getSymbolAtLocation(left);
566
+ if (!symbol)
567
+ return;
568
+ const declarator = symbol.valueDeclaration ?? symbol.declarations?.[0];
569
+ if (!declarator)
570
+ return;
571
+ const init = unwrapExpression(right);
572
+ if (isMapValueLookupExpression(init, checker)) {
573
+ const valueType = checker.getTypeAtLocation(left);
574
+ if (isObjectLikeValueType(valueType) && !isClassInstanceType(valueType)) {
575
+ recordOrigin(declarator, "map-value-lookup");
576
+ return;
577
+ }
578
+ }
579
+ // The new value isn't a map-value copy — clear any prior copy origin so a
580
+ // later mutation isn't misattributed. (Keep param origins intact: an array
581
+ // parameter stays an array parameter regardless of reassignment inside the
582
+ // function body, because reassigning a parameter doesn't change its C++
583
+ // by-value passing.)
584
+ const prior = originByDeclaration.get(declarator);
585
+ if (prior === "map-value-lookup") {
586
+ originByDeclaration.delete(declarator);
587
+ }
588
+ }
589
+ // Build the BindingResolver that gate rules will use.
590
+ const resolver = {
591
+ resolveOrigin(identifier) {
592
+ const symbol = checker.getSymbolAtLocation(identifier);
593
+ if (!symbol)
594
+ return undefined;
595
+ // Resolve aliases (imports) to the underlying value declaration.
596
+ let valueSymbol = symbol;
597
+ if (symbol.flags & ts.SymbolFlags.Alias) {
598
+ try {
599
+ valueSymbol = checker.getAliasedSymbol(symbol);
600
+ }
601
+ catch {
602
+ /* keep original */
603
+ }
604
+ }
605
+ const declarations = valueSymbol.valueDeclaration
606
+ ? [valueSymbol.valueDeclaration, ...(valueSymbol.declarations ?? [])]
607
+ : valueSymbol.declarations ?? [];
608
+ for (const decl of declarations) {
609
+ // The declaration node itself is the key we recorded (the identifier
610
+ // for simple bindings, or the BindingElement/identifier for patterns).
611
+ if (originByDeclaration.has(decl)) {
612
+ return originByDeclaration.get(decl);
613
+ }
614
+ }
615
+ return undefined;
616
+ },
617
+ };
618
+ // Attach the resolver to the result via a closure, exposed through a
619
+ // separate field so gate rules in type-checker.ts can resolve identifiers.
620
+ return {
621
+ facts,
622
+ diagnostics,
623
+ resolver,
624
+ };
625
+ }
626
+ function isFunctionLikeWithBodyNode(node) {
627
+ return ((ts.isFunctionDeclaration(node) ||
628
+ ts.isMethodDeclaration(node) ||
629
+ ts.isConstructorDeclaration(node) ||
630
+ ts.isGetAccessorDeclaration(node) ||
631
+ ts.isSetAccessorDeclaration(node) ||
632
+ ts.isFunctionExpression(node) ||
633
+ ts.isArrowFunction(node)) &&
634
+ !!node.body);
635
+ }
636
+ function isAssignmentOperatorKind(kind) {
637
+ return (kind === ts.SyntaxKind.EqualsToken ||
638
+ kind === ts.SyntaxKind.PlusEqualsToken ||
639
+ kind === ts.SyntaxKind.MinusEqualsToken ||
640
+ kind === ts.SyntaxKind.AsteriskEqualsToken ||
641
+ kind === ts.SyntaxKind.SlashEqualsToken ||
642
+ kind === ts.SyntaxKind.PercentEqualsToken ||
643
+ kind === ts.SyntaxKind.AmpersandEqualsToken ||
644
+ kind === ts.SyntaxKind.BarEqualsToken ||
645
+ kind === ts.SyntaxKind.CaretEqualsToken ||
646
+ kind === ts.SyntaxKind.LessThanLessThanEqualsToken ||
647
+ kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken ||
648
+ kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken ||
649
+ kind === ts.SyntaxKind.QuestionQuestionEqualsToken ||
650
+ kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
651
+ kind === ts.SyntaxKind.BarBarEqualsToken);
652
+ }