@soundscript/soundscript 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,2246 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { dirname, isAbsolute, join } from '../platform/path.ts';
|
|
3
|
+
|
|
4
|
+
import { createSoundStdlibCompilerHost } from '../bundled/sound_stdlib.ts';
|
|
5
|
+
import {
|
|
6
|
+
type BuiltinExpandedTsDiagnosticProgram,
|
|
7
|
+
createBuiltinExpandedProgram,
|
|
8
|
+
} from '../frontend/builtin_macro_support.ts';
|
|
9
|
+
import type {
|
|
10
|
+
MacroModuleCacheStats,
|
|
11
|
+
ProjectMacroEnvironment,
|
|
12
|
+
} from '../frontend/project_macro_support.ts';
|
|
13
|
+
import {
|
|
14
|
+
sourceTextLooksLikeMacroModule,
|
|
15
|
+
usesLegacyDefineMacroAuthoring,
|
|
16
|
+
} from '../frontend/macro_factory_support.ts';
|
|
17
|
+
import {
|
|
18
|
+
clearPreparedCompilerHostReuseState,
|
|
19
|
+
emitProjectedDeclarations,
|
|
20
|
+
getLineAndCharacterOfPosition,
|
|
21
|
+
getPositionOfLineAndCharacter,
|
|
22
|
+
isProjectedSoundscriptDeclarationFile,
|
|
23
|
+
isSoundscriptSourceFile,
|
|
24
|
+
mapProgramEnclosingRangeToSource,
|
|
25
|
+
mapProgramPositionToSource,
|
|
26
|
+
type PreparedCompilerHostReuseState,
|
|
27
|
+
type PreparedProgram,
|
|
28
|
+
type PreparedSourceFile,
|
|
29
|
+
toProjectedDeclarationFileName,
|
|
30
|
+
toProjectedDeclarationSourceFileName,
|
|
31
|
+
toSourceFileName,
|
|
32
|
+
} from '../frontend/project_frontend.ts';
|
|
33
|
+
import { collectSoundscriptRootNames, loadConfig } from '../config.ts';
|
|
34
|
+
import {
|
|
35
|
+
findNearestPackageJsonPath,
|
|
36
|
+
getSoundScriptPackageInfoForResolvedModule,
|
|
37
|
+
resolveSoundScriptAwareModule,
|
|
38
|
+
} from '../soundscript_packages.ts';
|
|
39
|
+
import {
|
|
40
|
+
hasErrorDiagnostics,
|
|
41
|
+
remapDiagnosticFilePaths,
|
|
42
|
+
toMergedDiagnostic,
|
|
43
|
+
} from './diagnostics.ts';
|
|
44
|
+
import { SOUND_DIAGNOSTIC_CODES } from './engine/diagnostic_codes.ts';
|
|
45
|
+
import { createAnalysisContext } from './engine/context.ts';
|
|
46
|
+
import { runSoundAnalysis } from './rules/index.ts';
|
|
47
|
+
import {
|
|
48
|
+
runSourceSupplementalPolicyAnalysis,
|
|
49
|
+
runUniversalPolicyAnalysis,
|
|
50
|
+
} from './rules/universal.ts';
|
|
51
|
+
import { measureCheckerTiming } from './timing.ts';
|
|
52
|
+
|
|
53
|
+
import type { AnalyzeProjectOptions, AnalyzeProjectResult } from '../service/types.ts';
|
|
54
|
+
import type {
|
|
55
|
+
DiagnosticRelatedInformation,
|
|
56
|
+
MergedDiagnostic,
|
|
57
|
+
SoundDiagnostic,
|
|
58
|
+
} from './diagnostics.ts';
|
|
59
|
+
import type { AnalysisContext } from './engine/types.ts';
|
|
60
|
+
|
|
61
|
+
export interface PreparedAnalysisView {
|
|
62
|
+
analysisContext: AnalysisContext;
|
|
63
|
+
analysisPreparedProgram: PreparedProgram;
|
|
64
|
+
diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>;
|
|
65
|
+
frontendDiagnostics: readonly MergedDiagnostic[];
|
|
66
|
+
macroEnvironment: ProjectMacroEnvironment;
|
|
67
|
+
macroCacheStats: MacroModuleCacheStats;
|
|
68
|
+
preparedProgram: PreparedProgram;
|
|
69
|
+
program: ts.Program;
|
|
70
|
+
runSound: boolean;
|
|
71
|
+
tsDiagnosticPrograms: readonly BuiltinExpandedTsDiagnosticProgram[];
|
|
72
|
+
universalPolicyScope: 'full' | 'sourceSupplemental';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface PreparedAnalysisProject {
|
|
76
|
+
analyzeOptions: AnalyzeProjectOptions;
|
|
77
|
+
configReuseSignature: string;
|
|
78
|
+
configuredSoundscriptRootNames: readonly string[];
|
|
79
|
+
localProjectedDeclarationOverrides: ReadonlyMap<string, string> | undefined;
|
|
80
|
+
packageSourcePolicyContentSignature: string;
|
|
81
|
+
packageSourcePolicyCompilerHostReuseState: PreparedCompilerHostReuseState | undefined;
|
|
82
|
+
packageSourcePolicyView: PreparedAnalysisView | null;
|
|
83
|
+
soundscriptRootContentSignature: string;
|
|
84
|
+
soundscriptRootDiscoverySignature: string;
|
|
85
|
+
stsCompilerHostReuseState: PreparedCompilerHostReuseState | undefined;
|
|
86
|
+
soundscriptFileOverridesSignature: string;
|
|
87
|
+
soundscriptRootNames: readonly string[];
|
|
88
|
+
stsView: PreparedAnalysisView | null;
|
|
89
|
+
tsCompilerHostReuseState: PreparedCompilerHostReuseState | undefined;
|
|
90
|
+
tsView: PreparedAnalysisView | null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface AnalyzedProgramResult {
|
|
94
|
+
frontendDiagnostics: readonly MergedDiagnostic[];
|
|
95
|
+
soundDiagnostics: readonly SoundDiagnostic[];
|
|
96
|
+
tsDiagnostics: readonly MergedDiagnostic[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fileScopedAnalysisContextCache = new WeakMap<
|
|
100
|
+
PreparedAnalysisView,
|
|
101
|
+
Map<string, AnalysisContext | null>
|
|
102
|
+
>();
|
|
103
|
+
const IGNORED_GENERATED_TOP_LEVEL_IMPORT_SPECIFIERS = new Set(['sts:prelude']);
|
|
104
|
+
|
|
105
|
+
interface PrepareProjectAnalysisOptions {
|
|
106
|
+
deferTypescriptView?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function combineRootNames(
|
|
110
|
+
rootNames: readonly string[],
|
|
111
|
+
additionalRootNames: readonly string[] = [],
|
|
112
|
+
): string[] {
|
|
113
|
+
return [...new Set([...rootNames, ...additionalRootNames])];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function rootNamesEqual(left: readonly string[], right: readonly string[]): boolean {
|
|
117
|
+
if (left.length !== right.length) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
122
|
+
if (left[index] !== right[index]) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function createFileOverrideSignature(
|
|
131
|
+
fileOverrides: ReadonlyMap<string, string> | undefined,
|
|
132
|
+
includeFileName: (fileName: string) => boolean,
|
|
133
|
+
): string {
|
|
134
|
+
if (!fileOverrides || fileOverrides.size === 0) {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return [...fileOverrides.entries()]
|
|
139
|
+
.filter(([fileName]) => includeFileName(fileName))
|
|
140
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
141
|
+
.map(([fileName, text]) => `${fileName}:${text.length}:${text}`)
|
|
142
|
+
.join('|');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function createSoundscriptRootDiscoverySignature(
|
|
146
|
+
projectPath: string,
|
|
147
|
+
loadedConfig: ReturnType<typeof loadConfig>,
|
|
148
|
+
): string {
|
|
149
|
+
const basePath = dirname(projectPath);
|
|
150
|
+
const rawConfig = loadedConfig.commandLine.raw as {
|
|
151
|
+
exclude?: readonly string[];
|
|
152
|
+
files?: readonly string[];
|
|
153
|
+
include?: readonly string[];
|
|
154
|
+
} | undefined;
|
|
155
|
+
const explicitFiles = (rawConfig?.files ?? [])
|
|
156
|
+
.map((fileName) => isAbsolute(fileName) ? fileName : join(basePath, fileName))
|
|
157
|
+
.map((fileName) => ts.sys.resolvePath(fileName))
|
|
158
|
+
.filter(isSoundscriptSourceFile)
|
|
159
|
+
.sort()
|
|
160
|
+
.join('\u0000');
|
|
161
|
+
const includePatterns = rawConfig?.include
|
|
162
|
+
? [...rawConfig.include]
|
|
163
|
+
: rawConfig?.files
|
|
164
|
+
? []
|
|
165
|
+
: ['**/*'];
|
|
166
|
+
const excludePatterns = rawConfig?.exclude
|
|
167
|
+
? [...rawConfig.exclude]
|
|
168
|
+
: ['node_modules', 'bower_components', 'jspm_packages', '.git'];
|
|
169
|
+
|
|
170
|
+
return [
|
|
171
|
+
basePath,
|
|
172
|
+
explicitFiles,
|
|
173
|
+
includePatterns.join('\u0001'),
|
|
174
|
+
excludePatterns.join('\u0001'),
|
|
175
|
+
].join('\u0002');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function stableConfigSignature(value: unknown): string {
|
|
179
|
+
return JSON.stringify(value, (_key, currentValue) => {
|
|
180
|
+
if (
|
|
181
|
+
currentValue !== null &&
|
|
182
|
+
typeof currentValue === 'object' &&
|
|
183
|
+
!Array.isArray(currentValue)
|
|
184
|
+
) {
|
|
185
|
+
return Object.fromEntries(
|
|
186
|
+
Object.entries(currentValue as Record<string, unknown>).sort(([left], [right]) =>
|
|
187
|
+
left.localeCompare(right)
|
|
188
|
+
),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return currentValue;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function createProjectConfigReuseSignature(
|
|
197
|
+
projectPath: string,
|
|
198
|
+
loadedConfig: ReturnType<typeof loadConfig>,
|
|
199
|
+
): string {
|
|
200
|
+
return [
|
|
201
|
+
projectPath,
|
|
202
|
+
stableConfigSignature(loadedConfig.commandLine.raw),
|
|
203
|
+
stableConfigSignature(loadedConfig.commandLine.options),
|
|
204
|
+
stableConfigSignature(loadedConfig.commandLine.projectReferences ?? []),
|
|
205
|
+
stableConfigSignature(loadedConfig.runtime),
|
|
206
|
+
].join('\u0003');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function createModuleResolutionHostWithOverrides(
|
|
210
|
+
fileOverrides: ReadonlyMap<string, string> | undefined,
|
|
211
|
+
): ts.ModuleResolutionHost {
|
|
212
|
+
const normalizedOverrides = fileOverrides
|
|
213
|
+
? new Map(
|
|
214
|
+
[...fileOverrides.entries()].map(([fileName, text]) => [ts.sys.resolvePath(fileName), text]),
|
|
215
|
+
)
|
|
216
|
+
: new Map<string, string>();
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
directoryExists(directoryName) {
|
|
220
|
+
const normalizedDirectoryName = ts.sys.resolvePath(directoryName);
|
|
221
|
+
if (
|
|
222
|
+
[...normalizedOverrides.keys()].some((fileName) =>
|
|
223
|
+
fileName === normalizedDirectoryName ||
|
|
224
|
+
fileName.startsWith(`${normalizedDirectoryName}/`) ||
|
|
225
|
+
fileName.startsWith(`${normalizedDirectoryName}\\`)
|
|
226
|
+
)
|
|
227
|
+
) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
return ts.sys.directoryExists?.(directoryName) ?? false;
|
|
231
|
+
},
|
|
232
|
+
fileExists(fileName) {
|
|
233
|
+
return normalizedOverrides.has(ts.sys.resolvePath(fileName)) || ts.sys.fileExists(fileName);
|
|
234
|
+
},
|
|
235
|
+
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
236
|
+
getDirectories: ts.sys.getDirectories,
|
|
237
|
+
readFile(fileName) {
|
|
238
|
+
return normalizedOverrides.get(ts.sys.resolvePath(fileName)) ?? ts.sys.readFile(fileName);
|
|
239
|
+
},
|
|
240
|
+
realpath: ts.sys.realpath,
|
|
241
|
+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function isRelativeOrAbsoluteModuleSpecifier(moduleSpecifier: string): boolean {
|
|
246
|
+
return moduleSpecifier.startsWith('.') ||
|
|
247
|
+
moduleSpecifier.startsWith('/') ||
|
|
248
|
+
/^[A-Za-z]:[/\\]/u.test(moduleSpecifier);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function resolveRelativeSoundscriptDependency(
|
|
252
|
+
containingFileName: string,
|
|
253
|
+
moduleSpecifier: string,
|
|
254
|
+
host: ts.ModuleResolutionHost,
|
|
255
|
+
): string | undefined {
|
|
256
|
+
if (!isRelativeOrAbsoluteModuleSpecifier(moduleSpecifier)) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const explicitNonSoundscriptExtensionPattern = /\.(?:[cm]?[jt]sx?|[cm]?js)$/u;
|
|
261
|
+
if (explicitNonSoundscriptExtensionPattern.test(moduleSpecifier)) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const candidateBase = ts.sys.resolvePath(
|
|
266
|
+
isAbsolute(moduleSpecifier)
|
|
267
|
+
? moduleSpecifier
|
|
268
|
+
: join(dirname(containingFileName), moduleSpecifier),
|
|
269
|
+
);
|
|
270
|
+
const candidates = moduleSpecifier.endsWith('.sts')
|
|
271
|
+
? [candidateBase]
|
|
272
|
+
: [`${candidateBase}.sts`, join(candidateBase, 'index.sts')];
|
|
273
|
+
|
|
274
|
+
for (const candidate of candidates) {
|
|
275
|
+
if (host.fileExists(candidate)) {
|
|
276
|
+
return candidate;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function collectReachableSoundscriptDependencyFiles(
|
|
284
|
+
rootNames: readonly string[],
|
|
285
|
+
compilerOptions: ts.CompilerOptions,
|
|
286
|
+
fileOverrides: ReadonlyMap<string, string> | undefined,
|
|
287
|
+
): readonly string[] {
|
|
288
|
+
const host = createModuleResolutionHostWithOverrides(fileOverrides);
|
|
289
|
+
const visited = new Set<string>();
|
|
290
|
+
const reachableFiles: string[] = [];
|
|
291
|
+
|
|
292
|
+
function visit(fileName: string): void {
|
|
293
|
+
const sourceFileName = ts.sys.resolvePath(toSourceFileName(fileName));
|
|
294
|
+
if (!isSoundscriptSourceFile(sourceFileName) || visited.has(sourceFileName)) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
visited.add(sourceFileName);
|
|
299
|
+
reachableFiles.push(sourceFileName);
|
|
300
|
+
|
|
301
|
+
const sourceText = host.readFile(sourceFileName);
|
|
302
|
+
if (!sourceText) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
for (const importedFile of ts.preProcessFile(sourceText, true, true).importedFiles) {
|
|
307
|
+
const resolvedDependency = resolveRelativeSoundscriptDependency(
|
|
308
|
+
sourceFileName,
|
|
309
|
+
importedFile.fileName,
|
|
310
|
+
host,
|
|
311
|
+
);
|
|
312
|
+
if (resolvedDependency) {
|
|
313
|
+
visit(resolvedDependency);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const resolvedModule = resolveSoundScriptAwareModule(
|
|
318
|
+
importedFile.fileName,
|
|
319
|
+
sourceFileName,
|
|
320
|
+
compilerOptions,
|
|
321
|
+
host,
|
|
322
|
+
);
|
|
323
|
+
if (resolvedModule) {
|
|
324
|
+
visit(resolvedModule.resolvedFileName);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
for (const rootName of rootNames) {
|
|
330
|
+
visit(rootName);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
reachableFiles.sort();
|
|
334
|
+
return reachableFiles;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function createSoundscriptRootContentSignature(
|
|
338
|
+
rootNames: readonly string[],
|
|
339
|
+
compilerOptions: ts.CompilerOptions,
|
|
340
|
+
fileOverrides: ReadonlyMap<string, string> | undefined,
|
|
341
|
+
): string {
|
|
342
|
+
const host = createModuleResolutionHostWithOverrides(fileOverrides);
|
|
343
|
+
return collectReachableSoundscriptDependencyFiles(rootNames, compilerOptions, fileOverrides)
|
|
344
|
+
.map((fileName) => {
|
|
345
|
+
const text = host.readFile(fileName) ?? '';
|
|
346
|
+
return `${fileName}\u0001${text.length}\u0001${text}`;
|
|
347
|
+
})
|
|
348
|
+
.join('\u0002');
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function getConfigFileParsingDiagnostics(
|
|
352
|
+
diagnostics: readonly ts.Diagnostic[],
|
|
353
|
+
additionalRootNames: readonly string[] = [],
|
|
354
|
+
): readonly ts.Diagnostic[] {
|
|
355
|
+
if (additionalRootNames.length === 0) {
|
|
356
|
+
return diagnostics;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return diagnostics.filter((diagnostic) => diagnostic.code !== 18003);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function remapDiagnostics<T extends MergedDiagnostic>(diagnostics: readonly T[]): T[] {
|
|
363
|
+
return diagnostics.map((diagnostic) => remapDiagnosticFilePaths(diagnostic, toSourceFileName));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function remapPreparedSoundDiagnosticRange<
|
|
367
|
+
T extends MergedDiagnostic | DiagnosticRelatedInformation,
|
|
368
|
+
>(
|
|
369
|
+
diagnostic: T,
|
|
370
|
+
preparedFile: PreparedSourceFile | undefined,
|
|
371
|
+
): T {
|
|
372
|
+
if (
|
|
373
|
+
!preparedFile ||
|
|
374
|
+
!diagnostic.filePath ||
|
|
375
|
+
diagnostic.line === undefined ||
|
|
376
|
+
diagnostic.column === undefined
|
|
377
|
+
) {
|
|
378
|
+
return diagnostic;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const programStart = getPositionOfLineAndCharacter(
|
|
382
|
+
preparedFile.rewrittenText,
|
|
383
|
+
diagnostic.line - 1,
|
|
384
|
+
diagnostic.column - 1,
|
|
385
|
+
);
|
|
386
|
+
const programEnd = diagnostic.endLine !== undefined && diagnostic.endColumn !== undefined
|
|
387
|
+
? getPositionOfLineAndCharacter(
|
|
388
|
+
preparedFile.rewrittenText,
|
|
389
|
+
diagnostic.endLine - 1,
|
|
390
|
+
diagnostic.endColumn - 1,
|
|
391
|
+
)
|
|
392
|
+
: programStart;
|
|
393
|
+
const mappedRange = mapProgramEnclosingRangeToSource(preparedFile, programStart, programEnd);
|
|
394
|
+
const mappedStart = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.start);
|
|
395
|
+
const mappedEnd = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.end);
|
|
396
|
+
|
|
397
|
+
return {
|
|
398
|
+
...diagnostic,
|
|
399
|
+
line: mappedStart.line + 1,
|
|
400
|
+
column: mappedStart.character + 1,
|
|
401
|
+
endLine: mappedEnd.line + 1,
|
|
402
|
+
endColumn: mappedEnd.character + 1,
|
|
403
|
+
} as T;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function remapSoundDiagnostics(
|
|
407
|
+
diagnostics: readonly SoundDiagnostic[],
|
|
408
|
+
diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>,
|
|
409
|
+
): SoundDiagnostic[] {
|
|
410
|
+
return diagnostics.map((diagnostic) => {
|
|
411
|
+
const preparedFile = diagnostic.filePath
|
|
412
|
+
? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.filePath))
|
|
413
|
+
: undefined;
|
|
414
|
+
const remapped = remapPreparedSoundDiagnosticRange(diagnostic, preparedFile);
|
|
415
|
+
return {
|
|
416
|
+
...remapped,
|
|
417
|
+
relatedInformation: remapped.relatedInformation?.map((relatedInformation) => {
|
|
418
|
+
const relatedPreparedFile = relatedInformation.filePath
|
|
419
|
+
? diagnosticPreparedFiles.get(toSourceFileName(relatedInformation.filePath))
|
|
420
|
+
: undefined;
|
|
421
|
+
return remapPreparedSoundDiagnosticRange(relatedInformation, relatedPreparedFile);
|
|
422
|
+
}),
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function remapMergedDiagnosticRange<T extends MergedDiagnostic | DiagnosticRelatedInformation>(
|
|
428
|
+
mergedDiagnostic: T,
|
|
429
|
+
diagnostic: ts.Diagnostic | ts.DiagnosticRelatedInformation,
|
|
430
|
+
preparedFile: PreparedSourceFile | undefined,
|
|
431
|
+
): T {
|
|
432
|
+
if (!preparedFile || !diagnostic.file || diagnostic.start === undefined) {
|
|
433
|
+
return mergedDiagnostic;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const diagnosticLength = diagnostic.length ?? 0;
|
|
437
|
+
const diagnosticText = diagnostic.file.text.slice(
|
|
438
|
+
diagnostic.start,
|
|
439
|
+
diagnostic.start + diagnosticLength,
|
|
440
|
+
);
|
|
441
|
+
const rawLineStartsAt = diagnostic.file.text.lastIndexOf('\n', diagnostic.start - 1) + 1;
|
|
442
|
+
const rawNextNewline = diagnostic.file.text.indexOf('\n', diagnostic.start);
|
|
443
|
+
const rawLineEndsAt = rawNextNewline === -1 ? diagnostic.file.text.length : rawNextNewline;
|
|
444
|
+
const rawLineText = diagnostic.file.text.slice(rawLineStartsAt, rawLineEndsAt);
|
|
445
|
+
const mappedRange = mapProgramEnclosingRangeToSource(
|
|
446
|
+
preparedFile,
|
|
447
|
+
diagnostic.start,
|
|
448
|
+
diagnostic.start + diagnosticLength,
|
|
449
|
+
);
|
|
450
|
+
const refinedRange = refineMappedRangeToMatchingText(
|
|
451
|
+
preparedFile.originalText,
|
|
452
|
+
mappedRange,
|
|
453
|
+
diagnosticText,
|
|
454
|
+
rawLineText,
|
|
455
|
+
);
|
|
456
|
+
const mappedStart = getLineAndCharacterOfPosition(preparedFile.originalText, refinedRange.start);
|
|
457
|
+
const mappedEnd = getLineAndCharacterOfPosition(preparedFile.originalText, refinedRange.end);
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
...mergedDiagnostic,
|
|
461
|
+
line: mappedStart.line + 1,
|
|
462
|
+
column: mappedStart.character + 1,
|
|
463
|
+
endLine: mappedEnd.line + 1,
|
|
464
|
+
endColumn: mappedEnd.character + 1,
|
|
465
|
+
} as T;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function refineMappedRangeToMatchingText(
|
|
469
|
+
originalText: string,
|
|
470
|
+
mappedRange: { intersectsReplacement: boolean; start: number; end: number },
|
|
471
|
+
diagnosticText: string,
|
|
472
|
+
rawLineText: string,
|
|
473
|
+
): { intersectsReplacement: boolean; start: number; end: number } {
|
|
474
|
+
if (
|
|
475
|
+
mappedRange.intersectsReplacement ||
|
|
476
|
+
diagnosticText.length === 0 ||
|
|
477
|
+
diagnosticText.includes('\n') ||
|
|
478
|
+
diagnosticText.includes('\r')
|
|
479
|
+
) {
|
|
480
|
+
return mappedRange;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (originalText.slice(mappedRange.start, mappedRange.end) === diagnosticText) {
|
|
484
|
+
return mappedRange;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const lineStart = originalText.lastIndexOf('\n', mappedRange.start - 1) + 1;
|
|
488
|
+
const nextNewline = originalText.indexOf('\n', mappedRange.start);
|
|
489
|
+
const lineEnd = nextNewline === -1 ? originalText.length : nextNewline;
|
|
490
|
+
const lineText = originalText.slice(lineStart, lineEnd);
|
|
491
|
+
if (lineText !== rawLineText) {
|
|
492
|
+
return mappedRange;
|
|
493
|
+
}
|
|
494
|
+
let bestStart: number | undefined;
|
|
495
|
+
let searchIndex = lineText.indexOf(diagnosticText);
|
|
496
|
+
|
|
497
|
+
while (searchIndex !== -1) {
|
|
498
|
+
const candidateStart = lineStart + searchIndex;
|
|
499
|
+
if (
|
|
500
|
+
bestStart === undefined ||
|
|
501
|
+
Math.abs(candidateStart - mappedRange.start) < Math.abs(bestStart - mappedRange.start)
|
|
502
|
+
) {
|
|
503
|
+
bestStart = candidateStart;
|
|
504
|
+
}
|
|
505
|
+
searchIndex = lineText.indexOf(diagnosticText, searchIndex + 1);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (bestStart === undefined) {
|
|
509
|
+
return mappedRange;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return {
|
|
513
|
+
intersectsReplacement: false,
|
|
514
|
+
start: bestStart,
|
|
515
|
+
end: bestStart + diagnosticText.length,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function toMappedMergedDiagnostic(
|
|
520
|
+
diagnostic: ts.Diagnostic,
|
|
521
|
+
diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>,
|
|
522
|
+
): MergedDiagnostic {
|
|
523
|
+
const mergedDiagnostic = toMergedDiagnostic(diagnostic);
|
|
524
|
+
const preparedFile = diagnostic.file
|
|
525
|
+
? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.file.fileName))
|
|
526
|
+
: undefined;
|
|
527
|
+
const remapped = remapMergedDiagnosticRange(mergedDiagnostic, diagnostic, preparedFile);
|
|
528
|
+
if (!mergedDiagnostic.relatedInformation || !diagnostic.relatedInformation) {
|
|
529
|
+
return remapped as MergedDiagnostic;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return {
|
|
533
|
+
...(remapped as MergedDiagnostic),
|
|
534
|
+
relatedInformation: mergedDiagnostic.relatedInformation.map((relatedInformation, index) => {
|
|
535
|
+
const relatedDiagnostic = diagnostic.relatedInformation?.[index];
|
|
536
|
+
const relatedPreparedFile = relatedDiagnostic?.file
|
|
537
|
+
? diagnosticPreparedFiles.get(toSourceFileName(relatedDiagnostic.file.fileName))
|
|
538
|
+
: undefined;
|
|
539
|
+
return remapMergedDiagnosticRange(
|
|
540
|
+
relatedInformation,
|
|
541
|
+
relatedDiagnostic ?? diagnostic,
|
|
542
|
+
relatedPreparedFile,
|
|
543
|
+
) as DiagnosticRelatedInformation;
|
|
544
|
+
}),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function mergeProjectedDeclarationOverrides(
|
|
549
|
+
first: ReadonlyMap<string, string> | undefined,
|
|
550
|
+
second: ReadonlyMap<string, string> | undefined,
|
|
551
|
+
): ReadonlyMap<string, string> | undefined {
|
|
552
|
+
if (!first && !second) {
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (!first) {
|
|
557
|
+
return second;
|
|
558
|
+
}
|
|
559
|
+
if (!second) {
|
|
560
|
+
return first;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const merged = new Map(first);
|
|
564
|
+
for (const [fileName, text] of second) {
|
|
565
|
+
merged.set(fileName, text);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return merged;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function filterProjectedDeclarationOverridesToRootNames(
|
|
572
|
+
projectedDeclarationOverrides: ReadonlyMap<string, string> | undefined,
|
|
573
|
+
rootNames: readonly string[],
|
|
574
|
+
): ReadonlyMap<string, string> | undefined {
|
|
575
|
+
if (!projectedDeclarationOverrides) {
|
|
576
|
+
return undefined;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const normalizedRootNames = new Set(rootNames.map((rootName) => ts.sys.resolvePath(rootName)));
|
|
580
|
+
const filtered = new Map<string, string>();
|
|
581
|
+
|
|
582
|
+
for (const [fileName, text] of projectedDeclarationOverrides) {
|
|
583
|
+
if (normalizedRootNames.has(ts.sys.resolvePath(fileName))) {
|
|
584
|
+
filtered.set(fileName, text);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return filtered;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function projectedDeclarationOverridesDiffer(
|
|
592
|
+
first: ReadonlyMap<string, string> | undefined,
|
|
593
|
+
second: ReadonlyMap<string, string> | undefined,
|
|
594
|
+
): boolean {
|
|
595
|
+
if (!first && !second) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (!first || !second) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (first.size !== second.size) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
for (const [fileName, text] of first) {
|
|
608
|
+
if (second.get(fileName) !== text) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function collectProjectedDeclarationCandidateRootNames(
|
|
617
|
+
program: ts.Program,
|
|
618
|
+
existingOverrides: ReadonlyMap<string, string> | undefined,
|
|
619
|
+
projectPackageJsonPath: string | undefined,
|
|
620
|
+
): readonly string[] {
|
|
621
|
+
const rootNames = new Set<string>();
|
|
622
|
+
|
|
623
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
624
|
+
const sourceFileName = toSourceFileName(sourceFile.fileName);
|
|
625
|
+
if (!isSoundscriptSourceFile(sourceFileName)) {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (isInstalledSoundStdlibSourceFileName(sourceFileName)) {
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
if (existingOverrides?.has(sourceFileName)) {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (!isSupplementalPackageSourceCandidate(sourceFileName, projectPackageJsonPath)) {
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
rootNames.add(sourceFileName);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return [...rootNames].sort();
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function hasNonRootProjectedDeclarationCandidates(
|
|
645
|
+
program: ts.Program,
|
|
646
|
+
soundscriptRootNameSet: ReadonlySet<string>,
|
|
647
|
+
projectPackageJsonPath: string | undefined,
|
|
648
|
+
): boolean {
|
|
649
|
+
return program.getSourceFiles().some((sourceFile) => {
|
|
650
|
+
const sourceFileName = toSourceFileName(sourceFile.fileName);
|
|
651
|
+
return isSoundscriptSourceFile(sourceFileName) &&
|
|
652
|
+
!isInstalledSoundStdlibSourceFileName(sourceFileName) &&
|
|
653
|
+
isSupplementalPackageSourceCandidate(sourceFileName, projectPackageJsonPath) &&
|
|
654
|
+
!soundscriptRootNameSet.has(ts.sys.resolvePath(sourceFileName));
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function collectProjectedDeclarationCandidateRootNamesFromPrograms(
|
|
659
|
+
programs: readonly (ts.Program | null | undefined)[],
|
|
660
|
+
existingOverrides: ReadonlyMap<string, string> | undefined,
|
|
661
|
+
projectPackageJsonPath: string | undefined,
|
|
662
|
+
): readonly string[] {
|
|
663
|
+
const rootNames = new Set<string>();
|
|
664
|
+
|
|
665
|
+
for (const program of programs) {
|
|
666
|
+
if (!program) {
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
for (
|
|
671
|
+
const rootName of collectProjectedDeclarationCandidateRootNames(
|
|
672
|
+
program,
|
|
673
|
+
existingOverrides,
|
|
674
|
+
projectPackageJsonPath,
|
|
675
|
+
)
|
|
676
|
+
) {
|
|
677
|
+
rootNames.add(rootName);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return [...rootNames].sort();
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function isInstalledSoundStdlibSourceFileName(fileName: string): boolean {
|
|
685
|
+
const normalizedFileName = toSourceFileName(fileName).replaceAll('\\', '/');
|
|
686
|
+
return normalizedFileName.includes('/node_modules/@soundscript/soundscript/soundscript/') &&
|
|
687
|
+
normalizedFileName.endsWith('.sts');
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function isNodeModulesPath(fileName: string): boolean {
|
|
691
|
+
const normalizedFileName = toSourceFileName(fileName).replaceAll('\\', '/');
|
|
692
|
+
return normalizedFileName.includes('/node_modules/');
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function shouldAnalyzeSoundscriptSourceFile(
|
|
696
|
+
sourceFile: ts.SourceFile,
|
|
697
|
+
preparedProgram: PreparedProgram,
|
|
698
|
+
): boolean {
|
|
699
|
+
const sourceFileName = toSourceFileName(sourceFile.fileName);
|
|
700
|
+
return isSoundscriptSourceFile(sourceFileName) &&
|
|
701
|
+
!isInstalledSoundStdlibSourceFileName(sourceFileName) &&
|
|
702
|
+
!isMacroAuthoringSourceFile(sourceFile, preparedProgram);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function normalizeOptionalResolvedPath(path: string | undefined): string | undefined {
|
|
706
|
+
return path ? ts.sys.resolvePath(path) : undefined;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function isSupplementalPackageSourceCandidate(
|
|
710
|
+
fileName: string,
|
|
711
|
+
projectPackageJsonPath: string | undefined,
|
|
712
|
+
): boolean {
|
|
713
|
+
if (!isSoundscriptSourceFile(fileName) || isInstalledSoundStdlibSourceFileName(fileName)) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const packageInfo = getSoundScriptPackageInfoForResolvedModule(fileName, ts.sys);
|
|
718
|
+
if (!packageInfo) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const normalizedProjectPackageJsonPath = normalizeOptionalResolvedPath(projectPackageJsonPath);
|
|
723
|
+
const normalizedFilePackageJsonPath = normalizeOptionalResolvedPath(packageInfo.packageJsonPath);
|
|
724
|
+
return normalizedProjectPackageJsonPath === undefined ||
|
|
725
|
+
normalizedFilePackageJsonPath !== normalizedProjectPackageJsonPath;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function shouldAnalyzeProjectSoundscriptSourceFile(
|
|
729
|
+
sourceFile: ts.SourceFile,
|
|
730
|
+
preparedProgram: PreparedProgram,
|
|
731
|
+
projectPackageJsonPath: string | undefined,
|
|
732
|
+
): boolean {
|
|
733
|
+
const sourceFileName = toSourceFileName(sourceFile.fileName);
|
|
734
|
+
return shouldAnalyzeSoundscriptSourceFile(sourceFile, preparedProgram) &&
|
|
735
|
+
!isSupplementalPackageSourceCandidate(sourceFileName, projectPackageJsonPath);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
function shouldAnalyzeTypescriptViewSourceFile(sourceFile: ts.SourceFile): boolean {
|
|
739
|
+
return !isSoundscriptSourceFile(toSourceFileName(sourceFile.fileName));
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function isIgnorableGeneratedTopLevelStatement(statement: ts.Statement): boolean {
|
|
743
|
+
return ts.isImportDeclaration(statement) &&
|
|
744
|
+
ts.isStringLiteralLike(statement.moduleSpecifier) &&
|
|
745
|
+
IGNORED_GENERATED_TOP_LEVEL_IMPORT_SPECIFIERS.has(statement.moduleSpecifier.text);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function hasGeneratedTopLevelStatements(
|
|
749
|
+
sourceFile: ts.SourceFile,
|
|
750
|
+
isGeneratedNode: (node: ts.Node) => boolean,
|
|
751
|
+
): boolean {
|
|
752
|
+
return sourceFile.statements.some((statement) =>
|
|
753
|
+
isGeneratedNode(statement) && !isIgnorableGeneratedTopLevelStatement(statement)
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function createOriginalSourceFileForPreparedSource(
|
|
758
|
+
fileName: string,
|
|
759
|
+
preparedSource: PreparedSourceFile,
|
|
760
|
+
): ts.SourceFile {
|
|
761
|
+
return ts.createSourceFile(
|
|
762
|
+
fileName,
|
|
763
|
+
preparedSource.originalText,
|
|
764
|
+
ts.ScriptTarget.Latest,
|
|
765
|
+
true,
|
|
766
|
+
/\.(?:[cm]?tsx|jsx|sts)$/iu.test(fileName) ? ts.ScriptKind.TSX : ts.ScriptKind.TS,
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function findInnermostNodeContainingPosition(
|
|
771
|
+
root: ts.Node,
|
|
772
|
+
position: number,
|
|
773
|
+
): ts.Node | undefined {
|
|
774
|
+
if (position < root.getFullStart() || position >= root.getEnd()) {
|
|
775
|
+
return undefined;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
let best: ts.Node = root;
|
|
779
|
+
const visit = (node: ts.Node): void => {
|
|
780
|
+
if (position < node.getFullStart() || position >= node.getEnd()) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
best = node;
|
|
784
|
+
ts.forEachChild(node, visit);
|
|
785
|
+
};
|
|
786
|
+
visit(root);
|
|
787
|
+
return best;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function isTopLevelMacroReplacement(
|
|
791
|
+
originalSourceFile: ts.SourceFile,
|
|
792
|
+
preparedSource: PreparedSourceFile,
|
|
793
|
+
replacementId: number,
|
|
794
|
+
): boolean {
|
|
795
|
+
const macroInvocation = preparedSource.rewriteResult.macrosById.get(replacementId);
|
|
796
|
+
if (!macroInvocation) {
|
|
797
|
+
return false;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const anchorPosition = macroInvocation.declarationSpan?.start ?? macroInvocation.span.start;
|
|
801
|
+
const anchorNode = findInnermostNodeContainingPosition(originalSourceFile, anchorPosition);
|
|
802
|
+
if (!anchorNode || ts.isSourceFile(anchorNode)) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
let current: ts.Node | undefined = anchorNode;
|
|
807
|
+
while (current?.parent && !ts.isSourceFile(current.parent)) {
|
|
808
|
+
if (
|
|
809
|
+
ts.isBlock(current.parent) ||
|
|
810
|
+
ts.isFunctionLike(current.parent) ||
|
|
811
|
+
ts.isModuleBlock(current.parent)
|
|
812
|
+
) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
current = current.parent;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return current !== undefined && ts.isSourceFile(current.parent);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function hasTopLevelMacroReplacements(
|
|
822
|
+
fileName: string,
|
|
823
|
+
preparedSource: PreparedSourceFile | undefined,
|
|
824
|
+
): boolean {
|
|
825
|
+
if (!preparedSource || preparedSource.rewriteResult.replacements.length === 0) {
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const originalSourceFile = createOriginalSourceFileForPreparedSource(fileName, preparedSource);
|
|
830
|
+
return preparedSource.rewriteResult.replacements.some((replacement) =>
|
|
831
|
+
isTopLevelMacroReplacement(originalSourceFile, preparedSource, replacement.id)
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function prepareAnalysisView(
|
|
836
|
+
options: AnalyzeProjectOptions,
|
|
837
|
+
loadedConfig: ReturnType<typeof loadConfig>,
|
|
838
|
+
rootNames: readonly string[],
|
|
839
|
+
baseHost: ts.CompilerHost,
|
|
840
|
+
configFileParsingDiagnostics: readonly ts.Diagnostic[],
|
|
841
|
+
includeSourceFile:
|
|
842
|
+
| ((sourceFile: ts.SourceFile, preparedProgram: PreparedProgram) => boolean)
|
|
843
|
+
| undefined,
|
|
844
|
+
projectedDeclarationOverrides: ReadonlyMap<string, string> | undefined,
|
|
845
|
+
runSound: boolean,
|
|
846
|
+
universalPolicyScope: 'full' | 'sourceSupplemental' = 'full',
|
|
847
|
+
reusableCompilerHostState?: PreparedCompilerHostReuseState,
|
|
848
|
+
oldProgram?: ts.Program,
|
|
849
|
+
): PreparedAnalysisView | null {
|
|
850
|
+
if (rootNames.length === 0) {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
const expandedProgram = createBuiltinExpandedProgram({
|
|
855
|
+
allowSupplementalDiagnosticPrograms: true,
|
|
856
|
+
baseHost,
|
|
857
|
+
configFileParsingDiagnostics,
|
|
858
|
+
fileOverrides: options.fileOverrides ?? new Map(),
|
|
859
|
+
oldProgram,
|
|
860
|
+
options: loadedConfig.commandLine.options,
|
|
861
|
+
projectReferences: loadedConfig.commandLine.projectReferences,
|
|
862
|
+
projectedDeclarationOverrides,
|
|
863
|
+
runtime: loadedConfig.runtime,
|
|
864
|
+
reusableCompilerHostState,
|
|
865
|
+
rootNames,
|
|
866
|
+
});
|
|
867
|
+
const program = expandedProgram.program;
|
|
868
|
+
const isGeneratedNode = createPreparedProgramGeneratedNodeDetector(
|
|
869
|
+
expandedProgram.analysisPreparedProgram,
|
|
870
|
+
);
|
|
871
|
+
const sourceFileHasTopLevelMacroReplacements = (sourceFile: ts.SourceFile): boolean => {
|
|
872
|
+
const sourceFileName = expandedProgram.analysisPreparedProgram.toSourceFileName(
|
|
873
|
+
sourceFile.fileName,
|
|
874
|
+
);
|
|
875
|
+
const preparedSource = expandedProgram.preparedProgram.preparedHost.getPreparedSourceFile(
|
|
876
|
+
sourceFileName,
|
|
877
|
+
);
|
|
878
|
+
return hasTopLevelMacroReplacements(sourceFileName, preparedSource);
|
|
879
|
+
};
|
|
880
|
+
const analysisContext = createAnalysisContext({
|
|
881
|
+
includeSourceFile: includeSourceFile
|
|
882
|
+
? (sourceFile) =>
|
|
883
|
+
!sourceFileHasTopLevelMacroReplacements(sourceFile) &&
|
|
884
|
+
!hasGeneratedTopLevelStatements(sourceFile, isGeneratedNode) &&
|
|
885
|
+
includeSourceFile(sourceFile, expandedProgram.analysisPreparedProgram)
|
|
886
|
+
: (sourceFile) =>
|
|
887
|
+
!sourceFileHasTopLevelMacroReplacements(sourceFile) &&
|
|
888
|
+
!hasGeneratedTopLevelStatements(sourceFile, isGeneratedNode),
|
|
889
|
+
isGeneratedNode,
|
|
890
|
+
program,
|
|
891
|
+
runtime: loadedConfig.runtime,
|
|
892
|
+
workingDirectory: options.workingDirectory,
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
return {
|
|
896
|
+
analysisContext,
|
|
897
|
+
analysisPreparedProgram: expandedProgram.analysisPreparedProgram,
|
|
898
|
+
diagnosticPreparedFiles: expandedProgram.diagnosticPreparedFiles,
|
|
899
|
+
frontendDiagnostics: remapDiagnostics(expandedProgram.frontendDiagnostics()),
|
|
900
|
+
macroEnvironment: expandedProgram.macroEnvironment,
|
|
901
|
+
macroCacheStats: expandedProgram.macroEnvironment.cacheStats(),
|
|
902
|
+
preparedProgram: expandedProgram.preparedProgram,
|
|
903
|
+
program,
|
|
904
|
+
runSound,
|
|
905
|
+
tsDiagnosticPrograms: expandedProgram.tsDiagnosticPrograms,
|
|
906
|
+
universalPolicyScope,
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function analyzePreparedView(
|
|
911
|
+
preparedView: PreparedAnalysisView | null,
|
|
912
|
+
): AnalyzedProgramResult {
|
|
913
|
+
if (!preparedView) {
|
|
914
|
+
return {
|
|
915
|
+
frontendDiagnostics: [],
|
|
916
|
+
tsDiagnostics: [],
|
|
917
|
+
soundDiagnostics: [],
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
const frontendDiagnostics = [...preparedView.frontendDiagnostics];
|
|
922
|
+
const tsDiagnostics = collectPreparedViewTsDiagnostics(
|
|
923
|
+
preparedView,
|
|
924
|
+
frontendDiagnostics,
|
|
925
|
+
);
|
|
926
|
+
const hasFrontendErrors = hasErrorDiagnostics(frontendDiagnostics);
|
|
927
|
+
const hasTsErrors = hasErrorDiagnostics(tsDiagnostics);
|
|
928
|
+
const universalDiagnostics = hasFrontendErrors ? [] : collectPreparedViewUniversalDiagnostics(
|
|
929
|
+
preparedView,
|
|
930
|
+
preparedView.analysisContext,
|
|
931
|
+
);
|
|
932
|
+
const soundDiagnostics = hasFrontendErrors ? [] : collectPreparedViewSoundDiagnostics(
|
|
933
|
+
preparedView,
|
|
934
|
+
preparedView.analysisContext,
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
return {
|
|
938
|
+
frontendDiagnostics,
|
|
939
|
+
tsDiagnostics,
|
|
940
|
+
soundDiagnostics: hasTsErrors
|
|
941
|
+
? retainSoundDiagnosticsAlongsideTsErrors([...universalDiagnostics, ...soundDiagnostics])
|
|
942
|
+
: [...universalDiagnostics, ...soundDiagnostics],
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function emitProjectedDeclarationsFailClosed(
|
|
947
|
+
preparedView: PreparedAnalysisView | null,
|
|
948
|
+
rootNames?: readonly string[],
|
|
949
|
+
): ReadonlyMap<string, string> | undefined {
|
|
950
|
+
if (!preparedView) {
|
|
951
|
+
return undefined;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
try {
|
|
955
|
+
return emitProjectedDeclarations(preparedView.analysisPreparedProgram, rootNames);
|
|
956
|
+
} catch (error) {
|
|
957
|
+
const analyzedView = analyzePreparedView(preparedView);
|
|
958
|
+
if (
|
|
959
|
+
hasErrorDiagnostics([
|
|
960
|
+
...analyzedView.frontendDiagnostics,
|
|
961
|
+
...analyzedView.tsDiagnostics,
|
|
962
|
+
...analyzedView.soundDiagnostics,
|
|
963
|
+
])
|
|
964
|
+
) {
|
|
965
|
+
return undefined;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
throw error;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function analyzePreparedViewForFile(
|
|
973
|
+
preparedView: PreparedAnalysisView | null,
|
|
974
|
+
filePath: string,
|
|
975
|
+
): AnalyzedProgramResult {
|
|
976
|
+
if (!preparedView) {
|
|
977
|
+
return {
|
|
978
|
+
frontendDiagnostics: [],
|
|
979
|
+
tsDiagnostics: [],
|
|
980
|
+
soundDiagnostics: [],
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
const frontendDiagnosticPaths = collectPreparedViewFrontendDiagnosticPaths(
|
|
985
|
+
preparedView,
|
|
986
|
+
filePath,
|
|
987
|
+
);
|
|
988
|
+
const frontendDiagnostics = preparedView.frontendDiagnostics.filter((diagnostic) =>
|
|
989
|
+
matchesPreparedAnalysisAnyFilePath(diagnostic.filePath, frontendDiagnosticPaths)
|
|
990
|
+
);
|
|
991
|
+
const tsDiagnostics = collectPreparedViewTsDiagnostics(
|
|
992
|
+
preparedView,
|
|
993
|
+
frontendDiagnostics,
|
|
994
|
+
filePath,
|
|
995
|
+
true,
|
|
996
|
+
);
|
|
997
|
+
const hasFrontendErrors = hasErrorDiagnostics(frontendDiagnostics);
|
|
998
|
+
const hasTsErrors = hasErrorDiagnostics(tsDiagnostics);
|
|
999
|
+
const fileScopedAnalysisContext = getFileScopedAnalysisContext(preparedView, filePath);
|
|
1000
|
+
const universalDiagnostics = !fileScopedAnalysisContext || hasFrontendErrors
|
|
1001
|
+
? []
|
|
1002
|
+
: filterAnalyzedDiagnosticsForFile(
|
|
1003
|
+
collectPreparedViewUniversalDiagnostics(
|
|
1004
|
+
preparedView,
|
|
1005
|
+
fileScopedAnalysisContext,
|
|
1006
|
+
filePath,
|
|
1007
|
+
),
|
|
1008
|
+
filePath,
|
|
1009
|
+
);
|
|
1010
|
+
const soundDiagnostics = !fileScopedAnalysisContext ||
|
|
1011
|
+
hasFrontendErrors
|
|
1012
|
+
? []
|
|
1013
|
+
: filterAnalyzedDiagnosticsForFile(
|
|
1014
|
+
collectPreparedViewSoundDiagnostics(
|
|
1015
|
+
preparedView,
|
|
1016
|
+
fileScopedAnalysisContext,
|
|
1017
|
+
filePath,
|
|
1018
|
+
),
|
|
1019
|
+
filePath,
|
|
1020
|
+
);
|
|
1021
|
+
|
|
1022
|
+
return {
|
|
1023
|
+
frontendDiagnostics,
|
|
1024
|
+
tsDiagnostics,
|
|
1025
|
+
soundDiagnostics: hasTsErrors
|
|
1026
|
+
? retainSoundDiagnosticsAlongsideTsErrors([...universalDiagnostics, ...soundDiagnostics])
|
|
1027
|
+
: [...universalDiagnostics, ...soundDiagnostics],
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function analyzePreparedViewForDiagnosticPaths(
|
|
1032
|
+
preparedView: PreparedAnalysisView | null,
|
|
1033
|
+
diagnosticPaths: readonly string[],
|
|
1034
|
+
): AnalyzedProgramResult {
|
|
1035
|
+
if (!preparedView || diagnosticPaths.length === 0) {
|
|
1036
|
+
return {
|
|
1037
|
+
frontendDiagnostics: [],
|
|
1038
|
+
tsDiagnostics: [],
|
|
1039
|
+
soundDiagnostics: [],
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const frontendDiagnostics = preparedView.frontendDiagnostics.filter((diagnostic) =>
|
|
1044
|
+
matchesPreparedAnalysisAnyFilePath(diagnostic.filePath, diagnosticPaths)
|
|
1045
|
+
);
|
|
1046
|
+
const tsDiagnostics = hasErrorDiagnostics(frontendDiagnostics)
|
|
1047
|
+
? []
|
|
1048
|
+
: collectPreparedViewTsDiagnostics(preparedView, frontendDiagnostics).filter((diagnostic) =>
|
|
1049
|
+
matchesPreparedAnalysisAnyFilePath(diagnostic.filePath, diagnosticPaths)
|
|
1050
|
+
);
|
|
1051
|
+
const hasFrontendErrors = hasErrorDiagnostics(frontendDiagnostics);
|
|
1052
|
+
const hasTsErrors = hasErrorDiagnostics(tsDiagnostics);
|
|
1053
|
+
const universalDiagnostics = hasFrontendErrors
|
|
1054
|
+
? []
|
|
1055
|
+
: collectPreparedViewUniversalDiagnostics(preparedView, preparedView.analysisContext).filter(
|
|
1056
|
+
(diagnostic) => matchesPreparedAnalysisAnyFilePath(diagnostic.filePath, diagnosticPaths),
|
|
1057
|
+
);
|
|
1058
|
+
const soundDiagnostics = hasFrontendErrors
|
|
1059
|
+
? []
|
|
1060
|
+
: collectPreparedViewSoundDiagnostics(preparedView, preparedView.analysisContext).filter(
|
|
1061
|
+
(diagnostic) => matchesPreparedAnalysisAnyFilePath(diagnostic.filePath, diagnosticPaths),
|
|
1062
|
+
);
|
|
1063
|
+
|
|
1064
|
+
return {
|
|
1065
|
+
frontendDiagnostics,
|
|
1066
|
+
tsDiagnostics,
|
|
1067
|
+
soundDiagnostics: hasTsErrors
|
|
1068
|
+
? retainSoundDiagnosticsAlongsideTsErrors([...universalDiagnostics, ...soundDiagnostics])
|
|
1069
|
+
: [...universalDiagnostics, ...soundDiagnostics],
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function retainSoundDiagnosticsAlongsideTsErrors(
|
|
1074
|
+
diagnostics: readonly MergedDiagnostic[],
|
|
1075
|
+
): readonly SoundDiagnostic[] {
|
|
1076
|
+
return diagnostics.filter((diagnostic): diagnostic is SoundDiagnostic =>
|
|
1077
|
+
diagnostic.source === 'sound' &&
|
|
1078
|
+
(diagnostic.code === SOUND_DIAGNOSTIC_CODES.constructionLifecycleViolation ||
|
|
1079
|
+
diagnostic.code === SOUND_DIAGNOSTIC_CODES.fieldReadBeforeInitialization)
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
function matchesPreparedAnalysisAnyFilePath(
|
|
1084
|
+
candidateFilePath: string | undefined,
|
|
1085
|
+
expectedFilePaths: readonly string[],
|
|
1086
|
+
): boolean {
|
|
1087
|
+
return expectedFilePaths.some((expectedFilePath) =>
|
|
1088
|
+
matchesPreparedAnalysisFilePath(candidateFilePath, expectedFilePath)
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function collectPreparedViewFrontendDiagnosticPaths(
|
|
1093
|
+
preparedView: PreparedAnalysisView,
|
|
1094
|
+
filePath: string,
|
|
1095
|
+
): readonly string[] {
|
|
1096
|
+
const diagnosticPaths = new Set<string>();
|
|
1097
|
+
const addDiagnosticPath = (candidateFilePath: string): void => {
|
|
1098
|
+
for (const variant of collectPreparedAnalysisFilePathCandidates(candidateFilePath)) {
|
|
1099
|
+
diagnosticPaths.add(variant);
|
|
1100
|
+
}
|
|
1101
|
+
if (isSoundscriptSourceFile(candidateFilePath)) {
|
|
1102
|
+
for (
|
|
1103
|
+
const variant of collectPreparedAnalysisFilePathCandidates(
|
|
1104
|
+
toProjectedDeclarationFileName(candidateFilePath),
|
|
1105
|
+
)
|
|
1106
|
+
) {
|
|
1107
|
+
diagnosticPaths.add(variant);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
addDiagnosticPath(filePath);
|
|
1113
|
+
|
|
1114
|
+
const traversalRoots: Array<{
|
|
1115
|
+
readonly key: string;
|
|
1116
|
+
readonly program: ts.Program;
|
|
1117
|
+
readonly sourceFile: ts.SourceFile;
|
|
1118
|
+
}> = [];
|
|
1119
|
+
const addTraversalRoot = (
|
|
1120
|
+
key: string,
|
|
1121
|
+
program: ts.Program,
|
|
1122
|
+
sourceFile: ts.SourceFile | null,
|
|
1123
|
+
): void => {
|
|
1124
|
+
if (!sourceFile || traversalRoots.some((root) => root.key === key)) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
traversalRoots.push({ key, program, sourceFile });
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
const sourceFileMatch = getPreparedViewSourceFileMatch(preparedView, filePath);
|
|
1131
|
+
addTraversalRoot('prepared', preparedView.program, sourceFileMatch?.sourceFile ?? null);
|
|
1132
|
+
|
|
1133
|
+
const tsDiagnosticProgramMatch = getPreparedViewTsDiagnosticProgramMatch(preparedView, filePath);
|
|
1134
|
+
addTraversalRoot(
|
|
1135
|
+
`ts:${tsDiagnosticProgramMatch?.diagnosticProgram.filePaths?.join(',') ?? 'all'}`,
|
|
1136
|
+
tsDiagnosticProgramMatch?.diagnosticProgram.program ?? preparedView.program,
|
|
1137
|
+
tsDiagnosticProgramMatch?.sourceFile ?? null,
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
if (traversalRoots.length === 0) {
|
|
1141
|
+
return [...diagnosticPaths];
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
const visitedSourceFiles = new Set<string>();
|
|
1145
|
+
const getTraversalSourceFile = (
|
|
1146
|
+
program: ts.Program,
|
|
1147
|
+
candidateFilePath: string,
|
|
1148
|
+
): ts.SourceFile | null => {
|
|
1149
|
+
for (const candidate of collectPreparedAnalysisFilePathCandidates(candidateFilePath)) {
|
|
1150
|
+
const sourceFile = program.getSourceFile(
|
|
1151
|
+
preparedView.preparedProgram.toProgramFileName(candidate),
|
|
1152
|
+
);
|
|
1153
|
+
if (sourceFile) {
|
|
1154
|
+
return sourceFile;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
if (isSoundscriptSourceFile(candidate)) {
|
|
1158
|
+
const projectedCandidate = toProjectedDeclarationFileName(candidate);
|
|
1159
|
+
const projectedSourceFile = program.getSourceFile(
|
|
1160
|
+
preparedView.preparedProgram.toProgramFileName(projectedCandidate),
|
|
1161
|
+
);
|
|
1162
|
+
if (projectedSourceFile) {
|
|
1163
|
+
return projectedSourceFile;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
return null;
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1171
|
+
const visit = (programKey: string, program: ts.Program, sourceFile: ts.SourceFile): void => {
|
|
1172
|
+
const sourceFilePath = preparedView.preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
1173
|
+
const visitKey = `${programKey}:${sourceFilePath}`;
|
|
1174
|
+
if (visitedSourceFiles.has(visitKey)) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
visitedSourceFiles.add(visitKey);
|
|
1178
|
+
addDiagnosticPath(sourceFilePath);
|
|
1179
|
+
|
|
1180
|
+
for (const moduleSpecifier of getStaticSourceFileModuleSpecifiers(sourceFile)) {
|
|
1181
|
+
const resolvedModule = resolveSoundScriptAwareModule(
|
|
1182
|
+
moduleSpecifier,
|
|
1183
|
+
sourceFilePath,
|
|
1184
|
+
preparedView.preparedProgram.options,
|
|
1185
|
+
preparedView.preparedProgram.preparedHost.host,
|
|
1186
|
+
);
|
|
1187
|
+
if (!resolvedModule) {
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
const resolvedSourcePath = preparedView.preparedProgram.toSourceFileName(
|
|
1192
|
+
resolvedModule.resolvedFileName,
|
|
1193
|
+
);
|
|
1194
|
+
if (
|
|
1195
|
+
!isSoundscriptSourceFile(resolvedSourcePath) &&
|
|
1196
|
+
!isProjectedSoundscriptDeclarationFile(resolvedSourcePath)
|
|
1197
|
+
) {
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
addDiagnosticPath(resolvedSourcePath);
|
|
1202
|
+
const dependencySourceFile = getTraversalSourceFile(program, resolvedSourcePath);
|
|
1203
|
+
if (dependencySourceFile) {
|
|
1204
|
+
visit(programKey, program, dependencySourceFile);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
for (const traversalRoot of traversalRoots) {
|
|
1210
|
+
visit(traversalRoot.key, traversalRoot.program, traversalRoot.sourceFile);
|
|
1211
|
+
}
|
|
1212
|
+
return [...diagnosticPaths];
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
function getStaticSourceFileModuleSpecifiers(sourceFile: ts.SourceFile): readonly string[] {
|
|
1216
|
+
const moduleSpecifiers: string[] = [];
|
|
1217
|
+
|
|
1218
|
+
for (const statement of sourceFile.statements) {
|
|
1219
|
+
if (
|
|
1220
|
+
(ts.isImportDeclaration(statement) || ts.isExportDeclaration(statement)) &&
|
|
1221
|
+
statement.moduleSpecifier &&
|
|
1222
|
+
ts.isStringLiteral(statement.moduleSpecifier)
|
|
1223
|
+
) {
|
|
1224
|
+
moduleSpecifiers.push(statement.moduleSpecifier.text);
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
if (
|
|
1229
|
+
ts.isImportEqualsDeclaration(statement) &&
|
|
1230
|
+
ts.isExternalModuleReference(statement.moduleReference) &&
|
|
1231
|
+
ts.isStringLiteral(statement.moduleReference.expression)
|
|
1232
|
+
) {
|
|
1233
|
+
moduleSpecifiers.push(statement.moduleReference.expression.text);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
return moduleSpecifiers;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function getPreparedViewTsDiagnosticProgramMatch(
|
|
1241
|
+
preparedView: PreparedAnalysisView,
|
|
1242
|
+
filePath: string,
|
|
1243
|
+
): {
|
|
1244
|
+
readonly diagnosticProgram: BuiltinExpandedTsDiagnosticProgram;
|
|
1245
|
+
readonly matchedFilePath: string;
|
|
1246
|
+
readonly sourceFile: ts.SourceFile;
|
|
1247
|
+
} | null {
|
|
1248
|
+
const preferredPrograms = [
|
|
1249
|
+
...preparedView.tsDiagnosticPrograms.filter((program) => program.filePaths !== undefined),
|
|
1250
|
+
...preparedView.tsDiagnosticPrograms.filter((program) => program.filePaths === undefined),
|
|
1251
|
+
];
|
|
1252
|
+
|
|
1253
|
+
for (const candidateFilePath of collectPreparedAnalysisFilePathCandidates(filePath)) {
|
|
1254
|
+
const programFileName = preparedView.preparedProgram.toProgramFileName(candidateFilePath);
|
|
1255
|
+
for (const diagnosticProgram of preferredPrograms) {
|
|
1256
|
+
if (
|
|
1257
|
+
diagnosticProgram.filePaths !== undefined &&
|
|
1258
|
+
!diagnosticProgram.filePaths.includes(candidateFilePath)
|
|
1259
|
+
) {
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
const sourceFile = diagnosticProgram.program.getSourceFile(programFileName);
|
|
1264
|
+
if (!sourceFile) {
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
return {
|
|
1269
|
+
diagnosticProgram,
|
|
1270
|
+
matchedFilePath: candidateFilePath,
|
|
1271
|
+
sourceFile,
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
return null;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
function collectPreparedViewTsDiagnostics(
|
|
1280
|
+
preparedView: PreparedAnalysisView,
|
|
1281
|
+
frontendDiagnostics: readonly MergedDiagnostic[],
|
|
1282
|
+
filePath?: string,
|
|
1283
|
+
requireSourceFile = false,
|
|
1284
|
+
): readonly MergedDiagnostic[] {
|
|
1285
|
+
if (
|
|
1286
|
+
preparedView.universalPolicyScope === 'sourceSupplemental' ||
|
|
1287
|
+
hasErrorDiagnostics(frontendDiagnostics) ||
|
|
1288
|
+
(requireSourceFile && !filePath)
|
|
1289
|
+
) {
|
|
1290
|
+
return [];
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
const sourceFileMatch = filePath
|
|
1294
|
+
? getPreparedViewTsDiagnosticProgramMatch(preparedView, filePath)
|
|
1295
|
+
: null;
|
|
1296
|
+
if (requireSourceFile && !sourceFileMatch) {
|
|
1297
|
+
return [];
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
const metadata: Record<string, boolean | number | string | undefined> = {
|
|
1301
|
+
fileScoped: filePath !== undefined,
|
|
1302
|
+
requireSourceFile,
|
|
1303
|
+
rootCount: sourceFileMatch
|
|
1304
|
+
? sourceFileMatch.diagnosticProgram.program.getRootFileNames().length
|
|
1305
|
+
: preparedView.program.getRootFileNames().length,
|
|
1306
|
+
universalPolicyScope: preparedView.universalPolicyScope,
|
|
1307
|
+
};
|
|
1308
|
+
if (sourceFileMatch) {
|
|
1309
|
+
metadata.filePath = sourceFileMatch.matchedFilePath;
|
|
1310
|
+
}
|
|
1311
|
+
const diagnostics = measureCheckerTiming(
|
|
1312
|
+
'project.analyze.tsDiagnostics',
|
|
1313
|
+
metadata,
|
|
1314
|
+
() => {
|
|
1315
|
+
const handledFilePaths = new Set(
|
|
1316
|
+
preparedView.tsDiagnosticPrograms.flatMap((diagnosticProgram) =>
|
|
1317
|
+
diagnosticProgram.filePaths ? [...diagnosticProgram.filePaths] : []
|
|
1318
|
+
),
|
|
1319
|
+
);
|
|
1320
|
+
const collectedDiagnostics = sourceFileMatch
|
|
1321
|
+
? ts.getPreEmitDiagnostics(
|
|
1322
|
+
sourceFileMatch.diagnosticProgram.program,
|
|
1323
|
+
sourceFileMatch.sourceFile,
|
|
1324
|
+
)
|
|
1325
|
+
: preparedView.tsDiagnosticPrograms.flatMap((diagnosticProgram) => {
|
|
1326
|
+
if (!diagnosticProgram.filePaths || diagnosticProgram.filePaths.length === 0) {
|
|
1327
|
+
return ts.getPreEmitDiagnostics(diagnosticProgram.program).filter((diagnostic) =>
|
|
1328
|
+
!diagnostic.file ||
|
|
1329
|
+
!handledFilePaths.has(toSourceFileName(diagnostic.file.fileName))
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
return diagnosticProgram.filePaths.flatMap((diagnosticFilePath) => {
|
|
1334
|
+
const programFileName = preparedView.preparedProgram.toProgramFileName(
|
|
1335
|
+
diagnosticFilePath,
|
|
1336
|
+
);
|
|
1337
|
+
const diagnosticSourceFile = diagnosticProgram.program.getSourceFile(programFileName);
|
|
1338
|
+
return diagnosticSourceFile
|
|
1339
|
+
? ts.getPreEmitDiagnostics(diagnosticProgram.program, diagnosticSourceFile)
|
|
1340
|
+
: [];
|
|
1341
|
+
});
|
|
1342
|
+
});
|
|
1343
|
+
metadata.diagnostics = collectedDiagnostics.length;
|
|
1344
|
+
return collectedDiagnostics;
|
|
1345
|
+
},
|
|
1346
|
+
{ always: true },
|
|
1347
|
+
);
|
|
1348
|
+
|
|
1349
|
+
return remapDiagnostics(
|
|
1350
|
+
diagnostics.map((diagnostic) =>
|
|
1351
|
+
toMappedMergedDiagnostic(diagnostic, preparedView.diagnosticPreparedFiles)
|
|
1352
|
+
),
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
function collectPreparedViewUniversalDiagnostics(
|
|
1357
|
+
preparedView: PreparedAnalysisView,
|
|
1358
|
+
analysisContext: AnalysisContext,
|
|
1359
|
+
filePath?: string,
|
|
1360
|
+
): readonly SoundDiagnostic[] {
|
|
1361
|
+
const metadata: Record<string, boolean | number | string | undefined> = {
|
|
1362
|
+
fileScoped: filePath !== undefined,
|
|
1363
|
+
rootCount: preparedView.program.getRootFileNames().length,
|
|
1364
|
+
universalPolicyScope: preparedView.universalPolicyScope,
|
|
1365
|
+
};
|
|
1366
|
+
if (filePath) {
|
|
1367
|
+
metadata.filePath = filePath;
|
|
1368
|
+
}
|
|
1369
|
+
return measureCheckerTiming(
|
|
1370
|
+
'project.analyze.universalPolicy',
|
|
1371
|
+
metadata,
|
|
1372
|
+
() => {
|
|
1373
|
+
const diagnostics = remapDiagnostics(
|
|
1374
|
+
remapSoundDiagnostics(
|
|
1375
|
+
preparedView.universalPolicyScope === 'sourceSupplemental'
|
|
1376
|
+
? runSourceSupplementalPolicyAnalysis(analysisContext)
|
|
1377
|
+
: runUniversalPolicyAnalysis(analysisContext),
|
|
1378
|
+
preparedView.diagnosticPreparedFiles,
|
|
1379
|
+
),
|
|
1380
|
+
);
|
|
1381
|
+
metadata.diagnostics = diagnostics.length;
|
|
1382
|
+
return diagnostics;
|
|
1383
|
+
},
|
|
1384
|
+
{ always: true },
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
function collectPreparedViewSoundDiagnostics(
|
|
1389
|
+
preparedView: PreparedAnalysisView,
|
|
1390
|
+
analysisContext: AnalysisContext,
|
|
1391
|
+
filePath?: string,
|
|
1392
|
+
): readonly SoundDiagnostic[] {
|
|
1393
|
+
const metadata: Record<string, boolean | number | string | undefined> = {
|
|
1394
|
+
fileScoped: filePath !== undefined,
|
|
1395
|
+
rootCount: preparedView.program.getRootFileNames().length,
|
|
1396
|
+
runSound: preparedView.runSound,
|
|
1397
|
+
};
|
|
1398
|
+
if (filePath) {
|
|
1399
|
+
metadata.filePath = filePath;
|
|
1400
|
+
}
|
|
1401
|
+
return measureCheckerTiming(
|
|
1402
|
+
'project.analyze.soundRules',
|
|
1403
|
+
metadata,
|
|
1404
|
+
() => {
|
|
1405
|
+
const diagnostics = remapDiagnostics(
|
|
1406
|
+
remapSoundDiagnostics(
|
|
1407
|
+
preparedView.runSound ? runSoundAnalysis(analysisContext) : [],
|
|
1408
|
+
preparedView.diagnosticPreparedFiles,
|
|
1409
|
+
),
|
|
1410
|
+
);
|
|
1411
|
+
metadata.diagnostics = diagnostics.length;
|
|
1412
|
+
return diagnostics;
|
|
1413
|
+
},
|
|
1414
|
+
{ always: true },
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function getFileScopedAnalysisContext(
|
|
1419
|
+
preparedView: PreparedAnalysisView,
|
|
1420
|
+
filePath: string,
|
|
1421
|
+
): AnalysisContext | null {
|
|
1422
|
+
let byFile = fileScopedAnalysisContextCache.get(preparedView);
|
|
1423
|
+
if (!byFile) {
|
|
1424
|
+
byFile = new Map<string, AnalysisContext | null>();
|
|
1425
|
+
fileScopedAnalysisContextCache.set(preparedView, byFile);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
const cached = byFile.get(filePath);
|
|
1429
|
+
if (cached !== undefined) {
|
|
1430
|
+
return cached;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
const sourceFileMatch = getPreparedViewSourceFileMatch(preparedView, filePath);
|
|
1434
|
+
if (!sourceFileMatch) {
|
|
1435
|
+
byFile.set(filePath, null);
|
|
1436
|
+
return null;
|
|
1437
|
+
}
|
|
1438
|
+
const sourceFile = sourceFileMatch.sourceFile;
|
|
1439
|
+
const preparedSource = preparedView.preparedProgram.preparedHost.getPreparedSourceFile(
|
|
1440
|
+
sourceFileMatch.matchedFilePath,
|
|
1441
|
+
);
|
|
1442
|
+
if (
|
|
1443
|
+
hasTopLevelMacroReplacements(sourceFileMatch.matchedFilePath, preparedSource) ||
|
|
1444
|
+
hasGeneratedTopLevelStatements(sourceFile, preparedView.analysisContext.isGeneratedNode)
|
|
1445
|
+
) {
|
|
1446
|
+
byFile.set(filePath, null);
|
|
1447
|
+
return null;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
const analysisContext = createAnalysisContext({
|
|
1451
|
+
includeSourceFile: (candidate) =>
|
|
1452
|
+
matchesPreparedAnalysisFilePath(toSourceFileName(candidate.fileName), filePath) &&
|
|
1453
|
+
!isMacroAuthoringSourceFile(candidate, preparedView.analysisPreparedProgram),
|
|
1454
|
+
isGeneratedNode: createPreparedProgramGeneratedNodeDetector(
|
|
1455
|
+
preparedView.analysisPreparedProgram,
|
|
1456
|
+
),
|
|
1457
|
+
program: preparedView.program,
|
|
1458
|
+
runtime: preparedView.analysisContext.runtime,
|
|
1459
|
+
workingDirectory: preparedView.analysisContext.workingDirectory,
|
|
1460
|
+
});
|
|
1461
|
+
byFile.set(filePath, analysisContext);
|
|
1462
|
+
return analysisContext;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
function createSummary(diagnostics: readonly { category: 'error' | 'warning' | 'message' }[]) {
|
|
1466
|
+
return {
|
|
1467
|
+
total: diagnostics.length,
|
|
1468
|
+
errors: diagnostics.filter((diagnostic) => diagnostic.category === 'error').length,
|
|
1469
|
+
warnings: diagnostics.filter((diagnostic) => diagnostic.category === 'warning').length,
|
|
1470
|
+
messages: diagnostics.filter((diagnostic) => diagnostic.category === 'message').length,
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
function isMacroAuthoringSourceFile(
|
|
1475
|
+
sourceFile: ts.SourceFile,
|
|
1476
|
+
preparedProgram?: PreparedProgram,
|
|
1477
|
+
): boolean {
|
|
1478
|
+
const sourceText = preparedProgram?.preparedHost.getPreparedSourceFile(
|
|
1479
|
+
toSourceFileName(sourceFile.fileName),
|
|
1480
|
+
)?.originalText ?? sourceFile.text;
|
|
1481
|
+
return sourceTextLooksLikeMacroModule(sourceText) ||
|
|
1482
|
+
usesLegacyDefineMacroAuthoring(sourceText);
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
function applyMacroCacheStatsToMetadata(
|
|
1486
|
+
metadata: Record<string, string | number>,
|
|
1487
|
+
macroCacheStats: MacroModuleCacheStats,
|
|
1488
|
+
): void {
|
|
1489
|
+
metadata.macroCacheHits = macroCacheStats.moduleCacheHits;
|
|
1490
|
+
metadata.macroCacheMisses = macroCacheStats.moduleCacheMisses;
|
|
1491
|
+
metadata.macroCacheInvalidations = macroCacheStats.moduleCacheInvalidations;
|
|
1492
|
+
metadata.macroModulesEvaluated = macroCacheStats.evaluatedModules;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
function createPreparedProgramGeneratedNodeDetector(
|
|
1496
|
+
preparedProgram: PreparedProgram,
|
|
1497
|
+
): (node: ts.Node) => boolean {
|
|
1498
|
+
const preparedFileCache = new Map<string, PreparedSourceFile | null>();
|
|
1499
|
+
|
|
1500
|
+
function getPreparedFile(sourceFile: ts.SourceFile | undefined): PreparedSourceFile | undefined {
|
|
1501
|
+
if (!sourceFile) {
|
|
1502
|
+
return undefined;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
const sourceFileName = toSourceFileName(sourceFile.fileName);
|
|
1506
|
+
if (preparedFileCache.has(sourceFileName)) {
|
|
1507
|
+
return preparedFileCache.get(sourceFileName) ?? undefined;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
const preparedFile = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
1511
|
+
preparedFileCache.set(sourceFileName, preparedFile ?? null);
|
|
1512
|
+
return preparedFile;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
return (node: ts.Node): boolean => {
|
|
1516
|
+
if (ts.isSourceFile(node)) {
|
|
1517
|
+
return false;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
const sourceFile = node.getSourceFile();
|
|
1521
|
+
const preparedFile = getPreparedFile(sourceFile);
|
|
1522
|
+
if (!preparedFile) {
|
|
1523
|
+
return false;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const programStart = node.getStart(sourceFile, false);
|
|
1527
|
+
const programEnd = node.getEnd();
|
|
1528
|
+
if (programEnd <= programStart) {
|
|
1529
|
+
return false;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
const startMapping = mapProgramPositionToSource(preparedFile, programStart);
|
|
1533
|
+
const endMapping = mapProgramPositionToSource(
|
|
1534
|
+
preparedFile,
|
|
1535
|
+
Math.max(programStart, programEnd - 1),
|
|
1536
|
+
);
|
|
1537
|
+
return startMapping.insideReplacement && endMapping.insideReplacement;
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
function aggregateMacroCacheStats(
|
|
1542
|
+
preparedProject: PreparedAnalysisProject,
|
|
1543
|
+
): MacroModuleCacheStats {
|
|
1544
|
+
const aggregated: MacroModuleCacheStats = {
|
|
1545
|
+
evaluatedModules: 0,
|
|
1546
|
+
moduleCacheHits: 0,
|
|
1547
|
+
moduleCacheInvalidations: 0,
|
|
1548
|
+
moduleCacheMisses: 0,
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
for (
|
|
1552
|
+
const view of [
|
|
1553
|
+
preparedProject.tsView,
|
|
1554
|
+
preparedProject.stsView,
|
|
1555
|
+
preparedProject.packageSourcePolicyView,
|
|
1556
|
+
]
|
|
1557
|
+
) {
|
|
1558
|
+
if (!view) {
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
aggregated.evaluatedModules += view.macroCacheStats.evaluatedModules;
|
|
1563
|
+
aggregated.moduleCacheHits += view.macroCacheStats.moduleCacheHits;
|
|
1564
|
+
aggregated.moduleCacheInvalidations += view.macroCacheStats.moduleCacheInvalidations;
|
|
1565
|
+
aggregated.moduleCacheMisses += view.macroCacheStats.moduleCacheMisses;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
return aggregated;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
function collectPreparedProjectViews(
|
|
1572
|
+
preparedProject: PreparedAnalysisProject | null | undefined,
|
|
1573
|
+
): readonly PreparedAnalysisView[] {
|
|
1574
|
+
if (!preparedProject) {
|
|
1575
|
+
return [];
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
return [
|
|
1579
|
+
preparedProject.tsView,
|
|
1580
|
+
preparedProject.stsView,
|
|
1581
|
+
preparedProject.packageSourcePolicyView,
|
|
1582
|
+
].filter((view): view is PreparedAnalysisView => view !== null);
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
export function disposePreparedAnalysisProject(
|
|
1586
|
+
preparedProject: PreparedAnalysisProject | null | undefined,
|
|
1587
|
+
retainedProject?: PreparedAnalysisProject | null,
|
|
1588
|
+
): void {
|
|
1589
|
+
const retainedViews = new Set(collectPreparedProjectViews(retainedProject));
|
|
1590
|
+
const retainedPreparedPrograms = new Set<PreparedProgram>(
|
|
1591
|
+
collectPreparedProjectViews(retainedProject).flatMap((view) => [
|
|
1592
|
+
view.analysisPreparedProgram,
|
|
1593
|
+
view.preparedProgram,
|
|
1594
|
+
]),
|
|
1595
|
+
);
|
|
1596
|
+
const retainedReuseStates = new Set<PreparedCompilerHostReuseState>(
|
|
1597
|
+
[...retainedPreparedPrograms].map((preparedProgram) => preparedProgram.preparedHost.reuseState),
|
|
1598
|
+
);
|
|
1599
|
+
const disposedMacroEnvironments = new Set<object>();
|
|
1600
|
+
const disposedPreparedPrograms = new Set<PreparedProgram>();
|
|
1601
|
+
|
|
1602
|
+
for (const view of collectPreparedProjectViews(preparedProject)) {
|
|
1603
|
+
if (retainedViews.has(view)) {
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
const macroEnvironment = view.macroEnvironment as object;
|
|
1607
|
+
if (disposedMacroEnvironments.has(macroEnvironment)) {
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
disposedMacroEnvironments.add(macroEnvironment);
|
|
1611
|
+
view.macroEnvironment.dispose();
|
|
1612
|
+
|
|
1613
|
+
for (const preparedProgram of [view.analysisPreparedProgram, view.preparedProgram]) {
|
|
1614
|
+
if (
|
|
1615
|
+
disposedPreparedPrograms.has(preparedProgram) ||
|
|
1616
|
+
retainedPreparedPrograms.has(preparedProgram)
|
|
1617
|
+
) {
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
disposedPreparedPrograms.add(preparedProgram);
|
|
1621
|
+
const reuseState = preparedProgram.preparedHost.reuseState;
|
|
1622
|
+
preparedProgram.dispose(false);
|
|
1623
|
+
if (!retainedReuseStates.has(reuseState)) {
|
|
1624
|
+
clearPreparedCompilerHostReuseState(reuseState);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
export function analyzeProject(options: AnalyzeProjectOptions): AnalyzeProjectResult {
|
|
1631
|
+
const preparedProject = prepareProjectAnalysis(options);
|
|
1632
|
+
try {
|
|
1633
|
+
return analyzePreparedProject(preparedProject);
|
|
1634
|
+
} finally {
|
|
1635
|
+
disposePreparedAnalysisProject(preparedProject);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
export function prepareProjectAnalysis(
|
|
1640
|
+
options: AnalyzeProjectOptions,
|
|
1641
|
+
reusableProject?: PreparedAnalysisProject,
|
|
1642
|
+
prepareOptions: PrepareProjectAnalysisOptions = {},
|
|
1643
|
+
): PreparedAnalysisProject {
|
|
1644
|
+
const prepareMetadata: Record<string, string | number> = {
|
|
1645
|
+
projectPath: options.projectPath,
|
|
1646
|
+
};
|
|
1647
|
+
return measureCheckerTiming(
|
|
1648
|
+
'project.prepareProjectAnalysis',
|
|
1649
|
+
prepareMetadata,
|
|
1650
|
+
() => {
|
|
1651
|
+
const loadedConfig = loadConfig(
|
|
1652
|
+
options.projectPath,
|
|
1653
|
+
{ target: options.target },
|
|
1654
|
+
options.additionalRootNames,
|
|
1655
|
+
);
|
|
1656
|
+
const projectPackageJsonPath = findNearestPackageJsonPath(options.projectPath, ts.sys);
|
|
1657
|
+
const configReuseSignature = createProjectConfigReuseSignature(
|
|
1658
|
+
options.projectPath,
|
|
1659
|
+
loadedConfig,
|
|
1660
|
+
);
|
|
1661
|
+
const soundscriptRootDiscoverySignature = createSoundscriptRootDiscoverySignature(
|
|
1662
|
+
options.projectPath,
|
|
1663
|
+
loadedConfig,
|
|
1664
|
+
);
|
|
1665
|
+
// Same-stem .sts roots are discovered from the current filesystem, so
|
|
1666
|
+
// reusing a previous discovered-root list can keep removed files alive
|
|
1667
|
+
// across prepared-project rebuilds.
|
|
1668
|
+
const configuredSoundscriptRootNames = collectSoundscriptRootNames(
|
|
1669
|
+
options.projectPath,
|
|
1670
|
+
loadedConfig,
|
|
1671
|
+
);
|
|
1672
|
+
const allRootNames = combineRootNames(
|
|
1673
|
+
combineRootNames(
|
|
1674
|
+
loadedConfig.commandLine.fileNames,
|
|
1675
|
+
configuredSoundscriptRootNames,
|
|
1676
|
+
),
|
|
1677
|
+
options.additionalRootNames,
|
|
1678
|
+
);
|
|
1679
|
+
const soundscriptRootNames = allRootNames.filter(isSoundscriptSourceFile);
|
|
1680
|
+
const typescriptRootNames = allRootNames.filter((fileName) =>
|
|
1681
|
+
!isSoundscriptSourceFile(fileName)
|
|
1682
|
+
);
|
|
1683
|
+
const configFileParsingDiagnostics = getConfigFileParsingDiagnostics(
|
|
1684
|
+
loadedConfig.diagnostics,
|
|
1685
|
+
options.additionalRootNames,
|
|
1686
|
+
);
|
|
1687
|
+
const soundscriptFileOverridesSignature = createFileOverrideSignature(
|
|
1688
|
+
options.fileOverrides,
|
|
1689
|
+
isSoundscriptSourceFile,
|
|
1690
|
+
);
|
|
1691
|
+
const soundscriptRootContentSignature = createSoundscriptRootContentSignature(
|
|
1692
|
+
soundscriptRootNames,
|
|
1693
|
+
loadedConfig.commandLine.options,
|
|
1694
|
+
options.fileOverrides,
|
|
1695
|
+
);
|
|
1696
|
+
const canReuseConfigArtifacts = reusableProject !== undefined &&
|
|
1697
|
+
reusableProject.analyzeOptions.projectPath === options.projectPath &&
|
|
1698
|
+
reusableProject.configReuseSignature === configReuseSignature;
|
|
1699
|
+
const canReuseStsArtifacts = canReuseConfigArtifacts &&
|
|
1700
|
+
rootNamesEqual(reusableProject.soundscriptRootNames, soundscriptRootNames) &&
|
|
1701
|
+
reusableProject.soundscriptRootContentSignature === soundscriptRootContentSignature &&
|
|
1702
|
+
reusableProject.soundscriptFileOverridesSignature === soundscriptFileOverridesSignature;
|
|
1703
|
+
const soundscriptRootNameSet = new Set(
|
|
1704
|
+
soundscriptRootNames.map((rootName) => ts.sys.resolvePath(rootName)),
|
|
1705
|
+
);
|
|
1706
|
+
const stsView = canReuseStsArtifacts ? reusableProject.stsView : (() => {
|
|
1707
|
+
const metadata: Record<string, string | number> = {
|
|
1708
|
+
rootCount: soundscriptRootNames.length,
|
|
1709
|
+
};
|
|
1710
|
+
return measureCheckerTiming(
|
|
1711
|
+
'project.prepare.stsView',
|
|
1712
|
+
metadata,
|
|
1713
|
+
() => {
|
|
1714
|
+
const preparedView = prepareAnalysisView(
|
|
1715
|
+
options,
|
|
1716
|
+
loadedConfig,
|
|
1717
|
+
soundscriptRootNames,
|
|
1718
|
+
createSoundStdlibCompilerHost(
|
|
1719
|
+
loadedConfig.commandLine.options,
|
|
1720
|
+
dirname(options.projectPath),
|
|
1721
|
+
),
|
|
1722
|
+
[],
|
|
1723
|
+
(sourceFile, preparedProgram) =>
|
|
1724
|
+
shouldAnalyzeProjectSoundscriptSourceFile(
|
|
1725
|
+
sourceFile,
|
|
1726
|
+
preparedProgram,
|
|
1727
|
+
projectPackageJsonPath,
|
|
1728
|
+
),
|
|
1729
|
+
undefined,
|
|
1730
|
+
true,
|
|
1731
|
+
'full',
|
|
1732
|
+
canReuseConfigArtifacts ? reusableProject?.stsCompilerHostReuseState : undefined,
|
|
1733
|
+
canReuseConfigArtifacts ? reusableProject?.stsView?.program : undefined,
|
|
1734
|
+
);
|
|
1735
|
+
if (preparedView) {
|
|
1736
|
+
applyMacroCacheStatsToMetadata(metadata, preparedView.macroCacheStats);
|
|
1737
|
+
}
|
|
1738
|
+
return preparedView;
|
|
1739
|
+
},
|
|
1740
|
+
{ always: true },
|
|
1741
|
+
);
|
|
1742
|
+
})();
|
|
1743
|
+
const shouldDeferTypescriptView = prepareOptions.deferTypescriptView === true;
|
|
1744
|
+
if (shouldDeferTypescriptView) {
|
|
1745
|
+
const canReuseLocalProjectedDeclarationOverrides = canReuseStsArtifacts &&
|
|
1746
|
+
reusableProject?.localProjectedDeclarationOverrides !== undefined;
|
|
1747
|
+
const localProjectedDeclarationOverrides = !canReuseLocalProjectedDeclarationOverrides
|
|
1748
|
+
? undefined
|
|
1749
|
+
: reusableProject.localProjectedDeclarationOverrides;
|
|
1750
|
+
const preparedProject = {
|
|
1751
|
+
analyzeOptions: { ...options },
|
|
1752
|
+
configReuseSignature,
|
|
1753
|
+
configuredSoundscriptRootNames,
|
|
1754
|
+
localProjectedDeclarationOverrides,
|
|
1755
|
+
packageSourcePolicyContentSignature: '',
|
|
1756
|
+
packageSourcePolicyCompilerHostReuseState: canReuseConfigArtifacts
|
|
1757
|
+
? reusableProject?.packageSourcePolicyCompilerHostReuseState
|
|
1758
|
+
: undefined,
|
|
1759
|
+
packageSourcePolicyView: null,
|
|
1760
|
+
soundscriptRootContentSignature,
|
|
1761
|
+
soundscriptRootDiscoverySignature,
|
|
1762
|
+
stsCompilerHostReuseState: stsView?.preparedProgram.preparedHost.reuseState,
|
|
1763
|
+
soundscriptFileOverridesSignature,
|
|
1764
|
+
soundscriptRootNames,
|
|
1765
|
+
stsView,
|
|
1766
|
+
tsCompilerHostReuseState: canReuseConfigArtifacts
|
|
1767
|
+
? reusableProject?.tsCompilerHostReuseState
|
|
1768
|
+
: undefined,
|
|
1769
|
+
tsView: null,
|
|
1770
|
+
};
|
|
1771
|
+
applyMacroCacheStatsToMetadata(prepareMetadata, aggregateMacroCacheStats(preparedProject));
|
|
1772
|
+
return preparedProject;
|
|
1773
|
+
}
|
|
1774
|
+
const needsSupplementalProjectionViews = typescriptRootNames.length > 0 ||
|
|
1775
|
+
(stsView !== null &&
|
|
1776
|
+
hasNonRootProjectedDeclarationCandidates(
|
|
1777
|
+
stsView.program,
|
|
1778
|
+
soundscriptRootNameSet,
|
|
1779
|
+
projectPackageJsonPath,
|
|
1780
|
+
));
|
|
1781
|
+
if (!needsSupplementalProjectionViews) {
|
|
1782
|
+
const preparedProject = {
|
|
1783
|
+
analyzeOptions: { ...options },
|
|
1784
|
+
configReuseSignature,
|
|
1785
|
+
configuredSoundscriptRootNames,
|
|
1786
|
+
localProjectedDeclarationOverrides: undefined,
|
|
1787
|
+
packageSourcePolicyContentSignature: '',
|
|
1788
|
+
packageSourcePolicyCompilerHostReuseState: canReuseConfigArtifacts
|
|
1789
|
+
? reusableProject?.packageSourcePolicyCompilerHostReuseState
|
|
1790
|
+
: undefined,
|
|
1791
|
+
packageSourcePolicyView: null,
|
|
1792
|
+
soundscriptRootContentSignature,
|
|
1793
|
+
soundscriptRootDiscoverySignature,
|
|
1794
|
+
stsCompilerHostReuseState: stsView?.preparedProgram.preparedHost.reuseState,
|
|
1795
|
+
soundscriptFileOverridesSignature,
|
|
1796
|
+
soundscriptRootNames,
|
|
1797
|
+
stsView,
|
|
1798
|
+
tsCompilerHostReuseState: canReuseConfigArtifacts
|
|
1799
|
+
? reusableProject?.tsCompilerHostReuseState
|
|
1800
|
+
: undefined,
|
|
1801
|
+
tsView: null,
|
|
1802
|
+
};
|
|
1803
|
+
applyMacroCacheStatsToMetadata(prepareMetadata, aggregateMacroCacheStats(preparedProject));
|
|
1804
|
+
return preparedProject;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
const canReuseLocalProjectedDeclarationOverrides = canReuseStsArtifacts &&
|
|
1808
|
+
reusableProject?.localProjectedDeclarationOverrides !== undefined;
|
|
1809
|
+
const localProjectedDeclarationOverrides = canReuseLocalProjectedDeclarationOverrides
|
|
1810
|
+
? reusableProject.localProjectedDeclarationOverrides
|
|
1811
|
+
: measureCheckerTiming(
|
|
1812
|
+
'project.prepare.localProjection',
|
|
1813
|
+
{
|
|
1814
|
+
hasStsView: stsView !== null,
|
|
1815
|
+
rootCount: soundscriptRootNames.length,
|
|
1816
|
+
},
|
|
1817
|
+
() =>
|
|
1818
|
+
filterProjectedDeclarationOverridesToRootNames(
|
|
1819
|
+
emitProjectedDeclarationsFailClosed(stsView, soundscriptRootNames),
|
|
1820
|
+
soundscriptRootNames,
|
|
1821
|
+
),
|
|
1822
|
+
{ always: true },
|
|
1823
|
+
);
|
|
1824
|
+
|
|
1825
|
+
const preliminaryTsView = (() => {
|
|
1826
|
+
const metadata: Record<string, string | number> = {
|
|
1827
|
+
rootCount: typescriptRootNames.length,
|
|
1828
|
+
localProjectionCount: localProjectedDeclarationOverrides?.size ?? 0,
|
|
1829
|
+
};
|
|
1830
|
+
return measureCheckerTiming(
|
|
1831
|
+
'project.prepare.preliminaryTsView',
|
|
1832
|
+
metadata,
|
|
1833
|
+
() => {
|
|
1834
|
+
const preparedView = prepareAnalysisView(
|
|
1835
|
+
options,
|
|
1836
|
+
loadedConfig,
|
|
1837
|
+
typescriptRootNames,
|
|
1838
|
+
ts.createCompilerHost(loadedConfig.commandLine.options),
|
|
1839
|
+
configFileParsingDiagnostics,
|
|
1840
|
+
(sourceFile) => shouldAnalyzeTypescriptViewSourceFile(sourceFile),
|
|
1841
|
+
localProjectedDeclarationOverrides,
|
|
1842
|
+
false,
|
|
1843
|
+
'full',
|
|
1844
|
+
canReuseConfigArtifacts ? reusableProject?.tsCompilerHostReuseState : undefined,
|
|
1845
|
+
canReuseConfigArtifacts ? reusableProject?.tsView?.program : undefined,
|
|
1846
|
+
);
|
|
1847
|
+
if (preparedView) {
|
|
1848
|
+
applyMacroCacheStatsToMetadata(metadata, preparedView.macroCacheStats);
|
|
1849
|
+
}
|
|
1850
|
+
return preparedView;
|
|
1851
|
+
},
|
|
1852
|
+
{ always: true },
|
|
1853
|
+
);
|
|
1854
|
+
})();
|
|
1855
|
+
const packageProjectedDeclarationRootNames = collectProjectedDeclarationCandidateRootNamesFromPrograms(
|
|
1856
|
+
[preliminaryTsView?.program, stsView?.program],
|
|
1857
|
+
localProjectedDeclarationOverrides,
|
|
1858
|
+
projectPackageJsonPath,
|
|
1859
|
+
);
|
|
1860
|
+
const packageSourcePolicyContentSignature = packageProjectedDeclarationRootNames.length === 0
|
|
1861
|
+
? ''
|
|
1862
|
+
: createSoundscriptRootContentSignature(
|
|
1863
|
+
packageProjectedDeclarationRootNames,
|
|
1864
|
+
loadedConfig.commandLine.options,
|
|
1865
|
+
options.fileOverrides,
|
|
1866
|
+
);
|
|
1867
|
+
const packageProjectedDeclarationOverrides = measureCheckerTiming(
|
|
1868
|
+
'project.prepare.packageProjection',
|
|
1869
|
+
{
|
|
1870
|
+
candidateCount: packageProjectedDeclarationRootNames.length,
|
|
1871
|
+
},
|
|
1872
|
+
() => {
|
|
1873
|
+
if (packageProjectedDeclarationRootNames.length === 0 || !preliminaryTsView) {
|
|
1874
|
+
return undefined;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
const expandedProgram = createBuiltinExpandedProgram({
|
|
1878
|
+
baseHost: createSoundStdlibCompilerHost(
|
|
1879
|
+
loadedConfig.commandLine.options,
|
|
1880
|
+
dirname(options.projectPath),
|
|
1881
|
+
),
|
|
1882
|
+
configFileParsingDiagnostics: [],
|
|
1883
|
+
fileOverrides: options.fileOverrides ?? new Map(),
|
|
1884
|
+
options: loadedConfig.commandLine.options,
|
|
1885
|
+
projectReferences: loadedConfig.commandLine.projectReferences,
|
|
1886
|
+
projectedDeclarationOverrides: localProjectedDeclarationOverrides,
|
|
1887
|
+
runtime: loadedConfig.runtime,
|
|
1888
|
+
rootNames: packageProjectedDeclarationRootNames,
|
|
1889
|
+
});
|
|
1890
|
+
try {
|
|
1891
|
+
return emitProjectedDeclarations(
|
|
1892
|
+
expandedProgram.analysisPreparedProgram,
|
|
1893
|
+
packageProjectedDeclarationRootNames,
|
|
1894
|
+
);
|
|
1895
|
+
} finally {
|
|
1896
|
+
expandedProgram.dispose();
|
|
1897
|
+
}
|
|
1898
|
+
},
|
|
1899
|
+
{ always: true },
|
|
1900
|
+
);
|
|
1901
|
+
const projectedDeclarationOverrides = mergeProjectedDeclarationOverrides(
|
|
1902
|
+
localProjectedDeclarationOverrides,
|
|
1903
|
+
packageProjectedDeclarationOverrides,
|
|
1904
|
+
);
|
|
1905
|
+
const canReusePackageSourcePolicyView = canReuseConfigArtifacts &&
|
|
1906
|
+
rootNamesEqual(
|
|
1907
|
+
reusableProject.packageSourcePolicyView?.program.getRootFileNames().map(
|
|
1908
|
+
toSourceFileName,
|
|
1909
|
+
) ?? [],
|
|
1910
|
+
packageProjectedDeclarationRootNames,
|
|
1911
|
+
) &&
|
|
1912
|
+
reusableProject.packageSourcePolicyContentSignature ===
|
|
1913
|
+
packageSourcePolicyContentSignature &&
|
|
1914
|
+
!projectedDeclarationOverridesDiffer(
|
|
1915
|
+
reusableProject.localProjectedDeclarationOverrides,
|
|
1916
|
+
localProjectedDeclarationOverrides,
|
|
1917
|
+
);
|
|
1918
|
+
const shouldRebuildTsView = projectedDeclarationOverridesDiffer(
|
|
1919
|
+
localProjectedDeclarationOverrides,
|
|
1920
|
+
projectedDeclarationOverrides,
|
|
1921
|
+
);
|
|
1922
|
+
|
|
1923
|
+
const preparedProject = {
|
|
1924
|
+
analyzeOptions: { ...options },
|
|
1925
|
+
configReuseSignature,
|
|
1926
|
+
configuredSoundscriptRootNames,
|
|
1927
|
+
localProjectedDeclarationOverrides,
|
|
1928
|
+
packageSourcePolicyContentSignature,
|
|
1929
|
+
packageSourcePolicyCompilerHostReuseState: canReusePackageSourcePolicyView
|
|
1930
|
+
? reusableProject?.packageSourcePolicyCompilerHostReuseState
|
|
1931
|
+
: undefined,
|
|
1932
|
+
packageSourcePolicyView: canReusePackageSourcePolicyView
|
|
1933
|
+
? reusableProject?.packageSourcePolicyView ?? null
|
|
1934
|
+
: measureCheckerTiming(
|
|
1935
|
+
'project.prepare.packageSourcePolicyView',
|
|
1936
|
+
{
|
|
1937
|
+
rootCount: packageProjectedDeclarationRootNames.length,
|
|
1938
|
+
},
|
|
1939
|
+
() =>
|
|
1940
|
+
prepareAnalysisView(
|
|
1941
|
+
options,
|
|
1942
|
+
loadedConfig,
|
|
1943
|
+
packageProjectedDeclarationRootNames,
|
|
1944
|
+
createSoundStdlibCompilerHost(
|
|
1945
|
+
loadedConfig.commandLine.options,
|
|
1946
|
+
dirname(options.projectPath),
|
|
1947
|
+
),
|
|
1948
|
+
[],
|
|
1949
|
+
shouldAnalyzeSoundscriptSourceFile,
|
|
1950
|
+
localProjectedDeclarationOverrides,
|
|
1951
|
+
true,
|
|
1952
|
+
'sourceSupplemental',
|
|
1953
|
+
canReusePackageSourcePolicyView
|
|
1954
|
+
? reusableProject?.packageSourcePolicyCompilerHostReuseState
|
|
1955
|
+
: undefined,
|
|
1956
|
+
canReusePackageSourcePolicyView
|
|
1957
|
+
? reusableProject?.packageSourcePolicyView?.program
|
|
1958
|
+
: undefined,
|
|
1959
|
+
),
|
|
1960
|
+
{ always: true },
|
|
1961
|
+
),
|
|
1962
|
+
soundscriptRootContentSignature,
|
|
1963
|
+
soundscriptRootDiscoverySignature,
|
|
1964
|
+
stsCompilerHostReuseState: stsView?.preparedProgram.preparedHost.reuseState,
|
|
1965
|
+
soundscriptFileOverridesSignature,
|
|
1966
|
+
soundscriptRootNames,
|
|
1967
|
+
stsView,
|
|
1968
|
+
tsCompilerHostReuseState: preliminaryTsView?.preparedProgram.preparedHost.reuseState,
|
|
1969
|
+
tsView: shouldRebuildTsView
|
|
1970
|
+
? (() => {
|
|
1971
|
+
const metadata: Record<string, string | number> = {
|
|
1972
|
+
rootCount: typescriptRootNames.length,
|
|
1973
|
+
projectionCount: projectedDeclarationOverrides?.size ?? 0,
|
|
1974
|
+
};
|
|
1975
|
+
return measureCheckerTiming(
|
|
1976
|
+
'project.prepare.finalTsView',
|
|
1977
|
+
metadata,
|
|
1978
|
+
() => {
|
|
1979
|
+
const preparedView = prepareAnalysisView(
|
|
1980
|
+
options,
|
|
1981
|
+
loadedConfig,
|
|
1982
|
+
typescriptRootNames,
|
|
1983
|
+
ts.createCompilerHost(loadedConfig.commandLine.options),
|
|
1984
|
+
configFileParsingDiagnostics,
|
|
1985
|
+
(sourceFile) => shouldAnalyzeTypescriptViewSourceFile(sourceFile),
|
|
1986
|
+
projectedDeclarationOverrides,
|
|
1987
|
+
false,
|
|
1988
|
+
'full',
|
|
1989
|
+
preliminaryTsView?.preparedProgram.preparedHost.reuseState ??
|
|
1990
|
+
reusableProject?.tsCompilerHostReuseState,
|
|
1991
|
+
preliminaryTsView?.program,
|
|
1992
|
+
);
|
|
1993
|
+
if (preparedView) {
|
|
1994
|
+
applyMacroCacheStatsToMetadata(metadata, preparedView.macroCacheStats);
|
|
1995
|
+
}
|
|
1996
|
+
return preparedView;
|
|
1997
|
+
},
|
|
1998
|
+
{ always: true },
|
|
1999
|
+
);
|
|
2000
|
+
})()
|
|
2001
|
+
: preliminaryTsView,
|
|
2002
|
+
};
|
|
2003
|
+
applyMacroCacheStatsToMetadata(prepareMetadata, aggregateMacroCacheStats(preparedProject));
|
|
2004
|
+
return preparedProject;
|
|
2005
|
+
},
|
|
2006
|
+
{ always: true },
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
export function getPreparedAnalysisViewForFile(
|
|
2011
|
+
preparedProject: PreparedAnalysisProject,
|
|
2012
|
+
filePath: string,
|
|
2013
|
+
): PreparedAnalysisView | null {
|
|
2014
|
+
if (isSoundscriptSourceFile(filePath)) {
|
|
2015
|
+
const packageSourceView = preparedProject.packageSourcePolicyView;
|
|
2016
|
+
if (
|
|
2017
|
+
packageSourceView &&
|
|
2018
|
+
isNodeModulesPath(filePath) &&
|
|
2019
|
+
getPreparedViewSourceFileMatch(packageSourceView, filePath)
|
|
2020
|
+
) {
|
|
2021
|
+
return packageSourceView;
|
|
2022
|
+
}
|
|
2023
|
+
const stsView = preparedProject.stsView;
|
|
2024
|
+
if (stsView && getPreparedViewSourceFileMatch(stsView, filePath)) {
|
|
2025
|
+
return stsView;
|
|
2026
|
+
}
|
|
2027
|
+
if (packageSourceView && getPreparedViewSourceFileMatch(packageSourceView, filePath)) {
|
|
2028
|
+
return packageSourceView;
|
|
2029
|
+
}
|
|
2030
|
+
return stsView;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
return preparedProject.tsView;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
function getPreparedAnalysisSupplementalViewsForFile(
|
|
2037
|
+
preparedProject: PreparedAnalysisProject,
|
|
2038
|
+
filePath: string,
|
|
2039
|
+
primaryView: PreparedAnalysisView | null,
|
|
2040
|
+
): readonly PreparedAnalysisView[] {
|
|
2041
|
+
const supplementalViews: PreparedAnalysisView[] = [];
|
|
2042
|
+
|
|
2043
|
+
const addView = (view: PreparedAnalysisView | null): void => {
|
|
2044
|
+
if (!view || view === primaryView || supplementalViews.includes(view)) {
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
supplementalViews.push(view);
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
if (isSoundscriptSourceFile(filePath)) {
|
|
2051
|
+
addView(preparedProject.packageSourcePolicyView);
|
|
2052
|
+
return supplementalViews;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
addView(preparedProject.stsView);
|
|
2056
|
+
addView(preparedProject.packageSourcePolicyView);
|
|
2057
|
+
return supplementalViews;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
export function analyzePreparedProjectForFile(
|
|
2061
|
+
preparedProject: PreparedAnalysisProject,
|
|
2062
|
+
filePath: string,
|
|
2063
|
+
): AnalyzeProjectResult {
|
|
2064
|
+
return measureCheckerTiming(
|
|
2065
|
+
'project.analyzePreparedProjectForFile',
|
|
2066
|
+
{
|
|
2067
|
+
filePath,
|
|
2068
|
+
hasTsView: preparedProject.tsView !== null,
|
|
2069
|
+
hasStsView: preparedProject.stsView !== null,
|
|
2070
|
+
},
|
|
2071
|
+
() => {
|
|
2072
|
+
const primaryView = getPreparedAnalysisViewForFile(preparedProject, filePath);
|
|
2073
|
+
const primaryAnalysis = analyzePreparedViewForFile(primaryView, filePath);
|
|
2074
|
+
const diagnosticPaths = primaryView
|
|
2075
|
+
? collectPreparedViewFrontendDiagnosticPaths(primaryView, filePath)
|
|
2076
|
+
: [filePath];
|
|
2077
|
+
const primaryDependencyAnalysis = analyzePreparedViewForDiagnosticPaths(
|
|
2078
|
+
primaryView,
|
|
2079
|
+
diagnosticPaths,
|
|
2080
|
+
);
|
|
2081
|
+
const supplementalAnalyses = getPreparedAnalysisSupplementalViewsForFile(
|
|
2082
|
+
preparedProject,
|
|
2083
|
+
filePath,
|
|
2084
|
+
primaryView,
|
|
2085
|
+
).map((view) => analyzePreparedViewForDiagnosticPaths(view, diagnosticPaths));
|
|
2086
|
+
const diagnostics = dedupeMergedDiagnostics([
|
|
2087
|
+
...primaryAnalysis.frontendDiagnostics,
|
|
2088
|
+
...primaryAnalysis.tsDiagnostics,
|
|
2089
|
+
...primaryAnalysis.soundDiagnostics,
|
|
2090
|
+
...primaryDependencyAnalysis.frontendDiagnostics,
|
|
2091
|
+
...primaryDependencyAnalysis.tsDiagnostics,
|
|
2092
|
+
...primaryDependencyAnalysis.soundDiagnostics,
|
|
2093
|
+
...supplementalAnalyses.flatMap((analyzedProgram) => [
|
|
2094
|
+
...analyzedProgram.frontendDiagnostics,
|
|
2095
|
+
...analyzedProgram.tsDiagnostics,
|
|
2096
|
+
...analyzedProgram.soundDiagnostics,
|
|
2097
|
+
]),
|
|
2098
|
+
]);
|
|
2099
|
+
|
|
2100
|
+
return {
|
|
2101
|
+
diagnostics,
|
|
2102
|
+
summary: createSummary(diagnostics),
|
|
2103
|
+
};
|
|
2104
|
+
},
|
|
2105
|
+
{ always: true },
|
|
2106
|
+
);
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
function collectPreparedAnalysisFilePathCandidates(filePath: string): readonly string[] {
|
|
2110
|
+
const candidates = new Set<string>();
|
|
2111
|
+
const addCandidate = (candidate: string | undefined): void => {
|
|
2112
|
+
if (candidate) {
|
|
2113
|
+
candidates.add(candidate);
|
|
2114
|
+
}
|
|
2115
|
+
};
|
|
2116
|
+
|
|
2117
|
+
addCandidate(filePath);
|
|
2118
|
+
if (isProjectedSoundscriptDeclarationFile(filePath)) {
|
|
2119
|
+
addCandidate(toProjectedDeclarationSourceFileName(filePath));
|
|
2120
|
+
}
|
|
2121
|
+
addCandidate(ts.sys.resolvePath(filePath));
|
|
2122
|
+
if (isProjectedSoundscriptDeclarationFile(filePath)) {
|
|
2123
|
+
addCandidate(ts.sys.resolvePath(toProjectedDeclarationSourceFileName(filePath)));
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
try {
|
|
2127
|
+
const realPath = ts.sys.realpath?.(filePath);
|
|
2128
|
+
addCandidate(realPath);
|
|
2129
|
+
if (realPath) {
|
|
2130
|
+
addCandidate(ts.sys.resolvePath(realPath));
|
|
2131
|
+
if (isProjectedSoundscriptDeclarationFile(realPath)) {
|
|
2132
|
+
const sourcePath = toProjectedDeclarationSourceFileName(realPath);
|
|
2133
|
+
addCandidate(sourcePath);
|
|
2134
|
+
addCandidate(ts.sys.resolvePath(sourcePath));
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
} catch {
|
|
2138
|
+
// Ignore realpath failures for virtual or missing paths and fall back to the raw path.
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
return [...candidates];
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
function matchesPreparedAnalysisFilePath(
|
|
2145
|
+
candidateFilePath: string | undefined,
|
|
2146
|
+
expectedFilePath: string,
|
|
2147
|
+
): boolean {
|
|
2148
|
+
if (!candidateFilePath) {
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
if (candidateFilePath === expectedFilePath) {
|
|
2153
|
+
return true;
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
const expectedCandidates = new Set(collectPreparedAnalysisFilePathCandidates(expectedFilePath));
|
|
2157
|
+
if (expectedCandidates.has(candidateFilePath)) {
|
|
2158
|
+
return true;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
return collectPreparedAnalysisFilePathCandidates(candidateFilePath).some((candidate) =>
|
|
2162
|
+
expectedCandidates.has(candidate)
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
export function filterAnalyzedDiagnosticsForFile<T extends MergedDiagnostic>(
|
|
2167
|
+
diagnostics: readonly T[],
|
|
2168
|
+
filePath: string,
|
|
2169
|
+
): T[] {
|
|
2170
|
+
return diagnostics.filter((diagnostic) =>
|
|
2171
|
+
matchesPreparedAnalysisFilePath(diagnostic.filePath, filePath)
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
function getPreparedViewSourceFileMatch(
|
|
2176
|
+
preparedView: PreparedAnalysisView,
|
|
2177
|
+
filePath: string,
|
|
2178
|
+
): { readonly matchedFilePath: string; readonly sourceFile: ts.SourceFile } | null {
|
|
2179
|
+
for (const candidateFilePath of collectPreparedAnalysisFilePathCandidates(filePath)) {
|
|
2180
|
+
const programFileName = preparedView.preparedProgram.toProgramFileName(candidateFilePath);
|
|
2181
|
+
const sourceFile = preparedView.program.getSourceFile(programFileName);
|
|
2182
|
+
if (sourceFile) {
|
|
2183
|
+
return {
|
|
2184
|
+
matchedFilePath: candidateFilePath,
|
|
2185
|
+
sourceFile,
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
return null;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
export function analyzePreparedProject(
|
|
2194
|
+
preparedProject: PreparedAnalysisProject,
|
|
2195
|
+
): AnalyzeProjectResult {
|
|
2196
|
+
return measureCheckerTiming(
|
|
2197
|
+
'project.analyzePreparedProject',
|
|
2198
|
+
{
|
|
2199
|
+
hasTsView: preparedProject.tsView !== null,
|
|
2200
|
+
hasStsView: preparedProject.stsView !== null,
|
|
2201
|
+
},
|
|
2202
|
+
() => {
|
|
2203
|
+
const analyzedPrograms = [
|
|
2204
|
+
analyzePreparedView(preparedProject.tsView),
|
|
2205
|
+
analyzePreparedView(preparedProject.stsView),
|
|
2206
|
+
analyzePreparedView(preparedProject.packageSourcePolicyView),
|
|
2207
|
+
];
|
|
2208
|
+
const diagnostics = dedupeMergedDiagnostics(analyzedPrograms.flatMap((programResult) => [
|
|
2209
|
+
...programResult.frontendDiagnostics,
|
|
2210
|
+
...programResult.tsDiagnostics,
|
|
2211
|
+
...programResult.soundDiagnostics,
|
|
2212
|
+
]));
|
|
2213
|
+
|
|
2214
|
+
return {
|
|
2215
|
+
diagnostics,
|
|
2216
|
+
summary: createSummary(diagnostics),
|
|
2217
|
+
};
|
|
2218
|
+
},
|
|
2219
|
+
{ always: true },
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
function dedupeMergedDiagnostics<T extends MergedDiagnostic>(diagnostics: readonly T[]): T[] {
|
|
2224
|
+
const deduped: T[] = [];
|
|
2225
|
+
const seen = new Set<string>();
|
|
2226
|
+
|
|
2227
|
+
for (const diagnostic of diagnostics) {
|
|
2228
|
+
const key = [
|
|
2229
|
+
diagnostic.source,
|
|
2230
|
+
diagnostic.code,
|
|
2231
|
+
diagnostic.filePath ?? '',
|
|
2232
|
+
diagnostic.line ?? 0,
|
|
2233
|
+
diagnostic.column ?? 0,
|
|
2234
|
+
diagnostic.endLine ?? 0,
|
|
2235
|
+
diagnostic.endColumn ?? 0,
|
|
2236
|
+
diagnostic.message,
|
|
2237
|
+
].join('\u0000');
|
|
2238
|
+
if (seen.has(key)) {
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
seen.add(key);
|
|
2242
|
+
deduped.push(diagnostic);
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
return deduped;
|
|
2246
|
+
}
|