@soundscript/soundscript 0.1.13 → 0.1.16

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 (444) hide show
  1. package/decode.d.ts +2 -2
  2. package/decode.js.map +1 -1
  3. package/package.json +15 -6
  4. package/project-transform/index.js +2 -0
  5. package/project-transform/index.ts +8 -0
  6. package/project-transform/src/annotation_syntax.js +948 -0
  7. package/project-transform/src/annotation_syntax.ts +1217 -0
  8. package/project-transform/src/build_package.js +475 -0
  9. package/project-transform/src/build_package.ts +683 -0
  10. package/project-transform/src/bundled/portable-web-globals.d.ts +153 -0
  11. package/project-transform/src/bundled/runtime_externs.js +220 -0
  12. package/project-transform/src/bundled/runtime_externs.ts +237 -0
  13. package/project-transform/src/bundled/sound-libs/lib.decorators.d.ts +385 -0
  14. package/project-transform/src/bundled/sound-libs/lib.decorators.legacy.d.ts +22 -0
  15. package/project-transform/src/bundled/sound-libs/lib.dom.asynciterable.d.ts +42 -0
  16. package/project-transform/src/bundled/sound-libs/lib.dom.d.ts +39440 -0
  17. package/project-transform/src/bundled/sound-libs/lib.es2015.collection.d.ts +149 -0
  18. package/project-transform/src/bundled/sound-libs/lib.es2015.core.d.ts +657 -0
  19. package/project-transform/src/bundled/sound-libs/lib.es2015.d.ts +28 -0
  20. package/project-transform/src/bundled/sound-libs/lib.es2015.generator.d.ts +77 -0
  21. package/project-transform/src/bundled/sound-libs/lib.es2015.iterable.d.ts +616 -0
  22. package/project-transform/src/bundled/sound-libs/lib.es2015.promise.d.ts +80 -0
  23. package/project-transform/src/bundled/sound-libs/lib.es2015.proxy.d.ts +128 -0
  24. package/project-transform/src/bundled/sound-libs/lib.es2015.reflect.d.ts +144 -0
  25. package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.d.ts +46 -0
  26. package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.wellknown.d.ts +170 -0
  27. package/project-transform/src/bundled/sound-libs/lib.es2016.array.include.d.ts +116 -0
  28. package/project-transform/src/bundled/sound-libs/lib.es2016.d.ts +21 -0
  29. package/project-transform/src/bundled/sound-libs/lib.es2017.arraybuffer.d.ts +21 -0
  30. package/project-transform/src/bundled/sound-libs/lib.es2017.d.ts +26 -0
  31. package/project-transform/src/bundled/sound-libs/lib.es2017.date.d.ts +31 -0
  32. package/project-transform/src/bundled/sound-libs/lib.es2017.object.d.ts +49 -0
  33. package/project-transform/src/bundled/sound-libs/lib.es2017.string.d.ts +45 -0
  34. package/project-transform/src/bundled/sound-libs/lib.es2017.typedarrays.d.ts +53 -0
  35. package/project-transform/src/bundled/sound-libs/lib.es2018.asyncgenerator.d.ts +77 -0
  36. package/project-transform/src/bundled/sound-libs/lib.es2018.asynciterable.d.ts +57 -0
  37. package/project-transform/src/bundled/sound-libs/lib.es2018.d.ts +24 -0
  38. package/project-transform/src/bundled/sound-libs/lib.es2018.promise.d.ts +30 -0
  39. package/project-transform/src/bundled/sound-libs/lib.es2018.regexp.d.ts +37 -0
  40. package/project-transform/src/bundled/sound-libs/lib.es2019.array.d.ts +79 -0
  41. package/project-transform/src/bundled/sound-libs/lib.es2019.d.ts +24 -0
  42. package/project-transform/src/bundled/sound-libs/lib.es2019.object.d.ts +47 -0
  43. package/project-transform/src/bundled/sound-libs/lib.es2019.string.d.ts +37 -0
  44. package/project-transform/src/bundled/sound-libs/lib.es2019.symbol.d.ts +24 -0
  45. package/project-transform/src/bundled/sound-libs/lib.es2020.bigint.d.ts +765 -0
  46. package/project-transform/src/bundled/sound-libs/lib.es2020.d.ts +27 -0
  47. package/project-transform/src/bundled/sound-libs/lib.es2020.date.d.ts +42 -0
  48. package/project-transform/src/bundled/sound-libs/lib.es2020.number.d.ts +28 -0
  49. package/project-transform/src/bundled/sound-libs/lib.es2020.promise.d.ts +49 -0
  50. package/project-transform/src/bundled/sound-libs/lib.es2020.string.d.ts +44 -0
  51. package/project-transform/src/bundled/sound-libs/lib.es2020.symbol.wellknown.d.ts +41 -0
  52. package/project-transform/src/bundled/sound-libs/lib.es2021.d.ts +23 -0
  53. package/project-transform/src/bundled/sound-libs/lib.es2021.promise.d.ts +48 -0
  54. package/project-transform/src/bundled/sound-libs/lib.es2021.string.d.ts +33 -0
  55. package/project-transform/src/bundled/sound-libs/lib.es2021.weakref.d.ts +78 -0
  56. package/project-transform/src/bundled/sound-libs/lib.es2022.array.d.ts +121 -0
  57. package/project-transform/src/bundled/sound-libs/lib.es2022.d.ts +25 -0
  58. package/project-transform/src/bundled/sound-libs/lib.es2022.error.d.ts +75 -0
  59. package/project-transform/src/bundled/sound-libs/lib.es2022.object.d.ts +26 -0
  60. package/project-transform/src/bundled/sound-libs/lib.es2022.regexp.d.ts +39 -0
  61. package/project-transform/src/bundled/sound-libs/lib.es2022.string.d.ts +25 -0
  62. package/project-transform/src/bundled/sound-libs/lib.es2023.array.d.ts +924 -0
  63. package/project-transform/src/bundled/sound-libs/lib.es2023.collection.d.ts +21 -0
  64. package/project-transform/src/bundled/sound-libs/lib.es2023.d.ts +22 -0
  65. package/project-transform/src/bundled/sound-libs/lib.es2024.arraybuffer.d.ts +65 -0
  66. package/project-transform/src/bundled/sound-libs/lib.es2024.collection.d.ts +29 -0
  67. package/project-transform/src/bundled/sound-libs/lib.es2024.d.ts +26 -0
  68. package/project-transform/src/bundled/sound-libs/lib.es2024.object.d.ts +33 -0
  69. package/project-transform/src/bundled/sound-libs/lib.es2024.promise.d.ts +35 -0
  70. package/project-transform/src/bundled/sound-libs/lib.es2024.regexp.d.ts +25 -0
  71. package/project-transform/src/bundled/sound-libs/lib.es2024.string.d.ts +29 -0
  72. package/project-transform/src/bundled/sound-libs/lib.es5.d.ts +4924 -0
  73. package/project-transform/src/bundled/sound_stdlib.js +142 -0
  74. package/project-transform/src/bundled/sound_stdlib.ts +180 -0
  75. package/project-transform/src/checker/analyze_project.js +1361 -0
  76. package/project-transform/src/checker/analyze_project.ts +2246 -0
  77. package/project-transform/src/checker/diagnostics.js +112 -0
  78. package/project-transform/src/checker/diagnostics.ts +222 -0
  79. package/project-transform/src/checker/engine/context.js +235 -0
  80. package/project-transform/src/checker/engine/context.ts +340 -0
  81. package/project-transform/src/checker/engine/diagnostic_codes.js +72 -0
  82. package/project-transform/src/checker/engine/diagnostic_codes.ts +95 -0
  83. package/project-transform/src/checker/engine/facts.js +35 -0
  84. package/project-transform/src/checker/engine/facts.ts +48 -0
  85. package/project-transform/src/checker/engine/types.js +1 -0
  86. package/project-transform/src/checker/engine/types.ts +485 -0
  87. package/project-transform/src/checker/proof_escape_hatch_diagnostics.js +104 -0
  88. package/project-transform/src/checker/proof_escape_hatch_diagnostics.ts +173 -0
  89. package/project-transform/src/checker/rules/async_surface.js +231 -0
  90. package/project-transform/src/checker/rules/async_surface.ts +335 -0
  91. package/project-transform/src/checker/rules/class_lifecycle.js +798 -0
  92. package/project-transform/src/checker/rules/class_lifecycle.ts +1276 -0
  93. package/project-transform/src/checker/rules/directive_validation.js +571 -0
  94. package/project-transform/src/checker/rules/directive_validation.ts +938 -0
  95. package/project-transform/src/checker/rules/directives.js +23 -0
  96. package/project-transform/src/checker/rules/directives.ts +25 -0
  97. package/project-transform/src/checker/rules/flow.js +202 -0
  98. package/project-transform/src/checker/rules/flow.ts +333 -0
  99. package/project-transform/src/checker/rules/flow_facts.js +601 -0
  100. package/project-transform/src/checker/rules/flow_facts.ts +978 -0
  101. package/project-transform/src/checker/rules/flow_invalidation.js +1116 -0
  102. package/project-transform/src/checker/rules/flow_invalidation.ts +2155 -0
  103. package/project-transform/src/checker/rules/flow_shared.js +2822 -0
  104. package/project-transform/src/checker/rules/flow_shared.ts +4383 -0
  105. package/project-transform/src/checker/rules/foreign_boundary.js +120 -0
  106. package/project-transform/src/checker/rules/foreign_boundary.ts +196 -0
  107. package/project-transform/src/checker/rules/foreign_projection.js +279 -0
  108. package/project-transform/src/checker/rules/foreign_projection.ts +425 -0
  109. package/project-transform/src/checker/rules/generated_helpers.js +13 -0
  110. package/project-transform/src/checker/rules/generated_helpers.ts +18 -0
  111. package/project-transform/src/checker/rules/index.js +35 -0
  112. package/project-transform/src/checker/rules/index.ts +49 -0
  113. package/project-transform/src/checker/rules/namespace_object.js +845 -0
  114. package/project-transform/src/checker/rules/namespace_object.ts +1224 -0
  115. package/project-transform/src/checker/rules/non_ordinary_recovery.js +1328 -0
  116. package/project-transform/src/checker/rules/non_ordinary_recovery.ts +2391 -0
  117. package/project-transform/src/checker/rules/null_prototype.js +3 -0
  118. package/project-transform/src/checker/rules/null_prototype.ts +6 -0
  119. package/project-transform/src/checker/rules/overloads.js +181 -0
  120. package/project-transform/src/checker/rules/overloads.ts +317 -0
  121. package/project-transform/src/checker/rules/predicate_verification.js +691 -0
  122. package/project-transform/src/checker/rules/predicate_verification.ts +1088 -0
  123. package/project-transform/src/checker/rules/prototype_hardening.js +237 -0
  124. package/project-transform/src/checker/rules/prototype_hardening.ts +343 -0
  125. package/project-transform/src/checker/rules/receiver_discipline.js +263 -0
  126. package/project-transform/src/checker/rules/receiver_discipline.ts +356 -0
  127. package/project-transform/src/checker/rules/relations.js +7015 -0
  128. package/project-transform/src/checker/rules/relations.ts +12364 -0
  129. package/project-transform/src/checker/rules/resolved_builtins.js +274 -0
  130. package/project-transform/src/checker/rules/resolved_builtins.ts +438 -0
  131. package/project-transform/src/checker/rules/trust.js +217 -0
  132. package/project-transform/src/checker/rules/trust.ts +301 -0
  133. package/project-transform/src/checker/rules/type_guards.js +173 -0
  134. package/project-transform/src/checker/rules/type_guards.ts +257 -0
  135. package/project-transform/src/checker/rules/universal.js +17 -0
  136. package/project-transform/src/checker/rules/universal.ts +22 -0
  137. package/project-transform/src/checker/rules/unsafe_value_origin.js +80 -0
  138. package/project-transform/src/checker/rules/unsafe_value_origin.ts +125 -0
  139. package/project-transform/src/checker/rules/unsound_imports.js +218 -0
  140. package/project-transform/src/checker/rules/unsound_imports.ts +301 -0
  141. package/project-transform/src/checker/rules/unsound_syntax.js +1695 -0
  142. package/project-transform/src/checker/rules/unsound_syntax.ts +2540 -0
  143. package/project-transform/src/checker/rules/value_types.js +206 -0
  144. package/project-transform/src/checker/rules/value_types.ts +407 -0
  145. package/project-transform/src/checker/timing.js +43 -0
  146. package/project-transform/src/checker/timing.ts +78 -0
  147. package/project-transform/src/checker/unsupported_feature_messages.js +337 -0
  148. package/project-transform/src/checker/unsupported_feature_messages.ts +531 -0
  149. package/project-transform/src/cli.js +892 -0
  150. package/project-transform/src/cli.ts +1476 -0
  151. package/project-transform/src/compiler/compile_project.js +319 -0
  152. package/project-transform/src/compiler/compile_project.ts +508 -0
  153. package/project-transform/src/compiler/errors.js +10 -0
  154. package/project-transform/src/compiler/errors.ts +29 -0
  155. package/project-transform/src/compiler/ir.js +1 -0
  156. package/project-transform/src/compiler/ir.ts +1526 -0
  157. package/project-transform/src/compiler/lower.js +30550 -0
  158. package/project-transform/src/compiler/lower.ts +43645 -0
  159. package/project-transform/src/compiler/lower_arrays.js +140 -0
  160. package/project-transform/src/compiler/lower_arrays.ts +190 -0
  161. package/project-transform/src/compiler/lower_strings.js +121 -0
  162. package/project-transform/src/compiler/lower_strings.ts +198 -0
  163. package/project-transform/src/compiler/lower_tagged.js +329 -0
  164. package/project-transform/src/compiler/lower_tagged.ts +427 -0
  165. package/project-transform/src/compiler/lower_views.js +171 -0
  166. package/project-transform/src/compiler/lower_views.ts +251 -0
  167. package/project-transform/src/compiler/object_keys.js +25 -0
  168. package/project-transform/src/compiler/object_keys.ts +35 -0
  169. package/project-transform/src/compiler/runtime_ir.js +30 -0
  170. package/project-transform/src/compiler/runtime_ir.ts +727 -0
  171. package/project-transform/src/compiler/tagged_boundary.js +18 -0
  172. package/project-transform/src/compiler/tagged_boundary.ts +37 -0
  173. package/project-transform/src/compiler/toolchain.js +170 -0
  174. package/project-transform/src/compiler/toolchain.ts +229 -0
  175. package/project-transform/src/compiler/unicode_case_data.js +2102 -0
  176. package/project-transform/src/compiler/unicode_case_data.ts +2112 -0
  177. package/project-transform/src/compiler/wasm_js_host_runtime.js +656 -0
  178. package/project-transform/src/compiler/wasm_js_host_runtime.ts +762 -0
  179. package/project-transform/src/compiler/wat_arrays.js +3132 -0
  180. package/project-transform/src/compiler/wat_arrays.ts +3768 -0
  181. package/project-transform/src/compiler/wat_emitter.js +17952 -0
  182. package/project-transform/src/compiler/wat_emitter.ts +22812 -0
  183. package/project-transform/src/compiler/wat_strings.js +129 -0
  184. package/project-transform/src/compiler/wat_strings.ts +187 -0
  185. package/project-transform/src/compiler/wat_tagged.js +548 -0
  186. package/project-transform/src/compiler/wat_tagged.ts +674 -0
  187. package/project-transform/src/compiler_generator_runner.js +153 -0
  188. package/project-transform/src/compiler_generator_runner.ts +171 -0
  189. package/project-transform/src/compiler_object_test_helpers.js +69 -0
  190. package/project-transform/src/compiler_object_test_helpers.ts +96 -0
  191. package/project-transform/src/compiler_promise_runner.js +2116 -0
  192. package/project-transform/src/compiler_promise_runner.ts +2184 -0
  193. package/project-transform/src/compiler_test_helpers.js +854 -0
  194. package/project-transform/src/compiler_test_helpers.ts +1087 -0
  195. package/project-transform/src/config.js +568 -0
  196. package/project-transform/src/config.ts +892 -0
  197. package/project-transform/src/diagnostic_metadata.js +67 -0
  198. package/project-transform/src/diagnostic_metadata.ts +99 -0
  199. package/project-transform/src/diagnostic_reference.js +1368 -0
  200. package/project-transform/src/diagnostic_reference.ts +1523 -0
  201. package/project-transform/src/editor_diagnostics_worker.js +176 -0
  202. package/project-transform/src/editor_diagnostics_worker.ts +250 -0
  203. package/project-transform/src/editor_projection.js +224 -0
  204. package/project-transform/src/editor_projection.ts +421 -0
  205. package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.js +47 -0
  206. package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.ts +72 -0
  207. package/project-transform/src/frontend/builtin_macro_support.js +842 -0
  208. package/project-transform/src/frontend/builtin_macro_support.ts +1386 -0
  209. package/project-transform/src/frontend/builtin_macros.js +409 -0
  210. package/project-transform/src/frontend/builtin_macros.ts +542 -0
  211. package/project-transform/src/frontend/component_poc_runtime.js +279 -0
  212. package/project-transform/src/frontend/component_poc_runtime.ts +372 -0
  213. package/project-transform/src/frontend/css_macro.js +148 -0
  214. package/project-transform/src/frontend/css_macro.ts +222 -0
  215. package/project-transform/src/frontend/derive_macros.js +2072 -0
  216. package/project-transform/src/frontend/derive_macros.ts +3188 -0
  217. package/project-transform/src/frontend/embedded_fragment_support.js +106 -0
  218. package/project-transform/src/frontend/embedded_fragment_support.ts +172 -0
  219. package/project-transform/src/frontend/error_normalization.js +403 -0
  220. package/project-transform/src/frontend/error_normalization.ts +832 -0
  221. package/project-transform/src/frontend/error_stdlib_support.js +1 -0
  222. package/project-transform/src/frontend/error_stdlib_support.ts +6 -0
  223. package/project-transform/src/frontend/expand_project.js +169 -0
  224. package/project-transform/src/frontend/expand_project.ts +248 -0
  225. package/project-transform/src/frontend/format_soundscript.js +297 -0
  226. package/project-transform/src/frontend/format_soundscript.ts +582 -0
  227. package/project-transform/src/frontend/graphql_macro.js +174 -0
  228. package/project-transform/src/frontend/graphql_macro.ts +253 -0
  229. package/project-transform/src/frontend/hash_context.js +83 -0
  230. package/project-transform/src/frontend/hash_context.ts +113 -0
  231. package/project-transform/src/frontend/hkt_macro.js +448 -0
  232. package/project-transform/src/frontend/hkt_macro.ts +897 -0
  233. package/project-transform/src/frontend/import_binding_usage.js +190 -0
  234. package/project-transform/src/frontend/import_binding_usage.ts +277 -0
  235. package/project-transform/src/frontend/macro_advanced_backend_adapter.js +58 -0
  236. package/project-transform/src/frontend/macro_advanced_backend_adapter.ts +123 -0
  237. package/project-transform/src/frontend/macro_advanced_context.js +826 -0
  238. package/project-transform/src/frontend/macro_advanced_context.ts +1102 -0
  239. package/project-transform/src/frontend/macro_advanced_output.js +21 -0
  240. package/project-transform/src/frontend/macro_advanced_output.ts +41 -0
  241. package/project-transform/src/frontend/macro_api.js +353 -0
  242. package/project-transform/src/frontend/macro_api.ts +1722 -0
  243. package/project-transform/src/frontend/macro_api_internal.js +35 -0
  244. package/project-transform/src/frontend/macro_api_internal.ts +80 -0
  245. package/project-transform/src/frontend/macro_api_module_support.js +39 -0
  246. package/project-transform/src/frontend/macro_api_module_support.ts +65 -0
  247. package/project-transform/src/frontend/macro_backend_adapter.js +272 -0
  248. package/project-transform/src/frontend/macro_backend_adapter.ts +420 -0
  249. package/project-transform/src/frontend/macro_context.js +816 -0
  250. package/project-transform/src/frontend/macro_context.ts +1105 -0
  251. package/project-transform/src/frontend/macro_debug.js +99 -0
  252. package/project-transform/src/frontend/macro_debug.ts +157 -0
  253. package/project-transform/src/frontend/macro_definition_support.js +28 -0
  254. package/project-transform/src/frontend/macro_definition_support.ts +73 -0
  255. package/project-transform/src/frontend/macro_errors.js +40 -0
  256. package/project-transform/src/frontend/macro_errors.ts +70 -0
  257. package/project-transform/src/frontend/macro_expander.js +919 -0
  258. package/project-transform/src/frontend/macro_expander.ts +1611 -0
  259. package/project-transform/src/frontend/macro_factory_support.js +176 -0
  260. package/project-transform/src/frontend/macro_factory_support.ts +263 -0
  261. package/project-transform/src/frontend/macro_host_ast_internal.js +64 -0
  262. package/project-transform/src/frontend/macro_host_ast_internal.ts +109 -0
  263. package/project-transform/src/frontend/macro_index.js +27 -0
  264. package/project-transform/src/frontend/macro_index.ts +50 -0
  265. package/project-transform/src/frontend/macro_loader.js +281 -0
  266. package/project-transform/src/frontend/macro_loader.ts +506 -0
  267. package/project-transform/src/frontend/macro_operand_semantics.js +838 -0
  268. package/project-transform/src/frontend/macro_operand_semantics.ts +1489 -0
  269. package/project-transform/src/frontend/macro_output.js +54 -0
  270. package/project-transform/src/frontend/macro_output.ts +123 -0
  271. package/project-transform/src/frontend/macro_parser.js +611 -0
  272. package/project-transform/src/frontend/macro_parser.ts +832 -0
  273. package/project-transform/src/frontend/macro_resolver.js +69 -0
  274. package/project-transform/src/frontend/macro_resolver.ts +125 -0
  275. package/project-transform/src/frontend/macro_rewrite.js +285 -0
  276. package/project-transform/src/frontend/macro_rewrite.ts +442 -0
  277. package/project-transform/src/frontend/macro_runtime_support.js +232 -0
  278. package/project-transform/src/frontend/macro_runtime_support.ts +324 -0
  279. package/project-transform/src/frontend/macro_scanner.js +393 -0
  280. package/project-transform/src/frontend/macro_scanner.ts +455 -0
  281. package/project-transform/src/frontend/macro_semantic_backend_adapter.js +87 -0
  282. package/project-transform/src/frontend/macro_semantic_backend_adapter.ts +166 -0
  283. package/project-transform/src/frontend/macro_semantic_context.js +5 -0
  284. package/project-transform/src/frontend/macro_semantic_context.ts +12 -0
  285. package/project-transform/src/frontend/macro_semantic_output.js +24 -0
  286. package/project-transform/src/frontend/macro_semantic_output.ts +47 -0
  287. package/project-transform/src/frontend/macro_semantic_types.js +1 -0
  288. package/project-transform/src/frontend/macro_semantic_types.ts +98 -0
  289. package/project-transform/src/frontend/macro_semantics.js +1172 -0
  290. package/project-transform/src/frontend/macro_semantics.ts +1502 -0
  291. package/project-transform/src/frontend/macro_site_kind_support.js +164 -0
  292. package/project-transform/src/frontend/macro_site_kind_support.ts +255 -0
  293. package/project-transform/src/frontend/macro_syntax_internal.js +1950 -0
  294. package/project-transform/src/frontend/macro_syntax_internal.ts +3338 -0
  295. package/project-transform/src/frontend/macro_templates.js +57 -0
  296. package/project-transform/src/frontend/macro_templates.ts +143 -0
  297. package/project-transform/src/frontend/macro_test_helpers.js +82 -0
  298. package/project-transform/src/frontend/macro_test_helpers.ts +136 -0
  299. package/project-transform/src/frontend/macro_types.js +1 -0
  300. package/project-transform/src/frontend/macro_types.ts +103 -0
  301. package/project-transform/src/frontend/macro_vm.js +39 -0
  302. package/project-transform/src/frontend/macro_vm.ts +113 -0
  303. package/project-transform/src/frontend/match_macro.js +885 -0
  304. package/project-transform/src/frontend/match_macro.ts +1220 -0
  305. package/project-transform/src/frontend/numeric_normalization.js +824 -0
  306. package/project-transform/src/frontend/numeric_normalization.ts +1380 -0
  307. package/project-transform/src/frontend/numeric_prelude.js +278 -0
  308. package/project-transform/src/frontend/numeric_prelude.ts +370 -0
  309. package/project-transform/src/frontend/project_frontend.js +2396 -0
  310. package/project-transform/src/frontend/project_frontend.ts +3776 -0
  311. package/project-transform/src/frontend/project_macro_support.js +1401 -0
  312. package/project-transform/src/frontend/project_macro_support.ts +2137 -0
  313. package/project-transform/src/frontend/sql_macro.js +175 -0
  314. package/project-transform/src/frontend/sql_macro.ts +254 -0
  315. package/project-transform/src/frontend/sql_stdlib_support.js +1 -0
  316. package/project-transform/src/frontend/sql_stdlib_support.ts +6 -0
  317. package/project-transform/src/frontend/std_package_support.js +228 -0
  318. package/project-transform/src/frontend/std_package_support.ts +400 -0
  319. package/project-transform/src/frontend/value_normalization.js +306 -0
  320. package/project-transform/src/frontend/value_normalization.ts +599 -0
  321. package/project-transform/src/lsp/project_service.js +4771 -0
  322. package/project-transform/src/lsp/project_service.ts +7580 -0
  323. package/project-transform/src/lsp/protocol.js +9 -0
  324. package/project-transform/src/lsp/protocol.ts +38 -0
  325. package/project-transform/src/lsp/server.js +355 -0
  326. package/project-transform/src/lsp/server.ts +671 -0
  327. package/project-transform/src/lsp/session.js +49 -0
  328. package/project-transform/src/lsp/session.ts +48 -0
  329. package/project-transform/src/lsp/timing.js +43 -0
  330. package/project-transform/src/lsp/timing.ts +76 -0
  331. package/project-transform/src/lsp/transport.js +205 -0
  332. package/project-transform/src/lsp/transport.ts +253 -0
  333. package/project-transform/src/lsp_main.js +5 -0
  334. package/project-transform/src/lsp_main.ts +7 -0
  335. package/project-transform/src/macros.d.ts +1 -0
  336. package/project-transform/src/macros.js +1 -0
  337. package/project-transform/src/macros.ts +1 -0
  338. package/project-transform/src/main.js +24 -0
  339. package/project-transform/src/main.ts +28 -0
  340. package/project-transform/src/platform/host.js +264 -0
  341. package/project-transform/src/platform/host.ts +343 -0
  342. package/project-transform/src/platform/path.js +8 -0
  343. package/project-transform/src/platform/path.ts +20 -0
  344. package/project-transform/src/public_macro_api/macro_api.d.ts +1054 -0
  345. package/project-transform/src/public_macro_api/macro_semantic_types.d.ts +66 -0
  346. package/project-transform/src/public_macro_api/macro_types.d.ts +70 -0
  347. package/project-transform/src/run_program.js +14 -0
  348. package/project-transform/src/run_program.ts +33 -0
  349. package/project-transform/src/runtime/materialize.js +371 -0
  350. package/project-transform/src/runtime/materialize.ts +502 -0
  351. package/project-transform/src/runtime/on_demand.js +203 -0
  352. package/project-transform/src/runtime/on_demand.ts +305 -0
  353. package/project-transform/src/runtime/source_maps.js +205 -0
  354. package/project-transform/src/runtime/source_maps.ts +297 -0
  355. package/project-transform/src/runtime/transform.js +148 -0
  356. package/project-transform/src/runtime/transform.ts +295 -0
  357. package/project-transform/src/service/types.js +1 -0
  358. package/project-transform/src/service/types.ts +22 -0
  359. package/project-transform/src/soundscript_packages.js +477 -0
  360. package/project-transform/src/soundscript_packages.ts +754 -0
  361. package/project-transform/src/soundscript_runtime_specifiers.js +88 -0
  362. package/project-transform/src/soundscript_runtime_specifiers.ts +96 -0
  363. package/project-transform/src/stdlib/async.d.ts +81 -0
  364. package/project-transform/src/stdlib/async.js +213 -0
  365. package/project-transform/src/stdlib/async.ts +315 -0
  366. package/project-transform/src/stdlib/codec.d.ts +32 -0
  367. package/project-transform/src/stdlib/codec.js +30 -0
  368. package/project-transform/src/stdlib/codec.ts +76 -0
  369. package/project-transform/src/stdlib/compare.d.ts +28 -0
  370. package/project-transform/src/stdlib/compare.js +115 -0
  371. package/project-transform/src/stdlib/compare.ts +151 -0
  372. package/project-transform/src/stdlib/css.d.ts +16 -0
  373. package/project-transform/src/stdlib/css.js +9 -0
  374. package/project-transform/src/stdlib/css.ts +28 -0
  375. package/project-transform/src/stdlib/debug.d.ts +2 -0
  376. package/project-transform/src/stdlib/debug.js +9 -0
  377. package/project-transform/src/stdlib/debug.ts +10 -0
  378. package/project-transform/src/stdlib/decode.d.ts +86 -0
  379. package/project-transform/src/stdlib/decode.js +254 -0
  380. package/project-transform/src/stdlib/decode.ts +390 -0
  381. package/project-transform/src/stdlib/derive.d.ts +6 -0
  382. package/project-transform/src/stdlib/derive.js +7 -0
  383. package/project-transform/src/stdlib/derive.ts +7 -0
  384. package/project-transform/src/stdlib/encode.d.ts +100 -0
  385. package/project-transform/src/stdlib/encode.js +130 -0
  386. package/project-transform/src/stdlib/encode.ts +259 -0
  387. package/project-transform/src/stdlib/failures.d.ts +23 -0
  388. package/project-transform/src/stdlib/failures.js +41 -0
  389. package/project-transform/src/stdlib/failures.ts +64 -0
  390. package/project-transform/src/stdlib/fetch.d.ts +67 -0
  391. package/project-transform/src/stdlib/fetch.js +5 -0
  392. package/project-transform/src/stdlib/fetch.ts +11 -0
  393. package/project-transform/src/stdlib/graphql.d.ts +16 -0
  394. package/project-transform/src/stdlib/graphql.js +9 -0
  395. package/project-transform/src/stdlib/graphql.ts +28 -0
  396. package/project-transform/src/stdlib/hash.d.ts +34 -0
  397. package/project-transform/src/stdlib/hash.js +110 -0
  398. package/project-transform/src/stdlib/hash.ts +188 -0
  399. package/project-transform/src/stdlib/hkt.d.ts +40 -0
  400. package/project-transform/src/stdlib/hkt.js +3 -0
  401. package/project-transform/src/stdlib/hkt.ts +41 -0
  402. package/project-transform/src/stdlib/index.d.ts +9 -0
  403. package/project-transform/src/stdlib/index.js +15 -0
  404. package/project-transform/src/stdlib/index.ts +23 -0
  405. package/project-transform/src/stdlib/json.d.ts +125 -0
  406. package/project-transform/src/stdlib/json.js +764 -0
  407. package/project-transform/src/stdlib/json.ts +1034 -0
  408. package/project-transform/src/stdlib/match.d.ts +11 -0
  409. package/project-transform/src/stdlib/match.js +13 -0
  410. package/project-transform/src/stdlib/match.ts +26 -0
  411. package/project-transform/src/stdlib/numerics.d.ts +523 -0
  412. package/project-transform/src/stdlib/numerics.js +1356 -0
  413. package/project-transform/src/stdlib/numerics.ts +1937 -0
  414. package/project-transform/src/stdlib/random.d.ts +19 -0
  415. package/project-transform/src/stdlib/random.js +3 -0
  416. package/project-transform/src/stdlib/random.ts +5 -0
  417. package/project-transform/src/stdlib/result.d.ts +68 -0
  418. package/project-transform/src/stdlib/result.js +139 -0
  419. package/project-transform/src/stdlib/result.ts +248 -0
  420. package/project-transform/src/stdlib/sql.d.ts +22 -0
  421. package/project-transform/src/stdlib/sql.js +23 -0
  422. package/project-transform/src/stdlib/sql.ts +53 -0
  423. package/project-transform/src/stdlib/text.d.ts +24 -0
  424. package/project-transform/src/stdlib/text.js +3 -0
  425. package/project-transform/src/stdlib/text.ts +4 -0
  426. package/project-transform/src/stdlib/thunk.d.ts +2 -0
  427. package/project-transform/src/stdlib/thunk.js +9 -0
  428. package/project-transform/src/stdlib/thunk.ts +15 -0
  429. package/project-transform/src/stdlib/typeclasses.d.ts +57 -0
  430. package/project-transform/src/stdlib/typeclasses.js +78 -0
  431. package/project-transform/src/stdlib/typeclasses.ts +173 -0
  432. package/project-transform/src/stdlib/url.d.ts +37 -0
  433. package/project-transform/src/stdlib/url.js +3 -0
  434. package/project-transform/src/stdlib/url.ts +4 -0
  435. package/project-transform/src/stdlib/value.d.ts +9 -0
  436. package/project-transform/src/stdlib/value.js +104 -0
  437. package/project-transform/src/stdlib/value.ts +133 -0
  438. package/project-transform/src/test_installed_stdlib.js +147 -0
  439. package/project-transform/src/test_installed_stdlib.ts +245 -0
  440. package/project-transform/src/test_macro_package_fixture.js +50 -0
  441. package/project-transform/src/test_macro_package_fixture.ts +68 -0
  442. package/project-transform/src/value_deep_safe.js +191 -0
  443. package/project-transform/src/value_deep_safe.ts +273 -0
  444. package/soundscript/decode.sts +2 -2
