@soundscript/soundscript 0.1.13 → 0.1.15

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