@soundscript/soundscript 0.1.12 → 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.
- package/package.json +15 -6
- package/project-transform/index.js +2 -0
- package/project-transform/index.ts +8 -0
- package/project-transform/src/annotation_syntax.js +948 -0
- package/project-transform/src/annotation_syntax.ts +1217 -0
- package/project-transform/src/build_package.js +475 -0
- package/project-transform/src/build_package.ts +683 -0
- package/project-transform/src/bundled/portable-web-globals.d.ts +153 -0
- package/project-transform/src/bundled/runtime_externs.js +220 -0
- package/project-transform/src/bundled/runtime_externs.ts +237 -0
- package/project-transform/src/bundled/sound-libs/lib.decorators.d.ts +385 -0
- package/project-transform/src/bundled/sound-libs/lib.decorators.legacy.d.ts +22 -0
- package/project-transform/src/bundled/sound-libs/lib.dom.asynciterable.d.ts +42 -0
- package/project-transform/src/bundled/sound-libs/lib.dom.d.ts +39440 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.collection.d.ts +149 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.core.d.ts +657 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.d.ts +28 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.generator.d.ts +77 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.iterable.d.ts +616 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.promise.d.ts +80 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.proxy.d.ts +128 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.reflect.d.ts +144 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.d.ts +46 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.wellknown.d.ts +170 -0
- package/project-transform/src/bundled/sound-libs/lib.es2016.array.include.d.ts +116 -0
- package/project-transform/src/bundled/sound-libs/lib.es2016.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.arraybuffer.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.date.d.ts +31 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.object.d.ts +49 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.string.d.ts +45 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.typedarrays.d.ts +53 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.asyncgenerator.d.ts +77 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.asynciterable.d.ts +57 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.promise.d.ts +30 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.regexp.d.ts +37 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.array.d.ts +79 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.object.d.ts +47 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.string.d.ts +37 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.symbol.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.bigint.d.ts +765 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.d.ts +27 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.date.d.ts +42 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.number.d.ts +28 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.promise.d.ts +49 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.string.d.ts +44 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.d.ts +23 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.promise.d.ts +48 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.string.d.ts +33 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.weakref.d.ts +78 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.array.d.ts +121 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.error.d.ts +75 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.object.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.regexp.d.ts +39 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.string.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.array.d.ts +924 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.collection.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.d.ts +22 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.arraybuffer.d.ts +65 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.collection.d.ts +29 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.object.d.ts +33 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.promise.d.ts +35 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.regexp.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.string.d.ts +29 -0
- package/project-transform/src/bundled/sound-libs/lib.es5.d.ts +4924 -0
- package/project-transform/src/bundled/sound_stdlib.js +142 -0
- package/project-transform/src/bundled/sound_stdlib.ts +180 -0
- package/project-transform/src/checker/analyze_project.js +1361 -0
- package/project-transform/src/checker/analyze_project.ts +2246 -0
- package/project-transform/src/checker/diagnostics.js +112 -0
- package/project-transform/src/checker/diagnostics.ts +222 -0
- package/project-transform/src/checker/engine/context.js +235 -0
- package/project-transform/src/checker/engine/context.ts +340 -0
- package/project-transform/src/checker/engine/diagnostic_codes.js +72 -0
- package/project-transform/src/checker/engine/diagnostic_codes.ts +95 -0
- package/project-transform/src/checker/engine/facts.js +35 -0
- package/project-transform/src/checker/engine/facts.ts +48 -0
- package/project-transform/src/checker/engine/types.js +1 -0
- package/project-transform/src/checker/engine/types.ts +485 -0
- package/project-transform/src/checker/proof_escape_hatch_diagnostics.js +104 -0
- package/project-transform/src/checker/proof_escape_hatch_diagnostics.ts +173 -0
- package/project-transform/src/checker/rules/async_surface.js +231 -0
- package/project-transform/src/checker/rules/async_surface.ts +335 -0
- package/project-transform/src/checker/rules/class_lifecycle.js +798 -0
- package/project-transform/src/checker/rules/class_lifecycle.ts +1276 -0
- package/project-transform/src/checker/rules/directive_validation.js +571 -0
- package/project-transform/src/checker/rules/directive_validation.ts +938 -0
- package/project-transform/src/checker/rules/directives.js +23 -0
- package/project-transform/src/checker/rules/directives.ts +25 -0
- package/project-transform/src/checker/rules/flow.js +202 -0
- package/project-transform/src/checker/rules/flow.ts +333 -0
- package/project-transform/src/checker/rules/flow_facts.js +601 -0
- package/project-transform/src/checker/rules/flow_facts.ts +978 -0
- package/project-transform/src/checker/rules/flow_invalidation.js +1119 -0
- package/project-transform/src/checker/rules/flow_invalidation.ts +2150 -0
- package/project-transform/src/checker/rules/flow_shared.js +2822 -0
- package/project-transform/src/checker/rules/flow_shared.ts +4383 -0
- package/project-transform/src/checker/rules/foreign_boundary.js +120 -0
- package/project-transform/src/checker/rules/foreign_boundary.ts +196 -0
- package/project-transform/src/checker/rules/foreign_projection.js +279 -0
- package/project-transform/src/checker/rules/foreign_projection.ts +425 -0
- package/project-transform/src/checker/rules/generated_helpers.js +13 -0
- package/project-transform/src/checker/rules/generated_helpers.ts +18 -0
- package/project-transform/src/checker/rules/index.js +35 -0
- package/project-transform/src/checker/rules/index.ts +49 -0
- package/project-transform/src/checker/rules/namespace_object.js +845 -0
- package/project-transform/src/checker/rules/namespace_object.ts +1224 -0
- package/project-transform/src/checker/rules/non_ordinary_recovery.js +1328 -0
- package/project-transform/src/checker/rules/non_ordinary_recovery.ts +2391 -0
- package/project-transform/src/checker/rules/null_prototype.js +3 -0
- package/project-transform/src/checker/rules/null_prototype.ts +6 -0
- package/project-transform/src/checker/rules/overloads.js +181 -0
- package/project-transform/src/checker/rules/overloads.ts +317 -0
- package/project-transform/src/checker/rules/predicate_verification.js +691 -0
- package/project-transform/src/checker/rules/predicate_verification.ts +1088 -0
- package/project-transform/src/checker/rules/prototype_hardening.js +237 -0
- package/project-transform/src/checker/rules/prototype_hardening.ts +343 -0
- package/project-transform/src/checker/rules/receiver_discipline.js +263 -0
- package/project-transform/src/checker/rules/receiver_discipline.ts +356 -0
- package/project-transform/src/checker/rules/relations.js +6861 -0
- package/project-transform/src/checker/rules/relations.ts +12158 -0
- package/project-transform/src/checker/rules/resolved_builtins.js +274 -0
- package/project-transform/src/checker/rules/resolved_builtins.ts +438 -0
- package/project-transform/src/checker/rules/trust.js +217 -0
- package/project-transform/src/checker/rules/trust.ts +301 -0
- package/project-transform/src/checker/rules/type_guards.js +173 -0
- package/project-transform/src/checker/rules/type_guards.ts +257 -0
- package/project-transform/src/checker/rules/universal.js +17 -0
- package/project-transform/src/checker/rules/universal.ts +22 -0
- package/project-transform/src/checker/rules/unsafe_value_origin.js +80 -0
- package/project-transform/src/checker/rules/unsafe_value_origin.ts +125 -0
- package/project-transform/src/checker/rules/unsound_imports.js +218 -0
- package/project-transform/src/checker/rules/unsound_imports.ts +301 -0
- package/project-transform/src/checker/rules/unsound_syntax.js +1695 -0
- package/project-transform/src/checker/rules/unsound_syntax.ts +2540 -0
- package/project-transform/src/checker/rules/value_types.js +206 -0
- package/project-transform/src/checker/rules/value_types.ts +407 -0
- package/project-transform/src/checker/timing.js +43 -0
- package/project-transform/src/checker/timing.ts +78 -0
- package/project-transform/src/checker/unsupported_feature_messages.js +337 -0
- package/project-transform/src/checker/unsupported_feature_messages.ts +531 -0
- package/project-transform/src/cli.js +892 -0
- package/project-transform/src/cli.ts +1476 -0
- package/project-transform/src/compiler/compile_project.js +319 -0
- package/project-transform/src/compiler/compile_project.ts +508 -0
- package/project-transform/src/compiler/errors.js +10 -0
- package/project-transform/src/compiler/errors.ts +29 -0
- package/project-transform/src/compiler/ir.js +1 -0
- package/project-transform/src/compiler/ir.ts +1526 -0
- package/project-transform/src/compiler/lower.js +30550 -0
- package/project-transform/src/compiler/lower.ts +43645 -0
- package/project-transform/src/compiler/lower_arrays.js +140 -0
- package/project-transform/src/compiler/lower_arrays.ts +190 -0
- package/project-transform/src/compiler/lower_strings.js +121 -0
- package/project-transform/src/compiler/lower_strings.ts +198 -0
- package/project-transform/src/compiler/lower_tagged.js +329 -0
- package/project-transform/src/compiler/lower_tagged.ts +427 -0
- package/project-transform/src/compiler/lower_views.js +171 -0
- package/project-transform/src/compiler/lower_views.ts +251 -0
- package/project-transform/src/compiler/object_keys.js +25 -0
- package/project-transform/src/compiler/object_keys.ts +35 -0
- package/project-transform/src/compiler/runtime_ir.js +30 -0
- package/project-transform/src/compiler/runtime_ir.ts +727 -0
- package/project-transform/src/compiler/tagged_boundary.js +18 -0
- package/project-transform/src/compiler/tagged_boundary.ts +37 -0
- package/project-transform/src/compiler/toolchain.js +170 -0
- package/project-transform/src/compiler/toolchain.ts +229 -0
- package/project-transform/src/compiler/unicode_case_data.js +2102 -0
- package/project-transform/src/compiler/unicode_case_data.ts +2112 -0
- package/project-transform/src/compiler/wasm_js_host_runtime.js +656 -0
- package/project-transform/src/compiler/wasm_js_host_runtime.ts +762 -0
- package/project-transform/src/compiler/wat_arrays.js +3132 -0
- package/project-transform/src/compiler/wat_arrays.ts +3768 -0
- package/project-transform/src/compiler/wat_emitter.js +17952 -0
- package/project-transform/src/compiler/wat_emitter.ts +22812 -0
- package/project-transform/src/compiler/wat_strings.js +129 -0
- package/project-transform/src/compiler/wat_strings.ts +187 -0
- package/project-transform/src/compiler/wat_tagged.js +548 -0
- package/project-transform/src/compiler/wat_tagged.ts +674 -0
- package/project-transform/src/compiler_generator_runner.js +153 -0
- package/project-transform/src/compiler_generator_runner.ts +171 -0
- package/project-transform/src/compiler_object_test_helpers.js +69 -0
- package/project-transform/src/compiler_object_test_helpers.ts +96 -0
- package/project-transform/src/compiler_promise_runner.js +2116 -0
- package/project-transform/src/compiler_promise_runner.ts +2184 -0
- package/project-transform/src/compiler_test_helpers.js +854 -0
- package/project-transform/src/compiler_test_helpers.ts +1087 -0
- package/project-transform/src/config.js +568 -0
- package/project-transform/src/config.ts +892 -0
- package/project-transform/src/diagnostic_metadata.js +67 -0
- package/project-transform/src/diagnostic_metadata.ts +99 -0
- package/project-transform/src/diagnostic_reference.js +1368 -0
- package/project-transform/src/diagnostic_reference.ts +1523 -0
- package/project-transform/src/editor_diagnostics_worker.js +176 -0
- package/project-transform/src/editor_diagnostics_worker.ts +250 -0
- package/project-transform/src/editor_projection.js +224 -0
- package/project-transform/src/editor_projection.ts +421 -0
- package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.js +47 -0
- package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.ts +72 -0
- package/project-transform/src/frontend/builtin_macro_support.js +842 -0
- package/project-transform/src/frontend/builtin_macro_support.ts +1386 -0
- package/project-transform/src/frontend/builtin_macros.js +409 -0
- package/project-transform/src/frontend/builtin_macros.ts +542 -0
- package/project-transform/src/frontend/component_poc_runtime.js +279 -0
- package/project-transform/src/frontend/component_poc_runtime.ts +372 -0
- package/project-transform/src/frontend/css_macro.js +148 -0
- package/project-transform/src/frontend/css_macro.ts +222 -0
- package/project-transform/src/frontend/derive_macros.js +2072 -0
- package/project-transform/src/frontend/derive_macros.ts +3188 -0
- package/project-transform/src/frontend/embedded_fragment_support.js +106 -0
- package/project-transform/src/frontend/embedded_fragment_support.ts +172 -0
- package/project-transform/src/frontend/error_normalization.js +403 -0
- package/project-transform/src/frontend/error_normalization.ts +832 -0
- package/project-transform/src/frontend/error_stdlib_support.js +1 -0
- package/project-transform/src/frontend/error_stdlib_support.ts +6 -0
- package/project-transform/src/frontend/expand_project.js +169 -0
- package/project-transform/src/frontend/expand_project.ts +248 -0
- package/project-transform/src/frontend/format_soundscript.js +297 -0
- package/project-transform/src/frontend/format_soundscript.ts +582 -0
- package/project-transform/src/frontend/graphql_macro.js +174 -0
- package/project-transform/src/frontend/graphql_macro.ts +253 -0
- package/project-transform/src/frontend/hash_context.js +83 -0
- package/project-transform/src/frontend/hash_context.ts +113 -0
- package/project-transform/src/frontend/hkt_macro.js +448 -0
- package/project-transform/src/frontend/hkt_macro.ts +897 -0
- package/project-transform/src/frontend/import_binding_usage.js +190 -0
- package/project-transform/src/frontend/import_binding_usage.ts +277 -0
- package/project-transform/src/frontend/macro_advanced_backend_adapter.js +58 -0
- package/project-transform/src/frontend/macro_advanced_backend_adapter.ts +123 -0
- package/project-transform/src/frontend/macro_advanced_context.js +826 -0
- package/project-transform/src/frontend/macro_advanced_context.ts +1102 -0
- package/project-transform/src/frontend/macro_advanced_output.js +21 -0
- package/project-transform/src/frontend/macro_advanced_output.ts +41 -0
- package/project-transform/src/frontend/macro_api.js +353 -0
- package/project-transform/src/frontend/macro_api.ts +1722 -0
- package/project-transform/src/frontend/macro_api_internal.js +35 -0
- package/project-transform/src/frontend/macro_api_internal.ts +80 -0
- package/project-transform/src/frontend/macro_api_module_support.js +39 -0
- package/project-transform/src/frontend/macro_api_module_support.ts +65 -0
- package/project-transform/src/frontend/macro_backend_adapter.js +272 -0
- package/project-transform/src/frontend/macro_backend_adapter.ts +420 -0
- package/project-transform/src/frontend/macro_context.js +816 -0
- package/project-transform/src/frontend/macro_context.ts +1105 -0
- package/project-transform/src/frontend/macro_debug.js +99 -0
- package/project-transform/src/frontend/macro_debug.ts +157 -0
- package/project-transform/src/frontend/macro_definition_support.js +28 -0
- package/project-transform/src/frontend/macro_definition_support.ts +73 -0
- package/project-transform/src/frontend/macro_errors.js +40 -0
- package/project-transform/src/frontend/macro_errors.ts +70 -0
- package/project-transform/src/frontend/macro_expander.js +919 -0
- package/project-transform/src/frontend/macro_expander.ts +1611 -0
- package/project-transform/src/frontend/macro_factory_support.js +176 -0
- package/project-transform/src/frontend/macro_factory_support.ts +263 -0
- package/project-transform/src/frontend/macro_host_ast_internal.js +64 -0
- package/project-transform/src/frontend/macro_host_ast_internal.ts +109 -0
- package/project-transform/src/frontend/macro_index.js +27 -0
- package/project-transform/src/frontend/macro_index.ts +50 -0
- package/project-transform/src/frontend/macro_loader.js +281 -0
- package/project-transform/src/frontend/macro_loader.ts +506 -0
- package/project-transform/src/frontend/macro_operand_semantics.js +838 -0
- package/project-transform/src/frontend/macro_operand_semantics.ts +1489 -0
- package/project-transform/src/frontend/macro_output.js +54 -0
- package/project-transform/src/frontend/macro_output.ts +123 -0
- package/project-transform/src/frontend/macro_parser.js +611 -0
- package/project-transform/src/frontend/macro_parser.ts +832 -0
- package/project-transform/src/frontend/macro_resolver.js +69 -0
- package/project-transform/src/frontend/macro_resolver.ts +125 -0
- package/project-transform/src/frontend/macro_rewrite.js +285 -0
- package/project-transform/src/frontend/macro_rewrite.ts +442 -0
- package/project-transform/src/frontend/macro_runtime_support.js +232 -0
- package/project-transform/src/frontend/macro_runtime_support.ts +324 -0
- package/project-transform/src/frontend/macro_scanner.js +393 -0
- package/project-transform/src/frontend/macro_scanner.ts +455 -0
- package/project-transform/src/frontend/macro_semantic_backend_adapter.js +87 -0
- package/project-transform/src/frontend/macro_semantic_backend_adapter.ts +166 -0
- package/project-transform/src/frontend/macro_semantic_context.js +5 -0
- package/project-transform/src/frontend/macro_semantic_context.ts +12 -0
- package/project-transform/src/frontend/macro_semantic_output.js +24 -0
- package/project-transform/src/frontend/macro_semantic_output.ts +47 -0
- package/project-transform/src/frontend/macro_semantic_types.js +1 -0
- package/project-transform/src/frontend/macro_semantic_types.ts +98 -0
- package/project-transform/src/frontend/macro_semantics.js +1172 -0
- package/project-transform/src/frontend/macro_semantics.ts +1502 -0
- package/project-transform/src/frontend/macro_site_kind_support.js +164 -0
- package/project-transform/src/frontend/macro_site_kind_support.ts +255 -0
- package/project-transform/src/frontend/macro_syntax_internal.js +1950 -0
- package/project-transform/src/frontend/macro_syntax_internal.ts +3338 -0
- package/project-transform/src/frontend/macro_templates.js +57 -0
- package/project-transform/src/frontend/macro_templates.ts +143 -0
- package/project-transform/src/frontend/macro_test_helpers.js +82 -0
- package/project-transform/src/frontend/macro_test_helpers.ts +136 -0
- package/project-transform/src/frontend/macro_types.js +1 -0
- package/project-transform/src/frontend/macro_types.ts +103 -0
- package/project-transform/src/frontend/macro_vm.js +39 -0
- package/project-transform/src/frontend/macro_vm.ts +113 -0
- package/project-transform/src/frontend/match_macro.js +885 -0
- package/project-transform/src/frontend/match_macro.ts +1220 -0
- package/project-transform/src/frontend/numeric_normalization.js +824 -0
- package/project-transform/src/frontend/numeric_normalization.ts +1380 -0
- package/project-transform/src/frontend/numeric_prelude.js +278 -0
- package/project-transform/src/frontend/numeric_prelude.ts +370 -0
- package/project-transform/src/frontend/project_frontend.js +2396 -0
- package/project-transform/src/frontend/project_frontend.ts +3776 -0
- package/project-transform/src/frontend/project_macro_support.js +1401 -0
- package/project-transform/src/frontend/project_macro_support.ts +2137 -0
- package/project-transform/src/frontend/sql_macro.js +175 -0
- package/project-transform/src/frontend/sql_macro.ts +254 -0
- package/project-transform/src/frontend/sql_stdlib_support.js +1 -0
- package/project-transform/src/frontend/sql_stdlib_support.ts +6 -0
- package/project-transform/src/frontend/std_package_support.js +228 -0
- package/project-transform/src/frontend/std_package_support.ts +400 -0
- package/project-transform/src/frontend/value_normalization.js +306 -0
- package/project-transform/src/frontend/value_normalization.ts +599 -0
- package/project-transform/src/lsp/project_service.js +4771 -0
- package/project-transform/src/lsp/project_service.ts +7580 -0
- package/project-transform/src/lsp/protocol.js +9 -0
- package/project-transform/src/lsp/protocol.ts +38 -0
- package/project-transform/src/lsp/server.js +355 -0
- package/project-transform/src/lsp/server.ts +671 -0
- package/project-transform/src/lsp/session.js +49 -0
- package/project-transform/src/lsp/session.ts +48 -0
- package/project-transform/src/lsp/timing.js +43 -0
- package/project-transform/src/lsp/timing.ts +76 -0
- package/project-transform/src/lsp/transport.js +205 -0
- package/project-transform/src/lsp/transport.ts +253 -0
- package/project-transform/src/lsp_main.js +5 -0
- package/project-transform/src/lsp_main.ts +7 -0
- package/project-transform/src/macros.d.ts +1 -0
- package/project-transform/src/macros.js +1 -0
- package/project-transform/src/macros.ts +1 -0
- package/project-transform/src/main.js +24 -0
- package/project-transform/src/main.ts +28 -0
- package/project-transform/src/platform/host.js +264 -0
- package/project-transform/src/platform/host.ts +343 -0
- package/project-transform/src/platform/path.js +8 -0
- package/project-transform/src/platform/path.ts +20 -0
- package/project-transform/src/public_macro_api/macro_api.d.ts +1054 -0
- package/project-transform/src/public_macro_api/macro_semantic_types.d.ts +66 -0
- package/project-transform/src/public_macro_api/macro_types.d.ts +70 -0
- package/project-transform/src/run_program.js +14 -0
- package/project-transform/src/run_program.ts +33 -0
- package/project-transform/src/runtime/materialize.js +371 -0
- package/project-transform/src/runtime/materialize.ts +502 -0
- package/project-transform/src/runtime/on_demand.js +203 -0
- package/project-transform/src/runtime/on_demand.ts +305 -0
- package/project-transform/src/runtime/source_maps.js +205 -0
- package/project-transform/src/runtime/source_maps.ts +297 -0
- package/project-transform/src/runtime/transform.js +148 -0
- package/project-transform/src/runtime/transform.ts +295 -0
- package/project-transform/src/service/types.js +1 -0
- package/project-transform/src/service/types.ts +22 -0
- package/project-transform/src/soundscript_packages.js +477 -0
- package/project-transform/src/soundscript_packages.ts +754 -0
- package/project-transform/src/soundscript_runtime_specifiers.js +88 -0
- package/project-transform/src/soundscript_runtime_specifiers.ts +96 -0
- package/project-transform/src/stdlib/async.d.ts +81 -0
- package/project-transform/src/stdlib/async.js +213 -0
- package/project-transform/src/stdlib/async.ts +315 -0
- package/project-transform/src/stdlib/codec.d.ts +32 -0
- package/project-transform/src/stdlib/codec.js +30 -0
- package/project-transform/src/stdlib/codec.ts +76 -0
- package/project-transform/src/stdlib/compare.d.ts +28 -0
- package/project-transform/src/stdlib/compare.js +115 -0
- package/project-transform/src/stdlib/compare.ts +151 -0
- package/project-transform/src/stdlib/css.d.ts +16 -0
- package/project-transform/src/stdlib/css.js +9 -0
- package/project-transform/src/stdlib/css.ts +28 -0
- package/project-transform/src/stdlib/debug.d.ts +2 -0
- package/project-transform/src/stdlib/debug.js +9 -0
- package/project-transform/src/stdlib/debug.ts +10 -0
- package/project-transform/src/stdlib/decode.d.ts +86 -0
- package/project-transform/src/stdlib/decode.js +254 -0
- package/project-transform/src/stdlib/decode.ts +390 -0
- package/project-transform/src/stdlib/derive.d.ts +6 -0
- package/project-transform/src/stdlib/derive.js +7 -0
- package/project-transform/src/stdlib/derive.ts +7 -0
- package/project-transform/src/stdlib/encode.d.ts +100 -0
- package/project-transform/src/stdlib/encode.js +130 -0
- package/project-transform/src/stdlib/encode.ts +259 -0
- package/project-transform/src/stdlib/failures.d.ts +23 -0
- package/project-transform/src/stdlib/failures.js +41 -0
- package/project-transform/src/stdlib/failures.ts +64 -0
- package/project-transform/src/stdlib/fetch.d.ts +67 -0
- package/project-transform/src/stdlib/fetch.js +5 -0
- package/project-transform/src/stdlib/fetch.ts +11 -0
- package/project-transform/src/stdlib/graphql.d.ts +16 -0
- package/project-transform/src/stdlib/graphql.js +9 -0
- package/project-transform/src/stdlib/graphql.ts +28 -0
- package/project-transform/src/stdlib/hash.d.ts +34 -0
- package/project-transform/src/stdlib/hash.js +110 -0
- package/project-transform/src/stdlib/hash.ts +188 -0
- package/project-transform/src/stdlib/hkt.d.ts +40 -0
- package/project-transform/src/stdlib/hkt.js +3 -0
- package/project-transform/src/stdlib/hkt.ts +41 -0
- package/project-transform/src/stdlib/index.d.ts +9 -0
- package/project-transform/src/stdlib/index.js +15 -0
- package/project-transform/src/stdlib/index.ts +23 -0
- package/project-transform/src/stdlib/json.d.ts +125 -0
- package/project-transform/src/stdlib/json.js +764 -0
- package/project-transform/src/stdlib/json.ts +1034 -0
- package/project-transform/src/stdlib/match.d.ts +11 -0
- package/project-transform/src/stdlib/match.js +13 -0
- package/project-transform/src/stdlib/match.ts +26 -0
- package/project-transform/src/stdlib/numerics.d.ts +523 -0
- package/project-transform/src/stdlib/numerics.js +1356 -0
- package/project-transform/src/stdlib/numerics.ts +1937 -0
- package/project-transform/src/stdlib/random.d.ts +19 -0
- package/project-transform/src/stdlib/random.js +3 -0
- package/project-transform/src/stdlib/random.ts +5 -0
- package/project-transform/src/stdlib/result.d.ts +68 -0
- package/project-transform/src/stdlib/result.js +139 -0
- package/project-transform/src/stdlib/result.ts +248 -0
- package/project-transform/src/stdlib/sql.d.ts +22 -0
- package/project-transform/src/stdlib/sql.js +23 -0
- package/project-transform/src/stdlib/sql.ts +53 -0
- package/project-transform/src/stdlib/text.d.ts +24 -0
- package/project-transform/src/stdlib/text.js +3 -0
- package/project-transform/src/stdlib/text.ts +4 -0
- package/project-transform/src/stdlib/thunk.d.ts +2 -0
- package/project-transform/src/stdlib/thunk.js +9 -0
- package/project-transform/src/stdlib/thunk.ts +15 -0
- package/project-transform/src/stdlib/typeclasses.d.ts +57 -0
- package/project-transform/src/stdlib/typeclasses.js +78 -0
- package/project-transform/src/stdlib/typeclasses.ts +173 -0
- package/project-transform/src/stdlib/url.d.ts +37 -0
- package/project-transform/src/stdlib/url.js +3 -0
- package/project-transform/src/stdlib/url.ts +4 -0
- package/project-transform/src/stdlib/value.d.ts +9 -0
- package/project-transform/src/stdlib/value.js +104 -0
- package/project-transform/src/stdlib/value.ts +133 -0
- package/project-transform/src/test_installed_stdlib.js +147 -0
- package/project-transform/src/test_installed_stdlib.ts +245 -0
- package/project-transform/src/test_macro_package_fixture.js +50 -0
- package/project-transform/src/test_macro_package_fixture.ts +68 -0
- package/project-transform/src/value_deep_safe.js +191 -0
- package/project-transform/src/value_deep_safe.ts +273 -0
|
@@ -0,0 +1,2822 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
const ARRAY_MUTATION_METHODS = new Set([
|
|
3
|
+
'copyWithin',
|
|
4
|
+
'fill',
|
|
5
|
+
'pop',
|
|
6
|
+
'push',
|
|
7
|
+
'reverse',
|
|
8
|
+
'shift',
|
|
9
|
+
'sort',
|
|
10
|
+
'splice',
|
|
11
|
+
'unshift',
|
|
12
|
+
]);
|
|
13
|
+
export const MUTATING_ASSIGNMENT_OPERATORS = new Set([
|
|
14
|
+
ts.SyntaxKind.EqualsToken,
|
|
15
|
+
ts.SyntaxKind.PlusEqualsToken,
|
|
16
|
+
ts.SyntaxKind.MinusEqualsToken,
|
|
17
|
+
ts.SyntaxKind.AsteriskAsteriskEqualsToken,
|
|
18
|
+
ts.SyntaxKind.AsteriskEqualsToken,
|
|
19
|
+
ts.SyntaxKind.SlashEqualsToken,
|
|
20
|
+
ts.SyntaxKind.PercentEqualsToken,
|
|
21
|
+
ts.SyntaxKind.LessThanLessThanEqualsToken,
|
|
22
|
+
ts.SyntaxKind.GreaterThanGreaterThanEqualsToken,
|
|
23
|
+
ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
|
|
24
|
+
ts.SyntaxKind.AmpersandEqualsToken,
|
|
25
|
+
ts.SyntaxKind.BarEqualsToken,
|
|
26
|
+
ts.SyntaxKind.CaretEqualsToken,
|
|
27
|
+
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
|
|
28
|
+
ts.SyntaxKind.BarBarEqualsToken,
|
|
29
|
+
ts.SyntaxKind.QuestionQuestionEqualsToken,
|
|
30
|
+
]);
|
|
31
|
+
export function cloneState(state) {
|
|
32
|
+
return {
|
|
33
|
+
aliases: new Map(state.aliases),
|
|
34
|
+
arrayRestAliases: new Map(state.arrayRestAliases),
|
|
35
|
+
boundValues: new Map(state.boundValues),
|
|
36
|
+
extractedBindings: new Map(state.extractedBindings),
|
|
37
|
+
objectRestAliases: new Map(state.objectRestAliases),
|
|
38
|
+
spreadAliases: new Map(state.spreadAliases),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function getSymbolId(context, symbol) {
|
|
42
|
+
return context.getSymbolId(symbol);
|
|
43
|
+
}
|
|
44
|
+
export function getExpressionSymbol(context, expression) {
|
|
45
|
+
const symbol = context.checker.getSymbolAtLocation(expression);
|
|
46
|
+
if (!symbol) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if ((symbol.flags & ts.SymbolFlags.Alias) !== 0) {
|
|
50
|
+
return context.checker.getAliasedSymbol(symbol);
|
|
51
|
+
}
|
|
52
|
+
return symbol;
|
|
53
|
+
}
|
|
54
|
+
function isThisExpression(expression) {
|
|
55
|
+
return expression.kind === ts.SyntaxKind.ThisKeyword;
|
|
56
|
+
}
|
|
57
|
+
function getMemberNameText(name) {
|
|
58
|
+
return name.text;
|
|
59
|
+
}
|
|
60
|
+
function isConstValueDeclaration(symbol) {
|
|
61
|
+
const declaration = symbol.valueDeclaration;
|
|
62
|
+
if (!declaration) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (ts.isVariableDeclaration(declaration) &&
|
|
66
|
+
declaration.parent !== undefined &&
|
|
67
|
+
ts.isVariableDeclarationList(declaration.parent)) {
|
|
68
|
+
return (declaration.parent.flags & ts.NodeFlags.Const) !== 0;
|
|
69
|
+
}
|
|
70
|
+
if (ts.isBindingElement(declaration) &&
|
|
71
|
+
declaration.parent.parent !== undefined &&
|
|
72
|
+
ts.isVariableDeclaration(declaration.parent.parent) &&
|
|
73
|
+
declaration.parent.parent.parent !== undefined &&
|
|
74
|
+
ts.isVariableDeclarationList(declaration.parent.parent.parent)) {
|
|
75
|
+
return (declaration.parent.parent.parent.flags & ts.NodeFlags.Const) !== 0;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
function getStateBoundValue(context, expression, state) {
|
|
80
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
81
|
+
if (!ts.isIdentifier(expression) && !isThisExpression(expression)) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
85
|
+
return symbol ? state.boundValues.get(getSymbolId(context, symbol)) : undefined;
|
|
86
|
+
}
|
|
87
|
+
function getEquivalentExpressionBranches(expression) {
|
|
88
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
89
|
+
if (ts.isConditionalExpression(expression)) {
|
|
90
|
+
return [expression.whenTrue, expression.whenFalse];
|
|
91
|
+
}
|
|
92
|
+
if (ts.isBinaryExpression(expression) &&
|
|
93
|
+
expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
94
|
+
return [expression.left, expression.right];
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
function getEquivalentRecoveredPath(expression, getPath) {
|
|
99
|
+
const branches = getEquivalentExpressionBranches(expression);
|
|
100
|
+
if (!branches) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const [left, right] = branches;
|
|
104
|
+
const leftPath = getPath(left);
|
|
105
|
+
const rightPath = getPath(right);
|
|
106
|
+
return leftPath && rightPath && pathsMatch(leftPath, rightPath) ? leftPath : undefined;
|
|
107
|
+
}
|
|
108
|
+
function getObjectLiteralComparableEntries(context, objectLiteral) {
|
|
109
|
+
const entries = new Map();
|
|
110
|
+
for (const property of objectLiteral.properties) {
|
|
111
|
+
if (ts.isSpreadAssignment(property)) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const key = getPropertyNameKey(context, property.name);
|
|
115
|
+
if (!key) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
if (ts.isPropertyAssignment(property)) {
|
|
119
|
+
entries.set(key, property.initializer);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
123
|
+
entries.set(key, property.name);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (ts.isMethodDeclaration(property)) {
|
|
127
|
+
entries.set(key, property);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return entries;
|
|
133
|
+
}
|
|
134
|
+
function recoveredValuesMatchWith(context, left, right, getPath, getValue) {
|
|
135
|
+
if (left === right) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
if (!ts.isExpression(left) || !ts.isExpression(right)) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const leftPath = getPath(left);
|
|
142
|
+
const rightPath = getPath(right);
|
|
143
|
+
if (leftPath && rightPath && pathsMatch(leftPath, rightPath)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const leftExpression = unwrapFlowTransparentExpression(left);
|
|
147
|
+
const rightExpression = unwrapFlowTransparentExpression(right);
|
|
148
|
+
if (ts.isObjectLiteralExpression(leftExpression) &&
|
|
149
|
+
ts.isObjectLiteralExpression(rightExpression)) {
|
|
150
|
+
const leftEntries = getObjectLiteralComparableEntries(context, leftExpression);
|
|
151
|
+
const rightEntries = getObjectLiteralComparableEntries(context, rightExpression);
|
|
152
|
+
if (!leftEntries || !rightEntries || leftEntries.size !== rightEntries.size) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
for (const [key, leftValue] of leftEntries) {
|
|
156
|
+
const rightValue = rightEntries.get(key);
|
|
157
|
+
if (!rightValue || !recoveredValuesMatchWith(context, leftValue, rightValue, getPath, getValue)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (ts.isArrayLiteralExpression(leftExpression) &&
|
|
164
|
+
ts.isArrayLiteralExpression(rightExpression)) {
|
|
165
|
+
if (leftExpression.elements.length !== rightExpression.elements.length) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
for (let index = 0; index < leftExpression.elements.length; index++) {
|
|
169
|
+
const leftElement = leftExpression.elements[index];
|
|
170
|
+
const rightElement = rightExpression.elements[index];
|
|
171
|
+
if (!leftElement || !rightElement) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (ts.isOmittedExpression(leftElement) || ts.isOmittedExpression(rightElement)) {
|
|
175
|
+
if (!ts.isOmittedExpression(leftElement) || !ts.isOmittedExpression(rightElement)) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (!recoveredValuesMatchWith(context, leftElement, rightElement, getPath, getValue)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
function getEquivalentRecoveredValue(context, expression, getPath, getValue) {
|
|
189
|
+
const branches = getEquivalentExpressionBranches(expression);
|
|
190
|
+
if (!branches) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
const [left, right] = branches;
|
|
194
|
+
const leftValue = getValue(left) ?? left;
|
|
195
|
+
const rightValue = getValue(right) ?? right;
|
|
196
|
+
return recoveredValuesMatchWith(context, leftValue, rightValue, getPath, getValue)
|
|
197
|
+
? leftValue
|
|
198
|
+
: undefined;
|
|
199
|
+
}
|
|
200
|
+
function getRecoveredExpressionMemberPath(expression, key, getValue, getMemberFromCall, getPathForValueExpression) {
|
|
201
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
202
|
+
if (ts.isCallExpression(expression)) {
|
|
203
|
+
return getMemberFromCall(expression, key);
|
|
204
|
+
}
|
|
205
|
+
const branches = getEquivalentExpressionBranches(expression);
|
|
206
|
+
if (branches) {
|
|
207
|
+
const [left, right] = branches;
|
|
208
|
+
const leftPath = getRecoveredExpressionMemberPath(left, key, getValue, getMemberFromCall, getPathForValueExpression);
|
|
209
|
+
const rightPath = getRecoveredExpressionMemberPath(right, key, getValue, getMemberFromCall, getPathForValueExpression);
|
|
210
|
+
return leftPath && rightPath && pathsMatch(leftPath, rightPath) ? leftPath : undefined;
|
|
211
|
+
}
|
|
212
|
+
const value = getValue(expression);
|
|
213
|
+
if (!value || !ts.isExpression(value)) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
if (ts.isCallExpression(value)) {
|
|
217
|
+
return getMemberFromCall(value, key);
|
|
218
|
+
}
|
|
219
|
+
const memberValue = getLiteralMemberValue(value, key);
|
|
220
|
+
return memberValue && ts.isExpression(memberValue)
|
|
221
|
+
? getPathForValueExpression(memberValue)
|
|
222
|
+
: undefined;
|
|
223
|
+
}
|
|
224
|
+
function getEquivalentExpressionPath(context, expression, state) {
|
|
225
|
+
return getEquivalentRecoveredPath(expression, (branch) => normalizeExpressionPath(context, branch, state));
|
|
226
|
+
}
|
|
227
|
+
function getEquivalentExpressionValue(context, expression, state) {
|
|
228
|
+
return getEquivalentRecoveredValue(context, expression, (branch) => normalizeExpressionPath(context, branch, state), (branch) => getExpressionLiteralValue(context, branch, state));
|
|
229
|
+
}
|
|
230
|
+
function getExpressionLiteralValue(context, expression, state) {
|
|
231
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
232
|
+
if (ts.isObjectLiteralExpression(expression) || ts.isArrayLiteralExpression(expression)) {
|
|
233
|
+
return expression;
|
|
234
|
+
}
|
|
235
|
+
const equivalentValue = getEquivalentExpressionValue(context, expression, state);
|
|
236
|
+
if (equivalentValue) {
|
|
237
|
+
return equivalentValue;
|
|
238
|
+
}
|
|
239
|
+
const boundValue = getStateBoundValue(context, expression, state);
|
|
240
|
+
if (boundValue) {
|
|
241
|
+
return boundValue;
|
|
242
|
+
}
|
|
243
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
244
|
+
const receiverValue = getExpressionLiteralValue(context, expression.expression, state);
|
|
245
|
+
return receiverValue
|
|
246
|
+
? getLiteralMemberValue(receiverValue, getMemberNameText(expression.name))
|
|
247
|
+
: undefined;
|
|
248
|
+
}
|
|
249
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
250
|
+
const key = getElementAccessKey(context, expression.argumentExpression);
|
|
251
|
+
if (!key) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
const receiverValue = getExpressionLiteralValue(context, expression.expression, state);
|
|
255
|
+
return receiverValue
|
|
256
|
+
? getLiteralMemberValue(receiverValue, key)
|
|
257
|
+
: undefined;
|
|
258
|
+
}
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
export function getUniformArrayElementBindingFromExpression(context, expression, state) {
|
|
262
|
+
const expressionValue = getExpressionLiteralValue(context, expression, state) ?? expression;
|
|
263
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
264
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
265
|
+
: expressionValue;
|
|
266
|
+
if (!ts.isArrayLiteralExpression(unwrappedExpression)) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
let representativePath;
|
|
270
|
+
let representativeValue;
|
|
271
|
+
let sawElement = false;
|
|
272
|
+
for (const element of unwrappedExpression.elements) {
|
|
273
|
+
if (ts.isSpreadElement(element) || ts.isOmittedExpression(element)) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
const elementPath = normalizeExpressionPath(context, element, state);
|
|
277
|
+
const elementValue = getExpressionLiteralValue(context, element, state) ?? element;
|
|
278
|
+
if (!sawElement) {
|
|
279
|
+
representativePath = elementPath;
|
|
280
|
+
representativeValue = elementValue;
|
|
281
|
+
sawElement = true;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const samePath = representativePath && elementPath && pathsMatch(representativePath, elementPath);
|
|
285
|
+
const bothNoPath = representativePath === undefined && elementPath === undefined;
|
|
286
|
+
if (!samePath && !bothNoPath) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
if (representativeValue !== undefined &&
|
|
290
|
+
elementValue !== undefined &&
|
|
291
|
+
!recoveredValuesMatchWith(context, representativeValue, elementValue, (candidate) => normalizeExpressionPath(context, candidate, state), (candidate) => getStateBoundValue(context, candidate, state))) {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return sawElement ? { path: representativePath, value: representativeValue } : undefined;
|
|
296
|
+
}
|
|
297
|
+
function isBuiltinSetConstruction(context, expression) {
|
|
298
|
+
const signature = context.checker.getResolvedSignature(expression);
|
|
299
|
+
const declaration = signature?.declaration;
|
|
300
|
+
if (!declaration?.getSourceFile().isDeclarationFile) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
const constructedType = context.checker.getTypeAtLocation(expression);
|
|
304
|
+
const symbol = constructedType.aliasSymbol ?? constructedType.getSymbol();
|
|
305
|
+
return symbol?.getName() === 'Set';
|
|
306
|
+
}
|
|
307
|
+
function isBuiltinMapConstruction(context, expression) {
|
|
308
|
+
const signature = context.checker.getResolvedSignature(expression);
|
|
309
|
+
const declaration = signature?.declaration;
|
|
310
|
+
if (!declaration?.getSourceFile().isDeclarationFile) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const constructedType = context.checker.getTypeAtLocation(expression);
|
|
314
|
+
const symbol = constructedType.aliasSymbol ?? constructedType.getSymbol();
|
|
315
|
+
return symbol?.getName() === 'Map';
|
|
316
|
+
}
|
|
317
|
+
function getArrayLiteralEntryComponent(value, index) {
|
|
318
|
+
const literal = getLiteralArrayValue(value);
|
|
319
|
+
if (!literal) {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
const element = literal.elements[index];
|
|
323
|
+
if (!element || ts.isSpreadElement(element) || ts.isOmittedExpression(element)) {
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
326
|
+
return element;
|
|
327
|
+
}
|
|
328
|
+
function getUniformMapEntryBindingsFromLiteral(context, iterableArgument, getPath, getValue) {
|
|
329
|
+
const iterableValue = getValue(iterableArgument) ?? iterableArgument;
|
|
330
|
+
const iterableLiteral = getLiteralArrayValue(iterableValue);
|
|
331
|
+
if (!iterableLiteral) {
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
let sawEntry = false;
|
|
335
|
+
let representativeKeyPath;
|
|
336
|
+
let representativeKeyValue;
|
|
337
|
+
let uniformKey = true;
|
|
338
|
+
let representativeValuePath;
|
|
339
|
+
let representativeValueValue;
|
|
340
|
+
let uniformValue = true;
|
|
341
|
+
for (const entry of iterableLiteral.elements) {
|
|
342
|
+
if (ts.isSpreadElement(entry) || ts.isOmittedExpression(entry)) {
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
const entryValue = getValue(entry) ?? entry;
|
|
346
|
+
const keyExpression = getArrayLiteralEntryComponent(entryValue, 0);
|
|
347
|
+
const valueExpression = getArrayLiteralEntryComponent(entryValue, 1);
|
|
348
|
+
if (!keyExpression || !valueExpression) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
const keyPath = getPath(keyExpression);
|
|
352
|
+
const keyValue = getValue(keyExpression) ?? keyExpression;
|
|
353
|
+
const valuePath = getPath(valueExpression);
|
|
354
|
+
const valueValue = getValue(valueExpression) ?? valueExpression;
|
|
355
|
+
if (!sawEntry) {
|
|
356
|
+
representativeKeyPath = keyPath;
|
|
357
|
+
representativeKeyValue = keyValue;
|
|
358
|
+
representativeValuePath = valuePath;
|
|
359
|
+
representativeValueValue = valueValue;
|
|
360
|
+
sawEntry = true;
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (uniformKey) {
|
|
364
|
+
const sameKeyPath = representativeKeyPath && keyPath && pathsMatch(representativeKeyPath, keyPath);
|
|
365
|
+
const bothNoKeyPath = representativeKeyPath === undefined && keyPath === undefined;
|
|
366
|
+
if (!sameKeyPath && !bothNoKeyPath) {
|
|
367
|
+
uniformKey = false;
|
|
368
|
+
}
|
|
369
|
+
else if (representativeKeyValue !== undefined &&
|
|
370
|
+
keyValue !== undefined &&
|
|
371
|
+
!recoveredValuesMatchWith(context, representativeKeyValue, keyValue, getPath, getValue)) {
|
|
372
|
+
uniformKey = false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (uniformValue) {
|
|
376
|
+
const sameValuePath = representativeValuePath && valuePath &&
|
|
377
|
+
pathsMatch(representativeValuePath, valuePath);
|
|
378
|
+
const bothNoValuePath = representativeValuePath === undefined && valuePath === undefined;
|
|
379
|
+
if (!sameValuePath && !bothNoValuePath) {
|
|
380
|
+
uniformValue = false;
|
|
381
|
+
}
|
|
382
|
+
else if (representativeValueValue !== undefined &&
|
|
383
|
+
valueValue !== undefined &&
|
|
384
|
+
!recoveredValuesMatchWith(context, representativeValueValue, valueValue, getPath, getValue)) {
|
|
385
|
+
uniformValue = false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (!sawEntry || (!uniformKey && !uniformValue)) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
key: uniformKey ? { path: representativeKeyPath, value: representativeKeyValue } : undefined,
|
|
394
|
+
value: uniformValue ? { path: representativeValuePath, value: representativeValueValue } : undefined,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
export function getUniformSetElementBindingFromExpression(context, expression, state) {
|
|
398
|
+
const expressionValue = getExpressionLiteralValue(context, expression, state) ?? expression;
|
|
399
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
400
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
401
|
+
: expressionValue;
|
|
402
|
+
if (!ts.isNewExpression(unwrappedExpression) || !isBuiltinSetConstruction(context, unwrappedExpression)) {
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
const [iterableArgument] = unwrappedExpression.arguments ?? [];
|
|
406
|
+
if (!iterableArgument) {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
return getUniformArrayElementBindingFromExpression(context, iterableArgument, state);
|
|
410
|
+
}
|
|
411
|
+
export function getUniformMapEntryBindingsFromExpression(context, expression, state) {
|
|
412
|
+
const expressionValue = getExpressionLiteralValue(context, expression, state) ?? expression;
|
|
413
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
414
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
415
|
+
: expressionValue;
|
|
416
|
+
if (!ts.isNewExpression(unwrappedExpression) || !isBuiltinMapConstruction(context, unwrappedExpression)) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
const [iterableArgument] = unwrappedExpression.arguments ?? [];
|
|
420
|
+
if (!iterableArgument) {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
return getUniformMapEntryBindingsFromLiteral(context, iterableArgument, (candidate) => normalizeExpressionPath(context, candidate, state), (candidate) => getStateBoundValue(context, candidate, state));
|
|
424
|
+
}
|
|
425
|
+
export function getStateExpressionBoundValue(context, expression, state) {
|
|
426
|
+
return getStateBoundValue(context, expression, state);
|
|
427
|
+
}
|
|
428
|
+
export function getShorthandStateBoundValue(context, assignment, state) {
|
|
429
|
+
const symbol = context.checker.getShorthandAssignmentValueSymbol(assignment);
|
|
430
|
+
return symbol ? state.boundValues.get(getSymbolId(context, symbol)) : undefined;
|
|
431
|
+
}
|
|
432
|
+
function getShorthandFunctionBindingPath(context, assignment, bindings) {
|
|
433
|
+
const symbol = context.checker.getShorthandAssignmentValueSymbol(assignment);
|
|
434
|
+
if (!symbol) {
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
const canonicalSymbol = (symbol.flags & ts.SymbolFlags.Alias) !== 0
|
|
438
|
+
? context.checker.getAliasedSymbol(symbol)
|
|
439
|
+
: symbol;
|
|
440
|
+
return bindings.rootPaths.get(getSymbolId(context, canonicalSymbol)) ?? {
|
|
441
|
+
baseSymbol: canonicalSymbol,
|
|
442
|
+
segments: [],
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function isObjectLikeType(type) {
|
|
446
|
+
return (type.flags & ts.TypeFlags.Object) !== 0;
|
|
447
|
+
}
|
|
448
|
+
export function typeMayAliasMutableState(context, type) {
|
|
449
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
450
|
+
if (constrainedType && constrainedType !== type) {
|
|
451
|
+
return typeMayAliasMutableState(context, constrainedType);
|
|
452
|
+
}
|
|
453
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
454
|
+
return type.types.some((part) => typeMayAliasMutableState(context, part));
|
|
455
|
+
}
|
|
456
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
457
|
+
return type.types.some((part) => typeMayAliasMutableState(context, part));
|
|
458
|
+
}
|
|
459
|
+
return (type.flags & (ts.TypeFlags.Object | ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
|
|
460
|
+
}
|
|
461
|
+
function constBindingMayAliasMutableState(context, symbol) {
|
|
462
|
+
const declaration = symbol.valueDeclaration;
|
|
463
|
+
if (declaration === undefined ||
|
|
464
|
+
(!ts.isVariableDeclaration(declaration) && !ts.isBindingElement(declaration))) {
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
return typeMayAliasMutableState(context, context.checker.getTypeAtLocation(declaration.name));
|
|
468
|
+
}
|
|
469
|
+
function shouldExtractConstAlias(context, symbol, path) {
|
|
470
|
+
return isConstValueDeclaration(symbol) &&
|
|
471
|
+
path.segments.length > 0 &&
|
|
472
|
+
!constBindingMayAliasMutableState(context, symbol);
|
|
473
|
+
}
|
|
474
|
+
function isArrayLikeType(context, type) {
|
|
475
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
476
|
+
if (constrainedType && constrainedType !== type) {
|
|
477
|
+
return isArrayLikeType(context, constrainedType);
|
|
478
|
+
}
|
|
479
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
480
|
+
return type.types.some((part) => isArrayLikeType(context, part));
|
|
481
|
+
}
|
|
482
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
483
|
+
return type.types.some((part) => isArrayLikeType(context, part));
|
|
484
|
+
}
|
|
485
|
+
if (context.checker.isArrayType(type) || context.checker.isTupleType(type)) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
if ((type.flags & ts.TypeFlags.Object) === 0) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const baseTypes = context.checker.getBaseTypes(type) ?? [];
|
|
492
|
+
return baseTypes.some((baseType) => isArrayLikeType(context, baseType));
|
|
493
|
+
}
|
|
494
|
+
function typeMayBeLengthKey(context, type) {
|
|
495
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
496
|
+
if (constrainedType && constrainedType !== type) {
|
|
497
|
+
return typeMayBeLengthKey(context, constrainedType);
|
|
498
|
+
}
|
|
499
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
500
|
+
return type.types.some((part) => typeMayBeLengthKey(context, part));
|
|
501
|
+
}
|
|
502
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
503
|
+
return type.types.some((part) => typeMayBeLengthKey(context, part));
|
|
504
|
+
}
|
|
505
|
+
return (type.flags & ts.TypeFlags.StringLiteral) !== 0 &&
|
|
506
|
+
type.value === 'length';
|
|
507
|
+
}
|
|
508
|
+
function getExactLiteralKeyFromType(context, type) {
|
|
509
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
510
|
+
if (constrainedType && constrainedType !== type) {
|
|
511
|
+
return getExactLiteralKeyFromType(context, constrainedType);
|
|
512
|
+
}
|
|
513
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
514
|
+
const literalKeys = new Set(type.types
|
|
515
|
+
.map((part) => getExactLiteralKeyFromType(context, part))
|
|
516
|
+
.filter((key) => key !== undefined));
|
|
517
|
+
return literalKeys.size === 1 ? literalKeys.values().next().value : undefined;
|
|
518
|
+
}
|
|
519
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
520
|
+
for (const part of type.types) {
|
|
521
|
+
const literalKey = getExactLiteralKeyFromType(context, part);
|
|
522
|
+
if (literalKey !== undefined) {
|
|
523
|
+
return literalKey;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if ((type.flags & ts.TypeFlags.StringLiteral) !== 0) {
|
|
528
|
+
return type.value;
|
|
529
|
+
}
|
|
530
|
+
if ((type.flags & ts.TypeFlags.NumberLiteral) !== 0) {
|
|
531
|
+
return String(type.value);
|
|
532
|
+
}
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
function typeMayBeArrayMutationMethod(context, type) {
|
|
536
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
537
|
+
if (constrainedType && constrainedType !== type) {
|
|
538
|
+
return typeMayBeArrayMutationMethod(context, constrainedType);
|
|
539
|
+
}
|
|
540
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
541
|
+
return type.types.some((part) => typeMayBeArrayMutationMethod(context, part));
|
|
542
|
+
}
|
|
543
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
544
|
+
return type.types.some((part) => typeMayBeArrayMutationMethod(context, part));
|
|
545
|
+
}
|
|
546
|
+
return (type.flags & ts.TypeFlags.StringLiteral) !== 0 &&
|
|
547
|
+
ARRAY_MUTATION_METHODS.has(type.value);
|
|
548
|
+
}
|
|
549
|
+
function typeIsPopOnlyMutationKey(context, type) {
|
|
550
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
551
|
+
if (constrainedType && constrainedType !== type) {
|
|
552
|
+
return typeIsPopOnlyMutationKey(context, constrainedType);
|
|
553
|
+
}
|
|
554
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
555
|
+
const parts = type.types;
|
|
556
|
+
return parts.length > 0 && parts.every((part) => typeIsPopOnlyMutationKey(context, part));
|
|
557
|
+
}
|
|
558
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
559
|
+
return type.types.some((part) => typeIsPopOnlyMutationKey(context, part));
|
|
560
|
+
}
|
|
561
|
+
return (type.flags & ts.TypeFlags.StringLiteral) !== 0 &&
|
|
562
|
+
type.value === 'pop';
|
|
563
|
+
}
|
|
564
|
+
function getElementAccessKey(context, argument) {
|
|
565
|
+
if (!argument) {
|
|
566
|
+
return undefined;
|
|
567
|
+
}
|
|
568
|
+
argument = unwrapFlowTransparentExpression(argument);
|
|
569
|
+
if (ts.isStringLiteral(argument) ||
|
|
570
|
+
ts.isNoSubstitutionTemplateLiteral(argument) ||
|
|
571
|
+
ts.isNumericLiteral(argument)) {
|
|
572
|
+
return argument.text;
|
|
573
|
+
}
|
|
574
|
+
const literalTypeKey = getExactLiteralKeyFromType(context, context.checker.getTypeAtLocation(argument));
|
|
575
|
+
if (literalTypeKey !== undefined) {
|
|
576
|
+
return literalTypeKey;
|
|
577
|
+
}
|
|
578
|
+
if (ts.isIdentifier(argument)) {
|
|
579
|
+
const symbol = getExpressionSymbol(context, argument);
|
|
580
|
+
if (!symbol) {
|
|
581
|
+
return undefined;
|
|
582
|
+
}
|
|
583
|
+
return `symbol:${getSymbolId(context, symbol)}`;
|
|
584
|
+
}
|
|
585
|
+
return undefined;
|
|
586
|
+
}
|
|
587
|
+
function isConstAssertionExpression(expression) {
|
|
588
|
+
return (ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression)) &&
|
|
589
|
+
ts.isConstTypeReference(expression.type);
|
|
590
|
+
}
|
|
591
|
+
function unwrapFlowTransparentExpression(expression) {
|
|
592
|
+
let current = expression;
|
|
593
|
+
while (true) {
|
|
594
|
+
if (ts.isParenthesizedExpression(current) || ts.isSatisfiesExpression(current)) {
|
|
595
|
+
current = current.expression;
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
if (isConstAssertionExpression(current)) {
|
|
599
|
+
current = current.expression;
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
return current;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function getObjectRestAliasPath(context, alias, key, state) {
|
|
606
|
+
const memberValue = getLiteralMemberValue(alias.value, key);
|
|
607
|
+
if (memberValue && ts.isExpression(memberValue)) {
|
|
608
|
+
const memberPath = normalizeExpressionPath(context, memberValue, state);
|
|
609
|
+
if (memberPath) {
|
|
610
|
+
return memberPath;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (alias.value && ts.isCallExpression(alias.value)) {
|
|
614
|
+
const callResultPath = getCallExpressionResultMemberPath(context, alias.value, key, state);
|
|
615
|
+
if (callResultPath) {
|
|
616
|
+
return callResultPath;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (alias.value && ts.isExpression(alias.value)) {
|
|
620
|
+
const recoveredPath = getExpressionMemberPath(context, alias.value, key, state);
|
|
621
|
+
if (recoveredPath) {
|
|
622
|
+
return recoveredPath;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (!alias.path) {
|
|
626
|
+
return undefined;
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
baseSymbol: alias.path.baseSymbol,
|
|
630
|
+
segments: [...alias.path.segments, key],
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function resolveFunctionAliasValuePath(context, expression, bindings) {
|
|
634
|
+
if (expressionStartsFromFunctionBinding(context, expression, bindings)) {
|
|
635
|
+
return normalizeFunctionBodyPath(context, expression, bindings) ??
|
|
636
|
+
normalizeExpressionPath(context, expression, bindings.sourceState);
|
|
637
|
+
}
|
|
638
|
+
return normalizeExpressionPath(context, expression, bindings.sourceState) ??
|
|
639
|
+
normalizeFunctionBodyPath(context, expression, bindings);
|
|
640
|
+
}
|
|
641
|
+
function getFunctionEquivalentExpressionPath(context, expression, bindings) {
|
|
642
|
+
return getEquivalentRecoveredPath(expression, (branch) => resolveFunctionAliasValuePath(context, branch, bindings));
|
|
643
|
+
}
|
|
644
|
+
function recoveredFunctionValuesMatch(context, left, right, bindings) {
|
|
645
|
+
return recoveredValuesMatchWith(context, left, right, (expression) => resolveFunctionAliasValuePath(context, expression, bindings), (expression) => getBoundValue(context, expression, bindings));
|
|
646
|
+
}
|
|
647
|
+
function getFunctionEquivalentExpressionValue(context, expression, bindings) {
|
|
648
|
+
return getEquivalentRecoveredValue(context, expression, (branch) => resolveFunctionAliasValuePath(context, branch, bindings), (branch) => getBoundValue(context, branch, bindings));
|
|
649
|
+
}
|
|
650
|
+
function getExpressionRootReference(expression) {
|
|
651
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
652
|
+
if (ts.isPropertyAccessExpression(expression) || ts.isElementAccessExpression(expression)) {
|
|
653
|
+
return getExpressionRootReference(expression.expression);
|
|
654
|
+
}
|
|
655
|
+
return ts.isIdentifier(expression) || isThisExpression(expression) ? expression : undefined;
|
|
656
|
+
}
|
|
657
|
+
function getRootReferenceSymbol(context, root) {
|
|
658
|
+
return getExpressionSymbol(context, root);
|
|
659
|
+
}
|
|
660
|
+
function getFunctionBoundRootPath(context, root, bindings) {
|
|
661
|
+
if (isThisExpression(root)) {
|
|
662
|
+
return bindings.receiverPath;
|
|
663
|
+
}
|
|
664
|
+
const symbol = getRootReferenceSymbol(context, root);
|
|
665
|
+
return symbol ? bindings.rootPaths.get(getSymbolId(context, symbol)) : undefined;
|
|
666
|
+
}
|
|
667
|
+
function getFunctionRootPath(context, root, bindings) {
|
|
668
|
+
const boundPath = getFunctionBoundRootPath(context, root, bindings);
|
|
669
|
+
if (boundPath) {
|
|
670
|
+
return boundPath;
|
|
671
|
+
}
|
|
672
|
+
const symbol = getRootReferenceSymbol(context, root);
|
|
673
|
+
return symbol
|
|
674
|
+
? {
|
|
675
|
+
baseSymbol: symbol,
|
|
676
|
+
segments: [],
|
|
677
|
+
}
|
|
678
|
+
: undefined;
|
|
679
|
+
}
|
|
680
|
+
function setFunctionRootPath(context, root, path, bindings) {
|
|
681
|
+
if (isThisExpression(root)) {
|
|
682
|
+
bindings.receiverPath = path;
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const symbol = getRootReferenceSymbol(context, root);
|
|
686
|
+
if (symbol) {
|
|
687
|
+
bindings.rootPaths.set(getSymbolId(context, symbol), path);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
export function bindFunctionReceiverPath(bindings, path) {
|
|
691
|
+
bindings.receiverPath = path;
|
|
692
|
+
bindings.receiverMemberPaths = undefined;
|
|
693
|
+
}
|
|
694
|
+
function expressionResolvesToBoundThis(context, expression, bindings, seen = new Set()) {
|
|
695
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
696
|
+
if (isThisExpression(expression)) {
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
if (!ts.isIdentifier(expression)) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
703
|
+
if (!symbol) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
const symbolId = getSymbolId(context, symbol);
|
|
707
|
+
if (seen.has(symbolId)) {
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
seen.add(symbolId);
|
|
711
|
+
const boundValue = bindings.boundValues.get(symbolId);
|
|
712
|
+
return !!boundValue && ts.isExpression(boundValue) &&
|
|
713
|
+
expressionResolvesToBoundThis(context, boundValue, bindings, seen);
|
|
714
|
+
}
|
|
715
|
+
function getFunctionReceiverMemberPath(context, receiver, key, bindings) {
|
|
716
|
+
return bindings.receiverMemberPaths && expressionResolvesToBoundThis(context, receiver, bindings)
|
|
717
|
+
? bindings.receiverMemberPaths.get(key)
|
|
718
|
+
: undefined;
|
|
719
|
+
}
|
|
720
|
+
function expressionStartsFromFunctionBinding(context, expression, bindings) {
|
|
721
|
+
const root = getExpressionRootReference(expression);
|
|
722
|
+
if (!root) {
|
|
723
|
+
return false;
|
|
724
|
+
}
|
|
725
|
+
if (getFunctionBoundRootPath(context, root, bindings)) {
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
if (!ts.isIdentifier(root)) {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
const symbol = getRootReferenceSymbol(context, root);
|
|
732
|
+
if (!symbol) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
const symbolId = getSymbolId(context, symbol);
|
|
736
|
+
return bindings.rootPaths.has(symbolId) ||
|
|
737
|
+
bindings.boundValues.has(symbolId) ||
|
|
738
|
+
bindings.arrayRestAliases.has(symbolId) ||
|
|
739
|
+
bindings.objectRestAliases.has(symbolId);
|
|
740
|
+
}
|
|
741
|
+
function getFunctionObjectRestAliasPath(context, alias, key, bindings) {
|
|
742
|
+
const memberValue = getLiteralMemberValue(alias.value, key);
|
|
743
|
+
if (memberValue && ts.isExpression(memberValue)) {
|
|
744
|
+
const memberPath = resolveFunctionAliasValuePath(context, memberValue, bindings);
|
|
745
|
+
if (memberPath) {
|
|
746
|
+
return memberPath;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
if (!alias.path) {
|
|
750
|
+
if (alias.value && ts.isExpression(alias.value)) {
|
|
751
|
+
return getFunctionExpressionMemberPath(context, alias.value, key, bindings);
|
|
752
|
+
}
|
|
753
|
+
return undefined;
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
baseSymbol: alias.path.baseSymbol,
|
|
757
|
+
segments: [...alias.path.segments, key],
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
function getFunctionExpressionMemberPath(context, expression, key, bindings) {
|
|
761
|
+
return getRecoveredExpressionMemberPath(expression, key, (branch) => getBoundValue(context, branch, bindings), (callExpression, memberKey) => getFunctionCallExpressionResultMemberPath(context, callExpression, memberKey, bindings), (memberExpression) => resolveFunctionAliasValuePath(context, memberExpression, bindings));
|
|
762
|
+
}
|
|
763
|
+
export function normalizeExpressionPath(context, expression, state) {
|
|
764
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
765
|
+
if (unwrappedExpression !== expression) {
|
|
766
|
+
return normalizeExpressionPath(context, unwrappedExpression, state);
|
|
767
|
+
}
|
|
768
|
+
if (ts.isIdentifier(expression) || isThisExpression(expression)) {
|
|
769
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
770
|
+
if (!symbol) {
|
|
771
|
+
return undefined;
|
|
772
|
+
}
|
|
773
|
+
return state.aliases.get(getSymbolId(context, symbol)) ?? {
|
|
774
|
+
baseSymbol: symbol,
|
|
775
|
+
segments: [],
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
if (ts.isCallExpression(expression)) {
|
|
779
|
+
return getCallExpressionResultPath(context, expression, state);
|
|
780
|
+
}
|
|
781
|
+
const equivalentPath = getEquivalentExpressionPath(context, expression, state);
|
|
782
|
+
if (equivalentPath) {
|
|
783
|
+
return equivalentPath;
|
|
784
|
+
}
|
|
785
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
786
|
+
if (ts.isIdentifier(expression.expression)) {
|
|
787
|
+
const receiverSymbol = getExpressionSymbol(context, expression.expression);
|
|
788
|
+
if (receiverSymbol) {
|
|
789
|
+
const receiverId = getSymbolId(context, receiverSymbol);
|
|
790
|
+
const propertyType = context.checker.getTypeAtLocation(expression);
|
|
791
|
+
const objectRestAlias = state.objectRestAliases.get(receiverId);
|
|
792
|
+
if (objectRestAlias &&
|
|
793
|
+
!objectRestAlias.excludedKeys.includes(getMemberNameText(expression.name))) {
|
|
794
|
+
const restPath = getObjectRestAliasPath(context, objectRestAlias, getMemberNameText(expression.name), state);
|
|
795
|
+
if (restPath) {
|
|
796
|
+
return restPath;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
const spreadAlias = state.spreadAliases.get(receiverId);
|
|
800
|
+
if (spreadAlias) {
|
|
801
|
+
if (isObjectLikeType(propertyType)) {
|
|
802
|
+
return {
|
|
803
|
+
baseSymbol: spreadAlias.baseSymbol,
|
|
804
|
+
segments: [...spreadAlias.segments, getMemberNameText(expression.name)],
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
const boundMemberValue = getLiteralMemberValue(state.boundValues.get(receiverId), getMemberNameText(expression.name));
|
|
809
|
+
if (boundMemberValue && ts.isExpression(boundMemberValue)) {
|
|
810
|
+
const boundMemberPath = normalizeExpressionPath(context, boundMemberValue, state);
|
|
811
|
+
if (boundMemberPath) {
|
|
812
|
+
return boundMemberPath;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const boundReceiverValue = state.boundValues.get(receiverId);
|
|
816
|
+
if (boundReceiverValue && ts.isExpression(boundReceiverValue) &&
|
|
817
|
+
ts.isCallExpression(boundReceiverValue)) {
|
|
818
|
+
const callResultPath = getCallExpressionResultMemberPath(context, boundReceiverValue, getMemberNameText(expression.name), state);
|
|
819
|
+
if (callResultPath) {
|
|
820
|
+
return callResultPath;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const literalMemberPath = getLiteralReadbackPath(context, expression.expression, getMemberNameText(expression.name), state);
|
|
826
|
+
if (literalMemberPath) {
|
|
827
|
+
return literalMemberPath;
|
|
828
|
+
}
|
|
829
|
+
const basePath = normalizeExpressionPath(context, expression.expression, state);
|
|
830
|
+
if (!basePath) {
|
|
831
|
+
return undefined;
|
|
832
|
+
}
|
|
833
|
+
return {
|
|
834
|
+
baseSymbol: basePath.baseSymbol,
|
|
835
|
+
segments: [...basePath.segments, getMemberNameText(expression.name)],
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
839
|
+
const key = getElementAccessKey(context, expression.argumentExpression);
|
|
840
|
+
if (ts.isIdentifier(expression.expression)) {
|
|
841
|
+
const receiverSymbol = getExpressionSymbol(context, expression.expression);
|
|
842
|
+
if (receiverSymbol) {
|
|
843
|
+
const receiverId = getSymbolId(context, receiverSymbol);
|
|
844
|
+
if (key) {
|
|
845
|
+
const objectRestAlias = state.objectRestAliases.get(receiverId);
|
|
846
|
+
if (objectRestAlias &&
|
|
847
|
+
!objectRestAlias.excludedKeys.includes(key)) {
|
|
848
|
+
const restPath = getObjectRestAliasPath(context, objectRestAlias, key, state);
|
|
849
|
+
if (restPath) {
|
|
850
|
+
return restPath;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
const restAlias = state.arrayRestAliases.get(receiverId);
|
|
855
|
+
if (restAlias) {
|
|
856
|
+
if (key && /^\d+$/.test(key)) {
|
|
857
|
+
const resolvedIndex = restAlias.offset + Number(key);
|
|
858
|
+
const restElementValue = getLiteralMemberValue(restAlias.value, String(resolvedIndex));
|
|
859
|
+
if (restElementValue && ts.isExpression(restElementValue)) {
|
|
860
|
+
const restElementPath = normalizeExpressionPath(context, restElementValue, state);
|
|
861
|
+
if (restElementPath) {
|
|
862
|
+
return restElementPath;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (!restAlias.path) {
|
|
866
|
+
return undefined;
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
baseSymbol: restAlias.path.baseSymbol,
|
|
870
|
+
segments: [...restAlias.path.segments, String(resolvedIndex)],
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
const boundMemberValue = key
|
|
875
|
+
? getLiteralMemberValue(state.boundValues.get(receiverId), key)
|
|
876
|
+
: undefined;
|
|
877
|
+
if (boundMemberValue && ts.isExpression(boundMemberValue)) {
|
|
878
|
+
const boundMemberPath = normalizeExpressionPath(context, boundMemberValue, state);
|
|
879
|
+
if (boundMemberPath) {
|
|
880
|
+
return boundMemberPath;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
const boundReceiverValue = state.boundValues.get(receiverId);
|
|
884
|
+
if (key && boundReceiverValue && ts.isExpression(boundReceiverValue) &&
|
|
885
|
+
ts.isCallExpression(boundReceiverValue)) {
|
|
886
|
+
const callResultPath = getCallExpressionResultMemberPath(context, boundReceiverValue, key, state);
|
|
887
|
+
if (callResultPath) {
|
|
888
|
+
return callResultPath;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (key) {
|
|
894
|
+
const literalElementPath = getLiteralReadbackPath(context, expression.expression, key, state);
|
|
895
|
+
if (literalElementPath) {
|
|
896
|
+
return literalElementPath;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
const basePath = normalizeExpressionPath(context, expression.expression, state);
|
|
900
|
+
if (!basePath) {
|
|
901
|
+
return undefined;
|
|
902
|
+
}
|
|
903
|
+
if (!key) {
|
|
904
|
+
return undefined;
|
|
905
|
+
}
|
|
906
|
+
return {
|
|
907
|
+
baseSymbol: basePath.baseSymbol,
|
|
908
|
+
segments: [...basePath.segments, key],
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
return undefined;
|
|
912
|
+
}
|
|
913
|
+
function getLiteralReadbackPath(context, receiver, key, state) {
|
|
914
|
+
return getExpressionMemberPath(context, receiver, key, state);
|
|
915
|
+
}
|
|
916
|
+
function getExpressionMemberPath(context, expression, key, state) {
|
|
917
|
+
return getRecoveredExpressionMemberPath(expression, key, (branch) => getExpressionLiteralValue(context, branch, state), (callExpression, memberKey) => getCallExpressionResultMemberPath(context, callExpression, memberKey, state), (memberExpression) => normalizeExpressionPath(context, memberExpression, state));
|
|
918
|
+
}
|
|
919
|
+
export function normalizeExpressionSourcePath(context, expression, state) {
|
|
920
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
921
|
+
if (unwrappedExpression !== expression) {
|
|
922
|
+
return normalizeExpressionSourcePath(context, unwrappedExpression, state);
|
|
923
|
+
}
|
|
924
|
+
if (ts.isIdentifier(expression) || isThisExpression(expression)) {
|
|
925
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
926
|
+
if (!symbol) {
|
|
927
|
+
return undefined;
|
|
928
|
+
}
|
|
929
|
+
const symbolId = getSymbolId(context, symbol);
|
|
930
|
+
return state.extractedBindings.get(symbolId) ??
|
|
931
|
+
state.aliases.get(symbolId) ?? {
|
|
932
|
+
baseSymbol: symbol,
|
|
933
|
+
segments: [],
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
937
|
+
const path = normalizeExpressionPath(context, expression, state);
|
|
938
|
+
const receiverPath = normalizeExpressionPath(context, expression.expression, state);
|
|
939
|
+
const receiverSourcePath = normalizeExpressionSourcePath(context, expression.expression, state);
|
|
940
|
+
if (path &&
|
|
941
|
+
receiverPath &&
|
|
942
|
+
receiverSourcePath &&
|
|
943
|
+
!pathsMatch(receiverPath, receiverSourcePath)) {
|
|
944
|
+
return {
|
|
945
|
+
baseSymbol: receiverSourcePath.baseSymbol,
|
|
946
|
+
segments: [...receiverSourcePath.segments, getMemberNameText(expression.name)],
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
return path;
|
|
950
|
+
}
|
|
951
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
952
|
+
const path = normalizeExpressionPath(context, expression, state);
|
|
953
|
+
const key = getElementAccessKey(context, expression.argumentExpression);
|
|
954
|
+
const receiverPath = normalizeExpressionPath(context, expression.expression, state);
|
|
955
|
+
const receiverSourcePath = normalizeExpressionSourcePath(context, expression.expression, state);
|
|
956
|
+
if (path &&
|
|
957
|
+
key &&
|
|
958
|
+
receiverPath &&
|
|
959
|
+
receiverSourcePath &&
|
|
960
|
+
!pathsMatch(receiverPath, receiverSourcePath)) {
|
|
961
|
+
return {
|
|
962
|
+
baseSymbol: receiverSourcePath.baseSymbol,
|
|
963
|
+
segments: [...receiverSourcePath.segments, key],
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return path;
|
|
967
|
+
}
|
|
968
|
+
return normalizeExpressionPath(context, expression, state);
|
|
969
|
+
}
|
|
970
|
+
function getFunctionBodyElementAccessKey(context, argument, bindings) {
|
|
971
|
+
if (!argument) {
|
|
972
|
+
return undefined;
|
|
973
|
+
}
|
|
974
|
+
if (ts.isIdentifier(argument)) {
|
|
975
|
+
const symbol = getExpressionSymbol(context, argument);
|
|
976
|
+
if (!symbol) {
|
|
977
|
+
return undefined;
|
|
978
|
+
}
|
|
979
|
+
const boundPath = bindings.rootPaths.get(getSymbolId(context, symbol));
|
|
980
|
+
if (boundPath && boundPath.segments.length === 0) {
|
|
981
|
+
return `symbol:${getSymbolId(context, boundPath.baseSymbol)}`;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return getElementAccessKey(context, argument);
|
|
985
|
+
}
|
|
986
|
+
export function pathsMatch(left, right) {
|
|
987
|
+
return left.baseSymbol === right.baseSymbol &&
|
|
988
|
+
left.segments.length === right.segments.length &&
|
|
989
|
+
left.segments.every((segment, index) => segment === right.segments[index]);
|
|
990
|
+
}
|
|
991
|
+
function pathIsPrefix(prefix, value) {
|
|
992
|
+
return prefix.baseSymbol === value.baseSymbol &&
|
|
993
|
+
prefix.segments.length <= value.segments.length &&
|
|
994
|
+
prefix.segments.every((segment, index) => segment === value.segments[index]);
|
|
995
|
+
}
|
|
996
|
+
export function appendSegment(path, segment) {
|
|
997
|
+
return {
|
|
998
|
+
baseSymbol: path.baseSymbol,
|
|
999
|
+
segments: [...path.segments, segment],
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
export function mutationAffectsNarrow(mutationPath, narrowPath) {
|
|
1003
|
+
return pathIsPrefix(mutationPath, narrowPath) || pathIsPrefix(narrowPath, mutationPath);
|
|
1004
|
+
}
|
|
1005
|
+
export function opaqueArgumentEscapeAffectsNarrow(argumentPath, narrowPath) {
|
|
1006
|
+
return argumentPath.baseSymbol === narrowPath.baseSymbol &&
|
|
1007
|
+
narrowPath.segments.length > 0 &&
|
|
1008
|
+
pathIsPrefix(argumentPath, narrowPath);
|
|
1009
|
+
}
|
|
1010
|
+
function isArrayDependentSegment(segment) {
|
|
1011
|
+
return segment === 'length' || /^\d+$/.test(segment);
|
|
1012
|
+
}
|
|
1013
|
+
function arrayMutationAffectsNarrow(receiverPath, narrowPath) {
|
|
1014
|
+
if (receiverPath.baseSymbol !== narrowPath.baseSymbol ||
|
|
1015
|
+
!pathIsPrefix(receiverPath, narrowPath) ||
|
|
1016
|
+
narrowPath.segments.length === receiverPath.segments.length) {
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
const affectedSegment = narrowPath.segments[receiverPath.segments.length];
|
|
1020
|
+
return affectedSegment !== undefined && isArrayDependentSegment(affectedSegment);
|
|
1021
|
+
}
|
|
1022
|
+
function getNumericLiteralValue(expression) {
|
|
1023
|
+
if (ts.isNumericLiteral(expression)) {
|
|
1024
|
+
return Number(expression.text);
|
|
1025
|
+
}
|
|
1026
|
+
if (ts.isPrefixUnaryExpression(expression) &&
|
|
1027
|
+
expression.operator === ts.SyntaxKind.MinusToken &&
|
|
1028
|
+
ts.isNumericLiteral(expression.operand)) {
|
|
1029
|
+
return -Number(expression.operand.text);
|
|
1030
|
+
}
|
|
1031
|
+
return undefined;
|
|
1032
|
+
}
|
|
1033
|
+
function getMinimumGuaranteedArrayLength(context, type) {
|
|
1034
|
+
const constrainedType = context.checker.getBaseConstraintOfType(type);
|
|
1035
|
+
if (constrainedType && constrainedType !== type) {
|
|
1036
|
+
return getMinimumGuaranteedArrayLength(context, constrainedType);
|
|
1037
|
+
}
|
|
1038
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
1039
|
+
return Math.min(...type.types.map((part) => getMinimumGuaranteedArrayLength(context, part)));
|
|
1040
|
+
}
|
|
1041
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
1042
|
+
return Math.max(...type.types.map((part) => getMinimumGuaranteedArrayLength(context, part)));
|
|
1043
|
+
}
|
|
1044
|
+
const guaranteedIndexes = new Set();
|
|
1045
|
+
for (const property of type.getProperties()) {
|
|
1046
|
+
if ((property.flags & ts.SymbolFlags.Optional) !== 0) {
|
|
1047
|
+
continue;
|
|
1048
|
+
}
|
|
1049
|
+
const propertyName = property.getName();
|
|
1050
|
+
if (!/^\d+$/.test(propertyName)) {
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
guaranteedIndexes.add(Number(propertyName));
|
|
1054
|
+
}
|
|
1055
|
+
let guaranteedLength = 0;
|
|
1056
|
+
while (guaranteedIndexes.has(guaranteedLength)) {
|
|
1057
|
+
guaranteedLength += 1;
|
|
1058
|
+
}
|
|
1059
|
+
return guaranteedLength;
|
|
1060
|
+
}
|
|
1061
|
+
function getLengthMutationReceiverPath(targetPath) {
|
|
1062
|
+
return {
|
|
1063
|
+
baseSymbol: targetPath.baseSymbol,
|
|
1064
|
+
segments: targetPath.segments.slice(0, -1),
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
function getArrayDependentNarrowSegment(receiverPath, narrowPath) {
|
|
1068
|
+
if (receiverPath.baseSymbol !== narrowPath.baseSymbol ||
|
|
1069
|
+
!pathIsPrefix(receiverPath, narrowPath) ||
|
|
1070
|
+
narrowPath.segments.length === receiverPath.segments.length) {
|
|
1071
|
+
return undefined;
|
|
1072
|
+
}
|
|
1073
|
+
const affectedSegment = narrowPath.segments[receiverPath.segments.length];
|
|
1074
|
+
return affectedSegment !== undefined && isArrayDependentSegment(affectedSegment)
|
|
1075
|
+
? affectedSegment
|
|
1076
|
+
: undefined;
|
|
1077
|
+
}
|
|
1078
|
+
function lengthMutationAffectsNarrowByOperator(context, receiverType, receiverPath, narrowPath, operator, rightHandSide) {
|
|
1079
|
+
const affectedSegment = getArrayDependentNarrowSegment(receiverPath, narrowPath);
|
|
1080
|
+
if (affectedSegment === undefined) {
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
if (affectedSegment === 'length') {
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
const affectedIndex = Number(affectedSegment);
|
|
1087
|
+
const minimumGuaranteedLength = getMinimumGuaranteedArrayLength(context, receiverType);
|
|
1088
|
+
const canGuaranteedlyPreserveIndex = (tailRemovalCount) => Math.max(0, minimumGuaranteedLength - tailRemovalCount) > affectedIndex;
|
|
1089
|
+
switch (operator) {
|
|
1090
|
+
case ts.SyntaxKind.PlusPlusToken:
|
|
1091
|
+
return false;
|
|
1092
|
+
case ts.SyntaxKind.MinusMinusToken:
|
|
1093
|
+
return !canGuaranteedlyPreserveIndex(1);
|
|
1094
|
+
case ts.SyntaxKind.EqualsToken: {
|
|
1095
|
+
if (!rightHandSide) {
|
|
1096
|
+
return true;
|
|
1097
|
+
}
|
|
1098
|
+
const assignedValue = getNumericLiteralValue(rightHandSide);
|
|
1099
|
+
return assignedValue === undefined || assignedValue <= Number(affectedSegment);
|
|
1100
|
+
}
|
|
1101
|
+
case ts.SyntaxKind.PlusEqualsToken: {
|
|
1102
|
+
if (!rightHandSide) {
|
|
1103
|
+
return true;
|
|
1104
|
+
}
|
|
1105
|
+
const delta = getNumericLiteralValue(rightHandSide);
|
|
1106
|
+
return delta === undefined || delta < 0;
|
|
1107
|
+
}
|
|
1108
|
+
case ts.SyntaxKind.MinusEqualsToken: {
|
|
1109
|
+
if (!rightHandSide) {
|
|
1110
|
+
return true;
|
|
1111
|
+
}
|
|
1112
|
+
const delta = getNumericLiteralValue(rightHandSide);
|
|
1113
|
+
if (delta === undefined) {
|
|
1114
|
+
return true;
|
|
1115
|
+
}
|
|
1116
|
+
return delta > 0 ? !canGuaranteedlyPreserveIndex(delta) : false;
|
|
1117
|
+
}
|
|
1118
|
+
default:
|
|
1119
|
+
return true;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
function getLengthMutationReceiver(context, expression) {
|
|
1123
|
+
if (ts.isPropertyAccessExpression(expression) && expression.name.text === 'length') {
|
|
1124
|
+
return expression.expression;
|
|
1125
|
+
}
|
|
1126
|
+
if (ts.isElementAccessExpression(expression) &&
|
|
1127
|
+
expression.argumentExpression) {
|
|
1128
|
+
const argument = expression.argumentExpression;
|
|
1129
|
+
if ((ts.isStringLiteral(argument) || ts.isNoSubstitutionTemplateLiteral(argument)) &&
|
|
1130
|
+
argument.text === 'length') {
|
|
1131
|
+
return expression.expression;
|
|
1132
|
+
}
|
|
1133
|
+
const argumentType = context.checker.getTypeAtLocation(argument);
|
|
1134
|
+
if (typeMayBeLengthKey(context, argumentType)) {
|
|
1135
|
+
return expression.expression;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return undefined;
|
|
1139
|
+
}
|
|
1140
|
+
export function assignmentAffectsNarrow(context, assignment, targetPath, narrowPath) {
|
|
1141
|
+
if (mutationAffectsNarrow(targetPath, narrowPath)) {
|
|
1142
|
+
return true;
|
|
1143
|
+
}
|
|
1144
|
+
const receiver = getLengthMutationReceiver(context, assignment.left);
|
|
1145
|
+
if (!receiver) {
|
|
1146
|
+
return false;
|
|
1147
|
+
}
|
|
1148
|
+
if (!isArrayLikeType(context, context.checker.getTypeAtLocation(receiver))) {
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
const receiverType = context.checker.getTypeAtLocation(receiver);
|
|
1152
|
+
return lengthMutationAffectsNarrowByOperator(context, receiverType, getLengthMutationReceiverPath(targetPath), narrowPath, assignment.operatorToken.kind, assignment.right);
|
|
1153
|
+
}
|
|
1154
|
+
export function typedUpdateExpressionAffectsNarrow(context, updateExpression, updatedPath, narrowPath) {
|
|
1155
|
+
if (mutationAffectsNarrow(updatedPath, narrowPath)) {
|
|
1156
|
+
return true;
|
|
1157
|
+
}
|
|
1158
|
+
const receiver = getLengthMutationReceiver(context, updateExpression.operand);
|
|
1159
|
+
if (!receiver) {
|
|
1160
|
+
return false;
|
|
1161
|
+
}
|
|
1162
|
+
if (!isArrayLikeType(context, context.checker.getTypeAtLocation(receiver))) {
|
|
1163
|
+
return false;
|
|
1164
|
+
}
|
|
1165
|
+
const receiverType = context.checker.getTypeAtLocation(receiver);
|
|
1166
|
+
return lengthMutationAffectsNarrowByOperator(context, receiverType, getLengthMutationReceiverPath(updatedPath), narrowPath, updateExpression.operator);
|
|
1167
|
+
}
|
|
1168
|
+
export function getCalledMember(context, expression) {
|
|
1169
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
1170
|
+
return {
|
|
1171
|
+
receiver: expression.expression,
|
|
1172
|
+
member: getMemberNameText(expression.name),
|
|
1173
|
+
memberType: undefined,
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
1177
|
+
return {
|
|
1178
|
+
receiver: expression.expression,
|
|
1179
|
+
member: getElementAccessKey(context, expression.argumentExpression),
|
|
1180
|
+
memberType: expression.argumentExpression
|
|
1181
|
+
? context.checker.getTypeAtLocation(expression.argumentExpression)
|
|
1182
|
+
: undefined,
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
return undefined;
|
|
1186
|
+
}
|
|
1187
|
+
export function getFunctionBodyCalledMember(context, expression, bindings) {
|
|
1188
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
1189
|
+
return {
|
|
1190
|
+
receiver: expression.expression,
|
|
1191
|
+
member: getMemberNameText(expression.name),
|
|
1192
|
+
memberType: undefined,
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
1196
|
+
return {
|
|
1197
|
+
receiver: expression.expression,
|
|
1198
|
+
member: getFunctionBodyElementAccessKey(context, expression.argumentExpression, bindings),
|
|
1199
|
+
memberType: expression.argumentExpression
|
|
1200
|
+
? context.checker.getTypeAtLocation(expression.argumentExpression)
|
|
1201
|
+
: undefined,
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
return undefined;
|
|
1205
|
+
}
|
|
1206
|
+
export function arrayMutationCallAffectsNarrow(context, receiverExpression, receiverPath, member, memberType, narrowPath) {
|
|
1207
|
+
const mayMutateArray = (member !== undefined && ARRAY_MUTATION_METHODS.has(member)) ||
|
|
1208
|
+
(memberType !== undefined && typeMayBeArrayMutationMethod(context, memberType));
|
|
1209
|
+
if (!receiverPath || !mayMutateArray) {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
const receiverType = context.checker.getTypeAtLocation(receiverExpression);
|
|
1213
|
+
if (!isArrayLikeType(context, receiverType)) {
|
|
1214
|
+
return false;
|
|
1215
|
+
}
|
|
1216
|
+
if (member === 'pop' ||
|
|
1217
|
+
(member === undefined && memberType !== undefined &&
|
|
1218
|
+
typeIsPopOnlyMutationKey(context, memberType))) {
|
|
1219
|
+
const affectedSegment = getArrayDependentNarrowSegment(receiverPath, narrowPath);
|
|
1220
|
+
if (affectedSegment === undefined) {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
if (affectedSegment === 'length') {
|
|
1224
|
+
return true;
|
|
1225
|
+
}
|
|
1226
|
+
const affectedIndex = Number(affectedSegment);
|
|
1227
|
+
return getMinimumGuaranteedArrayLength(context, receiverType) <= affectedIndex + 1;
|
|
1228
|
+
}
|
|
1229
|
+
return arrayMutationAffectsNarrow(receiverPath, narrowPath);
|
|
1230
|
+
}
|
|
1231
|
+
export function getUpdateExpressionOperand(node) {
|
|
1232
|
+
if (ts.isPrefixUnaryExpression(node) &&
|
|
1233
|
+
(node.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
1234
|
+
node.operator === ts.SyntaxKind.MinusMinusToken)) {
|
|
1235
|
+
return node.operand;
|
|
1236
|
+
}
|
|
1237
|
+
if (ts.isPostfixUnaryExpression(node) &&
|
|
1238
|
+
(node.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
1239
|
+
node.operator === ts.SyntaxKind.MinusMinusToken)) {
|
|
1240
|
+
return node.operand;
|
|
1241
|
+
}
|
|
1242
|
+
return undefined;
|
|
1243
|
+
}
|
|
1244
|
+
export function recordVariableAliases(context, declaration, state) {
|
|
1245
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
1246
|
+
const symbol = getExpressionSymbol(context, declaration.name);
|
|
1247
|
+
if (!symbol) {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
if (isConstValueDeclaration(symbol)) {
|
|
1251
|
+
const boundInitializer = getExpressionLiteralValue(context, declaration.initializer, state);
|
|
1252
|
+
state.boundValues.set(getSymbolId(context, symbol), boundInitializer ?? declaration.initializer);
|
|
1253
|
+
}
|
|
1254
|
+
const directAlias = normalizeExpressionPath(context, declaration.initializer, state);
|
|
1255
|
+
if (directAlias) {
|
|
1256
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1257
|
+
if (shouldExtractConstAlias(context, symbol, directAlias)) {
|
|
1258
|
+
state.extractedBindings.set(symbolId, directAlias);
|
|
1259
|
+
}
|
|
1260
|
+
else {
|
|
1261
|
+
state.aliases.set(symbolId, directAlias);
|
|
1262
|
+
}
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
if (ts.isObjectLiteralExpression(declaration.initializer) &&
|
|
1266
|
+
declaration.initializer.properties.some(ts.isSpreadAssignment)) {
|
|
1267
|
+
const spreadAssignment = declaration.initializer.properties.find(ts.isSpreadAssignment);
|
|
1268
|
+
if (!spreadAssignment) {
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
const spreadPath = normalizeExpressionPath(context, spreadAssignment.expression, state);
|
|
1272
|
+
if (spreadPath) {
|
|
1273
|
+
state.spreadAliases.set(getSymbolId(context, symbol), spreadPath);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
if ((ts.isObjectBindingPattern(declaration.name) || ts.isArrayBindingPattern(declaration.name)) &&
|
|
1279
|
+
declaration.initializer) {
|
|
1280
|
+
const initializerPath = normalizeExpressionPath(context, declaration.initializer, state);
|
|
1281
|
+
const boundInitializer = getExpressionLiteralValue(context, declaration.initializer, state) ??
|
|
1282
|
+
declaration.initializer;
|
|
1283
|
+
recordVariableBindingName(context, declaration.name, initializerPath, boundInitializer, state);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
function clearVariableBindingIdentifier(context, name, state) {
|
|
1287
|
+
const symbol = getExpressionSymbol(context, name);
|
|
1288
|
+
if (!symbol) {
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
clearVariableBindingSymbol(context, symbol, state);
|
|
1292
|
+
}
|
|
1293
|
+
function clearVariableBindingSymbol(context, symbol, state) {
|
|
1294
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1295
|
+
state.aliases.delete(symbolId);
|
|
1296
|
+
state.arrayRestAliases.delete(symbolId);
|
|
1297
|
+
state.boundValues.delete(symbolId);
|
|
1298
|
+
state.extractedBindings.delete(symbolId);
|
|
1299
|
+
state.objectRestAliases.delete(symbolId);
|
|
1300
|
+
state.spreadAliases.delete(symbolId);
|
|
1301
|
+
}
|
|
1302
|
+
function getShorthandAssignmentTargetSymbol(context, property) {
|
|
1303
|
+
const symbol = context.checker.getShorthandAssignmentValueSymbol(property);
|
|
1304
|
+
if (!symbol) {
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
return (symbol.flags & ts.SymbolFlags.Alias) !== 0
|
|
1308
|
+
? context.checker.getAliasedSymbol(symbol)
|
|
1309
|
+
: symbol;
|
|
1310
|
+
}
|
|
1311
|
+
function getObjectAssignmentPropertyKey(context, property) {
|
|
1312
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
1313
|
+
return property.name.text;
|
|
1314
|
+
}
|
|
1315
|
+
if (ts.isPropertyAssignment(property)) {
|
|
1316
|
+
return getPropertyNameKey(context, property.name);
|
|
1317
|
+
}
|
|
1318
|
+
return undefined;
|
|
1319
|
+
}
|
|
1320
|
+
function getAssignmentPatternTarget(expression) {
|
|
1321
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
1322
|
+
if (ts.isBinaryExpression(unwrappedExpression) &&
|
|
1323
|
+
unwrappedExpression.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
1324
|
+
return unwrapFlowTransparentExpression(unwrappedExpression.left);
|
|
1325
|
+
}
|
|
1326
|
+
return unwrappedExpression;
|
|
1327
|
+
}
|
|
1328
|
+
function getAssignmentPatternDefaultPath(context, expression, state) {
|
|
1329
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
1330
|
+
return ts.isBinaryExpression(unwrappedExpression) &&
|
|
1331
|
+
unwrappedExpression.operatorToken.kind === ts.SyntaxKind.EqualsToken
|
|
1332
|
+
? normalizeExpressionPath(context, unwrappedExpression.right, state)
|
|
1333
|
+
: undefined;
|
|
1334
|
+
}
|
|
1335
|
+
function getAssignmentPatternDefaultValue(context, expression, state) {
|
|
1336
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
1337
|
+
if (!ts.isBinaryExpression(unwrappedExpression) ||
|
|
1338
|
+
unwrappedExpression.operatorToken.kind !== ts.SyntaxKind.EqualsToken) {
|
|
1339
|
+
return undefined;
|
|
1340
|
+
}
|
|
1341
|
+
return unwrappedExpression.right;
|
|
1342
|
+
}
|
|
1343
|
+
function recordSpreadAlias(context, symbolId, argumentValue, state) {
|
|
1344
|
+
if (!argumentValue || !ts.isExpression(argumentValue)) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
const unwrappedValue = unwrapFlowTransparentExpression(argumentValue);
|
|
1348
|
+
if (!ts.isObjectLiteralExpression(unwrappedValue)) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
const spreadAssignment = unwrappedValue.properties.find(ts.isSpreadAssignment);
|
|
1352
|
+
if (!spreadAssignment) {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const spreadPath = normalizeExpressionPath(context, spreadAssignment.expression, state);
|
|
1356
|
+
if (spreadPath) {
|
|
1357
|
+
state.spreadAliases.set(symbolId, spreadPath);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
function createClearedBoundValueExpression() {
|
|
1361
|
+
return ts.factory.createVoidExpression(ts.factory.createNumericLiteral('0'));
|
|
1362
|
+
}
|
|
1363
|
+
function getRecordedBoundValueExpression(value) {
|
|
1364
|
+
return value && ts.isExpression(value) ? value : createClearedBoundValueExpression();
|
|
1365
|
+
}
|
|
1366
|
+
function createObjectLiteralMemberAssignment(key, value) {
|
|
1367
|
+
return /^\d+$/.test(key)
|
|
1368
|
+
? ts.factory.createPropertyAssignment(ts.factory.createNumericLiteral(key), value)
|
|
1369
|
+
: ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), value);
|
|
1370
|
+
}
|
|
1371
|
+
function updateObjectLiteralMemberValue(context, objectLiteral, key, value) {
|
|
1372
|
+
const properties = [];
|
|
1373
|
+
let replaced = false;
|
|
1374
|
+
for (const property of objectLiteral.properties) {
|
|
1375
|
+
if (ts.isSpreadAssignment(property)) {
|
|
1376
|
+
properties.push(property);
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
const propertyKey = ts.isShorthandPropertyAssignment(property)
|
|
1380
|
+
? property.name.text
|
|
1381
|
+
: (ts.isPropertyAssignment(property) ? getPropertyNameKey(context, property.name) : undefined);
|
|
1382
|
+
if (propertyKey !== key) {
|
|
1383
|
+
properties.push(property);
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
replaced = true;
|
|
1387
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
1388
|
+
properties.push(createObjectLiteralMemberAssignment(key, value));
|
|
1389
|
+
}
|
|
1390
|
+
else if (ts.isPropertyAssignment(property)) {
|
|
1391
|
+
properties.push(ts.factory.createPropertyAssignment(property.name, value));
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
properties.push(property);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
if (!replaced) {
|
|
1398
|
+
properties.push(createObjectLiteralMemberAssignment(key, value));
|
|
1399
|
+
}
|
|
1400
|
+
return ts.factory.createObjectLiteralExpression(properties, false);
|
|
1401
|
+
}
|
|
1402
|
+
function updateArrayLiteralMemberValue(arrayLiteral, key, value) {
|
|
1403
|
+
if (!/^\d+$/.test(key)) {
|
|
1404
|
+
return undefined;
|
|
1405
|
+
}
|
|
1406
|
+
const index = Number(key);
|
|
1407
|
+
const elements = [...arrayLiteral.elements];
|
|
1408
|
+
while (elements.length <= index) {
|
|
1409
|
+
elements.push(ts.factory.createOmittedExpression());
|
|
1410
|
+
}
|
|
1411
|
+
elements[index] = value;
|
|
1412
|
+
return ts.factory.createArrayLiteralExpression(elements, false);
|
|
1413
|
+
}
|
|
1414
|
+
function getAssignmentMemberTargetRoot(context, receiver) {
|
|
1415
|
+
const unwrappedReceiver = unwrapFlowTransparentExpression(receiver);
|
|
1416
|
+
if (ts.isIdentifier(unwrappedReceiver) || isThisExpression(unwrappedReceiver)) {
|
|
1417
|
+
return { root: unwrappedReceiver, segments: [] };
|
|
1418
|
+
}
|
|
1419
|
+
if (ts.isPropertyAccessExpression(unwrappedReceiver)) {
|
|
1420
|
+
const parent = getAssignmentMemberTargetRoot(context, unwrappedReceiver.expression);
|
|
1421
|
+
return parent
|
|
1422
|
+
? {
|
|
1423
|
+
root: parent.root,
|
|
1424
|
+
segments: [...parent.segments, getMemberNameText(unwrappedReceiver.name)],
|
|
1425
|
+
}
|
|
1426
|
+
: undefined;
|
|
1427
|
+
}
|
|
1428
|
+
if (ts.isElementAccessExpression(unwrappedReceiver)) {
|
|
1429
|
+
const key = getElementAccessKey(context, unwrappedReceiver.argumentExpression);
|
|
1430
|
+
if (!key) {
|
|
1431
|
+
return undefined;
|
|
1432
|
+
}
|
|
1433
|
+
const parent = getAssignmentMemberTargetRoot(context, unwrappedReceiver.expression);
|
|
1434
|
+
return parent
|
|
1435
|
+
? {
|
|
1436
|
+
root: parent.root,
|
|
1437
|
+
segments: [...parent.segments, key],
|
|
1438
|
+
}
|
|
1439
|
+
: undefined;
|
|
1440
|
+
}
|
|
1441
|
+
return undefined;
|
|
1442
|
+
}
|
|
1443
|
+
function createNestedBoundValueExpression(segments, value) {
|
|
1444
|
+
if (segments.length === 0) {
|
|
1445
|
+
return value;
|
|
1446
|
+
}
|
|
1447
|
+
const [segment, ...rest] = segments;
|
|
1448
|
+
const nestedValue = createNestedBoundValueExpression(rest, value);
|
|
1449
|
+
if (/^\d+$/.test(segment)) {
|
|
1450
|
+
const elements = [];
|
|
1451
|
+
for (let index = 0; index < Number(segment); index++) {
|
|
1452
|
+
elements.push(createClearedBoundValueExpression());
|
|
1453
|
+
}
|
|
1454
|
+
elements.push(nestedValue);
|
|
1455
|
+
return ts.factory.createArrayLiteralExpression(elements, false);
|
|
1456
|
+
}
|
|
1457
|
+
return ts.factory.createObjectLiteralExpression([createObjectLiteralMemberAssignment(segment, nestedValue)], false);
|
|
1458
|
+
}
|
|
1459
|
+
function updateBoundValueAtSegments(context, value, segments, updatedLeafValue) {
|
|
1460
|
+
if (segments.length === 0) {
|
|
1461
|
+
return updatedLeafValue;
|
|
1462
|
+
}
|
|
1463
|
+
const [segment, ...rest] = segments;
|
|
1464
|
+
const unwrappedValue = value && ts.isExpression(value)
|
|
1465
|
+
? unwrapFlowTransparentExpression(value)
|
|
1466
|
+
: undefined;
|
|
1467
|
+
const existingMemberValue = unwrappedValue
|
|
1468
|
+
? getLiteralMemberValue(unwrappedValue, segment)
|
|
1469
|
+
: undefined;
|
|
1470
|
+
const updatedMemberValue = updateBoundValueAtSegments(context, existingMemberValue, rest, updatedLeafValue);
|
|
1471
|
+
if (unwrappedValue && ts.isObjectLiteralExpression(unwrappedValue)) {
|
|
1472
|
+
const updatedObjectLiteral = updateObjectLiteralMemberValue(context, unwrappedValue, segment, updatedMemberValue);
|
|
1473
|
+
if (updatedObjectLiteral) {
|
|
1474
|
+
return updatedObjectLiteral;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
if (unwrappedValue && ts.isArrayLiteralExpression(unwrappedValue)) {
|
|
1478
|
+
const updatedArrayLiteral = updateArrayLiteralMemberValue(unwrappedValue, segment, updatedMemberValue);
|
|
1479
|
+
if (updatedArrayLiteral) {
|
|
1480
|
+
return updatedArrayLiteral;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
return createNestedBoundValueExpression(segments, updatedLeafValue);
|
|
1484
|
+
}
|
|
1485
|
+
function recordVariableAssignmentMemberTarget(context, receiver, key, argumentValue, state) {
|
|
1486
|
+
const receiverRoot = getAssignmentMemberTargetRoot(context, receiver);
|
|
1487
|
+
if (!receiverRoot) {
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
const symbol = getExpressionSymbol(context, receiverRoot.root);
|
|
1491
|
+
if (!symbol) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1495
|
+
const updatedMemberValue = getRecordedBoundValueExpression(argumentValue);
|
|
1496
|
+
const updatedReceiverValue = updateBoundValueAtSegments(context, state.boundValues.get(symbolId), [...receiverRoot.segments, key], updatedMemberValue);
|
|
1497
|
+
state.boundValues.set(symbolId, updatedReceiverValue);
|
|
1498
|
+
}
|
|
1499
|
+
function recordVariableAssignmentIdentifier(context, name, argumentPath, argumentValue, state) {
|
|
1500
|
+
setVariableBindingIdentifier(context, name, argumentPath, argumentValue, state);
|
|
1501
|
+
const symbol = getExpressionSymbol(context, name);
|
|
1502
|
+
if (!symbol) {
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
recordSpreadAlias(context, getSymbolId(context, symbol), argumentValue, state);
|
|
1506
|
+
}
|
|
1507
|
+
function recordVariableAssignmentShorthandProperty(context, property, argumentPath, argumentValue, state) {
|
|
1508
|
+
const symbol = getShorthandAssignmentTargetSymbol(context, property);
|
|
1509
|
+
if (!symbol) {
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
const valuePath = argumentValue && ts.isExpression(argumentValue)
|
|
1513
|
+
? normalizeExpressionPath(context, argumentValue, state)
|
|
1514
|
+
: undefined;
|
|
1515
|
+
const aliasPath = valuePath ?? argumentPath;
|
|
1516
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1517
|
+
if (aliasPath) {
|
|
1518
|
+
if (shouldExtractConstAlias(context, symbol, aliasPath)) {
|
|
1519
|
+
state.extractedBindings.set(symbolId, aliasPath);
|
|
1520
|
+
}
|
|
1521
|
+
else {
|
|
1522
|
+
state.aliases.set(symbolId, aliasPath);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (argumentValue) {
|
|
1526
|
+
state.boundValues.set(symbolId, argumentValue);
|
|
1527
|
+
}
|
|
1528
|
+
recordSpreadAlias(context, symbolId, argumentValue, state);
|
|
1529
|
+
}
|
|
1530
|
+
function clearVariableAssignmentTarget(context, target, state) {
|
|
1531
|
+
const unwrappedTarget = getAssignmentPatternTarget(target);
|
|
1532
|
+
if (ts.isIdentifier(unwrappedTarget)) {
|
|
1533
|
+
clearVariableBindingIdentifier(context, unwrappedTarget, state);
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
if (ts.isObjectLiteralExpression(unwrappedTarget)) {
|
|
1537
|
+
for (const property of unwrappedTarget.properties) {
|
|
1538
|
+
if (ts.isSpreadAssignment(property)) {
|
|
1539
|
+
clearVariableAssignmentTarget(context, property.expression, state);
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
1543
|
+
const symbol = getShorthandAssignmentTargetSymbol(context, property);
|
|
1544
|
+
if (symbol) {
|
|
1545
|
+
clearVariableBindingSymbol(context, symbol, state);
|
|
1546
|
+
}
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
if (ts.isPropertyAssignment(property)) {
|
|
1550
|
+
clearVariableAssignmentTarget(context, property.initializer, state);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
if (ts.isArrayLiteralExpression(unwrappedTarget)) {
|
|
1556
|
+
for (const element of unwrappedTarget.elements) {
|
|
1557
|
+
if (ts.isOmittedExpression(element)) {
|
|
1558
|
+
continue;
|
|
1559
|
+
}
|
|
1560
|
+
if (ts.isSpreadElement(element)) {
|
|
1561
|
+
clearVariableAssignmentTarget(context, element.expression, state);
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
clearVariableAssignmentTarget(context, element, state);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
function recordVariableAssignmentTarget(context, target, argumentPath, argumentValue, state) {
|
|
1569
|
+
const unwrappedTarget = getAssignmentPatternTarget(target);
|
|
1570
|
+
if (ts.isIdentifier(unwrappedTarget)) {
|
|
1571
|
+
recordVariableAssignmentIdentifier(context, unwrappedTarget, argumentPath, argumentValue, state);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
if (ts.isPropertyAccessExpression(unwrappedTarget)) {
|
|
1575
|
+
recordVariableAssignmentMemberTarget(context, unwrappedTarget.expression, getMemberNameText(unwrappedTarget.name), argumentValue, state);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
if (ts.isElementAccessExpression(unwrappedTarget)) {
|
|
1579
|
+
const key = getElementAccessKey(context, unwrappedTarget.argumentExpression);
|
|
1580
|
+
if (key) {
|
|
1581
|
+
recordVariableAssignmentMemberTarget(context, unwrappedTarget.expression, key, argumentValue, state);
|
|
1582
|
+
}
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
if (ts.isObjectLiteralExpression(unwrappedTarget)) {
|
|
1586
|
+
const excludedKeys = unwrappedTarget.properties
|
|
1587
|
+
.filter((property) => !ts.isSpreadAssignment(property))
|
|
1588
|
+
.map((property) => getObjectAssignmentPropertyKey(context, property))
|
|
1589
|
+
.filter((key) => key !== undefined);
|
|
1590
|
+
for (const property of unwrappedTarget.properties) {
|
|
1591
|
+
if (ts.isSpreadAssignment(property)) {
|
|
1592
|
+
if (ts.isIdentifier(property.expression)) {
|
|
1593
|
+
const symbol = getExpressionSymbol(context, property.expression);
|
|
1594
|
+
if (symbol) {
|
|
1595
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1596
|
+
state.objectRestAliases.set(symbolId, {
|
|
1597
|
+
excludedKeys,
|
|
1598
|
+
path: argumentPath,
|
|
1599
|
+
value: argumentValue,
|
|
1600
|
+
});
|
|
1601
|
+
if (argumentValue) {
|
|
1602
|
+
state.boundValues.set(symbolId, argumentValue);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
if (!ts.isShorthandPropertyAssignment(property) && !ts.isPropertyAssignment(property)) {
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
const key = getObjectAssignmentPropertyKey(context, property);
|
|
1612
|
+
if (!key) {
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
const propertyPath = argumentPath
|
|
1616
|
+
? {
|
|
1617
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
1618
|
+
segments: [...argumentPath.segments, key],
|
|
1619
|
+
}
|
|
1620
|
+
: undefined;
|
|
1621
|
+
const propertyValue = getLiteralMemberValue(argumentValue, key);
|
|
1622
|
+
const recoveredPropertyPath = argumentValue && ts.isExpression(argumentValue)
|
|
1623
|
+
? getExpressionMemberPath(context, argumentValue, key, state)
|
|
1624
|
+
: undefined;
|
|
1625
|
+
const propertyTarget = ts.isShorthandPropertyAssignment(property) ? property.name : property.initializer;
|
|
1626
|
+
const defaultPath = ts.isShorthandPropertyAssignment(property) && property.objectAssignmentInitializer
|
|
1627
|
+
? normalizeExpressionPath(context, property.objectAssignmentInitializer, state)
|
|
1628
|
+
: getAssignmentPatternDefaultPath(context, propertyTarget, state);
|
|
1629
|
+
const defaultValue = ts.isShorthandPropertyAssignment(property) && property.objectAssignmentInitializer
|
|
1630
|
+
? (getExpressionLiteralValue(context, property.objectAssignmentInitializer, state) ??
|
|
1631
|
+
property.objectAssignmentInitializer)
|
|
1632
|
+
: getAssignmentPatternDefaultValue(context, propertyTarget, state);
|
|
1633
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
1634
|
+
ts.isExpression(argumentValue) &&
|
|
1635
|
+
propertyValue === undefined &&
|
|
1636
|
+
recoveredPropertyPath === undefined &&
|
|
1637
|
+
defaultValue !== undefined;
|
|
1638
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
1639
|
+
recordVariableAssignmentShorthandProperty(context, property, shouldUseDefault ? defaultPath : (recoveredPropertyPath ?? propertyPath), shouldUseDefault ? defaultValue : propertyValue, state);
|
|
1640
|
+
continue;
|
|
1641
|
+
}
|
|
1642
|
+
recordVariableAssignmentTarget(context, propertyTarget, shouldUseDefault ? defaultPath : (recoveredPropertyPath ?? propertyPath), shouldUseDefault ? defaultValue : propertyValue, state);
|
|
1643
|
+
}
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
if (!ts.isArrayLiteralExpression(unwrappedTarget)) {
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
unwrappedTarget.elements.forEach((element, index) => {
|
|
1650
|
+
if (ts.isOmittedExpression(element)) {
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
if (ts.isSpreadElement(element)) {
|
|
1654
|
+
const arrayArgumentValue = getLiteralArrayValue(argumentValue);
|
|
1655
|
+
if (ts.isIdentifier(element.expression)) {
|
|
1656
|
+
const symbol = getExpressionSymbol(context, element.expression);
|
|
1657
|
+
if (symbol) {
|
|
1658
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1659
|
+
state.arrayRestAliases.set(symbolId, {
|
|
1660
|
+
offset: index,
|
|
1661
|
+
path: argumentPath,
|
|
1662
|
+
value: arrayArgumentValue,
|
|
1663
|
+
});
|
|
1664
|
+
if (arrayArgumentValue) {
|
|
1665
|
+
state.boundValues.set(symbolId, arrayArgumentValue);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
const elementPath = argumentPath
|
|
1672
|
+
? {
|
|
1673
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
1674
|
+
segments: [...argumentPath.segments, String(index)],
|
|
1675
|
+
}
|
|
1676
|
+
: undefined;
|
|
1677
|
+
const elementValue = getLiteralMemberValue(argumentValue, String(index));
|
|
1678
|
+
const recoveredElementPath = argumentValue && ts.isExpression(argumentValue)
|
|
1679
|
+
? getExpressionMemberPath(context, argumentValue, String(index), state)
|
|
1680
|
+
: undefined;
|
|
1681
|
+
const defaultPath = getAssignmentPatternDefaultPath(context, element, state);
|
|
1682
|
+
const defaultValue = getAssignmentPatternDefaultValue(context, element, state);
|
|
1683
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
1684
|
+
ts.isExpression(argumentValue) &&
|
|
1685
|
+
elementValue === undefined &&
|
|
1686
|
+
recoveredElementPath === undefined &&
|
|
1687
|
+
defaultValue !== undefined;
|
|
1688
|
+
recordVariableAssignmentTarget(context, element, shouldUseDefault ? defaultPath : (recoveredElementPath ?? elementPath), shouldUseDefault ? defaultValue : elementValue, state);
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
function recordAssignmentExpressionAliases(context, assignment, state) {
|
|
1692
|
+
if (assignment.operatorToken.kind !== ts.SyntaxKind.EqualsToken) {
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
clearVariableAssignmentTarget(context, assignment.left, state);
|
|
1696
|
+
const value = getExpressionLiteralValue(context, assignment.right, state) ?? assignment.right;
|
|
1697
|
+
const path = normalizeExpressionPath(context, assignment.right, state);
|
|
1698
|
+
recordVariableAssignmentTarget(context, assignment.left, path, value, state);
|
|
1699
|
+
}
|
|
1700
|
+
export function recordExecutedExpressionAliases(context, expression, state) {
|
|
1701
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
1702
|
+
if (!ts.isBinaryExpression(unwrappedExpression)) {
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
if (unwrappedExpression.operatorToken.kind === ts.SyntaxKind.CommaToken) {
|
|
1706
|
+
recordExecutedExpressionAliases(context, unwrappedExpression.left, state);
|
|
1707
|
+
recordExecutedExpressionAliases(context, unwrappedExpression.right, state);
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
recordAssignmentExpressionAliases(context, unwrappedExpression, state);
|
|
1711
|
+
}
|
|
1712
|
+
function getLiteralMemberValue(value, key) {
|
|
1713
|
+
if (!value || !ts.isExpression(value)) {
|
|
1714
|
+
return undefined;
|
|
1715
|
+
}
|
|
1716
|
+
const unwrappedValue = unwrapFlowTransparentExpression(value);
|
|
1717
|
+
if (ts.isObjectLiteralExpression(unwrappedValue)) {
|
|
1718
|
+
return getObjectLiteralPropertyValue(unwrappedValue, key);
|
|
1719
|
+
}
|
|
1720
|
+
if (ts.isArrayLiteralExpression(unwrappedValue) && /^\d+$/.test(key)) {
|
|
1721
|
+
return getArrayLiteralElementExpression(unwrappedValue, Number(key));
|
|
1722
|
+
}
|
|
1723
|
+
return undefined;
|
|
1724
|
+
}
|
|
1725
|
+
function getLiteralArrayValue(value) {
|
|
1726
|
+
if (!value || !ts.isExpression(value)) {
|
|
1727
|
+
return undefined;
|
|
1728
|
+
}
|
|
1729
|
+
const unwrappedValue = unwrapFlowTransparentExpression(value);
|
|
1730
|
+
return ts.isArrayLiteralExpression(unwrappedValue) ? unwrappedValue : undefined;
|
|
1731
|
+
}
|
|
1732
|
+
function getDefaultBindingPath(context, element, state) {
|
|
1733
|
+
return element.initializer
|
|
1734
|
+
? normalizeExpressionPath(context, element.initializer, state)
|
|
1735
|
+
: undefined;
|
|
1736
|
+
}
|
|
1737
|
+
function getDefaultBindingValue(context, element, state) {
|
|
1738
|
+
return element.initializer
|
|
1739
|
+
? (getExpressionLiteralValue(context, element.initializer, state) ?? element.initializer)
|
|
1740
|
+
: undefined;
|
|
1741
|
+
}
|
|
1742
|
+
function getFunctionDefaultBindingPath(context, element, bindings) {
|
|
1743
|
+
return element.initializer
|
|
1744
|
+
? (normalizeFunctionBodyPath(context, element.initializer, bindings) ??
|
|
1745
|
+
normalizeExpressionPath(context, element.initializer, bindings.sourceState))
|
|
1746
|
+
: undefined;
|
|
1747
|
+
}
|
|
1748
|
+
function getFunctionDefaultBindingValue(context, element, bindings) {
|
|
1749
|
+
if (!element.initializer) {
|
|
1750
|
+
return undefined;
|
|
1751
|
+
}
|
|
1752
|
+
const boundValue = getBoundValue(context, element.initializer, bindings);
|
|
1753
|
+
return boundValue ?? element.initializer;
|
|
1754
|
+
}
|
|
1755
|
+
function setVariableBindingIdentifier(context, name, argumentPath, argumentValue, state) {
|
|
1756
|
+
const symbol = getExpressionSymbol(context, name);
|
|
1757
|
+
if (!symbol) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
const valuePath = argumentValue && ts.isExpression(argumentValue)
|
|
1761
|
+
? normalizeExpressionPath(context, argumentValue, state)
|
|
1762
|
+
: undefined;
|
|
1763
|
+
const aliasPath = valuePath ?? argumentPath;
|
|
1764
|
+
if (aliasPath) {
|
|
1765
|
+
const symbolId = getSymbolId(context, symbol);
|
|
1766
|
+
if (shouldExtractConstAlias(context, symbol, aliasPath)) {
|
|
1767
|
+
state.extractedBindings.set(symbolId, aliasPath);
|
|
1768
|
+
}
|
|
1769
|
+
else {
|
|
1770
|
+
state.aliases.set(symbolId, aliasPath);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
if (argumentValue) {
|
|
1774
|
+
state.boundValues.set(getSymbolId(context, symbol), argumentValue);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
function recordVariableBindingElement(context, element, argumentPath, argumentValue, state) {
|
|
1778
|
+
recordVariableBindingName(context, element.name, argumentPath, argumentValue ?? getDefaultBindingValue(context, element, state), state);
|
|
1779
|
+
}
|
|
1780
|
+
function recordVariableBindingName(context, name, argumentPath, argumentValue, state) {
|
|
1781
|
+
if (ts.isIdentifier(name)) {
|
|
1782
|
+
setVariableBindingIdentifier(context, name, argumentPath, argumentValue, state);
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
if (ts.isObjectBindingPattern(name)) {
|
|
1786
|
+
const excludedKeys = name.elements
|
|
1787
|
+
.filter((element) => !element.dotDotDotToken)
|
|
1788
|
+
.map((element) => getObjectBindingElementKey(context, element))
|
|
1789
|
+
.filter((key) => key !== undefined);
|
|
1790
|
+
for (const element of name.elements) {
|
|
1791
|
+
if (element.dotDotDotToken) {
|
|
1792
|
+
if (ts.isIdentifier(element.name)) {
|
|
1793
|
+
const symbol = getExpressionSymbol(context, element.name);
|
|
1794
|
+
if (symbol) {
|
|
1795
|
+
state.objectRestAliases.set(getSymbolId(context, symbol), {
|
|
1796
|
+
excludedKeys,
|
|
1797
|
+
path: argumentPath,
|
|
1798
|
+
value: argumentValue,
|
|
1799
|
+
});
|
|
1800
|
+
if (argumentValue) {
|
|
1801
|
+
state.boundValues.set(getSymbolId(context, symbol), argumentValue);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
continue;
|
|
1806
|
+
}
|
|
1807
|
+
const key = getObjectBindingElementKey(context, element);
|
|
1808
|
+
if (!key) {
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
const propertyPath = argumentPath
|
|
1812
|
+
? {
|
|
1813
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
1814
|
+
segments: [...argumentPath.segments, key],
|
|
1815
|
+
}
|
|
1816
|
+
: undefined;
|
|
1817
|
+
const propertyValue = getLiteralMemberValue(argumentValue, key);
|
|
1818
|
+
const recoveredPropertyPath = argumentValue && ts.isExpression(argumentValue)
|
|
1819
|
+
? getExpressionMemberPath(context, argumentValue, key, state)
|
|
1820
|
+
: undefined;
|
|
1821
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
1822
|
+
ts.isExpression(argumentValue) &&
|
|
1823
|
+
propertyValue === undefined &&
|
|
1824
|
+
recoveredPropertyPath === undefined &&
|
|
1825
|
+
element.initializer !== undefined;
|
|
1826
|
+
recordVariableBindingElement(context, element, shouldUseDefault
|
|
1827
|
+
? getDefaultBindingPath(context, element, state)
|
|
1828
|
+
: (recoveredPropertyPath ?? propertyPath), shouldUseDefault ? getDefaultBindingValue(context, element, state) : propertyValue, state);
|
|
1829
|
+
}
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
name.elements.forEach((element, index) => {
|
|
1833
|
+
if (!ts.isBindingElement(element)) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
if (element.dotDotDotToken) {
|
|
1837
|
+
const arrayArgumentValue = getLiteralArrayValue(argumentValue);
|
|
1838
|
+
if (ts.isIdentifier(element.name) && argumentPath) {
|
|
1839
|
+
const symbol = getExpressionSymbol(context, element.name);
|
|
1840
|
+
if (symbol) {
|
|
1841
|
+
state.arrayRestAliases.set(getSymbolId(context, symbol), {
|
|
1842
|
+
offset: index,
|
|
1843
|
+
path: argumentPath,
|
|
1844
|
+
value: arrayArgumentValue,
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
if (ts.isIdentifier(element.name) && !argumentPath && arrayArgumentValue) {
|
|
1849
|
+
const symbol = getExpressionSymbol(context, element.name);
|
|
1850
|
+
if (symbol) {
|
|
1851
|
+
state.arrayRestAliases.set(getSymbolId(context, symbol), {
|
|
1852
|
+
offset: index,
|
|
1853
|
+
path: undefined,
|
|
1854
|
+
value: arrayArgumentValue,
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
const elementPath = argumentPath
|
|
1861
|
+
? {
|
|
1862
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
1863
|
+
segments: [...argumentPath.segments, String(index)],
|
|
1864
|
+
}
|
|
1865
|
+
: undefined;
|
|
1866
|
+
const elementValue = getLiteralMemberValue(argumentValue, String(index));
|
|
1867
|
+
const recoveredElementPath = argumentValue && ts.isExpression(argumentValue)
|
|
1868
|
+
? getExpressionMemberPath(context, argumentValue, String(index), state)
|
|
1869
|
+
: undefined;
|
|
1870
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
1871
|
+
ts.isExpression(argumentValue) &&
|
|
1872
|
+
elementValue === undefined &&
|
|
1873
|
+
recoveredElementPath === undefined &&
|
|
1874
|
+
element.initializer !== undefined;
|
|
1875
|
+
recordVariableBindingElement(context, element, shouldUseDefault
|
|
1876
|
+
? getDefaultBindingPath(context, element, state)
|
|
1877
|
+
: (recoveredElementPath ?? elementPath), shouldUseDefault ? getDefaultBindingValue(context, element, state) : elementValue, state);
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
export function recordForOfLoopHeaderAliases(context, bindingName, iterableExpression, state) {
|
|
1881
|
+
const iterableValue = getExpressionLiteralValue(context, iterableExpression, state) ?? iterableExpression;
|
|
1882
|
+
const unwrappedIterable = ts.isExpression(iterableValue)
|
|
1883
|
+
? unwrapFlowTransparentExpression(iterableValue)
|
|
1884
|
+
: iterableValue;
|
|
1885
|
+
if (!ts.isArrayLiteralExpression(unwrappedIterable)) {
|
|
1886
|
+
return false;
|
|
1887
|
+
}
|
|
1888
|
+
let representativePath;
|
|
1889
|
+
let representativeValue;
|
|
1890
|
+
let sawElement = false;
|
|
1891
|
+
for (const element of unwrappedIterable.elements) {
|
|
1892
|
+
if (ts.isSpreadElement(element) || ts.isOmittedExpression(element)) {
|
|
1893
|
+
return false;
|
|
1894
|
+
}
|
|
1895
|
+
const elementPath = normalizeExpressionPath(context, element, state);
|
|
1896
|
+
const elementValue = getExpressionLiteralValue(context, element, state) ?? element;
|
|
1897
|
+
if (!sawElement) {
|
|
1898
|
+
representativePath = elementPath;
|
|
1899
|
+
representativeValue = elementValue;
|
|
1900
|
+
sawElement = true;
|
|
1901
|
+
continue;
|
|
1902
|
+
}
|
|
1903
|
+
const samePath = representativePath && elementPath && pathsMatch(representativePath, elementPath);
|
|
1904
|
+
const bothNoPath = representativePath === undefined && elementPath === undefined;
|
|
1905
|
+
if (!samePath && !bothNoPath) {
|
|
1906
|
+
return false;
|
|
1907
|
+
}
|
|
1908
|
+
if (representativeValue !== undefined &&
|
|
1909
|
+
elementValue !== undefined &&
|
|
1910
|
+
!recoveredValuesMatchWith(context, representativeValue, elementValue, (expression) => normalizeExpressionPath(context, expression, state), (expression) => getStateBoundValue(context, expression, state))) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
if (!sawElement) {
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
recordVariableBindingName(context, bindingName, representativePath, representativeValue, state);
|
|
1918
|
+
return true;
|
|
1919
|
+
}
|
|
1920
|
+
export function getUniformArrayElementBindingFromFunctionBodyExpression(context, expression, bindings) {
|
|
1921
|
+
const expressionValue = getBoundValue(context, expression, bindings) ?? expression;
|
|
1922
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
1923
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
1924
|
+
: expressionValue;
|
|
1925
|
+
if (!ts.isArrayLiteralExpression(unwrappedExpression)) {
|
|
1926
|
+
return undefined;
|
|
1927
|
+
}
|
|
1928
|
+
let representativePath;
|
|
1929
|
+
let representativeValue;
|
|
1930
|
+
let sawElement = false;
|
|
1931
|
+
for (const element of unwrappedExpression.elements) {
|
|
1932
|
+
if (ts.isSpreadElement(element) || ts.isOmittedExpression(element)) {
|
|
1933
|
+
return undefined;
|
|
1934
|
+
}
|
|
1935
|
+
const elementPath = resolveFunctionAliasValuePath(context, element, bindings);
|
|
1936
|
+
const elementValue = getBoundValue(context, element, bindings) ?? element;
|
|
1937
|
+
if (!sawElement) {
|
|
1938
|
+
representativePath = elementPath;
|
|
1939
|
+
representativeValue = elementValue;
|
|
1940
|
+
sawElement = true;
|
|
1941
|
+
continue;
|
|
1942
|
+
}
|
|
1943
|
+
const samePath = representativePath && elementPath && pathsMatch(representativePath, elementPath);
|
|
1944
|
+
const bothNoPath = representativePath === undefined && elementPath === undefined;
|
|
1945
|
+
if (!samePath && !bothNoPath) {
|
|
1946
|
+
return undefined;
|
|
1947
|
+
}
|
|
1948
|
+
if (representativeValue !== undefined &&
|
|
1949
|
+
elementValue !== undefined &&
|
|
1950
|
+
!recoveredValuesMatchWith(context, representativeValue, elementValue, (candidate) => resolveFunctionAliasValuePath(context, candidate, bindings), (candidate) => getBoundValue(context, candidate, bindings))) {
|
|
1951
|
+
return undefined;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
return sawElement ? { path: representativePath, value: representativeValue } : undefined;
|
|
1955
|
+
}
|
|
1956
|
+
export function getUniformSetElementBindingFromFunctionBodyExpression(context, expression, bindings) {
|
|
1957
|
+
const expressionValue = getBoundValue(context, expression, bindings) ?? expression;
|
|
1958
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
1959
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
1960
|
+
: expressionValue;
|
|
1961
|
+
if (!ts.isNewExpression(unwrappedExpression) || !isBuiltinSetConstruction(context, unwrappedExpression)) {
|
|
1962
|
+
return undefined;
|
|
1963
|
+
}
|
|
1964
|
+
const [iterableArgument] = unwrappedExpression.arguments ?? [];
|
|
1965
|
+
if (!iterableArgument) {
|
|
1966
|
+
return undefined;
|
|
1967
|
+
}
|
|
1968
|
+
return getUniformArrayElementBindingFromFunctionBodyExpression(context, iterableArgument, bindings);
|
|
1969
|
+
}
|
|
1970
|
+
export function getUniformMapEntryBindingsFromFunctionBodyExpression(context, expression, bindings) {
|
|
1971
|
+
const expressionValue = getBoundValue(context, expression, bindings) ?? expression;
|
|
1972
|
+
const unwrappedExpression = ts.isExpression(expressionValue)
|
|
1973
|
+
? unwrapFlowTransparentExpression(expressionValue)
|
|
1974
|
+
: expressionValue;
|
|
1975
|
+
if (!ts.isNewExpression(unwrappedExpression) || !isBuiltinMapConstruction(context, unwrappedExpression)) {
|
|
1976
|
+
return undefined;
|
|
1977
|
+
}
|
|
1978
|
+
const [iterableArgument] = unwrappedExpression.arguments ?? [];
|
|
1979
|
+
if (!iterableArgument) {
|
|
1980
|
+
return undefined;
|
|
1981
|
+
}
|
|
1982
|
+
return getUniformMapEntryBindingsFromLiteral(context, iterableArgument, (candidate) => resolveFunctionAliasValuePath(context, candidate, bindings), (candidate) => getBoundValue(context, candidate, bindings));
|
|
1983
|
+
}
|
|
1984
|
+
export function getMutableBindingSymbol(path) {
|
|
1985
|
+
if (path.segments.length !== 0) {
|
|
1986
|
+
return undefined;
|
|
1987
|
+
}
|
|
1988
|
+
const declaration = path.baseSymbol.valueDeclaration;
|
|
1989
|
+
if (declaration &&
|
|
1990
|
+
ts.isVariableDeclaration(declaration) &&
|
|
1991
|
+
declaration.parent &&
|
|
1992
|
+
ts.isVariableDeclarationList(declaration.parent) &&
|
|
1993
|
+
(declaration.parent.flags & ts.NodeFlags.Const) === 0) {
|
|
1994
|
+
return path.baseSymbol;
|
|
1995
|
+
}
|
|
1996
|
+
return undefined;
|
|
1997
|
+
}
|
|
1998
|
+
export function isLocalBindingPath(path) {
|
|
1999
|
+
if (path.segments.length !== 0) {
|
|
2000
|
+
return false;
|
|
2001
|
+
}
|
|
2002
|
+
const declaration = path.baseSymbol.valueDeclaration;
|
|
2003
|
+
return declaration !== undefined &&
|
|
2004
|
+
(ts.isVariableDeclaration(declaration) || ts.isParameter(declaration));
|
|
2005
|
+
}
|
|
2006
|
+
export function isConstLocalBindingPath(path) {
|
|
2007
|
+
if (path.segments.length !== 0) {
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
const declaration = path.baseSymbol.valueDeclaration;
|
|
2011
|
+
if (declaration === undefined ||
|
|
2012
|
+
(!ts.isVariableDeclaration(declaration) && !ts.isBindingElement(declaration))) {
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
return isConstValueDeclaration(path.baseSymbol);
|
|
2016
|
+
}
|
|
2017
|
+
export function isStableConstLocalBindingPath(context, path) {
|
|
2018
|
+
return isConstLocalBindingPath(path) && !constBindingMayAliasMutableState(context, path.baseSymbol);
|
|
2019
|
+
}
|
|
2020
|
+
export function getFunctionLikeFromExpression(context, expression) {
|
|
2021
|
+
if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
|
|
2022
|
+
return expression;
|
|
2023
|
+
}
|
|
2024
|
+
if (!ts.isIdentifier(expression)) {
|
|
2025
|
+
return undefined;
|
|
2026
|
+
}
|
|
2027
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
2028
|
+
if (!symbol) {
|
|
2029
|
+
return undefined;
|
|
2030
|
+
}
|
|
2031
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
2032
|
+
if (ts.isFunctionDeclaration(declaration) && declaration.body) {
|
|
2033
|
+
return declaration;
|
|
2034
|
+
}
|
|
2035
|
+
if (ts.isVariableDeclaration(declaration) &&
|
|
2036
|
+
declaration.initializer &&
|
|
2037
|
+
(ts.isArrowFunction(declaration.initializer) ||
|
|
2038
|
+
ts.isFunctionExpression(declaration.initializer))) {
|
|
2039
|
+
return declaration.initializer;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
return undefined;
|
|
2043
|
+
}
|
|
2044
|
+
function getBoundValue(context, expression, bindings) {
|
|
2045
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
2046
|
+
const equivalentValue = getFunctionEquivalentExpressionValue(context, expression, bindings);
|
|
2047
|
+
if (equivalentValue) {
|
|
2048
|
+
return equivalentValue;
|
|
2049
|
+
}
|
|
2050
|
+
if (ts.isIdentifier(expression)) {
|
|
2051
|
+
const symbol = getExpressionSymbol(context, expression);
|
|
2052
|
+
return symbol ? bindings.boundValues.get(getSymbolId(context, symbol)) : undefined;
|
|
2053
|
+
}
|
|
2054
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
2055
|
+
const receiverValue = getBoundValue(context, expression.expression, bindings);
|
|
2056
|
+
return receiverValue
|
|
2057
|
+
? getLiteralMemberValue(receiverValue, getMemberNameText(expression.name))
|
|
2058
|
+
: undefined;
|
|
2059
|
+
}
|
|
2060
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
2061
|
+
const key = getFunctionBodyElementAccessKey(context, expression.argumentExpression, bindings);
|
|
2062
|
+
if (!key) {
|
|
2063
|
+
return undefined;
|
|
2064
|
+
}
|
|
2065
|
+
const receiverValue = getBoundValue(context, expression.expression, bindings);
|
|
2066
|
+
return receiverValue
|
|
2067
|
+
? getLiteralMemberValue(receiverValue, key)
|
|
2068
|
+
: undefined;
|
|
2069
|
+
}
|
|
2070
|
+
return undefined;
|
|
2071
|
+
}
|
|
2072
|
+
export function getFunctionLikeFromBoundValue(context, value) {
|
|
2073
|
+
if (!ts.isExpression(value)) {
|
|
2074
|
+
return isFunctionLikeWithBody(value) ? value : undefined;
|
|
2075
|
+
}
|
|
2076
|
+
return getFunctionLikeFromExpression(context, value);
|
|
2077
|
+
}
|
|
2078
|
+
export function getFunctionLikeFromCallExpression(context, callExpression) {
|
|
2079
|
+
const declaration = context.checker.getResolvedSignature(callExpression)?.declaration;
|
|
2080
|
+
if (declaration && isFunctionLikeWithBody(declaration)) {
|
|
2081
|
+
return declaration;
|
|
2082
|
+
}
|
|
2083
|
+
return getFunctionLikeFromExpression(context, callExpression.expression);
|
|
2084
|
+
}
|
|
2085
|
+
function mapsHaveSamePaths(left, right) {
|
|
2086
|
+
if (left.size !== right.size) {
|
|
2087
|
+
return false;
|
|
2088
|
+
}
|
|
2089
|
+
for (const [key, path] of left) {
|
|
2090
|
+
const otherPath = right.get(key);
|
|
2091
|
+
if (!otherPath || !pathsMatch(path, otherPath)) {
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
return true;
|
|
2096
|
+
}
|
|
2097
|
+
function flowCallResultShapesMatch(left, right) {
|
|
2098
|
+
if (left.kind !== right.kind) {
|
|
2099
|
+
return false;
|
|
2100
|
+
}
|
|
2101
|
+
switch (left.kind) {
|
|
2102
|
+
case 'path':
|
|
2103
|
+
return pathsMatch(left.path, right.path);
|
|
2104
|
+
case 'object':
|
|
2105
|
+
return mapsHaveSamePaths(left.members, right.members);
|
|
2106
|
+
case 'array':
|
|
2107
|
+
return mapsHaveSamePaths(left.elements, right.elements);
|
|
2108
|
+
default: {
|
|
2109
|
+
const exhaustiveCheck = left;
|
|
2110
|
+
return exhaustiveCheck;
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
function isDefinitelyNullishExpression(expression) {
|
|
2115
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
2116
|
+
return expression.kind === ts.SyntaxKind.NullKeyword ||
|
|
2117
|
+
(ts.isIdentifier(expression) && expression.text === 'undefined') ||
|
|
2118
|
+
ts.isVoidExpression(expression);
|
|
2119
|
+
}
|
|
2120
|
+
function combineEquivalentFlowCallResultSummaries(left, right) {
|
|
2121
|
+
if (left.shape && right.shape) {
|
|
2122
|
+
if (!flowCallResultShapesMatch(left.shape, right.shape)) {
|
|
2123
|
+
return undefined;
|
|
2124
|
+
}
|
|
2125
|
+
return {
|
|
2126
|
+
canBeNullish: left.canBeNullish || right.canBeNullish,
|
|
2127
|
+
shape: left.shape,
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
if (left.shape && right.canBeNullish) {
|
|
2131
|
+
return {
|
|
2132
|
+
canBeNullish: true,
|
|
2133
|
+
shape: left.shape,
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
if (right.shape && left.canBeNullish) {
|
|
2137
|
+
return {
|
|
2138
|
+
canBeNullish: true,
|
|
2139
|
+
shape: right.shape,
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
if (left.canBeNullish && right.canBeNullish) {
|
|
2143
|
+
return {
|
|
2144
|
+
canBeNullish: true,
|
|
2145
|
+
shape: undefined,
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
return undefined;
|
|
2149
|
+
}
|
|
2150
|
+
function getFlowCallResultSummaryFromExpression(context, expression, bindings) {
|
|
2151
|
+
expression = unwrapFlowTransparentExpression(expression);
|
|
2152
|
+
if (isDefinitelyNullishExpression(expression)) {
|
|
2153
|
+
return {
|
|
2154
|
+
canBeNullish: true,
|
|
2155
|
+
shape: undefined,
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
const boundValue = getBoundValue(context, expression, bindings);
|
|
2159
|
+
if (boundValue && ts.isExpression(boundValue) && boundValue !== expression) {
|
|
2160
|
+
const boundSummary = getFlowCallResultSummaryFromExpression(context, boundValue, bindings);
|
|
2161
|
+
if (boundSummary) {
|
|
2162
|
+
return boundSummary;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
const path = normalizeFunctionBodyPath(context, expression, bindings);
|
|
2166
|
+
if (path) {
|
|
2167
|
+
return {
|
|
2168
|
+
canBeNullish: false,
|
|
2169
|
+
shape: {
|
|
2170
|
+
kind: 'path',
|
|
2171
|
+
path,
|
|
2172
|
+
},
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
if (ts.isCallExpression(expression)) {
|
|
2176
|
+
return getFunctionCallExpressionResultSummary(context, expression, bindings);
|
|
2177
|
+
}
|
|
2178
|
+
if (ts.isBinaryExpression(expression) &&
|
|
2179
|
+
expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
2180
|
+
const leftSummary = getFlowCallResultSummaryFromExpression(context, expression.left, bindings) ??
|
|
2181
|
+
(isDefinitelyNullishExpression(expression.left)
|
|
2182
|
+
? { canBeNullish: true, shape: undefined }
|
|
2183
|
+
: undefined);
|
|
2184
|
+
const rightSummary = getFlowCallResultSummaryFromExpression(context, expression.right, bindings);
|
|
2185
|
+
if (!leftSummary || !rightSummary) {
|
|
2186
|
+
return undefined;
|
|
2187
|
+
}
|
|
2188
|
+
if (!leftSummary.canBeNullish && leftSummary.shape) {
|
|
2189
|
+
return leftSummary;
|
|
2190
|
+
}
|
|
2191
|
+
if (!leftSummary.shape) {
|
|
2192
|
+
return leftSummary.canBeNullish ? rightSummary : undefined;
|
|
2193
|
+
}
|
|
2194
|
+
if (!rightSummary.shape) {
|
|
2195
|
+
return undefined;
|
|
2196
|
+
}
|
|
2197
|
+
if (!flowCallResultShapesMatch(leftSummary.shape, rightSummary.shape)) {
|
|
2198
|
+
return undefined;
|
|
2199
|
+
}
|
|
2200
|
+
return {
|
|
2201
|
+
canBeNullish: rightSummary.canBeNullish,
|
|
2202
|
+
shape: leftSummary.shape,
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
const branches = getEquivalentExpressionBranches(expression);
|
|
2206
|
+
if (branches && !(ts.isBinaryExpression(expression) &&
|
|
2207
|
+
expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken)) {
|
|
2208
|
+
const [left, right] = branches;
|
|
2209
|
+
const leftSummary = getFlowCallResultSummaryFromExpression(context, left, bindings) ??
|
|
2210
|
+
(isDefinitelyNullishExpression(left)
|
|
2211
|
+
? { canBeNullish: true, shape: undefined }
|
|
2212
|
+
: undefined);
|
|
2213
|
+
const rightSummary = getFlowCallResultSummaryFromExpression(context, right, bindings) ??
|
|
2214
|
+
(isDefinitelyNullishExpression(right)
|
|
2215
|
+
? { canBeNullish: true, shape: undefined }
|
|
2216
|
+
: undefined);
|
|
2217
|
+
if (!leftSummary || !rightSummary) {
|
|
2218
|
+
return undefined;
|
|
2219
|
+
}
|
|
2220
|
+
return combineEquivalentFlowCallResultSummaries(leftSummary, rightSummary);
|
|
2221
|
+
}
|
|
2222
|
+
if (ts.isObjectLiteralExpression(expression)) {
|
|
2223
|
+
const members = new Map();
|
|
2224
|
+
for (const property of expression.properties) {
|
|
2225
|
+
let key;
|
|
2226
|
+
let memberPath;
|
|
2227
|
+
if (ts.isPropertyAssignment(property)) {
|
|
2228
|
+
key = getPropertyNameKey(context, property.name);
|
|
2229
|
+
if (key) {
|
|
2230
|
+
memberPath = resolveFunctionAliasValuePath(context, property.initializer, bindings);
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
else if (ts.isShorthandPropertyAssignment(property)) {
|
|
2234
|
+
key = property.name.text;
|
|
2235
|
+
memberPath = getShorthandFunctionBindingPath(context, property, bindings);
|
|
2236
|
+
}
|
|
2237
|
+
else {
|
|
2238
|
+
return undefined;
|
|
2239
|
+
}
|
|
2240
|
+
if (!key || !memberPath) {
|
|
2241
|
+
return undefined;
|
|
2242
|
+
}
|
|
2243
|
+
members.set(key, memberPath);
|
|
2244
|
+
}
|
|
2245
|
+
return {
|
|
2246
|
+
canBeNullish: false,
|
|
2247
|
+
shape: {
|
|
2248
|
+
kind: 'object',
|
|
2249
|
+
members,
|
|
2250
|
+
},
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
if (ts.isArrayLiteralExpression(expression)) {
|
|
2254
|
+
const elements = new Map();
|
|
2255
|
+
for (const [index, element] of expression.elements.entries()) {
|
|
2256
|
+
if (!element || ts.isOmittedExpression(element) || ts.isSpreadElement(element)) {
|
|
2257
|
+
return undefined;
|
|
2258
|
+
}
|
|
2259
|
+
const elementPath = resolveFunctionAliasValuePath(context, element, bindings);
|
|
2260
|
+
if (!elementPath) {
|
|
2261
|
+
return undefined;
|
|
2262
|
+
}
|
|
2263
|
+
elements.set(String(index), elementPath);
|
|
2264
|
+
}
|
|
2265
|
+
return {
|
|
2266
|
+
canBeNullish: false,
|
|
2267
|
+
shape: {
|
|
2268
|
+
elements,
|
|
2269
|
+
kind: 'array',
|
|
2270
|
+
},
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
return undefined;
|
|
2274
|
+
}
|
|
2275
|
+
function forEachFunctionReturnExpression(root, callback) {
|
|
2276
|
+
if (!ts.isBlock(root)) {
|
|
2277
|
+
return callback(root);
|
|
2278
|
+
}
|
|
2279
|
+
const visit = (node) => {
|
|
2280
|
+
if (node !== root && isFunctionLikeWithBody(node)) {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
2284
|
+
return callback(node.expression);
|
|
2285
|
+
}
|
|
2286
|
+
return ts.forEachChild(node, visit) ?? false;
|
|
2287
|
+
};
|
|
2288
|
+
return visit(root);
|
|
2289
|
+
}
|
|
2290
|
+
export function recordFunctionBodyConstBindings(context, body, bindings) {
|
|
2291
|
+
if (!ts.isBlock(body)) {
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
for (const statement of body.statements) {
|
|
2295
|
+
if (context.isGeneratedNode(statement)) {
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
2298
|
+
if (!ts.isVariableStatement(statement)) {
|
|
2299
|
+
continue;
|
|
2300
|
+
}
|
|
2301
|
+
if ((statement.declarationList.flags & ts.NodeFlags.Const) === 0) {
|
|
2302
|
+
continue;
|
|
2303
|
+
}
|
|
2304
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2305
|
+
if (!declaration.initializer) {
|
|
2306
|
+
continue;
|
|
2307
|
+
}
|
|
2308
|
+
const initializerPath = resolveFunctionAliasValuePath(context, declaration.initializer, bindings);
|
|
2309
|
+
const initializerValue = getBoundValue(context, declaration.initializer, bindings) ??
|
|
2310
|
+
declaration.initializer;
|
|
2311
|
+
recordBindingName(context, declaration.name, initializerPath, initializerValue, bindings);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
function getFunctionReturnSummary(context, body, bindings) {
|
|
2316
|
+
let sawReturn = false;
|
|
2317
|
+
let summary;
|
|
2318
|
+
let invalid = false;
|
|
2319
|
+
recordFunctionBodyConstBindings(context, body, bindings);
|
|
2320
|
+
forEachFunctionReturnExpression(body, (returnExpression) => {
|
|
2321
|
+
sawReturn = true;
|
|
2322
|
+
const currentSummary = getFlowCallResultSummaryFromExpression(context, returnExpression, bindings);
|
|
2323
|
+
if (!currentSummary) {
|
|
2324
|
+
invalid = true;
|
|
2325
|
+
return true;
|
|
2326
|
+
}
|
|
2327
|
+
if (!summary) {
|
|
2328
|
+
summary = currentSummary;
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
const combinedSummary = combineEquivalentFlowCallResultSummaries(summary, currentSummary);
|
|
2332
|
+
if (!combinedSummary) {
|
|
2333
|
+
invalid = true;
|
|
2334
|
+
return true;
|
|
2335
|
+
}
|
|
2336
|
+
summary = combinedSummary;
|
|
2337
|
+
return false;
|
|
2338
|
+
});
|
|
2339
|
+
return sawReturn && !invalid ? summary : undefined;
|
|
2340
|
+
}
|
|
2341
|
+
function createFunctionBodyBindings(sourceState) {
|
|
2342
|
+
return {
|
|
2343
|
+
arrayRestAliases: new Map(),
|
|
2344
|
+
boundValues: new Map(),
|
|
2345
|
+
objectRestAliases: new Map(),
|
|
2346
|
+
rootPaths: new Map(),
|
|
2347
|
+
receiverMemberPaths: undefined,
|
|
2348
|
+
sourceState,
|
|
2349
|
+
receiverPath: undefined,
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
function getCallExpressionReceiverExpression(expression) {
|
|
2353
|
+
if (ts.isPropertyAccessExpression(expression.expression) || ts.isElementAccessExpression(expression.expression)) {
|
|
2354
|
+
return expression.expression.expression;
|
|
2355
|
+
}
|
|
2356
|
+
return undefined;
|
|
2357
|
+
}
|
|
2358
|
+
function getCallExpressionResultSummary(context, expression, state) {
|
|
2359
|
+
const declaration = getFunctionLikeFromCallExpression(context, expression);
|
|
2360
|
+
const body = declaration?.body;
|
|
2361
|
+
if (!declaration || !body) {
|
|
2362
|
+
return undefined;
|
|
2363
|
+
}
|
|
2364
|
+
const bindings = getFunctionBindings(context, expression.arguments, declaration, state);
|
|
2365
|
+
const receiverExpression = getCallExpressionReceiverExpression(expression);
|
|
2366
|
+
if (receiverExpression) {
|
|
2367
|
+
bindFunctionReceiverPath(bindings, normalizeExpressionPath(context, receiverExpression, state));
|
|
2368
|
+
}
|
|
2369
|
+
return getFunctionReturnSummary(context, body, bindings);
|
|
2370
|
+
}
|
|
2371
|
+
export function getNestedFunctionBindings(context, argumentsList, declaration, parentBindings) {
|
|
2372
|
+
const bindings = createFunctionBodyBindings(cloneState(parentBindings.sourceState));
|
|
2373
|
+
bindings.receiverPath = parentBindings.receiverPath;
|
|
2374
|
+
bindings.receiverMemberPaths = parentBindings.receiverMemberPaths;
|
|
2375
|
+
for (const [symbolId, path] of parentBindings.rootPaths) {
|
|
2376
|
+
bindings.rootPaths.set(symbolId, path);
|
|
2377
|
+
}
|
|
2378
|
+
for (const [symbolId, value] of parentBindings.boundValues) {
|
|
2379
|
+
bindings.boundValues.set(symbolId, value);
|
|
2380
|
+
}
|
|
2381
|
+
for (const [symbolId, alias] of parentBindings.objectRestAliases) {
|
|
2382
|
+
bindings.objectRestAliases.set(symbolId, alias);
|
|
2383
|
+
}
|
|
2384
|
+
for (const [symbolId, alias] of parentBindings.arrayRestAliases) {
|
|
2385
|
+
bindings.arrayRestAliases.set(symbolId, alias);
|
|
2386
|
+
}
|
|
2387
|
+
declaration.parameters.forEach((parameter, index) => {
|
|
2388
|
+
const argument = argumentsList[index];
|
|
2389
|
+
const initializerArgument = argument ?? parameter.initializer;
|
|
2390
|
+
if (!initializerArgument) {
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
const argumentPath = argument
|
|
2394
|
+
? resolveFunctionAliasValuePath(context, argument, parentBindings)
|
|
2395
|
+
: undefined;
|
|
2396
|
+
const argumentValue = argument
|
|
2397
|
+
? (getBoundValue(context, argument, parentBindings) ?? argument)
|
|
2398
|
+
: initializerArgument;
|
|
2399
|
+
if (ts.isIdentifier(parameter.name)) {
|
|
2400
|
+
const symbol = getExpressionSymbol(context, parameter.name);
|
|
2401
|
+
if (symbol) {
|
|
2402
|
+
const aliasPath = ts.isExpression(argumentValue)
|
|
2403
|
+
? (resolveFunctionAliasValuePath(context, argumentValue, parentBindings) ?? argumentPath)
|
|
2404
|
+
: argumentPath;
|
|
2405
|
+
if (aliasPath) {
|
|
2406
|
+
setFunctionRootPath(context, parameter.name, aliasPath, bindings);
|
|
2407
|
+
}
|
|
2408
|
+
bindings.boundValues.set(getSymbolId(context, symbol), argument ?? initializerArgument);
|
|
2409
|
+
}
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
recordBindingName(context, parameter.name, argumentPath, argumentValue, bindings);
|
|
2413
|
+
});
|
|
2414
|
+
return bindings;
|
|
2415
|
+
}
|
|
2416
|
+
function getFunctionCallExpressionResultSummary(context, expression, bindings) {
|
|
2417
|
+
const declaration = getFunctionLikeFromCallExpression(context, expression);
|
|
2418
|
+
const body = declaration?.body;
|
|
2419
|
+
if (!declaration || !body) {
|
|
2420
|
+
return undefined;
|
|
2421
|
+
}
|
|
2422
|
+
const nestedBindings = getNestedFunctionBindings(context, expression.arguments, declaration, bindings);
|
|
2423
|
+
const receiverExpression = getCallExpressionReceiverExpression(expression);
|
|
2424
|
+
if (receiverExpression) {
|
|
2425
|
+
bindFunctionReceiverPath(nestedBindings, resolveFunctionAliasValuePath(context, receiverExpression, bindings));
|
|
2426
|
+
}
|
|
2427
|
+
return getFunctionReturnSummary(context, body, nestedBindings);
|
|
2428
|
+
}
|
|
2429
|
+
function getCallExpressionResultPath(context, expression, state) {
|
|
2430
|
+
const summary = getCallExpressionResultSummary(context, expression, state);
|
|
2431
|
+
return summary && !summary.canBeNullish && summary.shape?.kind === 'path'
|
|
2432
|
+
? summary.shape.path
|
|
2433
|
+
: undefined;
|
|
2434
|
+
}
|
|
2435
|
+
function getFunctionCallExpressionResultMemberPath(context, expression, key, bindings) {
|
|
2436
|
+
const summary = getFunctionCallExpressionResultSummary(context, expression, bindings);
|
|
2437
|
+
if (!summary || summary.canBeNullish || !summary.shape) {
|
|
2438
|
+
return undefined;
|
|
2439
|
+
}
|
|
2440
|
+
if (summary.shape.kind === 'object') {
|
|
2441
|
+
return summary.shape.members.get(key);
|
|
2442
|
+
}
|
|
2443
|
+
if (summary.shape.kind === 'array') {
|
|
2444
|
+
return summary.shape.elements.get(key);
|
|
2445
|
+
}
|
|
2446
|
+
return undefined;
|
|
2447
|
+
}
|
|
2448
|
+
function getCallExpressionResultMemberPath(context, expression, key, state) {
|
|
2449
|
+
const summary = getCallExpressionResultSummary(context, expression, state);
|
|
2450
|
+
if (!summary || summary.canBeNullish || !summary.shape) {
|
|
2451
|
+
return undefined;
|
|
2452
|
+
}
|
|
2453
|
+
let result;
|
|
2454
|
+
if (summary.shape.kind === 'object') {
|
|
2455
|
+
result = summary.shape.members.get(key);
|
|
2456
|
+
}
|
|
2457
|
+
else if (summary.shape.kind === 'array') {
|
|
2458
|
+
result = summary.shape.elements.get(key);
|
|
2459
|
+
}
|
|
2460
|
+
return result;
|
|
2461
|
+
}
|
|
2462
|
+
function getObjectBindingElementKey(context, element) {
|
|
2463
|
+
if (!element.propertyName) {
|
|
2464
|
+
return ts.isIdentifier(element.name) ? element.name.text : undefined;
|
|
2465
|
+
}
|
|
2466
|
+
if (ts.isComputedPropertyName(element.propertyName)) {
|
|
2467
|
+
return getElementAccessKey(context, element.propertyName.expression);
|
|
2468
|
+
}
|
|
2469
|
+
if (ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName) ||
|
|
2470
|
+
ts.isNumericLiteral(element.propertyName)) {
|
|
2471
|
+
return element.propertyName.text;
|
|
2472
|
+
}
|
|
2473
|
+
return undefined;
|
|
2474
|
+
}
|
|
2475
|
+
function getPropertyNameKey(context, name) {
|
|
2476
|
+
if (ts.isComputedPropertyName(name)) {
|
|
2477
|
+
return getElementAccessKey(context, name.expression);
|
|
2478
|
+
}
|
|
2479
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name) ||
|
|
2480
|
+
ts.isNumericLiteral(name)) {
|
|
2481
|
+
return name.text;
|
|
2482
|
+
}
|
|
2483
|
+
return undefined;
|
|
2484
|
+
}
|
|
2485
|
+
function getObjectLiteralPropertyValue(objectLiteral, key) {
|
|
2486
|
+
for (const property of objectLiteral.properties) {
|
|
2487
|
+
if (ts.isPropertyAssignment(property) &&
|
|
2488
|
+
(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) ||
|
|
2489
|
+
ts.isNumericLiteral(property.name)) &&
|
|
2490
|
+
property.name.text === key) {
|
|
2491
|
+
return property.initializer;
|
|
2492
|
+
}
|
|
2493
|
+
if (ts.isShorthandPropertyAssignment(property) &&
|
|
2494
|
+
property.name.text === key) {
|
|
2495
|
+
return property.name;
|
|
2496
|
+
}
|
|
2497
|
+
if (ts.isMethodDeclaration(property) &&
|
|
2498
|
+
(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) ||
|
|
2499
|
+
ts.isNumericLiteral(property.name)) &&
|
|
2500
|
+
property.name.text === key) {
|
|
2501
|
+
return property;
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
return undefined;
|
|
2505
|
+
}
|
|
2506
|
+
function getArrayLiteralElementExpression(arrayLiteral, index) {
|
|
2507
|
+
const element = arrayLiteral.elements[index];
|
|
2508
|
+
return element && !ts.isOmittedExpression(element) ? element : undefined;
|
|
2509
|
+
}
|
|
2510
|
+
function getBoundMemberValue(context, expression, bindings) {
|
|
2511
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
2512
|
+
const receiver = getBoundValue(context, expression.expression, bindings);
|
|
2513
|
+
return receiver && ts.isObjectLiteralExpression(receiver)
|
|
2514
|
+
? getObjectLiteralPropertyValue(receiver, expression.name.text)
|
|
2515
|
+
: undefined;
|
|
2516
|
+
}
|
|
2517
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
2518
|
+
const receiver = getBoundValue(context, expression.expression, bindings);
|
|
2519
|
+
if (!receiver) {
|
|
2520
|
+
return undefined;
|
|
2521
|
+
}
|
|
2522
|
+
const key = getFunctionBodyElementAccessKey(context, expression.argumentExpression, bindings);
|
|
2523
|
+
if (key === undefined) {
|
|
2524
|
+
return undefined;
|
|
2525
|
+
}
|
|
2526
|
+
if (ts.isObjectLiteralExpression(receiver)) {
|
|
2527
|
+
return getObjectLiteralPropertyValue(receiver, key);
|
|
2528
|
+
}
|
|
2529
|
+
return ts.isArrayLiteralExpression(receiver)
|
|
2530
|
+
? getArrayLiteralElementExpression(receiver, Number(key))
|
|
2531
|
+
: undefined;
|
|
2532
|
+
}
|
|
2533
|
+
return undefined;
|
|
2534
|
+
}
|
|
2535
|
+
export function getFunctionLikeFromBoundMemberCall(context, expression, bindings) {
|
|
2536
|
+
const boundValue = getBoundMemberValue(context, expression, bindings);
|
|
2537
|
+
return boundValue ? getFunctionLikeFromBoundValue(context, boundValue) : undefined;
|
|
2538
|
+
}
|
|
2539
|
+
function recordBindingElement(context, element, argumentPath, argumentValue, bindings) {
|
|
2540
|
+
recordBindingName(context, element.name, argumentPath, argumentValue ?? getFunctionDefaultBindingValue(context, element, bindings), bindings);
|
|
2541
|
+
}
|
|
2542
|
+
function recordBindingName(context, name, argumentPath, argumentValue, bindings) {
|
|
2543
|
+
if (ts.isIdentifier(name)) {
|
|
2544
|
+
const symbol = getExpressionSymbol(context, name);
|
|
2545
|
+
if (!symbol) {
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
const valuePath = argumentValue && ts.isExpression(argumentValue)
|
|
2549
|
+
? resolveFunctionAliasValuePath(context, argumentValue, bindings)
|
|
2550
|
+
: undefined;
|
|
2551
|
+
const aliasPath = valuePath ?? argumentPath;
|
|
2552
|
+
if (aliasPath) {
|
|
2553
|
+
setFunctionRootPath(context, name, aliasPath, bindings);
|
|
2554
|
+
}
|
|
2555
|
+
if (argumentValue) {
|
|
2556
|
+
bindings.boundValues.set(getSymbolId(context, symbol), argumentValue);
|
|
2557
|
+
}
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2560
|
+
if (ts.isObjectBindingPattern(name)) {
|
|
2561
|
+
const excludedKeys = name.elements
|
|
2562
|
+
.filter((element) => !element.dotDotDotToken)
|
|
2563
|
+
.map((element) => getObjectBindingElementKey(context, element))
|
|
2564
|
+
.filter((key) => key !== undefined);
|
|
2565
|
+
for (const element of name.elements) {
|
|
2566
|
+
if (element.dotDotDotToken) {
|
|
2567
|
+
if (ts.isIdentifier(element.name)) {
|
|
2568
|
+
const symbol = getExpressionSymbol(context, element.name);
|
|
2569
|
+
if (symbol) {
|
|
2570
|
+
bindings.objectRestAliases.set(getSymbolId(context, symbol), {
|
|
2571
|
+
excludedKeys,
|
|
2572
|
+
path: argumentPath,
|
|
2573
|
+
value: argumentValue,
|
|
2574
|
+
});
|
|
2575
|
+
if (argumentValue) {
|
|
2576
|
+
bindings.boundValues.set(getSymbolId(context, symbol), argumentValue);
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
continue;
|
|
2581
|
+
}
|
|
2582
|
+
const key = getObjectBindingElementKey(context, element);
|
|
2583
|
+
if (!key) {
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
const propertyPath = argumentPath
|
|
2587
|
+
? {
|
|
2588
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
2589
|
+
segments: [...argumentPath.segments, key],
|
|
2590
|
+
}
|
|
2591
|
+
: undefined;
|
|
2592
|
+
const propertyValue = getLiteralMemberValue(argumentValue, key);
|
|
2593
|
+
const recoveredPropertyPath = argumentValue && ts.isExpression(argumentValue)
|
|
2594
|
+
? getFunctionExpressionMemberPath(context, argumentValue, key, bindings)
|
|
2595
|
+
: undefined;
|
|
2596
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
2597
|
+
ts.isExpression(argumentValue) &&
|
|
2598
|
+
propertyValue === undefined &&
|
|
2599
|
+
recoveredPropertyPath === undefined &&
|
|
2600
|
+
element.initializer !== undefined;
|
|
2601
|
+
recordBindingElement(context, element, shouldUseDefault
|
|
2602
|
+
? getFunctionDefaultBindingPath(context, element, bindings)
|
|
2603
|
+
: (recoveredPropertyPath ?? propertyPath), shouldUseDefault ? getFunctionDefaultBindingValue(context, element, bindings) : propertyValue, bindings);
|
|
2604
|
+
}
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
name.elements.forEach((element, index) => {
|
|
2608
|
+
if (!ts.isBindingElement(element)) {
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2611
|
+
if (element.dotDotDotToken) {
|
|
2612
|
+
const arrayArgumentValue = getLiteralArrayValue(argumentValue);
|
|
2613
|
+
if (ts.isIdentifier(element.name)) {
|
|
2614
|
+
const symbol = getExpressionSymbol(context, element.name);
|
|
2615
|
+
if (symbol) {
|
|
2616
|
+
bindings.arrayRestAliases.set(getSymbolId(context, symbol), {
|
|
2617
|
+
offset: index,
|
|
2618
|
+
path: argumentPath,
|
|
2619
|
+
value: arrayArgumentValue,
|
|
2620
|
+
});
|
|
2621
|
+
if (arrayArgumentValue) {
|
|
2622
|
+
bindings.boundValues.set(getSymbolId(context, symbol), arrayArgumentValue);
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
return;
|
|
2627
|
+
}
|
|
2628
|
+
const elementPath = argumentPath
|
|
2629
|
+
? {
|
|
2630
|
+
baseSymbol: argumentPath.baseSymbol,
|
|
2631
|
+
segments: [...argumentPath.segments, String(index)],
|
|
2632
|
+
}
|
|
2633
|
+
: undefined;
|
|
2634
|
+
const elementValue = getLiteralMemberValue(argumentValue, String(index));
|
|
2635
|
+
const recoveredElementPath = argumentValue && ts.isExpression(argumentValue)
|
|
2636
|
+
? getFunctionExpressionMemberPath(context, argumentValue, String(index), bindings)
|
|
2637
|
+
: undefined;
|
|
2638
|
+
const shouldUseDefault = argumentValue !== undefined &&
|
|
2639
|
+
ts.isExpression(argumentValue) &&
|
|
2640
|
+
elementValue === undefined &&
|
|
2641
|
+
recoveredElementPath === undefined &&
|
|
2642
|
+
element.initializer !== undefined;
|
|
2643
|
+
recordBindingElement(context, element, shouldUseDefault
|
|
2644
|
+
? getFunctionDefaultBindingPath(context, element, bindings)
|
|
2645
|
+
: (recoveredElementPath ?? elementPath), shouldUseDefault ? getFunctionDefaultBindingValue(context, element, bindings) : elementValue, bindings);
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
export function bindFunctionBindingName(context, name, argumentPath, argumentValue, bindings) {
|
|
2649
|
+
recordBindingName(context, name, argumentPath, argumentValue, bindings);
|
|
2650
|
+
}
|
|
2651
|
+
export function getFunctionBindings(context, argumentsList, declaration, state) {
|
|
2652
|
+
const bindings = createFunctionBodyBindings(cloneState(state));
|
|
2653
|
+
declaration.parameters.forEach((parameter, index) => {
|
|
2654
|
+
const argument = argumentsList[index];
|
|
2655
|
+
const initializerArgument = argument ?? parameter.initializer;
|
|
2656
|
+
if (!initializerArgument) {
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
const argumentPath = argument
|
|
2660
|
+
? normalizeExpressionSourcePath(context, argument, state)
|
|
2661
|
+
: undefined;
|
|
2662
|
+
if (ts.isIdentifier(parameter.name)) {
|
|
2663
|
+
const symbol = getExpressionSymbol(context, parameter.name);
|
|
2664
|
+
if (symbol) {
|
|
2665
|
+
const argumentValue = argument
|
|
2666
|
+
? (getExpressionLiteralValue(context, argument, state) ??
|
|
2667
|
+
getStateBoundValue(context, argument, state) ?? argument)
|
|
2668
|
+
: initializerArgument;
|
|
2669
|
+
const aliasPath = ts.isExpression(argumentValue)
|
|
2670
|
+
? (normalizeExpressionPath(context, argumentValue, state) ?? argumentPath)
|
|
2671
|
+
: argumentPath;
|
|
2672
|
+
if (aliasPath) {
|
|
2673
|
+
setFunctionRootPath(context, parameter.name, aliasPath, bindings);
|
|
2674
|
+
}
|
|
2675
|
+
bindings.boundValues.set(getSymbolId(context, symbol), argument ?? initializerArgument);
|
|
2676
|
+
}
|
|
2677
|
+
return;
|
|
2678
|
+
}
|
|
2679
|
+
recordBindingName(context, parameter.name, argumentPath, initializerArgument, bindings);
|
|
2680
|
+
});
|
|
2681
|
+
return bindings;
|
|
2682
|
+
}
|
|
2683
|
+
export function normalizeFunctionBodyPath(context, expression, bindings) {
|
|
2684
|
+
const unwrappedExpression = unwrapFlowTransparentExpression(expression);
|
|
2685
|
+
if (unwrappedExpression !== expression) {
|
|
2686
|
+
return normalizeFunctionBodyPath(context, unwrappedExpression, bindings);
|
|
2687
|
+
}
|
|
2688
|
+
if (isThisExpression(expression)) {
|
|
2689
|
+
return getFunctionRootPath(context, expression, bindings);
|
|
2690
|
+
}
|
|
2691
|
+
if (ts.isIdentifier(expression)) {
|
|
2692
|
+
return getFunctionRootPath(context, expression, bindings);
|
|
2693
|
+
}
|
|
2694
|
+
const equivalentPath = getFunctionEquivalentExpressionPath(context, expression, bindings);
|
|
2695
|
+
if (equivalentPath) {
|
|
2696
|
+
return equivalentPath;
|
|
2697
|
+
}
|
|
2698
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
2699
|
+
const receiverMemberPath = getFunctionReceiverMemberPath(context, expression.expression, getMemberNameText(expression.name), bindings);
|
|
2700
|
+
if (receiverMemberPath) {
|
|
2701
|
+
return receiverMemberPath;
|
|
2702
|
+
}
|
|
2703
|
+
if (ts.isIdentifier(expression.expression)) {
|
|
2704
|
+
const receiverSymbol = getExpressionSymbol(context, expression.expression);
|
|
2705
|
+
if (receiverSymbol) {
|
|
2706
|
+
const receiverId = getSymbolId(context, receiverSymbol);
|
|
2707
|
+
const objectRestAlias = bindings.objectRestAliases.get(receiverId);
|
|
2708
|
+
if (objectRestAlias &&
|
|
2709
|
+
!objectRestAlias.excludedKeys.includes(getMemberNameText(expression.name))) {
|
|
2710
|
+
const restPath = getFunctionObjectRestAliasPath(context, objectRestAlias, getMemberNameText(expression.name), bindings);
|
|
2711
|
+
if (restPath) {
|
|
2712
|
+
return restPath;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
const boundMemberValue = getLiteralMemberValue(bindings.boundValues.get(receiverId), getMemberNameText(expression.name));
|
|
2716
|
+
if (boundMemberValue && ts.isExpression(boundMemberValue)) {
|
|
2717
|
+
const boundMemberPath = resolveFunctionAliasValuePath(context, boundMemberValue, bindings);
|
|
2718
|
+
if (boundMemberPath) {
|
|
2719
|
+
return boundMemberPath;
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
const boundReceiverValue = bindings.boundValues.get(receiverId);
|
|
2723
|
+
if (boundReceiverValue && ts.isExpression(boundReceiverValue) &&
|
|
2724
|
+
ts.isCallExpression(boundReceiverValue)) {
|
|
2725
|
+
const callResultPath = getFunctionCallExpressionResultMemberPath(context, boundReceiverValue, getMemberNameText(expression.name), bindings);
|
|
2726
|
+
if (callResultPath) {
|
|
2727
|
+
return callResultPath;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
const basePath = normalizeFunctionBodyPath(context, expression.expression, bindings);
|
|
2733
|
+
if (!basePath) {
|
|
2734
|
+
return undefined;
|
|
2735
|
+
}
|
|
2736
|
+
return {
|
|
2737
|
+
baseSymbol: basePath.baseSymbol,
|
|
2738
|
+
segments: [...basePath.segments, getMemberNameText(expression.name)],
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2741
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
2742
|
+
const key = getFunctionBodyElementAccessKey(context, expression.argumentExpression, bindings);
|
|
2743
|
+
if (key) {
|
|
2744
|
+
const receiverMemberPath = getFunctionReceiverMemberPath(context, expression.expression, key, bindings);
|
|
2745
|
+
if (receiverMemberPath) {
|
|
2746
|
+
return receiverMemberPath;
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
if (ts.isIdentifier(expression.expression)) {
|
|
2750
|
+
const receiverSymbol = getExpressionSymbol(context, expression.expression);
|
|
2751
|
+
if (receiverSymbol) {
|
|
2752
|
+
const receiverId = getSymbolId(context, receiverSymbol);
|
|
2753
|
+
if (key) {
|
|
2754
|
+
const objectRestAlias = bindings.objectRestAliases.get(receiverId);
|
|
2755
|
+
if (objectRestAlias &&
|
|
2756
|
+
!objectRestAlias.excludedKeys.includes(key)) {
|
|
2757
|
+
const restPath = getFunctionObjectRestAliasPath(context, objectRestAlias, key, bindings);
|
|
2758
|
+
if (restPath) {
|
|
2759
|
+
return restPath;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
const restAlias = bindings.arrayRestAliases.get(receiverId);
|
|
2764
|
+
if (restAlias && key && /^\d+$/.test(key)) {
|
|
2765
|
+
const resolvedIndex = restAlias.offset + Number(key);
|
|
2766
|
+
const restElementValue = getLiteralMemberValue(restAlias.value, String(resolvedIndex));
|
|
2767
|
+
if (restElementValue && ts.isExpression(restElementValue)) {
|
|
2768
|
+
const restElementPath = resolveFunctionAliasValuePath(context, restElementValue, bindings);
|
|
2769
|
+
if (restElementPath) {
|
|
2770
|
+
return restElementPath;
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
if (!restAlias.path) {
|
|
2774
|
+
return undefined;
|
|
2775
|
+
}
|
|
2776
|
+
return {
|
|
2777
|
+
baseSymbol: restAlias.path.baseSymbol,
|
|
2778
|
+
segments: [...restAlias.path.segments, String(resolvedIndex)],
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
const boundMemberValue = key
|
|
2782
|
+
? getLiteralMemberValue(bindings.boundValues.get(receiverId), key)
|
|
2783
|
+
: undefined;
|
|
2784
|
+
if (boundMemberValue && ts.isExpression(boundMemberValue)) {
|
|
2785
|
+
const boundMemberPath = resolveFunctionAliasValuePath(context, boundMemberValue, bindings);
|
|
2786
|
+
if (boundMemberPath) {
|
|
2787
|
+
return boundMemberPath;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
const boundReceiverValue = bindings.boundValues.get(receiverId);
|
|
2791
|
+
if (key && boundReceiverValue && ts.isExpression(boundReceiverValue) &&
|
|
2792
|
+
ts.isCallExpression(boundReceiverValue)) {
|
|
2793
|
+
const callResultPath = getFunctionCallExpressionResultMemberPath(context, boundReceiverValue, key, bindings);
|
|
2794
|
+
if (callResultPath) {
|
|
2795
|
+
return callResultPath;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
const basePath = normalizeFunctionBodyPath(context, expression.expression, bindings);
|
|
2801
|
+
if (!basePath) {
|
|
2802
|
+
return undefined;
|
|
2803
|
+
}
|
|
2804
|
+
if (!key) {
|
|
2805
|
+
return undefined;
|
|
2806
|
+
}
|
|
2807
|
+
return {
|
|
2808
|
+
baseSymbol: basePath.baseSymbol,
|
|
2809
|
+
segments: [...basePath.segments, key],
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
return undefined;
|
|
2813
|
+
}
|
|
2814
|
+
export function isFunctionLikeWithBody(node) {
|
|
2815
|
+
return (ts.isFunctionDeclaration(node) ||
|
|
2816
|
+
ts.isMethodDeclaration(node) ||
|
|
2817
|
+
ts.isConstructorDeclaration(node) ||
|
|
2818
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
2819
|
+
ts.isSetAccessorDeclaration(node) ||
|
|
2820
|
+
ts.isFunctionExpression(node) ||
|
|
2821
|
+
ts.isArrowFunction(node)) && node.body !== undefined;
|
|
2822
|
+
}
|