@@ -0,0 +1,2155 @@
1
+ import ts from 'typescript';
2
+
3
+ import type {
4
+ AnalysisContext,
5
+ FlowInvalidationCandidateFact,
6
+ FlowInvalidationStructureFact,
7
+ } from '../engine/types.ts';
8
+
9
+ import type { FlowFactEnvironment } from './flow_facts.ts';
10
+
11
+ import {
12
+ type AnalysisState,
13
+ bindFunctionBindingName,
14
+ type FunctionBodyBindings,
15
+ appendSegment,
16
+ arrayMutationCallAffectsNarrow,
17
+ assignmentAffectsNarrow,
18
+ bindFunctionReceiverPath,
19
+ cloneState,
20
+ getCalledMember,
21
+ getExpressionSymbol,
22
+ getFunctionBindings,
23
+ getFunctionBodyCalledMember,
24
+ getFunctionLikeFromExpression,
25
+ getFunctionLikeFromBoundMemberCall,
26
+ getFunctionLikeFromBoundValue,
27
+ getFunctionLikeFromCallExpression,
28
+ getStateExpressionBoundValue,
29
+ getUniformArrayElementBindingFromExpression,
30
+ getUniformArrayElementBindingFromFunctionBodyExpression,
31
+ getUniformMapEntryBindingsFromExpression,
32
+ getUniformMapEntryBindingsFromFunctionBodyExpression,
33
+ getUniformSetElementBindingFromExpression,
34
+ getUniformSetElementBindingFromFunctionBodyExpression,
35
+ getNestedFunctionBindings,
36
+ getMutableBindingSymbol,
37
+ getShorthandStateBoundValue,
38
+ getSymbolId,
39
+ getUpdateExpressionOperand,
40
+ isConstLocalBindingPath,
41
+ isFunctionLikeWithBody,
42
+ isLocalBindingPath,
43
+ isStableConstLocalBindingPath,
44
+ MUTATING_ASSIGNMENT_OPERATORS,
45
+ mutationAffectsNarrow,
46
+ type NormalizedPath,
47
+ normalizeExpressionPath,
48
+ normalizeExpressionSourcePath,
49
+ normalizeFunctionBodyPath,
50
+ opaqueArgumentEscapeAffectsNarrow,
51
+ pathsMatch,
52
+ recordForOfLoopHeaderAliases,
53
+ recordFunctionBodyConstBindings,
54
+ recordExecutedExpressionAliases,
55
+ recordVariableAliases,
56
+ typeMayAliasMutableState,
57
+ typedUpdateExpressionAffectsNarrow,
58
+ } from './flow_shared.ts';
59
+
60
+ export type { AnalysisState, BoundValue, NormalizedPath } from './flow_shared.ts';
61
+ export {
62
+ appendSegment,
63
+ cloneState,
64
+ isFunctionLikeWithBody,
65
+ normalizeExpressionPath,
66
+ recordExecutedExpressionAliases,
67
+ recordVariableAliases,
68
+ } from './flow_shared.ts';
69
+
70
+ type ExpressionUseKind = 'mutation' | 'opaqueEscape' | 'return';
71
+
72
+ const SYNCHRONOUS_ARRAY_CALLBACK_PARAMETER_BINDINGS = new Map<
73
+ string,
74
+ { readonly arrayParameterIndex?: number; readonly callbackArgumentIndex: number; readonly elementParameterIndex: number }
75
+ >([
76
+ ['every', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
77
+ ['filter', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
78
+ ['find', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
79
+ ['findIndex', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
80
+ ['findLast', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
81
+ ['findLastIndex', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
82
+ ['flatMap', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
83
+ ['forEach', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
84
+ ['map', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
85
+ ['reduce', { callbackArgumentIndex: 0, elementParameterIndex: 1, arrayParameterIndex: 3 }],
86
+ ['reduceRight', { callbackArgumentIndex: 0, elementParameterIndex: 1, arrayParameterIndex: 3 }],
87
+ ['some', { callbackArgumentIndex: 0, elementParameterIndex: 0, arrayParameterIndex: 2 }],
88
+ ]);
89
+
90
+ const SYNCHRONOUS_SET_CALLBACK_PARAMETER_BINDINGS = new Map<
91
+ string,
92
+ {
93
+ readonly callbackArgumentIndex: number;
94
+ readonly elementParameterIndexes: readonly number[];
95
+ readonly receiverParameterIndex?: number;
96
+ }
97
+ >([
98
+ ['forEach', { callbackArgumentIndex: 0, elementParameterIndexes: [0, 1], receiverParameterIndex: 2 }],
99
+ ]);
100
+
101
+ const SYNCHRONOUS_MAP_CALLBACK_PARAMETER_BINDINGS = new Map<
102
+ string,
103
+ {
104
+ readonly callbackArgumentIndex: number;
105
+ readonly keyParameterIndex?: number;
106
+ readonly receiverParameterIndex?: number;
107
+ readonly valueParameterIndex?: number;
108
+ }
109
+ >([
110
+ ['forEach', { callbackArgumentIndex: 0, valueParameterIndex: 0, keyParameterIndex: 1, receiverParameterIndex: 2 }],
111
+ ]);
112
+
113
+ interface ExpressionPathInfo {
114
+ readonly readPath: NormalizedPath | undefined;
115
+ readonly sourcePath: NormalizedPath | undefined;
116
+ readonly extracted: boolean;
117
+ }
118
+
119
+ interface ReceiverBinding {
120
+ readonly memberPaths: ReadonlyMap<string, NormalizedPath> | undefined;
121
+ readonly path: NormalizedPath | undefined;
122
+ }
123
+
124
+ function unwrapTransparentExpression(expression: ts.Expression): ts.Expression {
125
+ while (
126
+ ts.isParenthesizedExpression(expression) ||
127
+ ts.isAsExpression(expression) ||
128
+ ts.isTypeAssertionExpression(expression) ||
129
+ ts.isNonNullExpression(expression) ||
130
+ ts.isSatisfiesExpression(expression)
131
+ ) {
132
+ expression = expression.expression;
133
+ }
134
+
135
+ return expression;
136
+ }
137
+
138
+ function expressionIsThisLikeInBindings(
139
+ context: AnalysisContext,
140
+ expression: ts.Expression,
141
+ bindings: FunctionBodyBindings,
142
+ seen = new Set<number>(),
143
+ ): boolean {
144
+ expression = unwrapTransparentExpression(expression);
145
+
146
+ if (expression.kind === ts.SyntaxKind.ThisKeyword) {
147
+ return true;
148
+ }
149
+
150
+ if (!ts.isIdentifier(expression)) {
151
+ return false;
152
+ }
153
+
154
+ const symbol = getExpressionSymbol(context, expression);
155
+ if (!symbol) {
156
+ return false;
157
+ }
158
+
159
+ const symbolId = getSymbolId(context, symbol);
160
+ if (seen.has(symbolId)) {
161
+ return false;
162
+ }
163
+ seen.add(symbolId);
164
+
165
+ const boundValue = bindings.boundValues.get(symbolId);
166
+ return !!boundValue && ts.isExpression(boundValue) &&
167
+ expressionIsThisLikeInBindings(context, boundValue, bindings, seen);
168
+ }
169
+
170
+ function getAssignedReceiverMemberKey(
171
+ context: AnalysisContext,
172
+ expression: ts.Expression,
173
+ bindings: FunctionBodyBindings,
174
+ ): string | undefined {
175
+ expression = unwrapTransparentExpression(expression);
176
+
177
+ if (ts.isPropertyAccessExpression(expression)) {
178
+ return expressionIsThisLikeInBindings(context, expression.expression, bindings)
179
+ ? expression.name.text
180
+ : undefined;
181
+ }
182
+
183
+ if (ts.isElementAccessExpression(expression)) {
184
+ if (!expressionIsThisLikeInBindings(context, expression.expression, bindings)) {
185
+ return undefined;
186
+ }
187
+
188
+ const argument = expression.argumentExpression;
189
+ if (!argument) {
190
+ return undefined;
191
+ }
192
+
193
+ const unwrappedArgument = unwrapTransparentExpression(argument);
194
+ if (
195
+ ts.isStringLiteral(unwrappedArgument) ||
196
+ ts.isNumericLiteral(unwrappedArgument) ||
197
+ ts.isNoSubstitutionTemplateLiteral(unwrappedArgument)
198
+ ) {
199
+ return unwrappedArgument.text;
200
+ }
201
+ }
202
+
203
+ return undefined;
204
+ }
205
+
206
+ function getConstructorAssignedReceiverMemberPaths(
207
+ context: AnalysisContext,
208
+ declaration: ts.Declaration,
209
+ bindings: FunctionBodyBindings,
210
+ ): ReadonlyMap<string, NormalizedPath> | undefined {
211
+ if (!ts.isConstructorDeclaration(declaration) || !declaration.body) {
212
+ return undefined;
213
+ }
214
+
215
+ const memberPaths = new Map<string, NormalizedPath>();
216
+ recordFunctionBodyConstBindings(context, declaration.body, bindings);
217
+
218
+ for (const candidate of getFlowInvalidationStructure(context, declaration.body, 'functionBody').candidates) {
219
+ if (
220
+ candidate.kind !== 'assignment' ||
221
+ candidate.node.operatorToken.kind !== ts.SyntaxKind.EqualsToken ||
222
+ context.isGeneratedNode(candidate.node)
223
+ ) {
224
+ continue;
225
+ }
226
+
227
+ const key = getAssignedReceiverMemberKey(context, candidate.left, bindings);
228
+ if (!key) {
229
+ continue;
230
+ }
231
+
232
+ const rightPath = normalizeFunctionBodyPath(context, candidate.right, bindings);
233
+ if (rightPath) {
234
+ memberPaths.set(key, rightPath);
235
+ }
236
+ }
237
+
238
+ return memberPaths.size > 0 ? memberPaths : undefined;
239
+ }
240
+
241
+ function getConstructorReceiverBindingFromState(
242
+ context: AnalysisContext,
243
+ declaration: ts.Declaration,
244
+ argumentsList: readonly ts.Expression[],
245
+ state: AnalysisState,
246
+ ): ReceiverBinding | undefined {
247
+ if (!isFunctionLikeWithBody(declaration)) {
248
+ return undefined;
249
+ }
250
+
251
+ const bindings = getFunctionBindings(context, argumentsList, declaration, state);
252
+ const memberPaths = getConstructorAssignedReceiverMemberPaths(context, declaration, bindings);
253
+ return memberPaths ? { path: undefined, memberPaths } : undefined;
254
+ }
255
+
256
+ function getConstructorReceiverBindingFromBindings(
257
+ context: AnalysisContext,
258
+ declaration: ts.Declaration,
259
+ argumentsList: readonly ts.Expression[],
260
+ bindings: FunctionBodyBindings,
261
+ ): ReceiverBinding | undefined {
262
+ if (!isFunctionLikeWithBody(declaration)) {
263
+ return undefined;
264
+ }
265
+
266
+ const nestedBindings = getNestedFunctionBindings(context, argumentsList, declaration, bindings);
267
+ const memberPaths = getConstructorAssignedReceiverMemberPaths(context, declaration, nestedBindings);
268
+ return memberPaths ? { path: undefined, memberPaths } : undefined;
269
+ }
270
+
271
+ function getStateConstructedReceiverBinding(
272
+ context: AnalysisContext,
273
+ expression: ts.Expression,
274
+ state: AnalysisState,
275
+ kind: ExpressionUseKind,
276
+ seen = new Set<number>(),
277
+ ): ReceiverBinding | undefined {
278
+ expression = unwrapTransparentExpression(expression);
279
+
280
+ if (ts.isIdentifier(expression)) {
281
+ const symbol = getExpressionSymbol(context, expression);
282
+ if (!symbol) {
283
+ return undefined;
284
+ }
285
+
286
+ const symbolId = getSymbolId(context, symbol);
287
+ if (seen.has(symbolId)) {
288
+ return {
289
+ path: getInvalidationPath(context, expression, state, kind),
290
+ memberPaths: undefined,
291
+ };
292
+ }
293
+ seen.add(symbolId);
294
+
295
+ const boundValue = state.boundValues.get(symbolId);
296
+ if (boundValue && ts.isExpression(boundValue)) {
297
+ return getStateConstructedReceiverBinding(context, boundValue, state, kind, seen) ?? {
298
+ path: getInvalidationPath(context, expression, state, kind),
299
+ memberPaths: undefined,
300
+ };
301
+ }
302
+ }
303
+
304
+ if (!ts.isNewExpression(expression)) {
305
+ const path = getInvalidationPath(context, expression, state, kind);
306
+ return path ? { path, memberPaths: undefined } : undefined;
307
+ }
308
+
309
+ const constructorDeclaration = context.checker.getResolvedSignature(expression)?.declaration;
310
+ return constructorDeclaration
311
+ ? getConstructorReceiverBindingFromState(
312
+ context,
313
+ constructorDeclaration,
314
+ expression.arguments ?? [],
315
+ state,
316
+ )
317
+ : undefined;
318
+ }
319
+
320
+ function getFunctionConstructedReceiverBinding(
321
+ context: AnalysisContext,
322
+ expression: ts.Expression,
323
+ bindings: FunctionBodyBindings,
324
+ seen = new Set<number>(),
325
+ ): ReceiverBinding | undefined {
326
+ expression = unwrapTransparentExpression(expression);
327
+
328
+ if (expression.kind === ts.SyntaxKind.ThisKeyword) {
329
+ return bindings.receiverPath || bindings.receiverMemberPaths
330
+ ? {
331
+ path: bindings.receiverPath,
332
+ memberPaths: bindings.receiverMemberPaths,
333
+ }
334
+ : undefined;
335
+ }
336
+
337
+ if (ts.isIdentifier(expression)) {
338
+ const symbol = getExpressionSymbol(context, expression);
339
+ if (!symbol) {
340
+ return undefined;
341
+ }
342
+
343
+ const symbolId = getSymbolId(context, symbol);
344
+ if (seen.has(symbolId)) {
345
+ const path = normalizeFunctionBodyPath(context, expression, bindings);
346
+ return path ? { path, memberPaths: undefined } : undefined;
347
+ }
348
+ seen.add(symbolId);
349
+
350
+ const boundValue = bindings.boundValues.get(symbolId);
351
+ if (boundValue && ts.isExpression(boundValue)) {
352
+ return getFunctionConstructedReceiverBinding(context, boundValue, bindings, seen) ?? {
353
+ path: normalizeFunctionBodyPath(context, expression, bindings),
354
+ memberPaths: undefined,
355
+ };
356
+ }
357
+ }
358
+
359
+ if (!ts.isNewExpression(expression)) {
360
+ const path = normalizeFunctionBodyPath(context, expression, bindings);
361
+ return path ? { path, memberPaths: undefined } : undefined;
362
+ }
363
+
364
+ const constructorDeclaration = context.checker.getResolvedSignature(expression)?.declaration;
365
+ return constructorDeclaration
366
+ ? getConstructorReceiverBindingFromBindings(
367
+ context,
368
+ constructorDeclaration,
369
+ expression.arguments ?? [],
370
+ bindings,
371
+ )
372
+ : undefined;
373
+ }
374
+
375
+ function getExpressionPathInfo(
376
+ context: AnalysisContext,
377
+ expression: ts.Expression,
378
+ state: AnalysisState,
379
+ ): ExpressionPathInfo {
380
+ const readPath = normalizeExpressionPath(context, expression, state);
381
+ const sourcePath = normalizeExpressionSourcePath(context, expression, state);
382
+ return {
383
+ readPath,
384
+ sourcePath,
385
+ extracted: !!readPath && !!sourcePath && !pathsMatch(readPath, sourcePath),
386
+ };
387
+ }
388
+
389
+ function getInvalidationPath(
390
+ context: AnalysisContext,
391
+ expression: ts.Expression,
392
+ state: AnalysisState,
393
+ kind: ExpressionUseKind,
394
+ ): NormalizedPath | undefined {
395
+ const pathInfo = getExpressionPathInfo(context, expression, state);
396
+ if (!pathInfo.extracted) {
397
+ return pathInfo.readPath;
398
+ }
399
+
400
+ if (!pathInfo.sourcePath) {
401
+ return pathInfo.readPath;
402
+ }
403
+
404
+ if (kind === 'opaqueEscape' && pathInfo.sourcePath.segments.length > 0) {
405
+ const type = context.checker.getTypeAtLocation(expression);
406
+ if (!typeMayAliasMutableState(context, type)) {
407
+ return undefined;
408
+ }
409
+ }
410
+
411
+ if (kind === 'return' && pathInfo.sourcePath.segments.length > 0) {
412
+ return undefined;
413
+ }
414
+
415
+ return pathInfo.sourcePath;
416
+ }
417
+
418
+ function isExtractedReadOnlyReturnArgument(
419
+ context: AnalysisContext,
420
+ expression: ts.Expression,
421
+ state: AnalysisState,
422
+ ): boolean {
423
+ const sourcePath = normalizeExpressionSourcePath(context, expression, state);
424
+ return !!sourcePath && sourcePath.segments.length > 0;
425
+ }
426
+
427
+ function expressionPathEscapesNarrow(
428
+ context: AnalysisContext,
429
+ expression: ts.Expression,
430
+ narrowPath: NormalizedPath,
431
+ state: AnalysisState,
432
+ ): boolean {
433
+ const expressionPath = normalizeExpressionPath(context, expression, state);
434
+ return expressionPath !== undefined &&
435
+ opaqueArgumentEscapeAffectsNarrow(expressionPath, narrowPath);
436
+ }
437
+
438
+ function functionBodyPathEscapesNarrow(
439
+ context: AnalysisContext,
440
+ expression: ts.Expression,
441
+ bindings: ReturnType<typeof getFunctionBindings>,
442
+ narrowPath: NormalizedPath,
443
+ ): boolean {
444
+ const expressionPath = normalizeFunctionBodyPath(context, expression, bindings);
445
+ return expressionPath !== undefined &&
446
+ opaqueArgumentEscapeAffectsNarrow(expressionPath, narrowPath);
447
+ }
448
+
449
+ function boundParameterAffectsNarrow(
450
+ context: AnalysisContext,
451
+ node: ts.Identifier,
452
+ bindings: ReturnType<typeof getFunctionBindings>,
453
+ narrowPath: NormalizedPath,
454
+ state: AnalysisState,
455
+ ): boolean {
456
+ if (
457
+ (ts.isCallExpression(node.parent) || ts.isNewExpression(node.parent)) &&
458
+ node.parent.expression === node
459
+ ) {
460
+ return false;
461
+ }
462
+
463
+ const parameterSymbol = getExpressionSymbol(context, node);
464
+ if (!parameterSymbol) {
465
+ return false;
466
+ }
467
+
468
+ const boundValue = bindings.boundValues.get(getSymbolId(context, parameterSymbol));
469
+ if (!boundValue) {
470
+ return false;
471
+ }
472
+
473
+ if (
474
+ ts.isExpression(boundValue) &&
475
+ !expressionPathEscapesNarrow(context, boundValue, narrowPath, state) &&
476
+ escapingExpressionAffectsNarrow(context, boundValue, narrowPath, state)
477
+ ) {
478
+ return true;
479
+ }
480
+
481
+ const boundFunction = getFunctionLikeFromBoundValue(context, boundValue);
482
+ return boundFunction
483
+ ? functionLikeAffectsNarrow(
484
+ context,
485
+ boundFunction,
486
+ [],
487
+ narrowPath,
488
+ state,
489
+ false,
490
+ )
491
+ : false;
492
+ }
493
+
494
+ function isNodeWithinScope(node: ts.Node, scope: ts.Node): boolean {
495
+ for (let current: ts.Node | undefined = node; current; current = current.parent) {
496
+ if (current === scope) {
497
+ return true;
498
+ }
499
+ }
500
+
501
+ return false;
502
+ }
503
+
504
+ function getLocalConstInitializer(
505
+ context: AnalysisContext,
506
+ identifier: ts.Identifier,
507
+ scope: ts.Node,
508
+ ): ts.Expression | undefined {
509
+ const symbol = getExpressionSymbol(context, identifier);
510
+ if (!symbol) {
511
+ return undefined;
512
+ }
513
+
514
+ const declaration = symbol.valueDeclaration;
515
+ if (
516
+ !declaration ||
517
+ !ts.isVariableDeclaration(declaration) ||
518
+ !declaration.initializer ||
519
+ !declaration.parent ||
520
+ !ts.isVariableDeclarationList(declaration.parent) ||
521
+ (declaration.parent.flags & ts.NodeFlags.Const) === 0 ||
522
+ !isNodeWithinScope(declaration, scope)
523
+ ) {
524
+ return undefined;
525
+ }
526
+
527
+ return declaration.initializer;
528
+ }
529
+
530
+ function forEachReturnExpression(
531
+ root: ts.Node,
532
+ callback: (expression: ts.Expression) => boolean,
533
+ ): boolean {
534
+ const visit = (node: ts.Node): boolean => {
535
+ if (node !== root && isFunctionLikeWithBody(node)) {
536
+ return false;
537
+ }
538
+
539
+ if (ts.isReturnStatement(node) && node.expression) {
540
+ return callback(node.expression);
541
+ }
542
+
543
+ return ts.forEachChild(node, visit) ?? false;
544
+ };
545
+
546
+ return visit(root);
547
+ }
548
+
549
+ function functionBodyExpressionEscapesNarrow(
550
+ context: AnalysisContext,
551
+ expression: ts.Expression,
552
+ bindings: ReturnType<typeof getFunctionBindings>,
553
+ narrowPath: NormalizedPath,
554
+ state: AnalysisState,
555
+ scope: ts.Node,
556
+ activeDeclarations: Set<ts.FunctionLikeDeclaration>,
557
+ seenExpressions: Set<ts.Expression>,
558
+ ): boolean {
559
+ if (seenExpressions.has(expression)) {
560
+ return false;
561
+ }
562
+ seenExpressions.add(expression);
563
+
564
+ if (isFunctionLikeWithBody(expression)) {
565
+ const nestedBindings = getNestedFunctionBindings(context, [], expression, bindings);
566
+ return functionLikeAffectsNarrow(
567
+ context,
568
+ expression,
569
+ [],
570
+ narrowPath,
571
+ state,
572
+ false,
573
+ undefined,
574
+ nestedBindings,
575
+ );
576
+ }
577
+
578
+ for (
579
+ const candidate of getFlowInvalidationStructure(
580
+ context,
581
+ expression,
582
+ 'functionBodyResultExpression',
583
+ ).candidates
584
+ ) {
585
+ if (candidate.kind === 'access') {
586
+ if (functionBodyPathEscapesNarrow(context, candidate.node, bindings, narrowPath)) {
587
+ return true;
588
+ }
589
+
590
+ if (ts.isIdentifier(candidate.node)) {
591
+ const initializer = getLocalConstInitializer(context, candidate.node, scope);
592
+ if (
593
+ initializer &&
594
+ functionBodyExpressionEscapesNarrow(
595
+ context,
596
+ initializer,
597
+ bindings,
598
+ narrowPath,
599
+ state,
600
+ scope,
601
+ activeDeclarations,
602
+ seenExpressions,
603
+ )
604
+ ) {
605
+ return true;
606
+ }
607
+ }
608
+ }
609
+
610
+ if (candidate.kind === 'call') {
611
+ const calleeDeclaration = getFunctionLikeFromCallExpression(context, candidate.node);
612
+ if (
613
+ calleeDeclaration &&
614
+ functionLikeResultEscapesNarrow(
615
+ context,
616
+ calleeDeclaration,
617
+ candidate.node.arguments,
618
+ narrowPath,
619
+ state,
620
+ activeDeclarations,
621
+ )
622
+ ) {
623
+ return true;
624
+ }
625
+ }
626
+ }
627
+
628
+ return false;
629
+ }
630
+
631
+ function functionLikeResultEscapesNarrow(
632
+ context: AnalysisContext,
633
+ declaration: ts.FunctionLikeDeclaration,
634
+ argumentsList: readonly ts.Expression[],
635
+ narrowPath: NormalizedPath,
636
+ state: AnalysisState,
637
+ activeDeclarations: Set<ts.FunctionLikeDeclaration> = new Set(),
638
+ ): boolean {
639
+ const body = declaration.body;
640
+ if (!body || activeDeclarations.has(declaration)) {
641
+ return false;
642
+ }
643
+
644
+ activeDeclarations.add(declaration);
645
+ try {
646
+ const bindings = getFunctionBindings(context, argumentsList, declaration, state);
647
+ return forEachReturnExpression(body, (expression) =>
648
+ functionBodyExpressionEscapesNarrow(
649
+ context,
650
+ expression,
651
+ bindings,
652
+ narrowPath,
653
+ state,
654
+ body,
655
+ activeDeclarations,
656
+ new Set(),
657
+ )
658
+ );
659
+ } finally {
660
+ activeDeclarations.delete(declaration);
661
+ }
662
+ }
663
+
664
+ function opaqueArgumentExpressionAffectsNarrow(
665
+ context: AnalysisContext,
666
+ expression: ts.Expression,
667
+ narrowPath: NormalizedPath,
668
+ state: AnalysisState,
669
+ ): boolean {
670
+ const pathInfo = getExpressionPathInfo(context, expression, state);
671
+ if (
672
+ pathInfo.sourcePath &&
673
+ pathInfo.sourcePath.segments.length > 0 &&
674
+ !typeMayAliasMutableState(context, context.checker.getTypeAtLocation(expression))
675
+ ) {
676
+ return false;
677
+ }
678
+
679
+ if (
680
+ pathInfo.extracted &&
681
+ pathInfo.sourcePath &&
682
+ pathInfo.sourcePath.segments.length > 0 &&
683
+ !typeMayAliasMutableState(context, context.checker.getTypeAtLocation(expression))
684
+ ) {
685
+ return false;
686
+ }
687
+
688
+ const invalidationPath = getInvalidationPath(context, expression, state, 'opaqueEscape');
689
+ if (invalidationPath && opaqueArgumentEscapeAffectsNarrow(invalidationPath, narrowPath)) {
690
+ return true;
691
+ }
692
+
693
+ if (!pathInfo.extracted) {
694
+ if (expressionPathEscapesNarrow(context, expression, narrowPath, state)) {
695
+ return true;
696
+ }
697
+
698
+ if (escapingExpressionAffectsNarrow(context, expression, narrowPath, state)) {
699
+ return true;
700
+ }
701
+
702
+ if (stateBoundValueAffectsNarrow(context, expression, narrowPath, state)) {
703
+ return true;
704
+ }
705
+ }
706
+
707
+ if (!ts.isCallExpression(expression)) {
708
+ return false;
709
+ }
710
+
711
+ const calleeDeclaration = getFunctionLikeFromCallExpression(context, expression);
712
+ return calleeDeclaration
713
+ ? functionLikeResultEscapesNarrow(
714
+ context,
715
+ calleeDeclaration,
716
+ expression.arguments,
717
+ narrowPath,
718
+ state,
719
+ )
720
+ : false;
721
+ }
722
+
723
+ function opaqueFunctionBodyArgumentExpressionAffectsNarrow(
724
+ context: AnalysisContext,
725
+ expression: ts.Expression,
726
+ bindings: ReturnType<typeof getFunctionBindings>,
727
+ narrowPath: NormalizedPath,
728
+ state: AnalysisState,
729
+ scope: ts.Node,
730
+ ): boolean {
731
+ const functionBodyPath = normalizeFunctionBodyPath(context, expression, bindings);
732
+ if (
733
+ functionBodyPath &&
734
+ functionBodyPath.segments.length > 0 &&
735
+ !typeMayAliasMutableState(context, context.checker.getTypeAtLocation(expression))
736
+ ) {
737
+ return false;
738
+ }
739
+
740
+ return functionBodyPathEscapesNarrow(context, expression, bindings, narrowPath) ||
741
+ functionBodyExpressionEscapesNarrow(
742
+ context,
743
+ expression,
744
+ bindings,
745
+ narrowPath,
746
+ state,
747
+ scope,
748
+ new Set(),
749
+ new Set(),
750
+ );
751
+ }
752
+
753
+ function getLocalCallbackFunctionLike(
754
+ context: AnalysisContext,
755
+ expression: ts.Expression,
756
+ bindings: FunctionBodyBindings,
757
+ ): ts.FunctionLikeDeclaration | undefined {
758
+ expression = unwrapTransparentExpression(expression);
759
+
760
+ if (isFunctionLikeWithBody(expression)) {
761
+ return expression;
762
+ }
763
+
764
+ if (!ts.isIdentifier(expression)) {
765
+ return undefined;
766
+ }
767
+
768
+ const symbol = getExpressionSymbol(context, expression);
769
+ if (!symbol) {
770
+ return getFunctionLikeFromExpression(context, expression);
771
+ }
772
+
773
+ const boundValue = bindings.boundValues.get(getSymbolId(context, symbol));
774
+ return boundValue
775
+ ? getFunctionLikeFromBoundValue(context, boundValue)
776
+ : getFunctionLikeFromExpression(context, expression);
777
+ }
778
+
779
+ function getStateCallbackFunctionLike(
780
+ context: AnalysisContext,
781
+ expression: ts.Expression,
782
+ state: AnalysisState,
783
+ ): ts.FunctionLikeDeclaration | undefined {
784
+ expression = unwrapTransparentExpression(expression);
785
+
786
+ if (isFunctionLikeWithBody(expression)) {
787
+ return expression;
788
+ }
789
+
790
+ const boundValue = getStateExpressionBoundValue(context, expression, state);
791
+ return boundValue
792
+ ? getFunctionLikeFromBoundValue(context, boundValue)
793
+ : getFunctionLikeFromExpression(context, expression);
794
+ }
795
+
796
+ function arrayCallbackArgumentAffectsNarrow(
797
+ context: AnalysisContext,
798
+ receiver: ts.Expression,
799
+ member: string | undefined,
800
+ callExpression: ts.CallExpression,
801
+ bindings: FunctionBodyBindings,
802
+ narrowPath: NormalizedPath,
803
+ state: AnalysisState,
804
+ ): boolean {
805
+ const callbackBinding = member
806
+ ? SYNCHRONOUS_ARRAY_CALLBACK_PARAMETER_BINDINGS.get(member)
807
+ : undefined;
808
+ if (!callbackBinding) {
809
+ return false;
810
+ }
811
+
812
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
813
+ if (!callbackArgument) {
814
+ return false;
815
+ }
816
+
817
+ const callbackDeclaration = getLocalCallbackFunctionLike(context, callbackArgument, bindings);
818
+ if (!callbackDeclaration) {
819
+ return false;
820
+ }
821
+
822
+ const representativeElement = getUniformArrayElementBindingFromFunctionBodyExpression(
823
+ context,
824
+ receiver,
825
+ bindings,
826
+ );
827
+ if (!representativeElement) {
828
+ return false;
829
+ }
830
+
831
+ const nestedBindings = getNestedFunctionBindings(context, [], callbackDeclaration, bindings);
832
+ const elementParameter = callbackDeclaration.parameters[callbackBinding.elementParameterIndex];
833
+ if (elementParameter) {
834
+ bindFunctionBindingName(
835
+ context,
836
+ elementParameter.name,
837
+ representativeElement.path,
838
+ representativeElement.value,
839
+ nestedBindings,
840
+ );
841
+ }
842
+
843
+ if (callbackBinding.arrayParameterIndex !== undefined) {
844
+ const arrayParameter = callbackDeclaration.parameters[callbackBinding.arrayParameterIndex];
845
+ if (arrayParameter) {
846
+ bindFunctionBindingName(
847
+ context,
848
+ arrayParameter.name,
849
+ normalizeFunctionBodyPath(context, receiver, bindings),
850
+ receiver,
851
+ nestedBindings,
852
+ );
853
+ }
854
+ }
855
+
856
+ return functionLikeAffectsNarrow(
857
+ context,
858
+ callbackDeclaration,
859
+ [],
860
+ narrowPath,
861
+ state,
862
+ false,
863
+ undefined,
864
+ nestedBindings,
865
+ );
866
+ }
867
+
868
+ function arrayCallbackExpressionAffectsNarrow(
869
+ context: AnalysisContext,
870
+ receiver: ts.Expression,
871
+ member: string | undefined,
872
+ callExpression: ts.CallExpression,
873
+ narrowPath: NormalizedPath,
874
+ state: AnalysisState,
875
+ ): boolean {
876
+ const callbackBinding = member
877
+ ? SYNCHRONOUS_ARRAY_CALLBACK_PARAMETER_BINDINGS.get(member)
878
+ : undefined;
879
+ if (!callbackBinding) {
880
+ return false;
881
+ }
882
+
883
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
884
+ if (!callbackArgument) {
885
+ return false;
886
+ }
887
+
888
+ const callbackDeclaration = getStateCallbackFunctionLike(context, callbackArgument, state);
889
+ if (!callbackDeclaration) {
890
+ return false;
891
+ }
892
+
893
+ const representativeElement = getUniformArrayElementBindingFromExpression(
894
+ context,
895
+ receiver,
896
+ state,
897
+ );
898
+ if (!representativeElement) {
899
+ return false;
900
+ }
901
+
902
+ const bindings = getFunctionBindings(context, [], callbackDeclaration, state);
903
+ const elementParameter = callbackDeclaration.parameters[callbackBinding.elementParameterIndex];
904
+ if (elementParameter) {
905
+ bindFunctionBindingName(
906
+ context,
907
+ elementParameter.name,
908
+ representativeElement.path,
909
+ representativeElement.value,
910
+ bindings,
911
+ );
912
+ }
913
+
914
+ if (callbackBinding.arrayParameterIndex !== undefined) {
915
+ const arrayParameter = callbackDeclaration.parameters[callbackBinding.arrayParameterIndex];
916
+ if (arrayParameter) {
917
+ bindFunctionBindingName(
918
+ context,
919
+ arrayParameter.name,
920
+ normalizeExpressionPath(context, receiver, state),
921
+ getStateExpressionBoundValue(context, receiver, state) ?? receiver,
922
+ bindings,
923
+ );
924
+ }
925
+ }
926
+
927
+ return functionLikeAffectsNarrow(
928
+ context,
929
+ callbackDeclaration,
930
+ [],
931
+ narrowPath,
932
+ state,
933
+ false,
934
+ undefined,
935
+ bindings,
936
+ );
937
+ }
938
+
939
+ function setCallbackArgumentAffectsNarrow(
940
+ context: AnalysisContext,
941
+ receiver: ts.Expression,
942
+ member: string | undefined,
943
+ callExpression: ts.CallExpression,
944
+ bindings: FunctionBodyBindings,
945
+ narrowPath: NormalizedPath,
946
+ state: AnalysisState,
947
+ ): boolean {
948
+ const callbackBinding = member
949
+ ? SYNCHRONOUS_SET_CALLBACK_PARAMETER_BINDINGS.get(member)
950
+ : undefined;
951
+ if (!callbackBinding) {
952
+ return false;
953
+ }
954
+
955
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
956
+ if (!callbackArgument) {
957
+ return false;
958
+ }
959
+
960
+ const callbackDeclaration = getLocalCallbackFunctionLike(context, callbackArgument, bindings);
961
+ if (!callbackDeclaration) {
962
+ return false;
963
+ }
964
+
965
+ const representativeElement = getUniformSetElementBindingFromFunctionBodyExpression(
966
+ context,
967
+ receiver,
968
+ bindings,
969
+ );
970
+ if (!representativeElement) {
971
+ return false;
972
+ }
973
+
974
+ const nestedBindings = getNestedFunctionBindings(context, [], callbackDeclaration, bindings);
975
+ for (const parameterIndex of callbackBinding.elementParameterIndexes) {
976
+ const parameter = callbackDeclaration.parameters[parameterIndex];
977
+ if (!parameter) {
978
+ continue;
979
+ }
980
+ bindFunctionBindingName(
981
+ context,
982
+ parameter.name,
983
+ representativeElement.path,
984
+ representativeElement.value,
985
+ nestedBindings,
986
+ );
987
+ }
988
+
989
+ if (callbackBinding.receiverParameterIndex !== undefined) {
990
+ const receiverParameter = callbackDeclaration.parameters[callbackBinding.receiverParameterIndex];
991
+ if (receiverParameter) {
992
+ bindFunctionBindingName(
993
+ context,
994
+ receiverParameter.name,
995
+ normalizeFunctionBodyPath(context, receiver, bindings),
996
+ receiver,
997
+ nestedBindings,
998
+ );
999
+ }
1000
+ }
1001
+
1002
+ return functionLikeAffectsNarrow(
1003
+ context,
1004
+ callbackDeclaration,
1005
+ [],
1006
+ narrowPath,
1007
+ state,
1008
+ false,
1009
+ undefined,
1010
+ nestedBindings,
1011
+ );
1012
+ }
1013
+
1014
+ function setCallbackExpressionAffectsNarrow(
1015
+ context: AnalysisContext,
1016
+ receiver: ts.Expression,
1017
+ member: string | undefined,
1018
+ callExpression: ts.CallExpression,
1019
+ narrowPath: NormalizedPath,
1020
+ state: AnalysisState,
1021
+ ): boolean {
1022
+ const callbackBinding = member
1023
+ ? SYNCHRONOUS_SET_CALLBACK_PARAMETER_BINDINGS.get(member)
1024
+ : undefined;
1025
+ if (!callbackBinding) {
1026
+ return false;
1027
+ }
1028
+
1029
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
1030
+ if (!callbackArgument) {
1031
+ return false;
1032
+ }
1033
+
1034
+ const callbackDeclaration = getStateCallbackFunctionLike(context, callbackArgument, state);
1035
+ if (!callbackDeclaration) {
1036
+ return false;
1037
+ }
1038
+
1039
+ const representativeElement = getUniformSetElementBindingFromExpression(
1040
+ context,
1041
+ receiver,
1042
+ state,
1043
+ );
1044
+ if (!representativeElement) {
1045
+ return false;
1046
+ }
1047
+
1048
+ const bindings = getFunctionBindings(context, [], callbackDeclaration, state);
1049
+ for (const parameterIndex of callbackBinding.elementParameterIndexes) {
1050
+ const parameter = callbackDeclaration.parameters[parameterIndex];
1051
+ if (!parameter) {
1052
+ continue;
1053
+ }
1054
+ bindFunctionBindingName(
1055
+ context,
1056
+ parameter.name,
1057
+ representativeElement.path,
1058
+ representativeElement.value,
1059
+ bindings,
1060
+ );
1061
+ }
1062
+
1063
+ if (callbackBinding.receiverParameterIndex !== undefined) {
1064
+ const receiverParameter = callbackDeclaration.parameters[callbackBinding.receiverParameterIndex];
1065
+ if (receiverParameter) {
1066
+ bindFunctionBindingName(
1067
+ context,
1068
+ receiverParameter.name,
1069
+ normalizeExpressionPath(context, receiver, state),
1070
+ getStateExpressionBoundValue(context, receiver, state) ?? receiver,
1071
+ bindings,
1072
+ );
1073
+ }
1074
+ }
1075
+
1076
+ return functionLikeAffectsNarrow(
1077
+ context,
1078
+ callbackDeclaration,
1079
+ [],
1080
+ narrowPath,
1081
+ state,
1082
+ false,
1083
+ undefined,
1084
+ bindings,
1085
+ );
1086
+ }
1087
+
1088
+ function mapCallbackArgumentAffectsNarrow(
1089
+ context: AnalysisContext,
1090
+ receiver: ts.Expression,
1091
+ member: string | undefined,
1092
+ callExpression: ts.CallExpression,
1093
+ bindings: FunctionBodyBindings,
1094
+ narrowPath: NormalizedPath,
1095
+ state: AnalysisState,
1096
+ ): boolean {
1097
+ const callbackBinding = member
1098
+ ? SYNCHRONOUS_MAP_CALLBACK_PARAMETER_BINDINGS.get(member)
1099
+ : undefined;
1100
+ if (!callbackBinding) {
1101
+ return false;
1102
+ }
1103
+
1104
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
1105
+ if (!callbackArgument) {
1106
+ return false;
1107
+ }
1108
+
1109
+ const callbackDeclaration = getLocalCallbackFunctionLike(context, callbackArgument, bindings);
1110
+ if (!callbackDeclaration) {
1111
+ return false;
1112
+ }
1113
+
1114
+ const representativeEntry = getUniformMapEntryBindingsFromFunctionBodyExpression(
1115
+ context,
1116
+ receiver,
1117
+ bindings,
1118
+ );
1119
+ if (!representativeEntry) {
1120
+ return false;
1121
+ }
1122
+
1123
+ const nestedBindings = getNestedFunctionBindings(context, [], callbackDeclaration, bindings);
1124
+
1125
+ if (callbackBinding.valueParameterIndex !== undefined && representativeEntry.value) {
1126
+ const parameter = callbackDeclaration.parameters[callbackBinding.valueParameterIndex];
1127
+ if (parameter) {
1128
+ bindFunctionBindingName(
1129
+ context,
1130
+ parameter.name,
1131
+ representativeEntry.value.path,
1132
+ representativeEntry.value.value,
1133
+ nestedBindings,
1134
+ );
1135
+ }
1136
+ }
1137
+
1138
+ if (callbackBinding.keyParameterIndex !== undefined && representativeEntry.key) {
1139
+ const parameter = callbackDeclaration.parameters[callbackBinding.keyParameterIndex];
1140
+ if (parameter) {
1141
+ bindFunctionBindingName(
1142
+ context,
1143
+ parameter.name,
1144
+ representativeEntry.key.path,
1145
+ representativeEntry.key.value,
1146
+ nestedBindings,
1147
+ );
1148
+ }
1149
+ }
1150
+
1151
+ if (callbackBinding.receiverParameterIndex !== undefined) {
1152
+ const receiverParameter = callbackDeclaration.parameters[callbackBinding.receiverParameterIndex];
1153
+ if (receiverParameter) {
1154
+ bindFunctionBindingName(
1155
+ context,
1156
+ receiverParameter.name,
1157
+ normalizeFunctionBodyPath(context, receiver, bindings),
1158
+ receiver,
1159
+ nestedBindings,
1160
+ );
1161
+ }
1162
+ }
1163
+
1164
+ return functionLikeAffectsNarrow(
1165
+ context,
1166
+ callbackDeclaration,
1167
+ [],
1168
+ narrowPath,
1169
+ state,
1170
+ false,
1171
+ undefined,
1172
+ nestedBindings,
1173
+ );
1174
+ }
1175
+
1176
+ function mapCallbackExpressionAffectsNarrow(
1177
+ context: AnalysisContext,
1178
+ receiver: ts.Expression,
1179
+ member: string | undefined,
1180
+ callExpression: ts.CallExpression,
1181
+ narrowPath: NormalizedPath,
1182
+ state: AnalysisState,
1183
+ ): boolean {
1184
+ const callbackBinding = member
1185
+ ? SYNCHRONOUS_MAP_CALLBACK_PARAMETER_BINDINGS.get(member)
1186
+ : undefined;
1187
+ if (!callbackBinding) {
1188
+ return false;
1189
+ }
1190
+
1191
+ const callbackArgument = callExpression.arguments[callbackBinding.callbackArgumentIndex];
1192
+ if (!callbackArgument) {
1193
+ return false;
1194
+ }
1195
+
1196
+ const callbackDeclaration = getStateCallbackFunctionLike(context, callbackArgument, state);
1197
+ if (!callbackDeclaration) {
1198
+ return false;
1199
+ }
1200
+
1201
+ const representativeEntry = getUniformMapEntryBindingsFromExpression(
1202
+ context,
1203
+ receiver,
1204
+ state,
1205
+ );
1206
+ if (!representativeEntry) {
1207
+ return false;
1208
+ }
1209
+
1210
+ const bindings = getFunctionBindings(context, [], callbackDeclaration, state);
1211
+
1212
+ if (callbackBinding.valueParameterIndex !== undefined && representativeEntry.value) {
1213
+ const parameter = callbackDeclaration.parameters[callbackBinding.valueParameterIndex];
1214
+ if (parameter) {
1215
+ bindFunctionBindingName(
1216
+ context,
1217
+ parameter.name,
1218
+ representativeEntry.value.path,
1219
+ representativeEntry.value.value,
1220
+ bindings,
1221
+ );
1222
+ }
1223
+ }
1224
+
1225
+ if (callbackBinding.keyParameterIndex !== undefined && representativeEntry.key) {
1226
+ const parameter = callbackDeclaration.parameters[callbackBinding.keyParameterIndex];
1227
+ if (parameter) {
1228
+ bindFunctionBindingName(
1229
+ context,
1230
+ parameter.name,
1231
+ representativeEntry.key.path,
1232
+ representativeEntry.key.value,
1233
+ bindings,
1234
+ );
1235
+ }
1236
+ }
1237
+
1238
+ if (callbackBinding.receiverParameterIndex !== undefined) {
1239
+ const receiverParameter = callbackDeclaration.parameters[callbackBinding.receiverParameterIndex];
1240
+ if (receiverParameter) {
1241
+ bindFunctionBindingName(
1242
+ context,
1243
+ receiverParameter.name,
1244
+ normalizeExpressionPath(context, receiver, state),
1245
+ getStateExpressionBoundValue(context, receiver, state) ?? receiver,
1246
+ bindings,
1247
+ );
1248
+ }
1249
+ }
1250
+
1251
+ return functionLikeAffectsNarrow(
1252
+ context,
1253
+ callbackDeclaration,
1254
+ [],
1255
+ narrowPath,
1256
+ state,
1257
+ false,
1258
+ undefined,
1259
+ bindings,
1260
+ );
1261
+ }
1262
+
1263
+ function functionLikeAffectsNarrow(
1264
+ context: AnalysisContext,
1265
+ declaration: ts.FunctionLikeDeclaration,
1266
+ argumentsList: readonly ts.Expression[],
1267
+ narrowPath: NormalizedPath,
1268
+ state: AnalysisState,
1269
+ allowCapturedRead: boolean,
1270
+ receiverBinding?: ReceiverBinding,
1271
+ precomputedBindings?: ReturnType<typeof getFunctionBindings>,
1272
+ activeDeclarations: Set<ts.FunctionLikeDeclaration> = new Set(),
1273
+ ): boolean {
1274
+ const body = declaration.body;
1275
+ if (!body || activeDeclarations.has(declaration)) {
1276
+ return false;
1277
+ }
1278
+
1279
+ activeDeclarations.add(declaration);
1280
+ try {
1281
+ const bindings = precomputedBindings ?? getFunctionBindings(
1282
+ context,
1283
+ argumentsList,
1284
+ declaration,
1285
+ state,
1286
+ );
1287
+ if (receiverBinding) {
1288
+ bindFunctionReceiverPath(bindings, receiverBinding.path);
1289
+ bindings.receiverMemberPaths = receiverBinding.memberPaths;
1290
+ }
1291
+ recordFunctionBodyConstBindings(context, body, bindings);
1292
+ for (const candidate of getFlowInvalidationStructure(context, body, 'functionBody').candidates) {
1293
+ if (candidate.kind === 'assignment') {
1294
+ const leftPath = normalizeFunctionBodyPath(context, candidate.left, bindings);
1295
+ if (leftPath && assignmentAffectsNarrow(context, candidate.node, leftPath, narrowPath)) {
1296
+ return true;
1297
+ }
1298
+ }
1299
+
1300
+ if (candidate.kind === 'delete') {
1301
+ const targetPath = normalizeFunctionBodyPath(context, candidate.expression, bindings);
1302
+ if (targetPath && mutationAffectsNarrow(targetPath, narrowPath)) {
1303
+ return true;
1304
+ }
1305
+ }
1306
+
1307
+ if (candidate.kind === 'update') {
1308
+ const operandPath = normalizeFunctionBodyPath(context, candidate.operand, bindings);
1309
+ if (
1310
+ operandPath &&
1311
+ typedUpdateExpressionAffectsNarrow(context, candidate.node, operandPath, narrowPath)
1312
+ ) {
1313
+ return true;
1314
+ }
1315
+ }
1316
+
1317
+ if (candidate.kind === 'call') {
1318
+ const directCalleeDeclaration = getFunctionLikeFromCallExpression(context, candidate.node);
1319
+ const directCalleeHasBody = directCalleeDeclaration &&
1320
+ isFunctionLikeWithBody(directCalleeDeclaration);
1321
+ const calledMember = getFunctionBodyCalledMember(
1322
+ context,
1323
+ candidate.node.expression,
1324
+ bindings,
1325
+ );
1326
+ if (
1327
+ calledMember &&
1328
+ arrayMutationCallAffectsNarrow(
1329
+ context,
1330
+ calledMember.receiver,
1331
+ normalizeFunctionBodyPath(context, calledMember.receiver, bindings),
1332
+ calledMember.member,
1333
+ calledMember.memberType,
1334
+ narrowPath,
1335
+ )
1336
+ ) {
1337
+ return true;
1338
+ }
1339
+
1340
+ if (
1341
+ calledMember &&
1342
+ arrayCallbackArgumentAffectsNarrow(
1343
+ context,
1344
+ calledMember.receiver,
1345
+ calledMember.member,
1346
+ candidate.node,
1347
+ bindings,
1348
+ narrowPath,
1349
+ state,
1350
+ )
1351
+ ) {
1352
+ return true;
1353
+ }
1354
+
1355
+ if (
1356
+ calledMember &&
1357
+ setCallbackArgumentAffectsNarrow(
1358
+ context,
1359
+ calledMember.receiver,
1360
+ calledMember.member,
1361
+ candidate.node,
1362
+ bindings,
1363
+ narrowPath,
1364
+ state,
1365
+ )
1366
+ ) {
1367
+ return true;
1368
+ }
1369
+
1370
+ if (
1371
+ calledMember &&
1372
+ mapCallbackArgumentAffectsNarrow(
1373
+ context,
1374
+ calledMember.receiver,
1375
+ calledMember.member,
1376
+ candidate.node,
1377
+ bindings,
1378
+ narrowPath,
1379
+ state,
1380
+ )
1381
+ ) {
1382
+ return true;
1383
+ }
1384
+
1385
+ const boundMemberDeclaration = getFunctionLikeFromBoundMemberCall(
1386
+ context,
1387
+ candidate.node.expression,
1388
+ bindings,
1389
+ );
1390
+ const boundMemberHasBody = boundMemberDeclaration && isFunctionLikeWithBody(boundMemberDeclaration);
1391
+ const receiverBinding = calledMember
1392
+ ? getFunctionConstructedReceiverBinding(context, calledMember.receiver, bindings)
1393
+ : undefined;
1394
+ if (
1395
+ boundMemberHasBody &&
1396
+ functionLikeAffectsNarrow(
1397
+ context,
1398
+ boundMemberDeclaration,
1399
+ candidate.node.arguments,
1400
+ narrowPath,
1401
+ state,
1402
+ false,
1403
+ receiverBinding,
1404
+ undefined,
1405
+ activeDeclarations,
1406
+ )
1407
+ ) {
1408
+ return true;
1409
+ }
1410
+
1411
+ if (
1412
+ ts.isElementAccessExpression(candidate.node.expression) ||
1413
+ candidate.node.questionDotToken !== undefined
1414
+ ) {
1415
+ const receiver = ts.isPropertyAccessExpression(candidate.node.expression) ||
1416
+ ts.isElementAccessExpression(candidate.node.expression)
1417
+ ? candidate.node.expression.expression
1418
+ : undefined;
1419
+ if (receiver) {
1420
+ const receiverPath = normalizeFunctionBodyPath(context, receiver, bindings);
1421
+ if (
1422
+ receiverPath &&
1423
+ receiverPath.baseSymbol === narrowPath.baseSymbol &&
1424
+ receiverPath.segments.length === 0 &&
1425
+ narrowPath.segments.length > 0
1426
+ ) {
1427
+ return true;
1428
+ }
1429
+ }
1430
+ }
1431
+
1432
+ if (
1433
+ directCalleeHasBody &&
1434
+ functionLikeAffectsNarrow(
1435
+ context,
1436
+ directCalleeDeclaration,
1437
+ candidate.node.arguments,
1438
+ narrowPath,
1439
+ state,
1440
+ false,
1441
+ receiverBinding,
1442
+ undefined,
1443
+ activeDeclarations,
1444
+ )
1445
+ ) {
1446
+ return true;
1447
+ }
1448
+
1449
+ if (ts.isIdentifier(candidate.node.expression)) {
1450
+ const parameterSymbol = getExpressionSymbol(context, candidate.node.expression);
1451
+ if (parameterSymbol) {
1452
+ const boundValue = bindings.boundValues.get(
1453
+ getSymbolId(context, parameterSymbol),
1454
+ );
1455
+ const boundFunction = boundValue
1456
+ ? getFunctionLikeFromBoundValue(context, boundValue)
1457
+ : undefined;
1458
+ const boundFunctionHasBody = boundFunction && isFunctionLikeWithBody(boundFunction);
1459
+ if (
1460
+ boundFunctionHasBody &&
1461
+ functionLikeAffectsNarrow(
1462
+ context,
1463
+ boundFunction,
1464
+ candidate.node.arguments,
1465
+ narrowPath,
1466
+ state,
1467
+ false,
1468
+ undefined,
1469
+ undefined,
1470
+ activeDeclarations,
1471
+ )
1472
+ ) {
1473
+ return true;
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ if (
1479
+ !directCalleeHasBody &&
1480
+ !boundMemberHasBody &&
1481
+ candidate.node.arguments.some((argument) =>
1482
+ opaqueFunctionBodyArgumentExpressionAffectsNarrow(
1483
+ context,
1484
+ argument,
1485
+ bindings,
1486
+ narrowPath,
1487
+ state,
1488
+ body,
1489
+ )
1490
+ )
1491
+ ) {
1492
+ return true;
1493
+ }
1494
+ }
1495
+
1496
+ if (
1497
+ allowCapturedRead &&
1498
+ getMutableBindingSymbol(narrowPath) &&
1499
+ candidate.kind === 'access'
1500
+ ) {
1501
+ const usedPath = normalizeFunctionBodyPath(context, candidate.node, bindings);
1502
+ if (usedPath && pathsMatch(usedPath, narrowPath)) {
1503
+ return true;
1504
+ }
1505
+ }
1506
+
1507
+ if (
1508
+ candidate.kind === 'access' &&
1509
+ ts.isIdentifier(candidate.node) &&
1510
+ boundParameterAffectsNarrow(context, candidate.node, bindings, narrowPath, state)
1511
+ ) {
1512
+ return true;
1513
+ }
1514
+ }
1515
+
1516
+ return false;
1517
+ } finally {
1518
+ activeDeclarations.delete(declaration);
1519
+ }
1520
+ }
1521
+
1522
+ function classInstanceMethodsAffectNarrow(
1523
+ context: AnalysisContext,
1524
+ constructorDeclaration: ts.Declaration,
1525
+ argumentsList: readonly ts.Expression[],
1526
+ narrowPath: NormalizedPath,
1527
+ state: AnalysisState,
1528
+ ): boolean {
1529
+ const classLike = constructorDeclaration.parent;
1530
+ if (!ts.isClassLike(classLike)) {
1531
+ return false;
1532
+ }
1533
+
1534
+ let hasInstanceMethod = false;
1535
+ const receiverBinding = getConstructorReceiverBindingFromState(
1536
+ context,
1537
+ constructorDeclaration,
1538
+ argumentsList,
1539
+ state,
1540
+ );
1541
+ for (const member of classLike.members) {
1542
+ if (
1543
+ (ts.isMethodDeclaration(member) || ts.isGetAccessorDeclaration(member) ||
1544
+ ts.isSetAccessorDeclaration(member)) &&
1545
+ !hasStaticModifier(member)
1546
+ ) {
1547
+ hasInstanceMethod = true;
1548
+ if (
1549
+ isFunctionLikeWithBody(member) &&
1550
+ functionLikeAffectsNarrow(
1551
+ context,
1552
+ member,
1553
+ [],
1554
+ narrowPath,
1555
+ state,
1556
+ false,
1557
+ receiverBinding,
1558
+ )
1559
+ ) {
1560
+ return true;
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+ return hasInstanceMethod &&
1566
+ argumentsList.some((argument) =>
1567
+ expressionPathEscapesNarrow(context, argument, narrowPath, state)
1568
+ );
1569
+ }
1570
+
1571
+ function hasStaticModifier(node: ts.Node): boolean {
1572
+ return (ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Static) !== 0;
1573
+ }
1574
+
1575
+ function escapingExpressionAffectsNarrow(
1576
+ context: AnalysisContext,
1577
+ expression: ts.Expression,
1578
+ narrowPath: NormalizedPath,
1579
+ state: AnalysisState,
1580
+ seenExpressions: Set<ts.Expression> = new Set(),
1581
+ ): boolean {
1582
+ expression = ts.isParenthesizedExpression(expression) ? expression.expression : expression;
1583
+ if (seenExpressions.has(expression)) {
1584
+ return false;
1585
+ }
1586
+ seenExpressions.add(expression);
1587
+
1588
+ for (
1589
+ const candidate of getFlowInvalidationStructure(context, expression, 'expression').candidates
1590
+ ) {
1591
+ if (candidate.kind === 'access' &&
1592
+ expressionPathEscapesNarrow(context, candidate.node, narrowPath, state)) {
1593
+ return true;
1594
+ }
1595
+
1596
+ if (candidate.kind === 'shorthandProperty') {
1597
+ const boundValue = getShorthandStateBoundValue(context, candidate.node, state);
1598
+ if (!boundValue) {
1599
+ continue;
1600
+ }
1601
+ if (
1602
+ ts.isExpression(boundValue) &&
1603
+ escapingExpressionAffectsNarrow(context, boundValue, narrowPath, state, seenExpressions)
1604
+ ) {
1605
+ return true;
1606
+ }
1607
+ const boundFunction = getFunctionLikeFromBoundValue(context, boundValue);
1608
+ if (
1609
+ boundFunction &&
1610
+ functionLikeAffectsNarrow(context, boundFunction, [], narrowPath, state, false)
1611
+ ) {
1612
+ return true;
1613
+ }
1614
+ }
1615
+
1616
+ if (
1617
+ candidate.kind === 'access' &&
1618
+ ts.isIdentifier(candidate.node) &&
1619
+ stateBoundValueAffectsNarrow(context, candidate.node, narrowPath, state, seenExpressions)
1620
+ ) {
1621
+ return true;
1622
+ }
1623
+
1624
+ if (
1625
+ candidate.kind === 'functionLike' &&
1626
+ functionLikeAffectsNarrow(context, candidate.node, [], narrowPath, state, false)
1627
+ ) {
1628
+ return true;
1629
+ }
1630
+
1631
+ if (candidate.kind === 'call') {
1632
+ const calledMember = getCalledMember(context, candidate.node.expression);
1633
+ if (
1634
+ calledMember &&
1635
+ arrayMutationCallAffectsNarrow(
1636
+ context,
1637
+ calledMember.receiver,
1638
+ normalizeExpressionPath(context, calledMember.receiver, state),
1639
+ calledMember.member,
1640
+ calledMember.memberType,
1641
+ narrowPath,
1642
+ )
1643
+ ) {
1644
+ return true;
1645
+ }
1646
+
1647
+ if (
1648
+ ts.isElementAccessExpression(candidate.node.expression) ||
1649
+ candidate.node.questionDotToken !== undefined
1650
+ ) {
1651
+ const receiver = ts.isPropertyAccessExpression(candidate.node.expression) ||
1652
+ ts.isElementAccessExpression(candidate.node.expression)
1653
+ ? candidate.node.expression.expression
1654
+ : undefined;
1655
+ if (receiver) {
1656
+ const receiverPath = normalizeExpressionPath(context, receiver, state);
1657
+ if (
1658
+ receiverPath &&
1659
+ receiverPath.baseSymbol === narrowPath.baseSymbol &&
1660
+ receiverPath.segments.length === 0 &&
1661
+ narrowPath.segments.length > 0
1662
+ ) {
1663
+ return true;
1664
+ }
1665
+ }
1666
+ }
1667
+
1668
+ const calleeDeclaration = getFunctionLikeFromCallExpression(context, candidate.node);
1669
+ if (
1670
+ calleeDeclaration &&
1671
+ functionLikeAffectsNarrow(
1672
+ context,
1673
+ calleeDeclaration,
1674
+ candidate.node.arguments,
1675
+ narrowPath,
1676
+ state,
1677
+ true,
1678
+ calledMember
1679
+ ? getStateConstructedReceiverBinding(
1680
+ context,
1681
+ calledMember.receiver,
1682
+ state,
1683
+ 'mutation',
1684
+ )
1685
+ : undefined,
1686
+ )
1687
+ ) {
1688
+ return true;
1689
+ }
1690
+
1691
+ if (
1692
+ !calleeDeclaration &&
1693
+ candidate.node.arguments.some((argument) =>
1694
+ opaqueArgumentExpressionAffectsNarrow(context, argument, narrowPath, state)
1695
+ )
1696
+ ) {
1697
+ return true;
1698
+ }
1699
+ }
1700
+
1701
+ if (candidate.kind === 'new') {
1702
+ const constructorDeclaration = context.checker.getResolvedSignature(candidate.node)
1703
+ ?.declaration;
1704
+ if (
1705
+ constructorDeclaration &&
1706
+ (
1707
+ (isFunctionLikeWithBody(constructorDeclaration) &&
1708
+ functionLikeAffectsNarrow(
1709
+ context,
1710
+ constructorDeclaration,
1711
+ candidate.node.arguments ?? [],
1712
+ narrowPath,
1713
+ state,
1714
+ false,
1715
+ )) ||
1716
+ classInstanceMethodsAffectNarrow(
1717
+ context,
1718
+ constructorDeclaration,
1719
+ candidate.node.arguments ?? [],
1720
+ narrowPath,
1721
+ state,
1722
+ )
1723
+ )
1724
+ ) {
1725
+ return true;
1726
+ }
1727
+ }
1728
+ }
1729
+
1730
+ return false;
1731
+ }
1732
+
1733
+ export const FLOW_FACT_ENVIRONMENT = {
1734
+ appendSegment,
1735
+ escapingExpressionAffectsNarrow,
1736
+ normalizeExpressionPath,
1737
+ normalizeWholeValueFactPath(
1738
+ context: AnalysisContext,
1739
+ expression: ts.Expression,
1740
+ state: AnalysisState,
1741
+ ): NormalizedPath | undefined {
1742
+ const path = normalizeExpressionPath(context, expression, state);
1743
+ if (!path) {
1744
+ return undefined;
1745
+ }
1746
+
1747
+ const unwrappedExpression = ts.isParenthesizedExpression(expression) ||
1748
+ ts.isAsExpression(expression) ||
1749
+ ts.isTypeAssertionExpression(expression) ||
1750
+ ts.isNonNullExpression(expression) ||
1751
+ ts.isSatisfiesExpression(expression)
1752
+ ? unwrapTransparentExpression(expression)
1753
+ : expression;
1754
+
1755
+ if (!ts.isIdentifier(unwrappedExpression)) {
1756
+ return path;
1757
+ }
1758
+
1759
+ const symbol = getExpressionSymbol(context, unwrappedExpression);
1760
+ if (!symbol) {
1761
+ return path;
1762
+ }
1763
+
1764
+ const localPath: NormalizedPath = {
1765
+ baseSymbol: symbol,
1766
+ segments: [],
1767
+ };
1768
+
1769
+ return isConstLocalBindingPath(localPath) ? localPath : path;
1770
+ },
1771
+ shouldTrackFact(
1772
+ context: AnalysisContext,
1773
+ path: NormalizedPath,
1774
+ ): boolean {
1775
+ return !isStableConstLocalBindingPath(context, path);
1776
+ },
1777
+ } satisfies FlowFactEnvironment<NormalizedPath, AnalysisState>;
1778
+
1779
+ function stateBoundValueAffectsNarrow(
1780
+ context: AnalysisContext,
1781
+ expression: ts.Expression,
1782
+ narrowPath: NormalizedPath,
1783
+ state: AnalysisState,
1784
+ seenExpressions: Set<ts.Expression> = new Set(),
1785
+ ): boolean {
1786
+ if (ts.isParenthesizedExpression(expression)) {
1787
+ return stateBoundValueAffectsNarrow(
1788
+ context,
1789
+ expression.expression,
1790
+ narrowPath,
1791
+ state,
1792
+ seenExpressions,
1793
+ );
1794
+ }
1795
+
1796
+ if (!ts.isIdentifier(expression)) {
1797
+ return false;
1798
+ }
1799
+
1800
+ if (seenExpressions.has(expression)) {
1801
+ return false;
1802
+ }
1803
+ seenExpressions.add(expression);
1804
+
1805
+ const symbol = getExpressionSymbol(context, expression);
1806
+ if (!symbol) {
1807
+ return false;
1808
+ }
1809
+
1810
+ const symbolId = getSymbolId(context, symbol);
1811
+ if (state.extractedBindings.has(symbolId)) {
1812
+ return false;
1813
+ }
1814
+
1815
+ const boundValue = state.boundValues.get(symbolId);
1816
+ if (!boundValue) {
1817
+ return false;
1818
+ }
1819
+
1820
+ if (
1821
+ ts.isExpression(boundValue) &&
1822
+ escapingExpressionAffectsNarrow(context, boundValue, narrowPath, state, seenExpressions)
1823
+ ) {
1824
+ return true;
1825
+ }
1826
+
1827
+ const boundFunction = getFunctionLikeFromBoundValue(context, boundValue);
1828
+ return boundFunction !== undefined &&
1829
+ functionLikeAffectsNarrow(context, boundFunction, [], narrowPath, state, false);
1830
+ }
1831
+
1832
+ function getFlowInvalidationStructure(
1833
+ context: AnalysisContext,
1834
+ node: ts.Node,
1835
+ optionsKey: string,
1836
+ ): FlowInvalidationStructureFact {
1837
+ return context.facts.getFlowInvalidationStructure(
1838
+ node,
1839
+ optionsKey,
1840
+ () =>
1841
+ parseFlowInvalidationStructure(
1842
+ node,
1843
+ optionsKey === 'expression',
1844
+ ),
1845
+ );
1846
+ }
1847
+
1848
+ function parseFlowInvalidationStructure(
1849
+ rootNode: ts.Node,
1850
+ includeNestedFunctionLikeCandidates: boolean,
1851
+ ): FlowInvalidationStructureFact {
1852
+ const candidates: FlowInvalidationCandidateFact[] = [];
1853
+
1854
+ const visit = (node: ts.Node): void => {
1855
+ if (isFunctionLikeWithBody(node)) {
1856
+ if (includeNestedFunctionLikeCandidates) {
1857
+ candidates.push({
1858
+ kind: 'functionLike',
1859
+ node,
1860
+ });
1861
+ }
1862
+ return;
1863
+ }
1864
+
1865
+ if (
1866
+ ts.isIdentifier(node) || ts.isPropertyAccessExpression(node) ||
1867
+ ts.isElementAccessExpression(node)
1868
+ ) {
1869
+ candidates.push({
1870
+ kind: 'access',
1871
+ node,
1872
+ });
1873
+ } else if (
1874
+ ts.isBinaryExpression(node) &&
1875
+ MUTATING_ASSIGNMENT_OPERATORS.has(node.operatorToken.kind)
1876
+ ) {
1877
+ candidates.push({
1878
+ kind: 'assignment',
1879
+ left: node.left,
1880
+ node,
1881
+ right: node.right,
1882
+ });
1883
+ } else if (ts.isDeleteExpression(node)) {
1884
+ candidates.push({
1885
+ kind: 'delete',
1886
+ expression: node.expression,
1887
+ node,
1888
+ });
1889
+ } else {
1890
+ const updateOperand = getUpdateExpressionOperand(node);
1891
+ if (
1892
+ updateOperand &&
1893
+ (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node))
1894
+ ) {
1895
+ candidates.push({
1896
+ kind: 'update',
1897
+ node,
1898
+ operand: updateOperand,
1899
+ });
1900
+ } else if (ts.isAwaitExpression(node) || ts.isYieldExpression(node)) {
1901
+ candidates.push({
1902
+ kind: 'awaitYield',
1903
+ node,
1904
+ });
1905
+ } else if (ts.isCallExpression(node)) {
1906
+ candidates.push({
1907
+ kind: 'call',
1908
+ node,
1909
+ });
1910
+ } else if (ts.isShorthandPropertyAssignment(node)) {
1911
+ candidates.push({
1912
+ kind: 'shorthandProperty',
1913
+ node,
1914
+ });
1915
+ } else if (ts.isNewExpression(node)) {
1916
+ candidates.push({
1917
+ kind: 'new',
1918
+ node,
1919
+ });
1920
+ }
1921
+ }
1922
+
1923
+ ts.forEachChild(node, visit);
1924
+ };
1925
+
1926
+ visit(rootNode);
1927
+
1928
+ return { candidates };
1929
+ }
1930
+
1931
+ export function statementAffectsNarrow(
1932
+ context: AnalysisContext,
1933
+ statement: ts.Statement,
1934
+ narrowPath: NormalizedPath,
1935
+ state: AnalysisState,
1936
+ ): ts.Node | undefined {
1937
+ for (
1938
+ const candidate of getFlowInvalidationStructure(context, statement, 'statement').candidates
1939
+ ) {
1940
+ if (candidate.kind === 'awaitYield') {
1941
+ if (narrowPath.segments.length > 0) {
1942
+ return candidate.node;
1943
+ }
1944
+ }
1945
+
1946
+ if (candidate.kind === 'assignment') {
1947
+ const leftPath = getInvalidationPath(context, candidate.left, state, 'mutation');
1948
+ if (leftPath && assignmentAffectsNarrow(context, candidate.node, leftPath, narrowPath)) {
1949
+ return candidate.left;
1950
+ }
1951
+
1952
+ if (
1953
+ leftPath &&
1954
+ !isLocalBindingPath(leftPath) &&
1955
+ escapingExpressionAffectsNarrow(context, candidate.right, narrowPath, state)
1956
+ ) {
1957
+ return candidate.left;
1958
+ }
1959
+ }
1960
+
1961
+ if (candidate.kind === 'delete') {
1962
+ const targetPath = getInvalidationPath(context, candidate.expression, state, 'mutation');
1963
+ if (targetPath && mutationAffectsNarrow(targetPath, narrowPath)) {
1964
+ return candidate.expression;
1965
+ }
1966
+ }
1967
+
1968
+ if (candidate.kind === 'update') {
1969
+ const operandPath = getInvalidationPath(context, candidate.operand, state, 'mutation');
1970
+ if (
1971
+ operandPath &&
1972
+ typedUpdateExpressionAffectsNarrow(context, candidate.node, operandPath, narrowPath)
1973
+ ) {
1974
+ return candidate.operand;
1975
+ }
1976
+ }
1977
+
1978
+ if (candidate.kind === 'call') {
1979
+ const calledMember = getCalledMember(context, candidate.node.expression);
1980
+ const receiverBinding = calledMember
1981
+ ? getStateConstructedReceiverBinding(
1982
+ context,
1983
+ calledMember.receiver,
1984
+ state,
1985
+ 'mutation',
1986
+ )
1987
+ : undefined;
1988
+ if (
1989
+ calledMember &&
1990
+ arrayMutationCallAffectsNarrow(
1991
+ context,
1992
+ calledMember.receiver,
1993
+ receiverBinding?.path,
1994
+ calledMember.member,
1995
+ calledMember.memberType,
1996
+ narrowPath,
1997
+ )
1998
+ ) {
1999
+ return candidate.node;
2000
+ }
2001
+
2002
+ if (
2003
+ calledMember &&
2004
+ arrayCallbackExpressionAffectsNarrow(
2005
+ context,
2006
+ calledMember.receiver,
2007
+ calledMember.member,
2008
+ candidate.node,
2009
+ narrowPath,
2010
+ state,
2011
+ )
2012
+ ) {
2013
+ return candidate.node;
2014
+ }
2015
+
2016
+ if (
2017
+ calledMember &&
2018
+ setCallbackExpressionAffectsNarrow(
2019
+ context,
2020
+ calledMember.receiver,
2021
+ calledMember.member,
2022
+ candidate.node,
2023
+ narrowPath,
2024
+ state,
2025
+ )
2026
+ ) {
2027
+ return candidate.node;
2028
+ }
2029
+
2030
+ if (
2031
+ calledMember &&
2032
+ mapCallbackExpressionAffectsNarrow(
2033
+ context,
2034
+ calledMember.receiver,
2035
+ calledMember.member,
2036
+ candidate.node,
2037
+ narrowPath,
2038
+ state,
2039
+ )
2040
+ ) {
2041
+ return candidate.node;
2042
+ }
2043
+
2044
+ if (
2045
+ ts.isElementAccessExpression(candidate.node.expression) ||
2046
+ candidate.node.questionDotToken !== undefined
2047
+ ) {
2048
+ const receiver = ts.isPropertyAccessExpression(candidate.node.expression) ||
2049
+ ts.isElementAccessExpression(candidate.node.expression)
2050
+ ? candidate.node.expression.expression
2051
+ : undefined;
2052
+ if (!receiver) {
2053
+ continue;
2054
+ }
2055
+ const receiverPath = normalizeExpressionPath(context, receiver, state);
2056
+ if (
2057
+ receiverPath &&
2058
+ receiverPath.baseSymbol === narrowPath.baseSymbol &&
2059
+ receiverPath.segments.length === 0 &&
2060
+ narrowPath.segments.length > 0
2061
+ ) {
2062
+ return candidate.node;
2063
+ }
2064
+ }
2065
+
2066
+ const calleeDeclaration = getFunctionLikeFromCallExpression(context, candidate.node);
2067
+ if (
2068
+ calleeDeclaration &&
2069
+ functionLikeAffectsNarrow(
2070
+ context,
2071
+ calleeDeclaration,
2072
+ candidate.node.arguments,
2073
+ narrowPath,
2074
+ state,
2075
+ true,
2076
+ receiverBinding,
2077
+ )
2078
+ ) {
2079
+ return candidate.node;
2080
+ }
2081
+
2082
+ if (
2083
+ !calleeDeclaration &&
2084
+ candidate.node.arguments.some((argument) => {
2085
+ if (!opaqueArgumentExpressionAffectsNarrow(context, argument, narrowPath, state)) {
2086
+ return false;
2087
+ }
2088
+
2089
+ if (!ts.isReturnStatement(statement)) {
2090
+ return true;
2091
+ }
2092
+
2093
+ return !isExtractedReadOnlyReturnArgument(context, argument, state);
2094
+ })
2095
+ ) {
2096
+ return candidate.node;
2097
+ }
2098
+ }
2099
+
2100
+ if (candidate.kind === 'new') {
2101
+ const constructorDeclaration = context.checker.getResolvedSignature(candidate.node)
2102
+ ?.declaration;
2103
+ if (
2104
+ constructorDeclaration &&
2105
+ isFunctionLikeWithBody(constructorDeclaration) &&
2106
+ functionLikeAffectsNarrow(
2107
+ context,
2108
+ constructorDeclaration,
2109
+ candidate.node.arguments ?? [],
2110
+ narrowPath,
2111
+ state,
2112
+ true,
2113
+ )
2114
+ ) {
2115
+ return candidate.node;
2116
+ }
2117
+ }
2118
+ }
2119
+
2120
+ return undefined;
2121
+ }
2122
+
2123
+ export function prepareChildRegionState(
2124
+ context: AnalysisContext,
2125
+ statement: ts.Statement,
2126
+ state: AnalysisState,
2127
+ ): AnalysisState {
2128
+ if (ts.isForStatement(statement) && statement.initializer) {
2129
+ const preparedState = cloneState(state);
2130
+ if (ts.isVariableDeclarationList(statement.initializer)) {
2131
+ for (const declaration of statement.initializer.declarations) {
2132
+ recordVariableAliases(context, declaration, preparedState);
2133
+ }
2134
+ return preparedState;
2135
+ }
2136
+
2137
+ recordExecutedExpressionAliases(context, statement.initializer, preparedState);
2138
+ return preparedState;
2139
+ }
2140
+
2141
+ if (
2142
+ ts.isForOfStatement(statement) &&
2143
+ ts.isVariableDeclarationList(statement.initializer)
2144
+ ) {
2145
+ const preparedState = cloneState(state);
2146
+ for (const declaration of statement.initializer.declarations) {
2147
+ if (!recordForOfLoopHeaderAliases(context, declaration.name, statement.expression, preparedState)) {
2148
+ recordVariableAliases(context, declaration, preparedState);
2149
+ }
2150
+ }
2151
+ return preparedState;
2152
+ }
2153
+
2154
+ return state;
2155
+ }