@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,2540 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import { SOUND_DIAGNOSTIC_CODES, SOUND_DIAGNOSTIC_MESSAGES } from '../engine/diagnostic_codes.ts';
|
|
4
|
+
import type { AnalysisContext } from '../engine/types.ts';
|
|
5
|
+
import { getNodeDiagnosticRange, type SoundDiagnostic } from '../diagnostics.ts';
|
|
6
|
+
import {
|
|
7
|
+
createAnyTypeDiagnostic,
|
|
8
|
+
createDefiniteAssignmentAssertionDiagnostic,
|
|
9
|
+
createNonNullAssertionDiagnostic,
|
|
10
|
+
createTypeAssertionDiagnostic,
|
|
11
|
+
} from '../proof_escape_hatch_diagnostics.ts';
|
|
12
|
+
import {
|
|
13
|
+
describeUnsupportedFeature,
|
|
14
|
+
type UnsupportedFeatureDiagnosticText,
|
|
15
|
+
type UnsupportedFeatureKind,
|
|
16
|
+
} from '../unsupported_feature_messages.ts';
|
|
17
|
+
import { isForeignSourceFile } from '../../soundscript_packages.ts';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
getResolvedBuiltinSignatureInfo,
|
|
21
|
+
getWrappedBuiltinInvocation,
|
|
22
|
+
matchesResolvedBuiltinCallableValue,
|
|
23
|
+
matchesResolvedBuiltinSignature,
|
|
24
|
+
resolvesToBuiltinGlobalValue,
|
|
25
|
+
type WrappedBuiltinInvocation,
|
|
26
|
+
} from './resolved_builtins.ts';
|
|
27
|
+
import { isInsideSyntheticErrorNormalizationHelper } from './generated_helpers.ts';
|
|
28
|
+
import { getLocalUnsafeProofOverrideChainRoot, isLocallyUnsafe } from './trust.ts';
|
|
29
|
+
|
|
30
|
+
const LEGACY_ACCESSOR_MEMBER_NAMES = new Set([
|
|
31
|
+
'__defineGetter__',
|
|
32
|
+
'__defineSetter__',
|
|
33
|
+
'__lookupGetter__',
|
|
34
|
+
'__lookupSetter__',
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
const LEGACY_FUNCTION_MEMBER_NAMES = new Set([
|
|
38
|
+
'arguments',
|
|
39
|
+
'caller',
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
const BANNED_SYMBOL_HOOK_MEMBER_NAMES = new Set([
|
|
43
|
+
'asyncIterator',
|
|
44
|
+
'hasInstance',
|
|
45
|
+
'iterator',
|
|
46
|
+
'match',
|
|
47
|
+
'replace',
|
|
48
|
+
'search',
|
|
49
|
+
'species',
|
|
50
|
+
'split',
|
|
51
|
+
'toPrimitive',
|
|
52
|
+
'toStringTag',
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
const ALWAYS_BANNED_DECLARATION_FILE_TYPE_NAMES = new Set([
|
|
56
|
+
'String',
|
|
57
|
+
'Number',
|
|
58
|
+
'Boolean',
|
|
59
|
+
'CallableFunction',
|
|
60
|
+
'NewableFunction',
|
|
61
|
+
'PromiseLike',
|
|
62
|
+
'PromiseConstructorLike',
|
|
63
|
+
'WeakRef',
|
|
64
|
+
'FinalizationRegistry',
|
|
65
|
+
'Iterator',
|
|
66
|
+
'Iterable',
|
|
67
|
+
'IterableIterator',
|
|
68
|
+
'IteratorObject',
|
|
69
|
+
'AsyncIterator',
|
|
70
|
+
'AsyncIterable',
|
|
71
|
+
'AsyncIterableIterator',
|
|
72
|
+
'AsyncIteratorObject',
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const CONDITIONALLY_BANNED_DECLARATION_FILE_TYPE_NAMES = new Set([
|
|
76
|
+
'WeakMap',
|
|
77
|
+
'WeakSet',
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
const PRIMITIVE_CONVERSION_HOOK_MEMBER_NAMES = new Set([
|
|
81
|
+
'toString',
|
|
82
|
+
'valueOf',
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
function isAnyType(type: ts.Type): boolean {
|
|
86
|
+
return (type.flags & ts.TypeFlags.Any) !== 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isUnknownType(type: ts.Type): boolean {
|
|
90
|
+
return (type.flags & ts.TypeFlags.Unknown) !== 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isAnyOrUnknownType(type: ts.Type): boolean {
|
|
94
|
+
return isAnyType(type) || isUnknownType(type);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isUnsafeBridgeCast(context: AnalysisContext, node: ts.AsExpression): boolean {
|
|
98
|
+
const sourceType = context.checker.getTypeAtLocation(node.expression);
|
|
99
|
+
const targetType = context.checker.getTypeAtLocation(node.type);
|
|
100
|
+
return isAnyOrUnknownType(sourceType) && !isAnyOrUnknownType(targetType);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function createDiagnostic(
|
|
104
|
+
node: ts.Node,
|
|
105
|
+
code:
|
|
106
|
+
| typeof SOUND_DIAGNOSTIC_CODES.anyType
|
|
107
|
+
| typeof SOUND_DIAGNOSTIC_CODES.ambientRuntimeDeclarationRequiresExtern
|
|
108
|
+
| typeof SOUND_DIAGNOSTIC_CODES.exportedAmbientRuntimeDeclaration
|
|
109
|
+
| typeof SOUND_DIAGNOSTIC_CODES.nullPrototypeObjectCreation
|
|
110
|
+
| typeof SOUND_DIAGNOSTIC_CODES.nonNullAssertion
|
|
111
|
+
| typeof SOUND_DIAGNOSTIC_CODES.throwNonError
|
|
112
|
+
| typeof SOUND_DIAGNOSTIC_CODES.typeAssertion
|
|
113
|
+
| typeof SOUND_DIAGNOSTIC_CODES.unsupportedJavaScriptFeature,
|
|
114
|
+
message: string,
|
|
115
|
+
options?: {
|
|
116
|
+
hint?: string;
|
|
117
|
+
metadata?: SoundDiagnostic['metadata'];
|
|
118
|
+
notes?: string[];
|
|
119
|
+
},
|
|
120
|
+
): SoundDiagnostic {
|
|
121
|
+
return {
|
|
122
|
+
source: 'sound',
|
|
123
|
+
code,
|
|
124
|
+
category: 'error',
|
|
125
|
+
message,
|
|
126
|
+
metadata: options?.metadata,
|
|
127
|
+
notes: options?.notes,
|
|
128
|
+
hint: options?.hint,
|
|
129
|
+
...getNodeDiagnosticRange(node),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface UnsupportedFeatureDiagnostic extends UnsupportedFeatureDiagnosticText {
|
|
134
|
+
node: ts.Node;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface AmbientRuntimeExportDiagnostic {
|
|
138
|
+
declarationNode: AmbientRuntimeDeclarationNode;
|
|
139
|
+
diagnosticNode: ts.Node;
|
|
140
|
+
exportForm: 'direct export' | 'local re-export' | 'default export alias';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function unsupportedFeature(
|
|
144
|
+
node: ts.Node,
|
|
145
|
+
kind: UnsupportedFeatureKind,
|
|
146
|
+
options?: {
|
|
147
|
+
name?: string;
|
|
148
|
+
},
|
|
149
|
+
): UnsupportedFeatureDiagnostic {
|
|
150
|
+
return {
|
|
151
|
+
node,
|
|
152
|
+
...describeUnsupportedFeature(kind, options),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createThrowNonErrorDiagnostic(
|
|
157
|
+
context: AnalysisContext,
|
|
158
|
+
expression: ts.Expression,
|
|
159
|
+
): SoundDiagnostic {
|
|
160
|
+
const thrownType = context.checker.typeToString(context.checker.getTypeAtLocation(expression));
|
|
161
|
+
const example =
|
|
162
|
+
'Write `throw new Error(String(problem));` or throw a concrete `Error` subclass instead.';
|
|
163
|
+
|
|
164
|
+
return createDiagnostic(
|
|
165
|
+
expression,
|
|
166
|
+
SOUND_DIAGNOSTIC_CODES.throwNonError,
|
|
167
|
+
SOUND_DIAGNOSTIC_MESSAGES.throwNonError,
|
|
168
|
+
{
|
|
169
|
+
metadata: {
|
|
170
|
+
rule: 'throw_non_error',
|
|
171
|
+
fixability: 'local_rewrite',
|
|
172
|
+
invariant:
|
|
173
|
+
'Thrown values must be real `Error` objects so downstream code can rely on the standard `Error` surface.',
|
|
174
|
+
replacementFamily: 'error_object_construction',
|
|
175
|
+
evidence: [{ label: 'thrownType', value: thrownType }],
|
|
176
|
+
counterexample:
|
|
177
|
+
'Throwing a bare value drops the `Error` surface that downstream code relies on for `message`, `name`, stack, and cause information.',
|
|
178
|
+
example,
|
|
179
|
+
},
|
|
180
|
+
notes: [
|
|
181
|
+
`The thrown value has type '${thrownType}', but soundscript only permits \`Error\`-family throws.`,
|
|
182
|
+
`Example: ${example}`,
|
|
183
|
+
],
|
|
184
|
+
hint:
|
|
185
|
+
'Wrap the payload in `Error` or a concrete `Error` subclass before throwing.',
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function createNullPrototypeObjectCreationDiagnostic(
|
|
191
|
+
expression: ts.Expression,
|
|
192
|
+
apiName: string,
|
|
193
|
+
): SoundDiagnostic {
|
|
194
|
+
const example =
|
|
195
|
+
'Use `Object.create(null)` and keep the value as `BareObject`, or use an ordinary object or `Map` if you want normal object behavior.';
|
|
196
|
+
|
|
197
|
+
return createDiagnostic(
|
|
198
|
+
expression,
|
|
199
|
+
SOUND_DIAGNOSTIC_CODES.nullPrototypeObjectCreation,
|
|
200
|
+
SOUND_DIAGNOSTIC_MESSAGES.nullPrototypeObjectCreation,
|
|
201
|
+
{
|
|
202
|
+
metadata: {
|
|
203
|
+
rule: 'null_prototype_object_creation',
|
|
204
|
+
fixability: 'local_rewrite',
|
|
205
|
+
invariant:
|
|
206
|
+
'Null-prototype values must flow through the explicit `BareObject` construction path instead of being created by prototype mutation.',
|
|
207
|
+
replacementFamily: 'bare_object_or_map',
|
|
208
|
+
evidence: [{ label: 'api', value: apiName }],
|
|
209
|
+
counterexample:
|
|
210
|
+
'Prototype surgery can create null-prototype objects after allocation, which breaks the ordinary object assumptions soundscript relies on.',
|
|
211
|
+
example,
|
|
212
|
+
},
|
|
213
|
+
notes: [
|
|
214
|
+
'This call creates a null-prototype object through prototype mutation instead of through the explicit `BareObject` path.',
|
|
215
|
+
`Example: ${example}`,
|
|
216
|
+
],
|
|
217
|
+
hint:
|
|
218
|
+
'Use `Object.create(null)` with `BareObject`, or use an ordinary object or `Map` instead of prototype surgery.',
|
|
219
|
+
},
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getAmbientRuntimeDeclarationInfo(
|
|
224
|
+
node: AmbientRuntimeDeclarationNode,
|
|
225
|
+
): { kind: string; name?: string } {
|
|
226
|
+
if (ts.isVariableStatement(node)) {
|
|
227
|
+
const firstDeclaration = node.declarationList.declarations[0];
|
|
228
|
+
return {
|
|
229
|
+
kind: 'const declaration',
|
|
230
|
+
name: firstDeclaration && ts.isIdentifier(firstDeclaration.name) ? firstDeclaration.name.text : undefined,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
235
|
+
return { kind: 'function declaration', name: node.name?.text };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return { kind: 'class declaration', name: node.name?.text };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function createAmbientRuntimeRequiresExternDiagnostic(
|
|
242
|
+
declarationNode: AmbientRuntimeDeclarationNode,
|
|
243
|
+
): SoundDiagnostic {
|
|
244
|
+
const diagnosticNode = getAmbientRuntimeDeclarationDiagnosticNode(declarationNode);
|
|
245
|
+
const info = getAmbientRuntimeDeclarationInfo(declarationNode);
|
|
246
|
+
const example =
|
|
247
|
+
'Add `// #[extern]` immediately above the declaration, or replace the declaration with a real implementation.';
|
|
248
|
+
|
|
249
|
+
return createDiagnostic(
|
|
250
|
+
diagnosticNode,
|
|
251
|
+
SOUND_DIAGNOSTIC_CODES.ambientRuntimeDeclarationRequiresExtern,
|
|
252
|
+
SOUND_DIAGNOSTIC_MESSAGES.ambientRuntimeDeclarationRequiresExtern,
|
|
253
|
+
{
|
|
254
|
+
metadata: {
|
|
255
|
+
rule: 'ambient_runtime_requires_extern',
|
|
256
|
+
primarySymbol: info.name,
|
|
257
|
+
fixability: 'boundary_annotation',
|
|
258
|
+
invariant:
|
|
259
|
+
'Declaration-only runtime names in `.sts` files must be marked as explicit extern boundaries instead of looking like ordinary checked implementations.',
|
|
260
|
+
replacementFamily: 'site_local_extern_boundary',
|
|
261
|
+
evidence: [
|
|
262
|
+
{ label: 'declarationKind', value: info.kind },
|
|
263
|
+
...(info.name ? [{ label: 'declarationName', value: info.name }] : []),
|
|
264
|
+
],
|
|
265
|
+
counterexample:
|
|
266
|
+
'Without `#[extern]`, a declaration-only runtime name looks like ordinary checked soundscript even though there is no local implementation.',
|
|
267
|
+
example,
|
|
268
|
+
},
|
|
269
|
+
notes: [
|
|
270
|
+
`This local ambient runtime declaration introduces \`${info.name ?? 'this name'}\` without a site-local extern boundary.`,
|
|
271
|
+
`Example: ${example}`,
|
|
272
|
+
],
|
|
273
|
+
hint:
|
|
274
|
+
"Use '// #[extern]' only for local runtime-provided declarations, or replace the declaration with a real implementation.",
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function createAmbientRuntimeExportDiagnostic(
|
|
280
|
+
info: AmbientRuntimeExportDiagnostic,
|
|
281
|
+
): SoundDiagnostic {
|
|
282
|
+
const declarationInfo = getAmbientRuntimeDeclarationInfo(info.declarationNode);
|
|
283
|
+
const example =
|
|
284
|
+
"Move the declaration to '.d.ts', keep it local with `// #[extern]`, or replace it with a real implementation.";
|
|
285
|
+
|
|
286
|
+
return createDiagnostic(
|
|
287
|
+
info.diagnosticNode,
|
|
288
|
+
SOUND_DIAGNOSTIC_CODES.exportedAmbientRuntimeDeclaration,
|
|
289
|
+
SOUND_DIAGNOSTIC_MESSAGES.exportedAmbientRuntimeDeclaration,
|
|
290
|
+
{
|
|
291
|
+
metadata: {
|
|
292
|
+
rule: 'ambient_runtime_export_forbidden',
|
|
293
|
+
primarySymbol: declarationInfo.name,
|
|
294
|
+
fixability: 'api_redesign',
|
|
295
|
+
invariant:
|
|
296
|
+
'Declaration-only runtime names may stay local extern boundaries, but they may not become exported checked module surfaces without implementations.',
|
|
297
|
+
replacementFamily: 'ambient_surface_split_or_real_implementation',
|
|
298
|
+
evidence: [
|
|
299
|
+
{ label: 'declarationKind', value: declarationInfo.kind },
|
|
300
|
+
...(declarationInfo.name ? [{ label: 'declarationName', value: declarationInfo.name }] : []),
|
|
301
|
+
{ label: 'exportForm', value: info.exportForm },
|
|
302
|
+
],
|
|
303
|
+
counterexample:
|
|
304
|
+
'An exported declaration-only runtime name creates a module API without a local implementation, so downstream code would treat a nonexistent checked value as real.',
|
|
305
|
+
example,
|
|
306
|
+
},
|
|
307
|
+
notes: [
|
|
308
|
+
`This ambient runtime declaration exports \`${declarationInfo.name ?? 'this name'}\` from a soundscript module even though there is no local implementation.`,
|
|
309
|
+
`Example: ${example}`,
|
|
310
|
+
],
|
|
311
|
+
hint:
|
|
312
|
+
"Keep declaration-only runtime names local with '// #[extern]', move exported declaration-only surfaces to '.d.ts', or provide a real implementation.",
|
|
313
|
+
},
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function getNullPrototypeObjectCreationDiagnostic(
|
|
318
|
+
context: AnalysisContext,
|
|
319
|
+
node: ts.Node,
|
|
320
|
+
): SoundDiagnostic | undefined {
|
|
321
|
+
if (!ts.isCallExpression(node)) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const wrappedInvocation = getWrappedBuiltinInvocation(node);
|
|
326
|
+
if (
|
|
327
|
+
wrappedInvocation &&
|
|
328
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
329
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
330
|
+
memberNames: ['setPrototypeOf'],
|
|
331
|
+
})
|
|
332
|
+
) {
|
|
333
|
+
const prototypeArgument = getWrappedInvocationArgument(node, wrappedInvocation, 1);
|
|
334
|
+
if (prototypeArgument && isDefinitelyNullExpression(context, prototypeArgument)) {
|
|
335
|
+
const ownerName = matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
336
|
+
ownerNames: ['Reflect'],
|
|
337
|
+
memberNames: ['setPrototypeOf'],
|
|
338
|
+
})
|
|
339
|
+
? 'Reflect.setPrototypeOf'
|
|
340
|
+
: 'Object.setPrototypeOf';
|
|
341
|
+
return createNullPrototypeObjectCreationDiagnostic(node.expression, ownerName);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (
|
|
346
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
347
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
348
|
+
memberNames: ['setPrototypeOf'],
|
|
349
|
+
}) ||
|
|
350
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
351
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
352
|
+
memberNames: ['setPrototypeOf'],
|
|
353
|
+
})
|
|
354
|
+
) {
|
|
355
|
+
const prototypeArgument = node.arguments[1];
|
|
356
|
+
if (prototypeArgument && isDefinitelyNullExpression(context, prototypeArgument)) {
|
|
357
|
+
const ownerName = matchesResolvedBuiltinSignature(context, node, {
|
|
358
|
+
ownerNames: ['Reflect'],
|
|
359
|
+
memberNames: ['setPrototypeOf'],
|
|
360
|
+
}) ||
|
|
361
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
362
|
+
ownerNames: ['Reflect'],
|
|
363
|
+
memberNames: ['setPrototypeOf'],
|
|
364
|
+
})
|
|
365
|
+
? 'Reflect.setPrototypeOf'
|
|
366
|
+
: 'Object.setPrototypeOf';
|
|
367
|
+
return createNullPrototypeObjectCreationDiagnostic(node.expression, ownerName);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return undefined;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function isConstAssertion(node: ts.AsExpression): boolean {
|
|
375
|
+
return ts.isTypeReferenceNode(node.type) &&
|
|
376
|
+
ts.isIdentifier(node.type.typeName) &&
|
|
377
|
+
node.type.typeName.text === 'const' &&
|
|
378
|
+
node.type.typeArguments === undefined;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function unwrapParenthesizedExpression(expression: ts.Expression): ts.Expression {
|
|
382
|
+
let current = expression;
|
|
383
|
+
|
|
384
|
+
while (ts.isParenthesizedExpression(current)) {
|
|
385
|
+
current = current.expression;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return current;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function getAmbientAugmentationDiagnosticNode(node: ts.Node): ts.Node | undefined {
|
|
392
|
+
if (!ts.isModuleDeclaration(node)) {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (!hasModifier(node, ts.SyntaxKind.DeclareKeyword)) {
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if ((node.flags & ts.NodeFlags.GlobalAugmentation) !== 0) {
|
|
401
|
+
return node.name;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (ts.isStringLiteralLike(node.name)) {
|
|
405
|
+
return node.name;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (ts.isIdentifier(node.name)) {
|
|
409
|
+
return node.name;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return undefined;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function getAmbientEnumDiagnosticNode(node: ts.Node): ts.Node | undefined {
|
|
416
|
+
if (!ts.isEnumDeclaration(node) || !hasModifier(node, ts.SyntaxKind.DeclareKeyword)) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return node.name;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function getScriptScopeInterfaceMergeDiagnosticNode(
|
|
424
|
+
context: AnalysisContext,
|
|
425
|
+
node: ts.Node,
|
|
426
|
+
): ts.Node | undefined {
|
|
427
|
+
if (!ts.isInterfaceDeclaration(node)) {
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const sourceFile = node.getSourceFile();
|
|
432
|
+
if (node.parent !== sourceFile) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const mergedSymbol = context.checker.getSymbolAtLocation(node.name);
|
|
437
|
+
const mergedDeclarations = mergedSymbol?.getDeclarations() ?? [];
|
|
438
|
+
if (
|
|
439
|
+
mergedDeclarations.some((declaration) =>
|
|
440
|
+
declaration !== node && declaration.getSourceFile().isDeclarationFile
|
|
441
|
+
)
|
|
442
|
+
) {
|
|
443
|
+
return node.name;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (ts.isExternalModule(sourceFile)) {
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
for (const candidateSourceFile of context.program.getSourceFiles()) {
|
|
451
|
+
if (candidateSourceFile === sourceFile || ts.isExternalModule(candidateSourceFile)) {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
for (const statement of candidateSourceFile.statements) {
|
|
456
|
+
if (context.isGeneratedNode(statement)) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (ts.isInterfaceDeclaration(statement) && statement.name.text === node.name.text) {
|
|
461
|
+
return node.name;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function getClassInterfaceMergeDiagnosticNode(
|
|
470
|
+
context: AnalysisContext,
|
|
471
|
+
node: ts.Node,
|
|
472
|
+
): ts.Node | undefined {
|
|
473
|
+
const nameNode = ts.isClassDeclaration(node)
|
|
474
|
+
? node.name
|
|
475
|
+
: ts.isInterfaceDeclaration(node)
|
|
476
|
+
? node.name
|
|
477
|
+
: undefined;
|
|
478
|
+
if (!nameNode) {
|
|
479
|
+
return undefined;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const currentKind = ts.isClassDeclaration(node) ? 'class' : 'interface';
|
|
483
|
+
const isOppositeKind = (candidate: ts.Statement): boolean =>
|
|
484
|
+
candidate !== node &&
|
|
485
|
+
((currentKind === 'class' && ts.isInterfaceDeclaration(candidate)) ||
|
|
486
|
+
(currentKind === 'interface' && ts.isClassDeclaration(candidate))) &&
|
|
487
|
+
candidate.name?.text === nameNode.text;
|
|
488
|
+
|
|
489
|
+
const container = node.parent as ts.Node & { statements?: ts.NodeArray<ts.Statement> };
|
|
490
|
+
for (const statement of container.statements ?? []) {
|
|
491
|
+
if (context.isGeneratedNode(statement)) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (isOppositeKind(statement)) {
|
|
496
|
+
return nameNode;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const sourceFile = node.getSourceFile();
|
|
501
|
+
if (node.parent !== sourceFile || ts.isExternalModule(sourceFile)) {
|
|
502
|
+
return undefined;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
for (const candidateSourceFile of context.program.getSourceFiles()) {
|
|
506
|
+
if (candidateSourceFile === sourceFile || ts.isExternalModule(candidateSourceFile)) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
for (const statement of candidateSourceFile.statements) {
|
|
511
|
+
if (context.isGeneratedNode(statement)) {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (isOppositeKind(statement)) {
|
|
516
|
+
return nameNode;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return undefined;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function isDefinitelyNullExpression(context: AnalysisContext, expression: ts.Expression): boolean {
|
|
525
|
+
return context.checker.typeToString(context.checker.getTypeAtLocation(expression)) === 'null';
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function isDefinitelyBooleanType(
|
|
529
|
+
checker: ts.TypeChecker,
|
|
530
|
+
type: ts.Type,
|
|
531
|
+
): boolean {
|
|
532
|
+
return getPrimitiveFamily(checker, type) === 'boolean';
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function isDefinitelyStringType(
|
|
536
|
+
checker: ts.TypeChecker,
|
|
537
|
+
type: ts.Type,
|
|
538
|
+
): boolean {
|
|
539
|
+
return getPrimitiveFamily(checker, type) === 'string';
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function isDefinitelyNumericType(
|
|
543
|
+
checker: ts.TypeChecker,
|
|
544
|
+
type: ts.Type,
|
|
545
|
+
): boolean {
|
|
546
|
+
const family = getPrimitiveFamily(checker, type);
|
|
547
|
+
return family === 'number' || family === 'bigint';
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function isDefinitelyNumberType(
|
|
551
|
+
checker: ts.TypeChecker,
|
|
552
|
+
type: ts.Type,
|
|
553
|
+
): boolean {
|
|
554
|
+
return getPrimitiveFamily(checker, type) === 'number';
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function isDefinitelyBigIntType(
|
|
558
|
+
checker: ts.TypeChecker,
|
|
559
|
+
type: ts.Type,
|
|
560
|
+
): boolean {
|
|
561
|
+
return getPrimitiveFamily(checker, type) === 'bigint';
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function isDefinitelyPrimitiveType(
|
|
565
|
+
checker: ts.TypeChecker,
|
|
566
|
+
type: ts.Type,
|
|
567
|
+
): boolean {
|
|
568
|
+
return getPrimitiveFamily(checker, type) !== undefined;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function isDefinitelyNonNullishPrimitiveType(
|
|
572
|
+
checker: ts.TypeChecker,
|
|
573
|
+
type: ts.Type,
|
|
574
|
+
): boolean {
|
|
575
|
+
const family = getPrimitiveFamily(checker, type);
|
|
576
|
+
return family !== undefined && family !== 'null' && family !== 'undefined';
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function isSupportedTemplateSpanType(
|
|
580
|
+
checker: ts.TypeChecker,
|
|
581
|
+
type: ts.Type,
|
|
582
|
+
): boolean {
|
|
583
|
+
return getPrimitiveFamily(checker, type) === 'string';
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function isBuiltinErrorFamilyType(
|
|
587
|
+
checker: ts.TypeChecker,
|
|
588
|
+
type: ts.Type,
|
|
589
|
+
visited = new Set<ts.Type>(),
|
|
590
|
+
): boolean {
|
|
591
|
+
if (visited.has(type)) {
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
visited.add(type);
|
|
595
|
+
|
|
596
|
+
const constraint = checker.getBaseConstraintOfType(type);
|
|
597
|
+
if (constraint && constraint !== type) {
|
|
598
|
+
return isBuiltinErrorFamilyType(checker, constraint, visited);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (type.isUnion()) {
|
|
602
|
+
return type.types.every((member) => isBuiltinErrorFamilyType(checker, member, visited));
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (type.isIntersection()) {
|
|
606
|
+
return type.types.some((member) => isBuiltinErrorFamilyType(checker, member, visited));
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const normalized = checker.getBaseTypeOfLiteralType(type);
|
|
610
|
+
const symbol = normalized.getSymbol();
|
|
611
|
+
if (symbol?.getName() === 'Error') {
|
|
612
|
+
const declarations = symbol.getDeclarations() ?? [];
|
|
613
|
+
if (declarations.some((declaration) => declaration.getSourceFile().isDeclarationFile)) {
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (!symbol || (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) === 0) {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const baseTypes = checker.getBaseTypes?.(normalized as ts.InterfaceType) ?? [];
|
|
623
|
+
return baseTypes.some((baseType) => isBuiltinErrorFamilyType(checker, baseType, visited));
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function isAllowedThrownExpression(context: AnalysisContext, expression: ts.Expression): boolean {
|
|
627
|
+
return isBuiltinErrorFamilyType(context.checker, context.checker.getTypeAtLocation(expression));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
type PrimitiveFamily =
|
|
631
|
+
| 'bigint'
|
|
632
|
+
| 'boolean'
|
|
633
|
+
| 'null'
|
|
634
|
+
| 'number'
|
|
635
|
+
| 'string'
|
|
636
|
+
| 'symbol'
|
|
637
|
+
| 'undefined';
|
|
638
|
+
|
|
639
|
+
function getPrimitiveFamily(
|
|
640
|
+
checker: ts.TypeChecker,
|
|
641
|
+
type: ts.Type,
|
|
642
|
+
visited = new Set<ts.Type>(),
|
|
643
|
+
): PrimitiveFamily | undefined {
|
|
644
|
+
if (visited.has(type)) {
|
|
645
|
+
return undefined;
|
|
646
|
+
}
|
|
647
|
+
visited.add(type);
|
|
648
|
+
|
|
649
|
+
const constraint = checker.getBaseConstraintOfType(type);
|
|
650
|
+
if (constraint && constraint !== type) {
|
|
651
|
+
return getPrimitiveFamily(checker, constraint, visited);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (type.isUnion()) {
|
|
655
|
+
const families = new Set(
|
|
656
|
+
type.types.map((member) => getPrimitiveFamily(checker, member, visited)),
|
|
657
|
+
);
|
|
658
|
+
if (families.size !== 1) {
|
|
659
|
+
return undefined;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const [family] = families;
|
|
663
|
+
return family;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (type.isIntersection()) {
|
|
667
|
+
const families = new Set<PrimitiveFamily>();
|
|
668
|
+
for (const member of type.types) {
|
|
669
|
+
const family = getPrimitiveFamily(checker, member, visited);
|
|
670
|
+
if (family !== undefined) {
|
|
671
|
+
families.add(family);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (families.size !== 1) {
|
|
675
|
+
return undefined;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const [family] = families;
|
|
679
|
+
return family;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const normalized = checker.getBaseTypeOfLiteralType(type);
|
|
683
|
+
if ((normalized.flags & ts.TypeFlags.StringLike) !== 0) {
|
|
684
|
+
return 'string';
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if ((normalized.flags & ts.TypeFlags.NumberLike) !== 0) {
|
|
688
|
+
return 'number';
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if ((normalized.flags & ts.TypeFlags.BigIntLike) !== 0) {
|
|
692
|
+
return 'bigint';
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if ((normalized.flags & ts.TypeFlags.BooleanLike) !== 0) {
|
|
696
|
+
return 'boolean';
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if ((normalized.flags & ts.TypeFlags.ESSymbolLike) !== 0) {
|
|
700
|
+
return 'symbol';
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if ((normalized.flags & ts.TypeFlags.Null) !== 0) {
|
|
704
|
+
return 'null';
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if ((normalized.flags & ts.TypeFlags.Undefined) !== 0) {
|
|
708
|
+
return 'undefined';
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return undefined;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function isBooleanConditionExpression(
|
|
715
|
+
context: AnalysisContext,
|
|
716
|
+
expression: ts.Expression,
|
|
717
|
+
): boolean {
|
|
718
|
+
return isDefinitelyBooleanType(context.checker, context.checker.getTypeAtLocation(expression));
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function isAllowedPlusOperandPair(
|
|
722
|
+
checker: ts.TypeChecker,
|
|
723
|
+
left: ts.Type,
|
|
724
|
+
right: ts.Type,
|
|
725
|
+
): boolean {
|
|
726
|
+
return (
|
|
727
|
+
isDefinitelyStringType(checker, left) && isDefinitelyStringType(checker, right)
|
|
728
|
+
) || (
|
|
729
|
+
isDefinitelyNumberType(checker, left) && isDefinitelyNumberType(checker, right)
|
|
730
|
+
) || (
|
|
731
|
+
isDefinitelyBigIntType(checker, left) && isDefinitelyBigIntType(checker, right)
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function isAllowedRelationalOperandPair(
|
|
736
|
+
checker: ts.TypeChecker,
|
|
737
|
+
left: ts.Type,
|
|
738
|
+
right: ts.Type,
|
|
739
|
+
): boolean {
|
|
740
|
+
return (
|
|
741
|
+
isDefinitelyStringType(checker, left) && isDefinitelyStringType(checker, right)
|
|
742
|
+
) || (
|
|
743
|
+
isDefinitelyNumberType(checker, left) && isDefinitelyNumberType(checker, right)
|
|
744
|
+
) || (
|
|
745
|
+
isDefinitelyBigIntType(checker, left) && isDefinitelyBigIntType(checker, right)
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function isProtoPropertyName(name: ts.PropertyName): ts.Node | undefined {
|
|
750
|
+
if (
|
|
751
|
+
(ts.isIdentifier(name) || ts.isStringLiteral(name) ||
|
|
752
|
+
ts.isNoSubstitutionTemplateLiteral(name)) &&
|
|
753
|
+
name.text === '__proto__'
|
|
754
|
+
) {
|
|
755
|
+
return name;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (
|
|
759
|
+
ts.isComputedPropertyName(name) &&
|
|
760
|
+
(ts.isStringLiteral(name.expression) || ts.isNoSubstitutionTemplateLiteral(name.expression)) &&
|
|
761
|
+
name.expression.text === '__proto__'
|
|
762
|
+
) {
|
|
763
|
+
return name.expression;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function isVoidZeroExpression(node: ts.VoidExpression): boolean {
|
|
770
|
+
const expression = unwrapParenthesizedExpression(node.expression);
|
|
771
|
+
return ts.isNumericLiteral(expression) && expression.text === '0';
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function isLegacyOctalNumericLiteral(node: ts.Node): node is ts.NumericLiteral {
|
|
775
|
+
return ts.isNumericLiteral(node) && /^0[0-7]+$/.test(node.getText());
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function hasLegacyOctalEscape(rawText: string): boolean {
|
|
779
|
+
let consecutiveBackslashes = 0;
|
|
780
|
+
|
|
781
|
+
for (let index = 0; index < rawText.length; index += 1) {
|
|
782
|
+
const char = rawText[index];
|
|
783
|
+
if (char === '\\') {
|
|
784
|
+
consecutiveBackslashes += 1;
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const escaped = consecutiveBackslashes % 2 === 1;
|
|
789
|
+
consecutiveBackslashes = 0;
|
|
790
|
+
if (!escaped) {
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (/[1-7]/.test(char)) {
|
|
795
|
+
return true;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (char === '0' && /[0-7]/.test(rawText[index + 1] ?? '')) {
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function isLegacyOctalEscapeLiteral(node: ts.Node): node is ts.StringLiteralLike {
|
|
807
|
+
return ts.isStringLiteralLike(node) && hasLegacyOctalEscape(node.getText().slice(1, -1));
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function getDeclarationParameterName(parameter: ts.ParameterDeclaration): string | undefined {
|
|
811
|
+
return ts.isIdentifier(parameter.name) ? parameter.name.text : undefined;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function isLengthOnlyArrayConstructorCall(
|
|
815
|
+
context: AnalysisContext,
|
|
816
|
+
node: ts.CallExpression | ts.NewExpression,
|
|
817
|
+
): boolean {
|
|
818
|
+
if (node.arguments?.length !== 1) {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const info = getResolvedBuiltinSignatureInfo(context, node);
|
|
823
|
+
if (info?.ownerName !== 'ArrayConstructor') {
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const [parameter] = info.declaration.parameters;
|
|
828
|
+
return parameter !== undefined &&
|
|
829
|
+
parameter.dotDotDotToken === undefined &&
|
|
830
|
+
getDeclarationParameterName(parameter) === 'arrayLength';
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function isBroadObjectEnumerationTarget(
|
|
834
|
+
context: AnalysisContext,
|
|
835
|
+
expression: ts.Expression,
|
|
836
|
+
): boolean {
|
|
837
|
+
const unwrapped = unwrapParenthesizedExpression(expression);
|
|
838
|
+
if (ts.isObjectLiteralExpression(unwrapped) && unwrapped.properties.length === 0) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const type = context.checker.getTypeAtLocation(unwrapped);
|
|
843
|
+
if (!isInspectableObjectType(type)) {
|
|
844
|
+
return false;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (context.checker.getPropertiesOfType(type).length > 0) {
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
return context.checker.getIndexTypeOfType(type, ts.IndexKind.String) === undefined &&
|
|
852
|
+
context.checker.getIndexTypeOfType(type, ts.IndexKind.Number) === undefined;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function getStaticMemberAccess(node: ts.Node): {
|
|
856
|
+
expression: ts.Expression;
|
|
857
|
+
memberName: string;
|
|
858
|
+
memberNode: ts.Node;
|
|
859
|
+
} | undefined {
|
|
860
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
861
|
+
return {
|
|
862
|
+
expression: node.expression,
|
|
863
|
+
memberName: node.name.text,
|
|
864
|
+
memberNode: node.name,
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (
|
|
869
|
+
ts.isElementAccessExpression(node) &&
|
|
870
|
+
node.argumentExpression !== undefined &&
|
|
871
|
+
(ts.isStringLiteral(node.argumentExpression) ||
|
|
872
|
+
ts.isNoSubstitutionTemplateLiteral(node.argumentExpression))
|
|
873
|
+
) {
|
|
874
|
+
return {
|
|
875
|
+
expression: node.expression,
|
|
876
|
+
memberName: node.argumentExpression.text,
|
|
877
|
+
memberNode: node.argumentExpression,
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
return undefined;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function isFunctionLikeValue(context: AnalysisContext, expression: ts.Expression): boolean {
|
|
885
|
+
return typeHasFunctionLikeBrand(context.checker, context.checker.getTypeAtLocation(expression));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
function typeHasFunctionLikeBrand(
|
|
889
|
+
checker: ts.TypeChecker,
|
|
890
|
+
type: ts.Type,
|
|
891
|
+
visited: Set<ts.Type> = new Set(),
|
|
892
|
+
): boolean {
|
|
893
|
+
if (visited.has(type)) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
visited.add(type);
|
|
897
|
+
|
|
898
|
+
if (type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) {
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if ((type.flags & ts.TypeFlags.Union) !== 0) {
|
|
903
|
+
return (type as ts.UnionType).types.some((member) =>
|
|
904
|
+
typeHasFunctionLikeBrand(checker, member, visited)
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if ((type.flags & ts.TypeFlags.Intersection) !== 0) {
|
|
909
|
+
return (type as ts.IntersectionType).types.some((member) =>
|
|
910
|
+
typeHasFunctionLikeBrand(checker, member, visited)
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const normalized = checker.getBaseTypeOfLiteralType(type);
|
|
915
|
+
if (
|
|
916
|
+
hasFunctionLikeTypeName(normalized.aliasSymbol) || hasFunctionLikeTypeName(normalized.getSymbol())
|
|
917
|
+
) {
|
|
918
|
+
return true;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
const symbol = normalized.getSymbol();
|
|
922
|
+
if (!symbol || (symbol.flags & (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)) === 0) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const baseTypes = checker.getBaseTypes?.(normalized as ts.InterfaceType) ?? [];
|
|
927
|
+
return baseTypes.some((baseType) => typeHasFunctionLikeBrand(checker, baseType, visited));
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function hasFunctionLikeTypeName(symbol: ts.Symbol | undefined): boolean {
|
|
931
|
+
const name = symbol?.getName();
|
|
932
|
+
return name === 'Function' || name === 'CallableFunction' || name === 'NewableFunction';
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function isInspectableObjectType(type: ts.Type): boolean {
|
|
936
|
+
return (type.flags & ts.TypeFlags.Object) !== 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function getCallableMutationTarget(
|
|
940
|
+
context: AnalysisContext,
|
|
941
|
+
expression: ts.Expression,
|
|
942
|
+
): ts.Node | undefined {
|
|
943
|
+
if (
|
|
944
|
+
ts.isPropertyAccessExpression(expression) && isFunctionLikeValue(context, expression.expression)
|
|
945
|
+
) {
|
|
946
|
+
return expression.name;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (
|
|
950
|
+
ts.isElementAccessExpression(expression) &&
|
|
951
|
+
expression.argumentExpression !== undefined &&
|
|
952
|
+
isFunctionLikeValue(context, expression.expression)
|
|
953
|
+
) {
|
|
954
|
+
return expression.argumentExpression;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return undefined;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function getCallableMutationTargetInAssignmentPattern(
|
|
961
|
+
context: AnalysisContext,
|
|
962
|
+
expression: ts.Expression,
|
|
963
|
+
): ts.Node | undefined {
|
|
964
|
+
const directTarget = getCallableMutationTarget(context, expression);
|
|
965
|
+
if (directTarget) {
|
|
966
|
+
return directTarget;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
if (ts.isParenthesizedExpression(expression)) {
|
|
970
|
+
return getCallableMutationTargetInAssignmentPattern(context, expression.expression);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
if (ts.isObjectLiteralExpression(expression)) {
|
|
974
|
+
for (const property of expression.properties) {
|
|
975
|
+
if (ts.isPropertyAssignment(property)) {
|
|
976
|
+
const target = getCallableMutationTargetInAssignmentPattern(context, property.initializer);
|
|
977
|
+
if (target) {
|
|
978
|
+
return target;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (ts.isArrayLiteralExpression(expression)) {
|
|
985
|
+
for (const element of expression.elements) {
|
|
986
|
+
if (!ts.isExpression(element)) {
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
const target = getCallableMutationTargetInAssignmentPattern(context, element);
|
|
991
|
+
if (target) {
|
|
992
|
+
return target;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return undefined;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
function isAssignmentOperatorToken(kind: ts.SyntaxKind): boolean {
|
|
1001
|
+
return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
function isArgumentsIdentifier(node: ts.Identifier): boolean {
|
|
1005
|
+
if (node.text !== 'arguments') {
|
|
1006
|
+
return false;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (ts.isQualifiedName(node.parent) && node.parent.right === node) {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (
|
|
1018
|
+
(ts.isPropertyAssignment(node.parent) ||
|
|
1019
|
+
ts.isPropertyDeclaration(node.parent) ||
|
|
1020
|
+
ts.isPropertySignature(node.parent) ||
|
|
1021
|
+
ts.isMethodDeclaration(node.parent) ||
|
|
1022
|
+
ts.isGetAccessorDeclaration(node.parent) ||
|
|
1023
|
+
ts.isSetAccessorDeclaration(node.parent)) &&
|
|
1024
|
+
node.parent.name === node
|
|
1025
|
+
) {
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return true;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
function hasModifier(node: ts.Node, kind: ts.SyntaxKind): boolean {
|
|
1033
|
+
return ts.canHaveModifiers(node) &&
|
|
1034
|
+
(ts.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function isSoundSourceFile(sourceFile: ts.SourceFile): boolean {
|
|
1038
|
+
return !sourceFile.isDeclarationFile &&
|
|
1039
|
+
(sourceFile.fileName.endsWith('.sts') || sourceFile.fileName.endsWith('.sts.ts'));
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
function isMacroAuthoringSourceFile(sourceFile: ts.SourceFile): boolean {
|
|
1043
|
+
return sourceFile.fileName.endsWith('.macro.sts') ||
|
|
1044
|
+
sourceFile.fileName.endsWith('.macro.sts.ts');
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function isSynthesizedNode(node: ts.Node): boolean {
|
|
1048
|
+
return node.pos < 0 || (node.flags & ts.NodeFlags.Synthesized) !== 0;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
function getCanonicalSymbol(
|
|
1052
|
+
checker: ts.TypeChecker,
|
|
1053
|
+
symbol: ts.Symbol | undefined,
|
|
1054
|
+
): ts.Symbol | undefined {
|
|
1055
|
+
if (!symbol) {
|
|
1056
|
+
return undefined;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
return (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
type AmbientRuntimeDeclarationNode =
|
|
1063
|
+
| ts.ClassDeclaration
|
|
1064
|
+
| ts.FunctionDeclaration
|
|
1065
|
+
| ts.VariableStatement;
|
|
1066
|
+
|
|
1067
|
+
function isMacroHelperAmbientRuntimeDeclaration(node: AmbientRuntimeDeclarationNode): boolean {
|
|
1068
|
+
return ts.isFunctionDeclaration(node) &&
|
|
1069
|
+
(node.name?.text === '__sts_macro_expr' || node.name?.text === '__sts_macro_stmt');
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
function isStrippedMacroFactoryPlaceholderDeclaration(
|
|
1073
|
+
node: AmbientRuntimeDeclarationNode,
|
|
1074
|
+
): boolean {
|
|
1075
|
+
if (!ts.isVariableStatement(node)) {
|
|
1076
|
+
return false;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
if (!node.getSourceFile().text.includes('/* soundscript:macros */')) {
|
|
1080
|
+
return false;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
return node.declarationList.declarations.length > 0 &&
|
|
1084
|
+
node.declarationList.declarations.every((declaration) =>
|
|
1085
|
+
ts.isIdentifier(declaration.name) &&
|
|
1086
|
+
declaration.initializer === undefined &&
|
|
1087
|
+
declaration.type?.kind === ts.SyntaxKind.UnknownKeyword
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
function getAmbientRuntimeDeclarationNode(
|
|
1092
|
+
context: AnalysisContext,
|
|
1093
|
+
node: ts.Node,
|
|
1094
|
+
): AmbientRuntimeDeclarationNode | undefined {
|
|
1095
|
+
const sourceFile = node.getSourceFile();
|
|
1096
|
+
if (
|
|
1097
|
+
isSynthesizedNode(node) ||
|
|
1098
|
+
context.isGeneratedNode(node) ||
|
|
1099
|
+
!isSoundSourceFile(sourceFile) ||
|
|
1100
|
+
isMacroAuthoringSourceFile(sourceFile)
|
|
1101
|
+
) {
|
|
1102
|
+
return undefined;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (ts.isVariableStatement(node) && hasModifier(node, ts.SyntaxKind.DeclareKeyword)) {
|
|
1106
|
+
return isStrippedMacroFactoryPlaceholderDeclaration(node) ? undefined : node;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
if (
|
|
1110
|
+
(ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) &&
|
|
1111
|
+
hasModifier(node, ts.SyntaxKind.DeclareKeyword)
|
|
1112
|
+
) {
|
|
1113
|
+
return isMacroHelperAmbientRuntimeDeclaration(node) ? undefined : node;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return undefined;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function getAmbientRuntimeDeclarationDiagnosticNode(
|
|
1120
|
+
node: AmbientRuntimeDeclarationNode,
|
|
1121
|
+
): ts.Node {
|
|
1122
|
+
if (ts.isVariableStatement(node)) {
|
|
1123
|
+
const firstDeclaration = node.declarationList.declarations[0];
|
|
1124
|
+
if (firstDeclaration && ts.isIdentifier(firstDeclaration.name)) {
|
|
1125
|
+
return firstDeclaration.name;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
return node;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
return node.name ?? node;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
function getAmbientRuntimeDeclarationSymbols(
|
|
1135
|
+
context: AnalysisContext,
|
|
1136
|
+
node: AmbientRuntimeDeclarationNode,
|
|
1137
|
+
): readonly ts.Symbol[] {
|
|
1138
|
+
if (ts.isVariableStatement(node)) {
|
|
1139
|
+
return node.declarationList.declarations
|
|
1140
|
+
.map((declaration) =>
|
|
1141
|
+
ts.isIdentifier(declaration.name)
|
|
1142
|
+
? getCanonicalSymbol(
|
|
1143
|
+
context.checker,
|
|
1144
|
+
context.checker.getSymbolAtLocation(declaration.name),
|
|
1145
|
+
)
|
|
1146
|
+
: undefined
|
|
1147
|
+
)
|
|
1148
|
+
.filter((symbol): symbol is ts.Symbol => symbol !== undefined);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (!node.name) {
|
|
1152
|
+
return [];
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const symbol = getCanonicalSymbol(
|
|
1156
|
+
context.checker,
|
|
1157
|
+
context.checker.getSymbolAtLocation(node.name),
|
|
1158
|
+
);
|
|
1159
|
+
return symbol ? [symbol] : [];
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function getAmbientRuntimeDeclarationFromSymbolDeclaration(
|
|
1163
|
+
context: AnalysisContext,
|
|
1164
|
+
declaration: ts.Declaration,
|
|
1165
|
+
): AmbientRuntimeDeclarationNode | undefined {
|
|
1166
|
+
if (ts.isVariableDeclaration(declaration)) {
|
|
1167
|
+
return ts.isVariableDeclarationList(declaration.parent) &&
|
|
1168
|
+
ts.isVariableStatement(declaration.parent.parent)
|
|
1169
|
+
? getAmbientRuntimeDeclarationNode(context, declaration.parent.parent)
|
|
1170
|
+
: undefined;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
return getAmbientRuntimeDeclarationNode(context, declaration);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
function nodeReferencesAmbientRuntimeDeclaration(
|
|
1177
|
+
context: AnalysisContext,
|
|
1178
|
+
node: ts.Node,
|
|
1179
|
+
declarationSymbols: readonly ts.Symbol[],
|
|
1180
|
+
): boolean {
|
|
1181
|
+
if (declarationSymbols.length === 0) {
|
|
1182
|
+
return false;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (ts.isExportAssignment(node)) {
|
|
1186
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
const symbol = getCanonicalSymbol(
|
|
1191
|
+
context.checker,
|
|
1192
|
+
context.checker.getSymbolAtLocation(node.expression),
|
|
1193
|
+
);
|
|
1194
|
+
return symbol !== undefined && declarationSymbols.includes(symbol);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (ts.isExportSpecifier(node)) {
|
|
1198
|
+
const localNode = node.propertyName ?? node.name;
|
|
1199
|
+
const symbol = getCanonicalSymbol(
|
|
1200
|
+
context.checker,
|
|
1201
|
+
context.checker.getSymbolAtLocation(localNode),
|
|
1202
|
+
);
|
|
1203
|
+
return symbol !== undefined && declarationSymbols.includes(symbol);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
function isAmbientRuntimeDeclarationReexported(
|
|
1210
|
+
context: AnalysisContext,
|
|
1211
|
+
node: AmbientRuntimeDeclarationNode,
|
|
1212
|
+
): boolean {
|
|
1213
|
+
const declarationSymbols = getAmbientRuntimeDeclarationSymbols(context, node);
|
|
1214
|
+
if (declarationSymbols.length === 0) {
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
const sourceFile = node.getSourceFile();
|
|
1219
|
+
for (const statement of sourceFile.statements) {
|
|
1220
|
+
if (context.isGeneratedNode(statement)) {
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
if (
|
|
1225
|
+
ts.isExportAssignment(statement) &&
|
|
1226
|
+
!statement.isExportEquals &&
|
|
1227
|
+
nodeReferencesAmbientRuntimeDeclaration(context, statement, declarationSymbols)
|
|
1228
|
+
) {
|
|
1229
|
+
return true;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
if (
|
|
1233
|
+
ts.isExportDeclaration(statement) &&
|
|
1234
|
+
!statement.isTypeOnly &&
|
|
1235
|
+
statement.exportClause &&
|
|
1236
|
+
ts.isNamedExports(statement.exportClause) &&
|
|
1237
|
+
statement.moduleSpecifier === undefined &&
|
|
1238
|
+
statement.exportClause.elements.some((element) =>
|
|
1239
|
+
nodeReferencesAmbientRuntimeDeclaration(context, element, declarationSymbols)
|
|
1240
|
+
)
|
|
1241
|
+
) {
|
|
1242
|
+
return true;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
return false;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
function hasExternDirective(context: AnalysisContext, node: ts.Node): boolean {
|
|
1250
|
+
return context.getAnnotationLookup(node.getSourceFile()).hasAttachedAnnotation(node, 'extern');
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
function isAmbientRuntimeDeclarationExported(node: AmbientRuntimeDeclarationNode): boolean {
|
|
1254
|
+
return hasModifier(node, ts.SyntaxKind.ExportKeyword) ||
|
|
1255
|
+
hasModifier(node, ts.SyntaxKind.DefaultKeyword);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function getAmbientRuntimeExportDiagnostic(
|
|
1259
|
+
context: AnalysisContext,
|
|
1260
|
+
node: ts.Node,
|
|
1261
|
+
): AmbientRuntimeExportDiagnostic | undefined {
|
|
1262
|
+
const declarationNode = getAmbientRuntimeDeclarationNode(context, node);
|
|
1263
|
+
if (declarationNode && isAmbientRuntimeDeclarationExported(declarationNode)) {
|
|
1264
|
+
return {
|
|
1265
|
+
declarationNode,
|
|
1266
|
+
diagnosticNode: getAmbientRuntimeDeclarationDiagnosticNode(declarationNode),
|
|
1267
|
+
exportForm: 'direct export',
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
if (
|
|
1272
|
+
ts.isExportAssignment(node) &&
|
|
1273
|
+
!node.isExportEquals &&
|
|
1274
|
+
ts.isIdentifier(node.expression)
|
|
1275
|
+
) {
|
|
1276
|
+
const symbol = getCanonicalSymbol(
|
|
1277
|
+
context.checker,
|
|
1278
|
+
context.checker.getSymbolAtLocation(node.expression),
|
|
1279
|
+
);
|
|
1280
|
+
if (
|
|
1281
|
+
symbol?.declarations?.some((declaration) =>
|
|
1282
|
+
declaration.getSourceFile() === node.getSourceFile() &&
|
|
1283
|
+
getAmbientRuntimeDeclarationFromSymbolDeclaration(context, declaration) !== undefined
|
|
1284
|
+
)
|
|
1285
|
+
) {
|
|
1286
|
+
const declarationNode = symbol.declarations
|
|
1287
|
+
?.filter((declaration) => declaration.getSourceFile() === node.getSourceFile())
|
|
1288
|
+
.map((declaration) => getAmbientRuntimeDeclarationFromSymbolDeclaration(context, declaration))
|
|
1289
|
+
.find((declaration): declaration is AmbientRuntimeDeclarationNode => declaration !== undefined);
|
|
1290
|
+
if (declarationNode) {
|
|
1291
|
+
return {
|
|
1292
|
+
declarationNode,
|
|
1293
|
+
diagnosticNode: node.expression,
|
|
1294
|
+
exportForm: 'default export alias',
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
if (
|
|
1301
|
+
ts.isExportSpecifier(node) &&
|
|
1302
|
+
node.parent.parent.moduleSpecifier === undefined
|
|
1303
|
+
) {
|
|
1304
|
+
const localNode = node.propertyName ?? node.name;
|
|
1305
|
+
const symbol = getCanonicalSymbol(
|
|
1306
|
+
context.checker,
|
|
1307
|
+
context.checker.getSymbolAtLocation(localNode),
|
|
1308
|
+
);
|
|
1309
|
+
if (
|
|
1310
|
+
symbol?.declarations?.some((declaration) => {
|
|
1311
|
+
return declaration.getSourceFile() === node.getSourceFile() &&
|
|
1312
|
+
getAmbientRuntimeDeclarationFromSymbolDeclaration(context, declaration) !== undefined;
|
|
1313
|
+
})
|
|
1314
|
+
) {
|
|
1315
|
+
const declarationNode = symbol.declarations
|
|
1316
|
+
?.filter((declaration) => declaration.getSourceFile() === node.getSourceFile())
|
|
1317
|
+
.map((declaration) => getAmbientRuntimeDeclarationFromSymbolDeclaration(context, declaration))
|
|
1318
|
+
.find((declaration): declaration is AmbientRuntimeDeclarationNode => declaration !== undefined);
|
|
1319
|
+
if (declarationNode) {
|
|
1320
|
+
return {
|
|
1321
|
+
declarationNode,
|
|
1322
|
+
diagnosticNode: node.name,
|
|
1323
|
+
exportForm: 'local re-export',
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
return undefined;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
function getAmbientRuntimeRequiresExternDeclarationNode(
|
|
1333
|
+
context: AnalysisContext,
|
|
1334
|
+
node: ts.Node,
|
|
1335
|
+
): AmbientRuntimeDeclarationNode | undefined {
|
|
1336
|
+
const declarationNode = getAmbientRuntimeDeclarationNode(context, node);
|
|
1337
|
+
if (!declarationNode) {
|
|
1338
|
+
return undefined;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
if (
|
|
1342
|
+
isAmbientRuntimeDeclarationExported(declarationNode) ||
|
|
1343
|
+
isAmbientRuntimeDeclarationReexported(context, declarationNode)
|
|
1344
|
+
) {
|
|
1345
|
+
return undefined;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
if (hasExternDirective(context, declarationNode)) {
|
|
1349
|
+
return undefined;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
return declarationNode;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function getProtoDefinitionNode(node: ts.Node): ts.Node | undefined {
|
|
1356
|
+
if (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) {
|
|
1357
|
+
return isProtoPropertyName(node.name);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
if (
|
|
1361
|
+
node.parent !== undefined &&
|
|
1362
|
+
ts.isObjectLiteralExpression(node.parent) &&
|
|
1363
|
+
(ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) ||
|
|
1364
|
+
ts.isSetAccessorDeclaration(node))
|
|
1365
|
+
) {
|
|
1366
|
+
return isProtoPropertyName(node.name);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return undefined;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function isSoundScriptSourceFilePath(fileName: string): boolean {
|
|
1373
|
+
return /\.sts(?:\.ts)?$/.test(fileName);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
function getDecoratorDiagnosticNode(node: ts.Node): ts.Node | undefined {
|
|
1377
|
+
if (!isSoundScriptSourceFilePath(node.getSourceFile().fileName) || !ts.canHaveDecorators(node)) {
|
|
1378
|
+
return undefined;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
const decorators = ts.getDecorators(node);
|
|
1382
|
+
return decorators && decorators.length > 0 ? decorators[0] : undefined;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
function isTopLevelThisExpression(node: ts.ThisExpression): boolean {
|
|
1386
|
+
let current: ts.Node | undefined = node.parent;
|
|
1387
|
+
|
|
1388
|
+
while (current) {
|
|
1389
|
+
if (
|
|
1390
|
+
ts.isFunctionLike(current) ||
|
|
1391
|
+
ts.isClassLike(current) ||
|
|
1392
|
+
current.kind === ts.SyntaxKind.ClassStaticBlockDeclaration
|
|
1393
|
+
) {
|
|
1394
|
+
return false;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
if (ts.isSourceFile(current)) {
|
|
1398
|
+
return true;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
current = current.parent;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
return false;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
function isAllowedThisContainer(node: ts.SignatureDeclarationBase): boolean {
|
|
1408
|
+
return ts.isConstructorDeclaration(node) ||
|
|
1409
|
+
ts.isMethodDeclaration(node) ||
|
|
1410
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
1411
|
+
ts.isSetAccessorDeclaration(node);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
function isBannedThisExpression(node: ts.ThisExpression): boolean {
|
|
1415
|
+
let current: ts.Node | undefined = node.parent;
|
|
1416
|
+
|
|
1417
|
+
while (current) {
|
|
1418
|
+
if (ts.isFunctionLike(current)) {
|
|
1419
|
+
return !isAllowedThisContainer(current);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
if (
|
|
1423
|
+
ts.isClassLike(current) ||
|
|
1424
|
+
current.kind === ts.SyntaxKind.ClassStaticBlockDeclaration
|
|
1425
|
+
) {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
if (ts.isSourceFile(current)) {
|
|
1430
|
+
return true;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
current = current.parent;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
return false;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
function isBannedDeclarationFileTypeReference(
|
|
1440
|
+
context: AnalysisContext,
|
|
1441
|
+
node: ts.TypeReferenceNode,
|
|
1442
|
+
): ts.Node | undefined {
|
|
1443
|
+
if (
|
|
1444
|
+
!ts.isIdentifier(node.typeName) ||
|
|
1445
|
+
!isBannedDeclarationFileTypeName(context, node.typeName.text)
|
|
1446
|
+
) {
|
|
1447
|
+
return undefined;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
const symbol = context.checker.getSymbolAtLocation(node.typeName);
|
|
1451
|
+
if (!symbol) {
|
|
1452
|
+
return undefined;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
const resolved = (symbol.flags & ts.SymbolFlags.Alias) !== 0
|
|
1456
|
+
? context.checker.getAliasedSymbol(symbol)
|
|
1457
|
+
: symbol;
|
|
1458
|
+
const declarations = resolved.declarations ?? [];
|
|
1459
|
+
if (
|
|
1460
|
+
declarations.length === 0 ||
|
|
1461
|
+
!declarations.every((declaration) => declaration.getSourceFile().isDeclarationFile)
|
|
1462
|
+
) {
|
|
1463
|
+
return undefined;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
return node.typeName;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
function supportsWeakCollections(context: AnalysisContext): boolean {
|
|
1470
|
+
return context.runtime.target !== 'wasm-wasi';
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function isBannedDeclarationFileTypeName(
|
|
1474
|
+
context: AnalysisContext,
|
|
1475
|
+
typeName: string,
|
|
1476
|
+
): boolean {
|
|
1477
|
+
if (ALWAYS_BANNED_DECLARATION_FILE_TYPE_NAMES.has(typeName)) {
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
if (
|
|
1481
|
+
CONDITIONALLY_BANNED_DECLARATION_FILE_TYPE_NAMES.has(typeName) &&
|
|
1482
|
+
!supportsWeakCollections(context)
|
|
1483
|
+
) {
|
|
1484
|
+
return true;
|
|
1485
|
+
}
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function getBannedConstructorOwnerNames(
|
|
1490
|
+
context: AnalysisContext,
|
|
1491
|
+
): readonly string[] {
|
|
1492
|
+
return supportsWeakCollections(context)
|
|
1493
|
+
? [
|
|
1494
|
+
'StringConstructor',
|
|
1495
|
+
'NumberConstructor',
|
|
1496
|
+
'BooleanConstructor',
|
|
1497
|
+
'FunctionConstructor',
|
|
1498
|
+
'ProxyConstructor',
|
|
1499
|
+
'WeakRefConstructor',
|
|
1500
|
+
'FinalizationRegistryConstructor',
|
|
1501
|
+
]
|
|
1502
|
+
: [
|
|
1503
|
+
'StringConstructor',
|
|
1504
|
+
'NumberConstructor',
|
|
1505
|
+
'BooleanConstructor',
|
|
1506
|
+
'FunctionConstructor',
|
|
1507
|
+
'ProxyConstructor',
|
|
1508
|
+
'WeakMapConstructor',
|
|
1509
|
+
'WeakSetConstructor',
|
|
1510
|
+
'WeakRefConstructor',
|
|
1511
|
+
'FinalizationRegistryConstructor',
|
|
1512
|
+
];
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
function isBannedSymbolHookName(
|
|
1516
|
+
context: AnalysisContext,
|
|
1517
|
+
name: ts.PropertyName,
|
|
1518
|
+
): ts.Node | undefined {
|
|
1519
|
+
if (!ts.isComputedPropertyName(name)) {
|
|
1520
|
+
return undefined;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
const expression = unwrapParenthesizedExpression(name.expression);
|
|
1524
|
+
if (
|
|
1525
|
+
ts.isPropertyAccessExpression(expression) &&
|
|
1526
|
+
resolvesToBuiltinGlobalValue(context, expression.expression, 'Symbol', {
|
|
1527
|
+
ownerNames: ['SymbolConstructor'],
|
|
1528
|
+
}) &&
|
|
1529
|
+
BANNED_SYMBOL_HOOK_MEMBER_NAMES.has(expression.name.text)
|
|
1530
|
+
) {
|
|
1531
|
+
return expression.name;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (
|
|
1535
|
+
ts.isElementAccessExpression(expression) &&
|
|
1536
|
+
resolvesToBuiltinGlobalValue(context, expression.expression, 'Symbol', {
|
|
1537
|
+
ownerNames: ['SymbolConstructor'],
|
|
1538
|
+
}) &&
|
|
1539
|
+
expression.argumentExpression !== undefined &&
|
|
1540
|
+
ts.isStringLiteralLike(expression.argumentExpression) &&
|
|
1541
|
+
BANNED_SYMBOL_HOOK_MEMBER_NAMES.has(expression.argumentExpression.text)
|
|
1542
|
+
) {
|
|
1543
|
+
return expression.argumentExpression;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
return undefined;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
function getWrappedInvocationArgument(
|
|
1550
|
+
node: ts.CallExpression,
|
|
1551
|
+
invocation: WrappedBuiltinInvocation,
|
|
1552
|
+
directArgumentIndex: number,
|
|
1553
|
+
): ts.Expression | undefined {
|
|
1554
|
+
if (invocation.wrapperKind === 'call') {
|
|
1555
|
+
return node.arguments[directArgumentIndex + 1];
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
const argumentList = node.arguments[1];
|
|
1559
|
+
if (!argumentList || !ts.isArrayLiteralExpression(argumentList)) {
|
|
1560
|
+
return undefined;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
const element = argumentList.elements[directArgumentIndex];
|
|
1564
|
+
return element && ts.isExpression(element) ? element : undefined;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
function getObjectBindingElementPropertyName(
|
|
1568
|
+
element: ts.BindingElement,
|
|
1569
|
+
): string | undefined {
|
|
1570
|
+
const propertyName = element.propertyName ?? element.name;
|
|
1571
|
+
if (ts.isIdentifier(propertyName) || ts.isStringLiteralLike(propertyName)) {
|
|
1572
|
+
return propertyName.text;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
return undefined;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
function isObjectPrototypePrimitiveConversionHookAlias(
|
|
1579
|
+
context: AnalysisContext,
|
|
1580
|
+
expression: ts.Expression,
|
|
1581
|
+
): boolean {
|
|
1582
|
+
if (!ts.isIdentifier(expression)) {
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
const symbol = context.checker.getSymbolAtLocation(expression);
|
|
1587
|
+
if (!symbol) {
|
|
1588
|
+
return false;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
const resolved = (symbol.flags & ts.SymbolFlags.Alias) !== 0
|
|
1592
|
+
? context.checker.getAliasedSymbol(symbol)
|
|
1593
|
+
: symbol;
|
|
1594
|
+
for (const declaration of resolved.declarations ?? []) {
|
|
1595
|
+
if (!ts.isBindingElement(declaration)) {
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
if (
|
|
1600
|
+
!PRIMITIVE_CONVERSION_HOOK_MEMBER_NAMES.has(
|
|
1601
|
+
getObjectBindingElementPropertyName(declaration) ?? '',
|
|
1602
|
+
)
|
|
1603
|
+
) {
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
const bindingPattern = declaration.parent;
|
|
1608
|
+
if (!ts.isObjectBindingPattern(bindingPattern)) {
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
const variableDeclaration = bindingPattern.parent;
|
|
1613
|
+
if (
|
|
1614
|
+
!ts.isVariableDeclaration(variableDeclaration) ||
|
|
1615
|
+
variableDeclaration.initializer === undefined
|
|
1616
|
+
) {
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
const initializer = unwrapParenthesizedExpression(variableDeclaration.initializer);
|
|
1621
|
+
if (
|
|
1622
|
+
ts.isPropertyAccessExpression(initializer) &&
|
|
1623
|
+
initializer.name.text === 'prototype' &&
|
|
1624
|
+
resolvesToBuiltinGlobalValue(context, initializer.expression, 'Object', {
|
|
1625
|
+
ownerNames: ['ObjectConstructor'],
|
|
1626
|
+
})
|
|
1627
|
+
) {
|
|
1628
|
+
return true;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
function isObjectPrototypePrimitiveConversionHookValue(
|
|
1636
|
+
context: AnalysisContext,
|
|
1637
|
+
expression: ts.Expression,
|
|
1638
|
+
): boolean {
|
|
1639
|
+
return matchesResolvedBuiltinCallableValue(context, expression, {
|
|
1640
|
+
ownerNames: ['Object'],
|
|
1641
|
+
memberNames: ['toString', 'valueOf'],
|
|
1642
|
+
}) || isObjectPrototypePrimitiveConversionHookAlias(context, expression);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
function isBannedConstructorValue(
|
|
1646
|
+
context: AnalysisContext,
|
|
1647
|
+
expression: ts.Expression,
|
|
1648
|
+
): boolean {
|
|
1649
|
+
return matchesResolvedBuiltinCallableValue(context, expression, {
|
|
1650
|
+
ownerNames: getBannedConstructorOwnerNames(context),
|
|
1651
|
+
}, 'construct');
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
function getBannedPrimitiveConversionHookCallNode(
|
|
1655
|
+
context: AnalysisContext,
|
|
1656
|
+
node: ts.CallExpression,
|
|
1657
|
+
): ts.Node | undefined {
|
|
1658
|
+
const memberAccess = getStaticMemberAccess(node.expression);
|
|
1659
|
+
if (
|
|
1660
|
+
memberAccess &&
|
|
1661
|
+
PRIMITIVE_CONVERSION_HOOK_MEMBER_NAMES.has(memberAccess.memberName) &&
|
|
1662
|
+
!isDefinitelyNonNullishPrimitiveType(
|
|
1663
|
+
context.checker,
|
|
1664
|
+
context.checker.getTypeAtLocation(memberAccess.expression),
|
|
1665
|
+
)
|
|
1666
|
+
) {
|
|
1667
|
+
return memberAccess.memberNode;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
const wrappedInvocation = getWrappedBuiltinInvocation(node);
|
|
1671
|
+
if (
|
|
1672
|
+
wrappedInvocation &&
|
|
1673
|
+
isObjectPrototypePrimitiveConversionHookValue(context, wrappedInvocation.target)
|
|
1674
|
+
) {
|
|
1675
|
+
return node.expression;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
if (ts.isCallExpression(node.expression)) {
|
|
1679
|
+
const bindTarget = getStaticMemberAccess(node.expression.expression);
|
|
1680
|
+
if (
|
|
1681
|
+
bindTarget?.memberName === 'bind' &&
|
|
1682
|
+
isObjectPrototypePrimitiveConversionHookValue(context, bindTarget.expression)
|
|
1683
|
+
) {
|
|
1684
|
+
return node.expression;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const wrappedBindInvocation = getWrappedBuiltinInvocation(node.expression);
|
|
1688
|
+
if (
|
|
1689
|
+
wrappedBindInvocation &&
|
|
1690
|
+
(wrappedBindInvocation.wrapperKind === 'call' ||
|
|
1691
|
+
wrappedBindInvocation.wrapperKind === 'apply')
|
|
1692
|
+
) {
|
|
1693
|
+
const bindMember = getStaticMemberAccess(wrappedBindInvocation.target);
|
|
1694
|
+
if (
|
|
1695
|
+
bindMember?.memberName === 'bind' &&
|
|
1696
|
+
isObjectPrototypePrimitiveConversionHookValue(context, bindMember.expression)
|
|
1697
|
+
) {
|
|
1698
|
+
return node.expression;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
return undefined;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
function getUnsupportedFeatureDiagnostic(
|
|
1707
|
+
context: AnalysisContext,
|
|
1708
|
+
node: ts.Node,
|
|
1709
|
+
): UnsupportedFeatureDiagnostic | undefined {
|
|
1710
|
+
const ambientAugmentationNode = getAmbientAugmentationDiagnosticNode(node);
|
|
1711
|
+
if (ambientAugmentationNode) {
|
|
1712
|
+
return unsupportedFeature(ambientAugmentationNode, 'ambientAugmentation');
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
const ambientEnumNode = getAmbientEnumDiagnosticNode(node);
|
|
1716
|
+
if (ambientEnumNode) {
|
|
1717
|
+
return unsupportedFeature(ambientEnumNode, 'ambientEnum');
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
const scriptScopeInterfaceMergeNode = getScriptScopeInterfaceMergeDiagnosticNode(context, node);
|
|
1721
|
+
if (scriptScopeInterfaceMergeNode) {
|
|
1722
|
+
return unsupportedFeature(scriptScopeInterfaceMergeNode, 'scriptScopeInterfaceMerge');
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const classInterfaceMergeNode = getClassInterfaceMergeDiagnosticNode(context, node);
|
|
1726
|
+
if (classInterfaceMergeNode) {
|
|
1727
|
+
return unsupportedFeature(classInterfaceMergeNode, 'classInterfaceMerge');
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
const decoratorNode = getDecoratorDiagnosticNode(node);
|
|
1731
|
+
if (decoratorNode) {
|
|
1732
|
+
return unsupportedFeature(decoratorNode, 'decorators');
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
if (ts.isWithStatement(node)) {
|
|
1736
|
+
return unsupportedFeature(node, 'withStatement');
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
if (
|
|
1740
|
+
(ts.isIfStatement(node) ||
|
|
1741
|
+
ts.isWhileStatement(node) ||
|
|
1742
|
+
ts.isDoStatement(node)) &&
|
|
1743
|
+
!isBooleanConditionExpression(context, node.expression)
|
|
1744
|
+
) {
|
|
1745
|
+
return unsupportedFeature(node.expression, 'nonBooleanCondition');
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
if (
|
|
1749
|
+
ts.isForStatement(node) &&
|
|
1750
|
+
node.condition !== undefined &&
|
|
1751
|
+
!isBooleanConditionExpression(context, node.condition)
|
|
1752
|
+
) {
|
|
1753
|
+
return unsupportedFeature(node.condition, 'nonBooleanCondition');
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
if (
|
|
1757
|
+
ts.isConditionalExpression(node) &&
|
|
1758
|
+
!isBooleanConditionExpression(context, node.condition)
|
|
1759
|
+
) {
|
|
1760
|
+
return unsupportedFeature(node.condition, 'nonBooleanCondition');
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
if (ts.isVariableDeclarationList(node) && (node.flags & ts.NodeFlags.BlockScoped) === 0) {
|
|
1764
|
+
return unsupportedFeature(node, 'varDeclaration');
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
if (isLegacyOctalNumericLiteral(node) || isLegacyOctalEscapeLiteral(node)) {
|
|
1768
|
+
return unsupportedFeature(node, 'legacyOctalLiteral');
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
1772
|
+
const bannedTypeReference = isBannedDeclarationFileTypeReference(context, node);
|
|
1773
|
+
if (bannedTypeReference) {
|
|
1774
|
+
return unsupportedFeature(bannedTypeReference, 'bannedDeclarationFileTypeReference', {
|
|
1775
|
+
name: bannedTypeReference.getText(bannedTypeReference.getSourceFile()),
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
if (ts.isIdentifier(node) && isArgumentsIdentifier(node)) {
|
|
1781
|
+
return unsupportedFeature(node, 'argumentsObject');
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
if (ts.isDebuggerStatement(node)) {
|
|
1785
|
+
return unsupportedFeature(node, 'debuggerStatement');
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
if (
|
|
1789
|
+
ts.isBinaryExpression(node) &&
|
|
1790
|
+
(node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
|
|
1791
|
+
node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken)
|
|
1792
|
+
) {
|
|
1793
|
+
return unsupportedFeature(node.operatorToken, 'looseEquality');
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
if (
|
|
1797
|
+
ts.isBinaryExpression(node) &&
|
|
1798
|
+
(node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
1799
|
+
node.operatorToken.kind === ts.SyntaxKind.BarBarToken) &&
|
|
1800
|
+
(
|
|
1801
|
+
!isDefinitelyBooleanType(context.checker, context.checker.getTypeAtLocation(node.left)) ||
|
|
1802
|
+
!isDefinitelyBooleanType(context.checker, context.checker.getTypeAtLocation(node.right))
|
|
1803
|
+
)
|
|
1804
|
+
) {
|
|
1805
|
+
return unsupportedFeature(node.operatorToken, 'nonBooleanLogicalOperator');
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
if (
|
|
1809
|
+
ts.isPrefixUnaryExpression(node) &&
|
|
1810
|
+
node.operator === ts.SyntaxKind.ExclamationToken &&
|
|
1811
|
+
!isDefinitelyBooleanType(context.checker, context.checker.getTypeAtLocation(node.operand))
|
|
1812
|
+
) {
|
|
1813
|
+
return unsupportedFeature(node, 'nonBooleanLogicalNot');
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
if (
|
|
1817
|
+
ts.isBinaryExpression(node) &&
|
|
1818
|
+
(node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1819
|
+
node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken)
|
|
1820
|
+
) {
|
|
1821
|
+
const leftFamily = getPrimitiveFamily(
|
|
1822
|
+
context.checker,
|
|
1823
|
+
context.checker.getTypeAtLocation(node.left),
|
|
1824
|
+
);
|
|
1825
|
+
const rightFamily = getPrimitiveFamily(
|
|
1826
|
+
context.checker,
|
|
1827
|
+
context.checker.getTypeAtLocation(node.right),
|
|
1828
|
+
);
|
|
1829
|
+
const nullishFamilies = new Set<PrimitiveFamily>(['null', 'undefined']);
|
|
1830
|
+
|
|
1831
|
+
if (
|
|
1832
|
+
leftFamily !== undefined &&
|
|
1833
|
+
rightFamily !== undefined &&
|
|
1834
|
+
leftFamily !== rightFamily &&
|
|
1835
|
+
!nullishFamilies.has(leftFamily) &&
|
|
1836
|
+
!nullishFamilies.has(rightFamily)
|
|
1837
|
+
) {
|
|
1838
|
+
return unsupportedFeature(node.operatorToken, 'incompatibleStrictEquality');
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
if (
|
|
1843
|
+
ts.isBinaryExpression(node) &&
|
|
1844
|
+
(
|
|
1845
|
+
node.operatorToken.kind === ts.SyntaxKind.LessThanToken ||
|
|
1846
|
+
node.operatorToken.kind === ts.SyntaxKind.LessThanEqualsToken ||
|
|
1847
|
+
node.operatorToken.kind === ts.SyntaxKind.GreaterThanToken ||
|
|
1848
|
+
node.operatorToken.kind === ts.SyntaxKind.GreaterThanEqualsToken
|
|
1849
|
+
) &&
|
|
1850
|
+
!isAllowedRelationalOperandPair(
|
|
1851
|
+
context.checker,
|
|
1852
|
+
context.checker.getTypeAtLocation(node.left),
|
|
1853
|
+
context.checker.getTypeAtLocation(node.right),
|
|
1854
|
+
)
|
|
1855
|
+
) {
|
|
1856
|
+
return unsupportedFeature(node.operatorToken, 'relationalComparison');
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
if (
|
|
1860
|
+
ts.isBinaryExpression(node) &&
|
|
1861
|
+
(node.operatorToken.kind === ts.SyntaxKind.PlusToken ||
|
|
1862
|
+
node.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken) &&
|
|
1863
|
+
!isAllowedPlusOperandPair(
|
|
1864
|
+
context.checker,
|
|
1865
|
+
context.checker.getTypeAtLocation(node.left),
|
|
1866
|
+
context.checker.getTypeAtLocation(node.right),
|
|
1867
|
+
)
|
|
1868
|
+
) {
|
|
1869
|
+
return unsupportedFeature(node.operatorToken, 'plusOperator');
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.CommaToken) {
|
|
1873
|
+
return unsupportedFeature(node.operatorToken, 'commaOperator');
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
if (ts.isVoidExpression(node) && isVoidZeroExpression(node)) {
|
|
1877
|
+
return unsupportedFeature(node, 'voidZero');
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
if (ts.isDeleteExpression(node)) {
|
|
1881
|
+
return unsupportedFeature(node, 'deleteExpression');
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
if (ts.isTemplateExpression(node)) {
|
|
1885
|
+
for (const span of node.templateSpans) {
|
|
1886
|
+
if (
|
|
1887
|
+
!isSupportedTemplateSpanType(
|
|
1888
|
+
context.checker,
|
|
1889
|
+
context.checker.getTypeAtLocation(span.expression),
|
|
1890
|
+
)
|
|
1891
|
+
) {
|
|
1892
|
+
return unsupportedFeature(span.expression, 'templateInterpolation');
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
if (
|
|
1898
|
+
ts.isBinaryExpression(node) &&
|
|
1899
|
+
node.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
1900
|
+
((ts.isPropertyAccessExpression(node.left) &&
|
|
1901
|
+
node.left.name.text === 'prototype' &&
|
|
1902
|
+
isFunctionLikeValue(context, node.left.expression)) ||
|
|
1903
|
+
(ts.isElementAccessExpression(node.left) &&
|
|
1904
|
+
node.left.argumentExpression !== undefined &&
|
|
1905
|
+
ts.isStringLiteralLike(node.left.argumentExpression) &&
|
|
1906
|
+
node.left.argumentExpression.text === 'prototype' &&
|
|
1907
|
+
isFunctionLikeValue(context, node.left.expression)))
|
|
1908
|
+
) {
|
|
1909
|
+
return unsupportedFeature(
|
|
1910
|
+
ts.isPropertyAccessExpression(node.left) ? node.left.name : node.left.argumentExpression,
|
|
1911
|
+
'prototypeMutation',
|
|
1912
|
+
);
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (
|
|
1916
|
+
ts.isBinaryExpression(node) &&
|
|
1917
|
+
isAssignmentOperatorToken(node.operatorToken.kind)
|
|
1918
|
+
) {
|
|
1919
|
+
const callableMutationTarget = getCallableMutationTargetInAssignmentPattern(context, node.left);
|
|
1920
|
+
if (callableMutationTarget) {
|
|
1921
|
+
return unsupportedFeature(callableMutationTarget, 'functionObjectMutation');
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
if (
|
|
1926
|
+
(ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) &&
|
|
1927
|
+
(
|
|
1928
|
+
node.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
1929
|
+
node.operator === ts.SyntaxKind.MinusMinusToken
|
|
1930
|
+
)
|
|
1931
|
+
) {
|
|
1932
|
+
const callableMutationTarget = getCallableMutationTarget(context, node.operand);
|
|
1933
|
+
if (callableMutationTarget) {
|
|
1934
|
+
return unsupportedFeature(callableMutationTarget, 'functionObjectMutation');
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
if (
|
|
1939
|
+
(ts.isPropertyDeclaration(node) || ts.isMethodDeclaration(node) ||
|
|
1940
|
+
ts.isConstructorDeclaration(node) ||
|
|
1941
|
+
ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) &&
|
|
1942
|
+
(hasModifier(node, ts.SyntaxKind.PrivateKeyword) ||
|
|
1943
|
+
hasModifier(node, ts.SyntaxKind.ProtectedKeyword))
|
|
1944
|
+
) {
|
|
1945
|
+
return unsupportedFeature(
|
|
1946
|
+
ts.isConstructorDeclaration(node) ? node : node.name,
|
|
1947
|
+
'privateOrProtectedMember',
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
|
|
1952
|
+
return unsupportedFeature(node.name, 'accessors');
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
if (
|
|
1956
|
+
ts.isMethodDeclaration(node) || ts.isPropertyDeclaration(node) ||
|
|
1957
|
+
ts.isPropertyAssignment(node)
|
|
1958
|
+
) {
|
|
1959
|
+
const bannedSymbolHookNode = isBannedSymbolHookName(context, node.name);
|
|
1960
|
+
if (bannedSymbolHookNode) {
|
|
1961
|
+
return unsupportedFeature(bannedSymbolHookNode, 'symbolHook');
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
if (ts.isArrayLiteralExpression(node) && node.elements.some(ts.isOmittedExpression)) {
|
|
1966
|
+
return unsupportedFeature(node, 'sparseArrayLiteral');
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
const protoDefinitionNode = getProtoDefinitionNode(node);
|
|
1970
|
+
if (protoDefinitionNode) {
|
|
1971
|
+
return unsupportedFeature(protoDefinitionNode, 'protoProperty');
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
const memberAccess = getStaticMemberAccess(node);
|
|
1975
|
+
if (memberAccess) {
|
|
1976
|
+
if (memberAccess.memberName === '__proto__') {
|
|
1977
|
+
return unsupportedFeature(memberAccess.memberNode, 'protoProperty');
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
if (LEGACY_ACCESSOR_MEMBER_NAMES.has(memberAccess.memberName)) {
|
|
1981
|
+
return unsupportedFeature(memberAccess.memberNode, 'legacyAccessorApi');
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
if (
|
|
1985
|
+
memberAccess.memberName === 'callee' &&
|
|
1986
|
+
ts.isIdentifier(memberAccess.expression) &&
|
|
1987
|
+
memberAccess.expression.text === 'arguments'
|
|
1988
|
+
) {
|
|
1989
|
+
return unsupportedFeature(memberAccess.memberNode, 'argumentsCallee');
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
if (
|
|
1993
|
+
LEGACY_FUNCTION_MEMBER_NAMES.has(memberAccess.memberName) &&
|
|
1994
|
+
isFunctionLikeValue(context, memberAccess.expression)
|
|
1995
|
+
) {
|
|
1996
|
+
return unsupportedFeature(memberAccess.memberNode, 'legacyFunctionMetadata');
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
if (ts.isCallExpression(node)) {
|
|
2001
|
+
const bannedPrimitiveConversionHookCallNode = getBannedPrimitiveConversionHookCallNode(
|
|
2002
|
+
context,
|
|
2003
|
+
node,
|
|
2004
|
+
);
|
|
2005
|
+
if (bannedPrimitiveConversionHookCallNode) {
|
|
2006
|
+
return unsupportedFeature(bannedPrimitiveConversionHookCallNode, 'primitiveConversionHookCall');
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
if (
|
|
2010
|
+
matchesResolvedBuiltinSignature(context, node, { ownerNames: ['SymbolConstructor'] }) ||
|
|
2011
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2012
|
+
ownerNames: ['SymbolConstructor'],
|
|
2013
|
+
}) ||
|
|
2014
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2015
|
+
ownerNames: ['SymbolConstructor'],
|
|
2016
|
+
memberNames: ['for'],
|
|
2017
|
+
}) ||
|
|
2018
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2019
|
+
ownerNames: ['SymbolConstructor'],
|
|
2020
|
+
memberNames: ['for'],
|
|
2021
|
+
})
|
|
2022
|
+
) {
|
|
2023
|
+
return unsupportedFeature(node.expression, 'symbolApi');
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
if (
|
|
2027
|
+
matchesResolvedBuiltinSignature(context, node, { memberNames: ['eval'] }) ||
|
|
2028
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, { memberNames: ['eval'] })
|
|
2029
|
+
) {
|
|
2030
|
+
return unsupportedFeature(node.expression, 'eval');
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
if (
|
|
2034
|
+
matchesResolvedBuiltinSignature(context, node, { ownerNames: ['FunctionConstructor'] }) ||
|
|
2035
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2036
|
+
ownerNames: ['FunctionConstructor'],
|
|
2037
|
+
})
|
|
2038
|
+
) {
|
|
2039
|
+
return unsupportedFeature(node.expression, 'functionConstructor');
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
if (
|
|
2043
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2044
|
+
ownerNames: ['ObjectConstructor'],
|
|
2045
|
+
memberNames: ['create'],
|
|
2046
|
+
}) ||
|
|
2047
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2048
|
+
ownerNames: ['ObjectConstructor'],
|
|
2049
|
+
memberNames: ['create'],
|
|
2050
|
+
})
|
|
2051
|
+
) {
|
|
2052
|
+
const prototypeArgument = node.arguments[0];
|
|
2053
|
+
if (prototypeArgument && !isDefinitelyNullExpression(context, prototypeArgument)) {
|
|
2054
|
+
return unsupportedFeature(node.expression, 'objectCreateNonNull');
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
if (ts.isNewExpression(node)) {
|
|
2060
|
+
if (
|
|
2061
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2062
|
+
ownerNames: getBannedConstructorOwnerNames(context),
|
|
2063
|
+
}) ||
|
|
2064
|
+
isBannedConstructorValue(context, node.expression)
|
|
2065
|
+
) {
|
|
2066
|
+
return unsupportedFeature(node.expression, 'bannedConstructor', {
|
|
2067
|
+
name: node.expression.getText(node.getSourceFile()),
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
if (isLengthOnlyArrayConstructorCall(context, node)) {
|
|
2072
|
+
return unsupportedFeature(node.expression, 'arrayLengthConstructor');
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
if (ts.isCallExpression(node)) {
|
|
2077
|
+
if (
|
|
2078
|
+
resolvesToBuiltinGlobalValue(context, node.expression, 'Object', {
|
|
2079
|
+
ownerNames: ['ObjectConstructor'],
|
|
2080
|
+
}) &&
|
|
2081
|
+
node.arguments.length > 0 &&
|
|
2082
|
+
isDefinitelyPrimitiveType(
|
|
2083
|
+
context.checker,
|
|
2084
|
+
context.checker.getTypeAtLocation(node.arguments[0]),
|
|
2085
|
+
)
|
|
2086
|
+
) {
|
|
2087
|
+
return unsupportedFeature(node.expression, 'objectPrimitiveBoxing');
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
if (
|
|
2091
|
+
(
|
|
2092
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2093
|
+
ownerNames: ['ObjectConstructor'],
|
|
2094
|
+
memberNames: ['entries', 'values'],
|
|
2095
|
+
}) ||
|
|
2096
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2097
|
+
ownerNames: ['ObjectConstructor'],
|
|
2098
|
+
memberNames: ['entries', 'values'],
|
|
2099
|
+
})
|
|
2100
|
+
) &&
|
|
2101
|
+
node.arguments.length > 0 &&
|
|
2102
|
+
isBroadObjectEnumerationTarget(context, node.arguments[0])
|
|
2103
|
+
) {
|
|
2104
|
+
return unsupportedFeature(node.arguments[0], 'broadObjectEnumeration');
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
if (
|
|
2108
|
+
(
|
|
2109
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2110
|
+
ownerNames: ['Reflect'],
|
|
2111
|
+
memberNames: ['apply'],
|
|
2112
|
+
}) ||
|
|
2113
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2114
|
+
ownerNames: ['Reflect'],
|
|
2115
|
+
memberNames: ['apply'],
|
|
2116
|
+
})
|
|
2117
|
+
) &&
|
|
2118
|
+
node.arguments.length > 0 &&
|
|
2119
|
+
isObjectPrototypePrimitiveConversionHookValue(context, node.arguments[0])
|
|
2120
|
+
) {
|
|
2121
|
+
return unsupportedFeature(node.expression, 'reflectApplyPrimitiveHook');
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
if (
|
|
2125
|
+
(
|
|
2126
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2127
|
+
ownerNames: ['Reflect'],
|
|
2128
|
+
memberNames: ['construct'],
|
|
2129
|
+
}) ||
|
|
2130
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2131
|
+
ownerNames: ['Reflect'],
|
|
2132
|
+
memberNames: ['construct'],
|
|
2133
|
+
})
|
|
2134
|
+
) &&
|
|
2135
|
+
(
|
|
2136
|
+
(node.arguments[0] !== undefined && isBannedConstructorValue(context, node.arguments[0])) ||
|
|
2137
|
+
(node.arguments[2] !== undefined && isBannedConstructorValue(context, node.arguments[2]))
|
|
2138
|
+
)
|
|
2139
|
+
) {
|
|
2140
|
+
return unsupportedFeature(node.expression, 'reflectConstructBannedConstructor');
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
if (
|
|
2144
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2145
|
+
ownerNames: ['ProxyConstructor'],
|
|
2146
|
+
memberNames: ['revocable'],
|
|
2147
|
+
}) ||
|
|
2148
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2149
|
+
ownerNames: ['ProxyConstructor'],
|
|
2150
|
+
memberNames: ['revocable'],
|
|
2151
|
+
})
|
|
2152
|
+
) {
|
|
2153
|
+
return unsupportedFeature(node.expression, 'proxyRevocable');
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
if (
|
|
2157
|
+
(
|
|
2158
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2159
|
+
ownerNames: ['ObjectConstructor'],
|
|
2160
|
+
memberNames: ['assign'],
|
|
2161
|
+
}) ||
|
|
2162
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2163
|
+
ownerNames: ['ObjectConstructor'],
|
|
2164
|
+
memberNames: ['assign'],
|
|
2165
|
+
}) ||
|
|
2166
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2167
|
+
ownerNames: ['Reflect'],
|
|
2168
|
+
memberNames: ['set'],
|
|
2169
|
+
}) ||
|
|
2170
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2171
|
+
ownerNames: ['Reflect'],
|
|
2172
|
+
memberNames: ['set'],
|
|
2173
|
+
})
|
|
2174
|
+
) &&
|
|
2175
|
+
node.arguments.length > 0 &&
|
|
2176
|
+
isFunctionLikeValue(context, node.arguments[0])
|
|
2177
|
+
) {
|
|
2178
|
+
return unsupportedFeature(node.expression, 'reflectivePropertyMutation');
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
const wrappedInvocation = getWrappedBuiltinInvocation(node);
|
|
2182
|
+
if (wrappedInvocation) {
|
|
2183
|
+
if (
|
|
2184
|
+
(
|
|
2185
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2186
|
+
ownerNames: ['ObjectConstructor'],
|
|
2187
|
+
memberNames: ['assign'],
|
|
2188
|
+
}) ||
|
|
2189
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2190
|
+
ownerNames: ['Reflect'],
|
|
2191
|
+
memberNames: ['set'],
|
|
2192
|
+
})
|
|
2193
|
+
)
|
|
2194
|
+
) {
|
|
2195
|
+
const targetArgument = getWrappedInvocationArgument(node, wrappedInvocation, 0);
|
|
2196
|
+
if (targetArgument && isFunctionLikeValue(context, targetArgument)) {
|
|
2197
|
+
return unsupportedFeature(node.expression, 'reflectivePropertyMutation');
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
if (
|
|
2202
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2203
|
+
ownerNames: ['ObjectConstructor'],
|
|
2204
|
+
memberNames: ['entries', 'values'],
|
|
2205
|
+
})
|
|
2206
|
+
) {
|
|
2207
|
+
const targetArgument = getWrappedInvocationArgument(node, wrappedInvocation, 0);
|
|
2208
|
+
if (targetArgument && isBroadObjectEnumerationTarget(context, targetArgument)) {
|
|
2209
|
+
return unsupportedFeature(node.expression, 'broadObjectEnumeration');
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
if (
|
|
2214
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2215
|
+
ownerNames: ['Reflect'],
|
|
2216
|
+
memberNames: ['apply'],
|
|
2217
|
+
})
|
|
2218
|
+
) {
|
|
2219
|
+
const targetArgument = getWrappedInvocationArgument(node, wrappedInvocation, 0);
|
|
2220
|
+
if (
|
|
2221
|
+
targetArgument && isObjectPrototypePrimitiveConversionHookValue(context, targetArgument)
|
|
2222
|
+
) {
|
|
2223
|
+
return unsupportedFeature(node.expression, 'reflectApplyPrimitiveHook');
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
if (
|
|
2228
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2229
|
+
ownerNames: ['Reflect'],
|
|
2230
|
+
memberNames: ['construct'],
|
|
2231
|
+
})
|
|
2232
|
+
) {
|
|
2233
|
+
const targetArgument = getWrappedInvocationArgument(node, wrappedInvocation, 0);
|
|
2234
|
+
const newTargetArgument = getWrappedInvocationArgument(node, wrappedInvocation, 2);
|
|
2235
|
+
if (
|
|
2236
|
+
(targetArgument && isBannedConstructorValue(context, targetArgument)) ||
|
|
2237
|
+
(newTargetArgument && isBannedConstructorValue(context, newTargetArgument))
|
|
2238
|
+
) {
|
|
2239
|
+
return unsupportedFeature(node.expression, 'reflectConstructBannedConstructor');
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
if (
|
|
2244
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2245
|
+
ownerNames: ['ProxyConstructor'],
|
|
2246
|
+
memberNames: ['revocable'],
|
|
2247
|
+
})
|
|
2248
|
+
) {
|
|
2249
|
+
return unsupportedFeature(node.expression, 'proxyRevocable');
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
if (
|
|
2253
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2254
|
+
ownerNames: ['SymbolConstructor'],
|
|
2255
|
+
}) ||
|
|
2256
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2257
|
+
ownerNames: ['SymbolConstructor'],
|
|
2258
|
+
memberNames: ['for'],
|
|
2259
|
+
})
|
|
2260
|
+
) {
|
|
2261
|
+
return unsupportedFeature(node.expression, 'symbolApi');
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
if (
|
|
2265
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2266
|
+
memberNames: ['eval'],
|
|
2267
|
+
})
|
|
2268
|
+
) {
|
|
2269
|
+
return unsupportedFeature(node.expression, 'eval');
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
if (
|
|
2273
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2274
|
+
ownerNames: ['FunctionConstructor'],
|
|
2275
|
+
})
|
|
2276
|
+
) {
|
|
2277
|
+
return unsupportedFeature(node.expression, 'functionConstructor');
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
if (
|
|
2281
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2282
|
+
ownerNames: ['ObjectConstructor'],
|
|
2283
|
+
memberNames: ['create'],
|
|
2284
|
+
})
|
|
2285
|
+
) {
|
|
2286
|
+
const prototypeArgument = getWrappedInvocationArgument(node, wrappedInvocation, 0);
|
|
2287
|
+
if (prototypeArgument && !isDefinitelyNullExpression(context, prototypeArgument)) {
|
|
2288
|
+
return unsupportedFeature(node.expression, 'objectCreateNonNull');
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
if (
|
|
2293
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2294
|
+
ownerNames: ['ObjectConstructor'],
|
|
2295
|
+
memberNames: [
|
|
2296
|
+
'defineProperties',
|
|
2297
|
+
'defineProperty',
|
|
2298
|
+
'freeze',
|
|
2299
|
+
'getOwnPropertyDescriptor',
|
|
2300
|
+
'getOwnPropertyDescriptors',
|
|
2301
|
+
'getOwnPropertyNames',
|
|
2302
|
+
'getOwnPropertySymbols',
|
|
2303
|
+
'preventExtensions',
|
|
2304
|
+
'seal',
|
|
2305
|
+
],
|
|
2306
|
+
}) ||
|
|
2307
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2308
|
+
ownerNames: ['Reflect'],
|
|
2309
|
+
memberNames: ['defineProperty', 'ownKeys'],
|
|
2310
|
+
})
|
|
2311
|
+
) {
|
|
2312
|
+
return unsupportedFeature(node.expression, 'reflectiveMetaObjectOperation');
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
if (
|
|
2316
|
+
matchesResolvedBuiltinCallableValue(context, wrappedInvocation.target, {
|
|
2317
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
2318
|
+
memberNames: ['setPrototypeOf'],
|
|
2319
|
+
})
|
|
2320
|
+
) {
|
|
2321
|
+
return unsupportedFeature(node.expression, 'prototypeMutation');
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
if (
|
|
2326
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2327
|
+
ownerNames: ['ObjectConstructor'],
|
|
2328
|
+
memberNames: [
|
|
2329
|
+
'defineProperties',
|
|
2330
|
+
'defineProperty',
|
|
2331
|
+
'freeze',
|
|
2332
|
+
'getOwnPropertyDescriptor',
|
|
2333
|
+
'getOwnPropertyDescriptors',
|
|
2334
|
+
'getOwnPropertyNames',
|
|
2335
|
+
'getOwnPropertySymbols',
|
|
2336
|
+
'preventExtensions',
|
|
2337
|
+
'seal',
|
|
2338
|
+
],
|
|
2339
|
+
}) ||
|
|
2340
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2341
|
+
ownerNames: ['ObjectConstructor'],
|
|
2342
|
+
memberNames: [
|
|
2343
|
+
'defineProperties',
|
|
2344
|
+
'defineProperty',
|
|
2345
|
+
'freeze',
|
|
2346
|
+
'getOwnPropertyDescriptor',
|
|
2347
|
+
'getOwnPropertyDescriptors',
|
|
2348
|
+
'getOwnPropertyNames',
|
|
2349
|
+
'getOwnPropertySymbols',
|
|
2350
|
+
'preventExtensions',
|
|
2351
|
+
'seal',
|
|
2352
|
+
],
|
|
2353
|
+
}) ||
|
|
2354
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2355
|
+
ownerNames: ['Reflect'],
|
|
2356
|
+
memberNames: ['defineProperty', 'ownKeys'],
|
|
2357
|
+
}) ||
|
|
2358
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2359
|
+
ownerNames: ['Reflect'],
|
|
2360
|
+
memberNames: ['defineProperty', 'ownKeys'],
|
|
2361
|
+
})
|
|
2362
|
+
) {
|
|
2363
|
+
return unsupportedFeature(node.expression, 'reflectiveMetaObjectOperation');
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
if (isLengthOnlyArrayConstructorCall(context, node)) {
|
|
2367
|
+
return unsupportedFeature(node.expression, 'arrayLengthConstructor');
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
if (
|
|
2371
|
+
matchesResolvedBuiltinSignature(context, node, {
|
|
2372
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
2373
|
+
memberNames: ['setPrototypeOf'],
|
|
2374
|
+
}) ||
|
|
2375
|
+
matchesResolvedBuiltinCallableValue(context, node.expression, {
|
|
2376
|
+
ownerNames: ['ObjectConstructor', 'Reflect'],
|
|
2377
|
+
memberNames: ['setPrototypeOf'],
|
|
2378
|
+
})
|
|
2379
|
+
) {
|
|
2380
|
+
return unsupportedFeature(node.expression, 'prototypeMutation');
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
if (ts.isForInStatement(node)) {
|
|
2385
|
+
return unsupportedFeature(node, 'forIn');
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
if (ts.isLabeledStatement(node)) {
|
|
2389
|
+
return unsupportedFeature(node.label, 'labeledStatement');
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
if (
|
|
2393
|
+
node.kind === ts.SyntaxKind.ThisKeyword &&
|
|
2394
|
+
(
|
|
2395
|
+
isTopLevelThisExpression(node as ts.ThisExpression) ||
|
|
2396
|
+
isBannedThisExpression(node as ts.ThisExpression)
|
|
2397
|
+
)
|
|
2398
|
+
) {
|
|
2399
|
+
return unsupportedFeature(node, 'disallowedThis');
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
return undefined;
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
export function runUnsoundSyntaxRules(context: AnalysisContext): SoundDiagnostic[] {
|
|
2406
|
+
const diagnostics: SoundDiagnostic[] = [];
|
|
2407
|
+
|
|
2408
|
+
context.forEachSourceFile((sourceFile) => {
|
|
2409
|
+
if (isForeignSourceFile(sourceFile.fileName, ts.sys)) {
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
context.traverse(sourceFile, (node) => {
|
|
2414
|
+
if (isInsideSyntheticErrorNormalizationHelper(node)) {
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
const nullPrototypeObjectCreationDiagnostic = getNullPrototypeObjectCreationDiagnostic(
|
|
2419
|
+
context,
|
|
2420
|
+
node,
|
|
2421
|
+
);
|
|
2422
|
+
if (nullPrototypeObjectCreationDiagnostic) {
|
|
2423
|
+
diagnostics.push(nullPrototypeObjectCreationDiagnostic);
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
const unsupportedFeatureDiagnostic = getUnsupportedFeatureDiagnostic(context, node);
|
|
2428
|
+
if (unsupportedFeatureDiagnostic) {
|
|
2429
|
+
diagnostics.push(
|
|
2430
|
+
createDiagnostic(
|
|
2431
|
+
unsupportedFeatureDiagnostic.node,
|
|
2432
|
+
SOUND_DIAGNOSTIC_CODES.unsupportedJavaScriptFeature,
|
|
2433
|
+
unsupportedFeatureDiagnostic.message,
|
|
2434
|
+
{
|
|
2435
|
+
hint: unsupportedFeatureDiagnostic.hint,
|
|
2436
|
+
metadata: unsupportedFeatureDiagnostic.metadata,
|
|
2437
|
+
notes: unsupportedFeatureDiagnostic.example
|
|
2438
|
+
? [`Example: ${unsupportedFeatureDiagnostic.example}`]
|
|
2439
|
+
: undefined,
|
|
2440
|
+
},
|
|
2441
|
+
),
|
|
2442
|
+
);
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
const exportedAmbientRuntimeDiagnostic = getAmbientRuntimeExportDiagnostic(context, node);
|
|
2447
|
+
if (exportedAmbientRuntimeDiagnostic) {
|
|
2448
|
+
diagnostics.push(createAmbientRuntimeExportDiagnostic(exportedAmbientRuntimeDiagnostic));
|
|
2449
|
+
return;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
const ambientRequiresExternDeclaration = getAmbientRuntimeRequiresExternDeclarationNode(
|
|
2453
|
+
context,
|
|
2454
|
+
node,
|
|
2455
|
+
);
|
|
2456
|
+
if (ambientRequiresExternDeclaration) {
|
|
2457
|
+
diagnostics.push(createAmbientRuntimeRequiresExternDiagnostic(ambientRequiresExternDeclaration));
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
if (node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
2462
|
+
diagnostics.push(createAnyTypeDiagnostic(node));
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
if (ts.isTypeAssertionExpression(node)) {
|
|
2467
|
+
diagnostics.push(createTypeAssertionDiagnostic(context, node));
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
if (ts.isThrowStatement(node) && !isAllowedThrownExpression(context, node.expression)) {
|
|
2472
|
+
diagnostics.push(createThrowNonErrorDiagnostic(context, node.expression));
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
if (ts.isAsExpression(node)) {
|
|
2477
|
+
if (getLocalUnsafeProofOverrideChainRoot(node) !== node) {
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
if (isConstAssertion(node)) {
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
if (isUnsafeBridgeCast(context, node)) {
|
|
2486
|
+
diagnostics.push(createTypeAssertionDiagnostic(context, node));
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
if (isLocallyUnsafe(context, node)) {
|
|
2491
|
+
return;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
diagnostics.push(createTypeAssertionDiagnostic(context, node));
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
if (ts.isNonNullExpression(node)) {
|
|
2499
|
+
if (getLocalUnsafeProofOverrideChainRoot(node) !== node) {
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
if (isLocallyUnsafe(context, node)) {
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
diagnostics.push(createNonNullAssertionDiagnostic(context, node));
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
if (
|
|
2512
|
+
ts.isVariableDeclaration(node) &&
|
|
2513
|
+
node.exclamationToken !== undefined &&
|
|
2514
|
+
node.initializer === undefined
|
|
2515
|
+
) {
|
|
2516
|
+
if (isLocallyUnsafe(context, node)) {
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
diagnostics.push(createDefiniteAssignmentAssertionDiagnostic(context, node));
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
if (
|
|
2525
|
+
ts.isPropertyDeclaration(node) &&
|
|
2526
|
+
node.exclamationToken !== undefined &&
|
|
2527
|
+
node.initializer === undefined
|
|
2528
|
+
) {
|
|
2529
|
+
diagnostics.push(createDefiniteAssignmentAssertionDiagnostic(context, node));
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
if (isLocallyUnsafe(context, node)) {
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
});
|
|
2537
|
+
});
|
|
2538
|
+
|
|
2539
|
+
return diagnostics;
|
|
2540
|
+
}
|