@soundscript/soundscript 0.1.12 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -6
- package/project-transform/index.js +2 -0
- package/project-transform/index.ts +8 -0
- package/project-transform/src/annotation_syntax.js +948 -0
- package/project-transform/src/annotation_syntax.ts +1217 -0
- package/project-transform/src/build_package.js +475 -0
- package/project-transform/src/build_package.ts +683 -0
- package/project-transform/src/bundled/portable-web-globals.d.ts +153 -0
- package/project-transform/src/bundled/runtime_externs.js +220 -0
- package/project-transform/src/bundled/runtime_externs.ts +237 -0
- package/project-transform/src/bundled/sound-libs/lib.decorators.d.ts +385 -0
- package/project-transform/src/bundled/sound-libs/lib.decorators.legacy.d.ts +22 -0
- package/project-transform/src/bundled/sound-libs/lib.dom.asynciterable.d.ts +42 -0
- package/project-transform/src/bundled/sound-libs/lib.dom.d.ts +39440 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.collection.d.ts +149 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.core.d.ts +657 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.d.ts +28 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.generator.d.ts +77 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.iterable.d.ts +616 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.promise.d.ts +80 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.proxy.d.ts +128 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.reflect.d.ts +144 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.d.ts +46 -0
- package/project-transform/src/bundled/sound-libs/lib.es2015.symbol.wellknown.d.ts +170 -0
- package/project-transform/src/bundled/sound-libs/lib.es2016.array.include.d.ts +116 -0
- package/project-transform/src/bundled/sound-libs/lib.es2016.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.arraybuffer.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.date.d.ts +31 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.object.d.ts +49 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.string.d.ts +45 -0
- package/project-transform/src/bundled/sound-libs/lib.es2017.typedarrays.d.ts +53 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.asyncgenerator.d.ts +77 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.asynciterable.d.ts +57 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.promise.d.ts +30 -0
- package/project-transform/src/bundled/sound-libs/lib.es2018.regexp.d.ts +37 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.array.d.ts +79 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.object.d.ts +47 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.string.d.ts +37 -0
- package/project-transform/src/bundled/sound-libs/lib.es2019.symbol.d.ts +24 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.bigint.d.ts +765 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.d.ts +27 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.date.d.ts +42 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.number.d.ts +28 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.promise.d.ts +49 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.string.d.ts +44 -0
- package/project-transform/src/bundled/sound-libs/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.d.ts +23 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.promise.d.ts +48 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.string.d.ts +33 -0
- package/project-transform/src/bundled/sound-libs/lib.es2021.weakref.d.ts +78 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.array.d.ts +121 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.error.d.ts +75 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.object.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.regexp.d.ts +39 -0
- package/project-transform/src/bundled/sound-libs/lib.es2022.string.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.array.d.ts +924 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.collection.d.ts +21 -0
- package/project-transform/src/bundled/sound-libs/lib.es2023.d.ts +22 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.arraybuffer.d.ts +65 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.collection.d.ts +29 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.d.ts +26 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.object.d.ts +33 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.promise.d.ts +35 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.regexp.d.ts +25 -0
- package/project-transform/src/bundled/sound-libs/lib.es2024.string.d.ts +29 -0
- package/project-transform/src/bundled/sound-libs/lib.es5.d.ts +4924 -0
- package/project-transform/src/bundled/sound_stdlib.js +142 -0
- package/project-transform/src/bundled/sound_stdlib.ts +180 -0
- package/project-transform/src/checker/analyze_project.js +1361 -0
- package/project-transform/src/checker/analyze_project.ts +2246 -0
- package/project-transform/src/checker/diagnostics.js +112 -0
- package/project-transform/src/checker/diagnostics.ts +222 -0
- package/project-transform/src/checker/engine/context.js +235 -0
- package/project-transform/src/checker/engine/context.ts +340 -0
- package/project-transform/src/checker/engine/diagnostic_codes.js +72 -0
- package/project-transform/src/checker/engine/diagnostic_codes.ts +95 -0
- package/project-transform/src/checker/engine/facts.js +35 -0
- package/project-transform/src/checker/engine/facts.ts +48 -0
- package/project-transform/src/checker/engine/types.js +1 -0
- package/project-transform/src/checker/engine/types.ts +485 -0
- package/project-transform/src/checker/proof_escape_hatch_diagnostics.js +104 -0
- package/project-transform/src/checker/proof_escape_hatch_diagnostics.ts +173 -0
- package/project-transform/src/checker/rules/async_surface.js +231 -0
- package/project-transform/src/checker/rules/async_surface.ts +335 -0
- package/project-transform/src/checker/rules/class_lifecycle.js +798 -0
- package/project-transform/src/checker/rules/class_lifecycle.ts +1276 -0
- package/project-transform/src/checker/rules/directive_validation.js +571 -0
- package/project-transform/src/checker/rules/directive_validation.ts +938 -0
- package/project-transform/src/checker/rules/directives.js +23 -0
- package/project-transform/src/checker/rules/directives.ts +25 -0
- package/project-transform/src/checker/rules/flow.js +202 -0
- package/project-transform/src/checker/rules/flow.ts +333 -0
- package/project-transform/src/checker/rules/flow_facts.js +601 -0
- package/project-transform/src/checker/rules/flow_facts.ts +978 -0
- package/project-transform/src/checker/rules/flow_invalidation.js +1119 -0
- package/project-transform/src/checker/rules/flow_invalidation.ts +2150 -0
- package/project-transform/src/checker/rules/flow_shared.js +2822 -0
- package/project-transform/src/checker/rules/flow_shared.ts +4383 -0
- package/project-transform/src/checker/rules/foreign_boundary.js +120 -0
- package/project-transform/src/checker/rules/foreign_boundary.ts +196 -0
- package/project-transform/src/checker/rules/foreign_projection.js +279 -0
- package/project-transform/src/checker/rules/foreign_projection.ts +425 -0
- package/project-transform/src/checker/rules/generated_helpers.js +13 -0
- package/project-transform/src/checker/rules/generated_helpers.ts +18 -0
- package/project-transform/src/checker/rules/index.js +35 -0
- package/project-transform/src/checker/rules/index.ts +49 -0
- package/project-transform/src/checker/rules/namespace_object.js +845 -0
- package/project-transform/src/checker/rules/namespace_object.ts +1224 -0
- package/project-transform/src/checker/rules/non_ordinary_recovery.js +1328 -0
- package/project-transform/src/checker/rules/non_ordinary_recovery.ts +2391 -0
- package/project-transform/src/checker/rules/null_prototype.js +3 -0
- package/project-transform/src/checker/rules/null_prototype.ts +6 -0
- package/project-transform/src/checker/rules/overloads.js +181 -0
- package/project-transform/src/checker/rules/overloads.ts +317 -0
- package/project-transform/src/checker/rules/predicate_verification.js +691 -0
- package/project-transform/src/checker/rules/predicate_verification.ts +1088 -0
- package/project-transform/src/checker/rules/prototype_hardening.js +237 -0
- package/project-transform/src/checker/rules/prototype_hardening.ts +343 -0
- package/project-transform/src/checker/rules/receiver_discipline.js +263 -0
- package/project-transform/src/checker/rules/receiver_discipline.ts +356 -0
- package/project-transform/src/checker/rules/relations.js +6861 -0
- package/project-transform/src/checker/rules/relations.ts +12158 -0
- package/project-transform/src/checker/rules/resolved_builtins.js +274 -0
- package/project-transform/src/checker/rules/resolved_builtins.ts +438 -0
- package/project-transform/src/checker/rules/trust.js +217 -0
- package/project-transform/src/checker/rules/trust.ts +301 -0
- package/project-transform/src/checker/rules/type_guards.js +173 -0
- package/project-transform/src/checker/rules/type_guards.ts +257 -0
- package/project-transform/src/checker/rules/universal.js +17 -0
- package/project-transform/src/checker/rules/universal.ts +22 -0
- package/project-transform/src/checker/rules/unsafe_value_origin.js +80 -0
- package/project-transform/src/checker/rules/unsafe_value_origin.ts +125 -0
- package/project-transform/src/checker/rules/unsound_imports.js +218 -0
- package/project-transform/src/checker/rules/unsound_imports.ts +301 -0
- package/project-transform/src/checker/rules/unsound_syntax.js +1695 -0
- package/project-transform/src/checker/rules/unsound_syntax.ts +2540 -0
- package/project-transform/src/checker/rules/value_types.js +206 -0
- package/project-transform/src/checker/rules/value_types.ts +407 -0
- package/project-transform/src/checker/timing.js +43 -0
- package/project-transform/src/checker/timing.ts +78 -0
- package/project-transform/src/checker/unsupported_feature_messages.js +337 -0
- package/project-transform/src/checker/unsupported_feature_messages.ts +531 -0
- package/project-transform/src/cli.js +892 -0
- package/project-transform/src/cli.ts +1476 -0
- package/project-transform/src/compiler/compile_project.js +319 -0
- package/project-transform/src/compiler/compile_project.ts +508 -0
- package/project-transform/src/compiler/errors.js +10 -0
- package/project-transform/src/compiler/errors.ts +29 -0
- package/project-transform/src/compiler/ir.js +1 -0
- package/project-transform/src/compiler/ir.ts +1526 -0
- package/project-transform/src/compiler/lower.js +30550 -0
- package/project-transform/src/compiler/lower.ts +43645 -0
- package/project-transform/src/compiler/lower_arrays.js +140 -0
- package/project-transform/src/compiler/lower_arrays.ts +190 -0
- package/project-transform/src/compiler/lower_strings.js +121 -0
- package/project-transform/src/compiler/lower_strings.ts +198 -0
- package/project-transform/src/compiler/lower_tagged.js +329 -0
- package/project-transform/src/compiler/lower_tagged.ts +427 -0
- package/project-transform/src/compiler/lower_views.js +171 -0
- package/project-transform/src/compiler/lower_views.ts +251 -0
- package/project-transform/src/compiler/object_keys.js +25 -0
- package/project-transform/src/compiler/object_keys.ts +35 -0
- package/project-transform/src/compiler/runtime_ir.js +30 -0
- package/project-transform/src/compiler/runtime_ir.ts +727 -0
- package/project-transform/src/compiler/tagged_boundary.js +18 -0
- package/project-transform/src/compiler/tagged_boundary.ts +37 -0
- package/project-transform/src/compiler/toolchain.js +170 -0
- package/project-transform/src/compiler/toolchain.ts +229 -0
- package/project-transform/src/compiler/unicode_case_data.js +2102 -0
- package/project-transform/src/compiler/unicode_case_data.ts +2112 -0
- package/project-transform/src/compiler/wasm_js_host_runtime.js +656 -0
- package/project-transform/src/compiler/wasm_js_host_runtime.ts +762 -0
- package/project-transform/src/compiler/wat_arrays.js +3132 -0
- package/project-transform/src/compiler/wat_arrays.ts +3768 -0
- package/project-transform/src/compiler/wat_emitter.js +17952 -0
- package/project-transform/src/compiler/wat_emitter.ts +22812 -0
- package/project-transform/src/compiler/wat_strings.js +129 -0
- package/project-transform/src/compiler/wat_strings.ts +187 -0
- package/project-transform/src/compiler/wat_tagged.js +548 -0
- package/project-transform/src/compiler/wat_tagged.ts +674 -0
- package/project-transform/src/compiler_generator_runner.js +153 -0
- package/project-transform/src/compiler_generator_runner.ts +171 -0
- package/project-transform/src/compiler_object_test_helpers.js +69 -0
- package/project-transform/src/compiler_object_test_helpers.ts +96 -0
- package/project-transform/src/compiler_promise_runner.js +2116 -0
- package/project-transform/src/compiler_promise_runner.ts +2184 -0
- package/project-transform/src/compiler_test_helpers.js +854 -0
- package/project-transform/src/compiler_test_helpers.ts +1087 -0
- package/project-transform/src/config.js +568 -0
- package/project-transform/src/config.ts +892 -0
- package/project-transform/src/diagnostic_metadata.js +67 -0
- package/project-transform/src/diagnostic_metadata.ts +99 -0
- package/project-transform/src/diagnostic_reference.js +1368 -0
- package/project-transform/src/diagnostic_reference.ts +1523 -0
- package/project-transform/src/editor_diagnostics_worker.js +176 -0
- package/project-transform/src/editor_diagnostics_worker.ts +250 -0
- package/project-transform/src/editor_projection.js +224 -0
- package/project-transform/src/editor_projection.ts +421 -0
- package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.js +47 -0
- package/project-transform/src/frontend/builtin_expanded_program_test_cleanup.ts +72 -0
- package/project-transform/src/frontend/builtin_macro_support.js +842 -0
- package/project-transform/src/frontend/builtin_macro_support.ts +1386 -0
- package/project-transform/src/frontend/builtin_macros.js +409 -0
- package/project-transform/src/frontend/builtin_macros.ts +542 -0
- package/project-transform/src/frontend/component_poc_runtime.js +279 -0
- package/project-transform/src/frontend/component_poc_runtime.ts +372 -0
- package/project-transform/src/frontend/css_macro.js +148 -0
- package/project-transform/src/frontend/css_macro.ts +222 -0
- package/project-transform/src/frontend/derive_macros.js +2072 -0
- package/project-transform/src/frontend/derive_macros.ts +3188 -0
- package/project-transform/src/frontend/embedded_fragment_support.js +106 -0
- package/project-transform/src/frontend/embedded_fragment_support.ts +172 -0
- package/project-transform/src/frontend/error_normalization.js +403 -0
- package/project-transform/src/frontend/error_normalization.ts +832 -0
- package/project-transform/src/frontend/error_stdlib_support.js +1 -0
- package/project-transform/src/frontend/error_stdlib_support.ts +6 -0
- package/project-transform/src/frontend/expand_project.js +169 -0
- package/project-transform/src/frontend/expand_project.ts +248 -0
- package/project-transform/src/frontend/format_soundscript.js +297 -0
- package/project-transform/src/frontend/format_soundscript.ts +582 -0
- package/project-transform/src/frontend/graphql_macro.js +174 -0
- package/project-transform/src/frontend/graphql_macro.ts +253 -0
- package/project-transform/src/frontend/hash_context.js +83 -0
- package/project-transform/src/frontend/hash_context.ts +113 -0
- package/project-transform/src/frontend/hkt_macro.js +448 -0
- package/project-transform/src/frontend/hkt_macro.ts +897 -0
- package/project-transform/src/frontend/import_binding_usage.js +190 -0
- package/project-transform/src/frontend/import_binding_usage.ts +277 -0
- package/project-transform/src/frontend/macro_advanced_backend_adapter.js +58 -0
- package/project-transform/src/frontend/macro_advanced_backend_adapter.ts +123 -0
- package/project-transform/src/frontend/macro_advanced_context.js +826 -0
- package/project-transform/src/frontend/macro_advanced_context.ts +1102 -0
- package/project-transform/src/frontend/macro_advanced_output.js +21 -0
- package/project-transform/src/frontend/macro_advanced_output.ts +41 -0
- package/project-transform/src/frontend/macro_api.js +353 -0
- package/project-transform/src/frontend/macro_api.ts +1722 -0
- package/project-transform/src/frontend/macro_api_internal.js +35 -0
- package/project-transform/src/frontend/macro_api_internal.ts +80 -0
- package/project-transform/src/frontend/macro_api_module_support.js +39 -0
- package/project-transform/src/frontend/macro_api_module_support.ts +65 -0
- package/project-transform/src/frontend/macro_backend_adapter.js +272 -0
- package/project-transform/src/frontend/macro_backend_adapter.ts +420 -0
- package/project-transform/src/frontend/macro_context.js +816 -0
- package/project-transform/src/frontend/macro_context.ts +1105 -0
- package/project-transform/src/frontend/macro_debug.js +99 -0
- package/project-transform/src/frontend/macro_debug.ts +157 -0
- package/project-transform/src/frontend/macro_definition_support.js +28 -0
- package/project-transform/src/frontend/macro_definition_support.ts +73 -0
- package/project-transform/src/frontend/macro_errors.js +40 -0
- package/project-transform/src/frontend/macro_errors.ts +70 -0
- package/project-transform/src/frontend/macro_expander.js +919 -0
- package/project-transform/src/frontend/macro_expander.ts +1611 -0
- package/project-transform/src/frontend/macro_factory_support.js +176 -0
- package/project-transform/src/frontend/macro_factory_support.ts +263 -0
- package/project-transform/src/frontend/macro_host_ast_internal.js +64 -0
- package/project-transform/src/frontend/macro_host_ast_internal.ts +109 -0
- package/project-transform/src/frontend/macro_index.js +27 -0
- package/project-transform/src/frontend/macro_index.ts +50 -0
- package/project-transform/src/frontend/macro_loader.js +281 -0
- package/project-transform/src/frontend/macro_loader.ts +506 -0
- package/project-transform/src/frontend/macro_operand_semantics.js +838 -0
- package/project-transform/src/frontend/macro_operand_semantics.ts +1489 -0
- package/project-transform/src/frontend/macro_output.js +54 -0
- package/project-transform/src/frontend/macro_output.ts +123 -0
- package/project-transform/src/frontend/macro_parser.js +611 -0
- package/project-transform/src/frontend/macro_parser.ts +832 -0
- package/project-transform/src/frontend/macro_resolver.js +69 -0
- package/project-transform/src/frontend/macro_resolver.ts +125 -0
- package/project-transform/src/frontend/macro_rewrite.js +285 -0
- package/project-transform/src/frontend/macro_rewrite.ts +442 -0
- package/project-transform/src/frontend/macro_runtime_support.js +232 -0
- package/project-transform/src/frontend/macro_runtime_support.ts +324 -0
- package/project-transform/src/frontend/macro_scanner.js +393 -0
- package/project-transform/src/frontend/macro_scanner.ts +455 -0
- package/project-transform/src/frontend/macro_semantic_backend_adapter.js +87 -0
- package/project-transform/src/frontend/macro_semantic_backend_adapter.ts +166 -0
- package/project-transform/src/frontend/macro_semantic_context.js +5 -0
- package/project-transform/src/frontend/macro_semantic_context.ts +12 -0
- package/project-transform/src/frontend/macro_semantic_output.js +24 -0
- package/project-transform/src/frontend/macro_semantic_output.ts +47 -0
- package/project-transform/src/frontend/macro_semantic_types.js +1 -0
- package/project-transform/src/frontend/macro_semantic_types.ts +98 -0
- package/project-transform/src/frontend/macro_semantics.js +1172 -0
- package/project-transform/src/frontend/macro_semantics.ts +1502 -0
- package/project-transform/src/frontend/macro_site_kind_support.js +164 -0
- package/project-transform/src/frontend/macro_site_kind_support.ts +255 -0
- package/project-transform/src/frontend/macro_syntax_internal.js +1950 -0
- package/project-transform/src/frontend/macro_syntax_internal.ts +3338 -0
- package/project-transform/src/frontend/macro_templates.js +57 -0
- package/project-transform/src/frontend/macro_templates.ts +143 -0
- package/project-transform/src/frontend/macro_test_helpers.js +82 -0
- package/project-transform/src/frontend/macro_test_helpers.ts +136 -0
- package/project-transform/src/frontend/macro_types.js +1 -0
- package/project-transform/src/frontend/macro_types.ts +103 -0
- package/project-transform/src/frontend/macro_vm.js +39 -0
- package/project-transform/src/frontend/macro_vm.ts +113 -0
- package/project-transform/src/frontend/match_macro.js +885 -0
- package/project-transform/src/frontend/match_macro.ts +1220 -0
- package/project-transform/src/frontend/numeric_normalization.js +824 -0
- package/project-transform/src/frontend/numeric_normalization.ts +1380 -0
- package/project-transform/src/frontend/numeric_prelude.js +278 -0
- package/project-transform/src/frontend/numeric_prelude.ts +370 -0
- package/project-transform/src/frontend/project_frontend.js +2396 -0
- package/project-transform/src/frontend/project_frontend.ts +3776 -0
- package/project-transform/src/frontend/project_macro_support.js +1401 -0
- package/project-transform/src/frontend/project_macro_support.ts +2137 -0
- package/project-transform/src/frontend/sql_macro.js +175 -0
- package/project-transform/src/frontend/sql_macro.ts +254 -0
- package/project-transform/src/frontend/sql_stdlib_support.js +1 -0
- package/project-transform/src/frontend/sql_stdlib_support.ts +6 -0
- package/project-transform/src/frontend/std_package_support.js +228 -0
- package/project-transform/src/frontend/std_package_support.ts +400 -0
- package/project-transform/src/frontend/value_normalization.js +306 -0
- package/project-transform/src/frontend/value_normalization.ts +599 -0
- package/project-transform/src/lsp/project_service.js +4771 -0
- package/project-transform/src/lsp/project_service.ts +7580 -0
- package/project-transform/src/lsp/protocol.js +9 -0
- package/project-transform/src/lsp/protocol.ts +38 -0
- package/project-transform/src/lsp/server.js +355 -0
- package/project-transform/src/lsp/server.ts +671 -0
- package/project-transform/src/lsp/session.js +49 -0
- package/project-transform/src/lsp/session.ts +48 -0
- package/project-transform/src/lsp/timing.js +43 -0
- package/project-transform/src/lsp/timing.ts +76 -0
- package/project-transform/src/lsp/transport.js +205 -0
- package/project-transform/src/lsp/transport.ts +253 -0
- package/project-transform/src/lsp_main.js +5 -0
- package/project-transform/src/lsp_main.ts +7 -0
- package/project-transform/src/macros.d.ts +1 -0
- package/project-transform/src/macros.js +1 -0
- package/project-transform/src/macros.ts +1 -0
- package/project-transform/src/main.js +24 -0
- package/project-transform/src/main.ts +28 -0
- package/project-transform/src/platform/host.js +264 -0
- package/project-transform/src/platform/host.ts +343 -0
- package/project-transform/src/platform/path.js +8 -0
- package/project-transform/src/platform/path.ts +20 -0
- package/project-transform/src/public_macro_api/macro_api.d.ts +1054 -0
- package/project-transform/src/public_macro_api/macro_semantic_types.d.ts +66 -0
- package/project-transform/src/public_macro_api/macro_types.d.ts +70 -0
- package/project-transform/src/run_program.js +14 -0
- package/project-transform/src/run_program.ts +33 -0
- package/project-transform/src/runtime/materialize.js +371 -0
- package/project-transform/src/runtime/materialize.ts +502 -0
- package/project-transform/src/runtime/on_demand.js +203 -0
- package/project-transform/src/runtime/on_demand.ts +305 -0
- package/project-transform/src/runtime/source_maps.js +205 -0
- package/project-transform/src/runtime/source_maps.ts +297 -0
- package/project-transform/src/runtime/transform.js +148 -0
- package/project-transform/src/runtime/transform.ts +295 -0
- package/project-transform/src/service/types.js +1 -0
- package/project-transform/src/service/types.ts +22 -0
- package/project-transform/src/soundscript_packages.js +477 -0
- package/project-transform/src/soundscript_packages.ts +754 -0
- package/project-transform/src/soundscript_runtime_specifiers.js +88 -0
- package/project-transform/src/soundscript_runtime_specifiers.ts +96 -0
- package/project-transform/src/stdlib/async.d.ts +81 -0
- package/project-transform/src/stdlib/async.js +213 -0
- package/project-transform/src/stdlib/async.ts +315 -0
- package/project-transform/src/stdlib/codec.d.ts +32 -0
- package/project-transform/src/stdlib/codec.js +30 -0
- package/project-transform/src/stdlib/codec.ts +76 -0
- package/project-transform/src/stdlib/compare.d.ts +28 -0
- package/project-transform/src/stdlib/compare.js +115 -0
- package/project-transform/src/stdlib/compare.ts +151 -0
- package/project-transform/src/stdlib/css.d.ts +16 -0
- package/project-transform/src/stdlib/css.js +9 -0
- package/project-transform/src/stdlib/css.ts +28 -0
- package/project-transform/src/stdlib/debug.d.ts +2 -0
- package/project-transform/src/stdlib/debug.js +9 -0
- package/project-transform/src/stdlib/debug.ts +10 -0
- package/project-transform/src/stdlib/decode.d.ts +86 -0
- package/project-transform/src/stdlib/decode.js +254 -0
- package/project-transform/src/stdlib/decode.ts +390 -0
- package/project-transform/src/stdlib/derive.d.ts +6 -0
- package/project-transform/src/stdlib/derive.js +7 -0
- package/project-transform/src/stdlib/derive.ts +7 -0
- package/project-transform/src/stdlib/encode.d.ts +100 -0
- package/project-transform/src/stdlib/encode.js +130 -0
- package/project-transform/src/stdlib/encode.ts +259 -0
- package/project-transform/src/stdlib/failures.d.ts +23 -0
- package/project-transform/src/stdlib/failures.js +41 -0
- package/project-transform/src/stdlib/failures.ts +64 -0
- package/project-transform/src/stdlib/fetch.d.ts +67 -0
- package/project-transform/src/stdlib/fetch.js +5 -0
- package/project-transform/src/stdlib/fetch.ts +11 -0
- package/project-transform/src/stdlib/graphql.d.ts +16 -0
- package/project-transform/src/stdlib/graphql.js +9 -0
- package/project-transform/src/stdlib/graphql.ts +28 -0
- package/project-transform/src/stdlib/hash.d.ts +34 -0
- package/project-transform/src/stdlib/hash.js +110 -0
- package/project-transform/src/stdlib/hash.ts +188 -0
- package/project-transform/src/stdlib/hkt.d.ts +40 -0
- package/project-transform/src/stdlib/hkt.js +3 -0
- package/project-transform/src/stdlib/hkt.ts +41 -0
- package/project-transform/src/stdlib/index.d.ts +9 -0
- package/project-transform/src/stdlib/index.js +15 -0
- package/project-transform/src/stdlib/index.ts +23 -0
- package/project-transform/src/stdlib/json.d.ts +125 -0
- package/project-transform/src/stdlib/json.js +764 -0
- package/project-transform/src/stdlib/json.ts +1034 -0
- package/project-transform/src/stdlib/match.d.ts +11 -0
- package/project-transform/src/stdlib/match.js +13 -0
- package/project-transform/src/stdlib/match.ts +26 -0
- package/project-transform/src/stdlib/numerics.d.ts +523 -0
- package/project-transform/src/stdlib/numerics.js +1356 -0
- package/project-transform/src/stdlib/numerics.ts +1937 -0
- package/project-transform/src/stdlib/random.d.ts +19 -0
- package/project-transform/src/stdlib/random.js +3 -0
- package/project-transform/src/stdlib/random.ts +5 -0
- package/project-transform/src/stdlib/result.d.ts +68 -0
- package/project-transform/src/stdlib/result.js +139 -0
- package/project-transform/src/stdlib/result.ts +248 -0
- package/project-transform/src/stdlib/sql.d.ts +22 -0
- package/project-transform/src/stdlib/sql.js +23 -0
- package/project-transform/src/stdlib/sql.ts +53 -0
- package/project-transform/src/stdlib/text.d.ts +24 -0
- package/project-transform/src/stdlib/text.js +3 -0
- package/project-transform/src/stdlib/text.ts +4 -0
- package/project-transform/src/stdlib/thunk.d.ts +2 -0
- package/project-transform/src/stdlib/thunk.js +9 -0
- package/project-transform/src/stdlib/thunk.ts +15 -0
- package/project-transform/src/stdlib/typeclasses.d.ts +57 -0
- package/project-transform/src/stdlib/typeclasses.js +78 -0
- package/project-transform/src/stdlib/typeclasses.ts +173 -0
- package/project-transform/src/stdlib/url.d.ts +37 -0
- package/project-transform/src/stdlib/url.js +3 -0
- package/project-transform/src/stdlib/url.ts +4 -0
- package/project-transform/src/stdlib/value.d.ts +9 -0
- package/project-transform/src/stdlib/value.js +104 -0
- package/project-transform/src/stdlib/value.ts +133 -0
- package/project-transform/src/test_installed_stdlib.js +147 -0
- package/project-transform/src/test_installed_stdlib.ts +245 -0
- package/project-transform/src/test_macro_package_fixture.js +50 -0
- package/project-transform/src/test_macro_package_fixture.ts +68 -0
- package/project-transform/src/value_deep_safe.js +191 -0
- package/project-transform/src/value_deep_safe.ts +273 -0
|
@@ -0,0 +1,2137 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import { createAnnotationLookup } from '../annotation_syntax.ts';
|
|
4
|
+
import { dirname, join } from '../platform/path.ts';
|
|
5
|
+
import {
|
|
6
|
+
SOUND_DIAGNOSTIC_CODES,
|
|
7
|
+
} from '../checker/engine/diagnostic_codes.ts';
|
|
8
|
+
import { describeUnsupportedFeature } from '../checker/unsupported_feature_messages.ts';
|
|
9
|
+
import * as publicMacroApi from '../macros.ts';
|
|
10
|
+
import { getSoundScriptPackageExportInfoForResolvedModule } from '../soundscript_packages.ts';
|
|
11
|
+
|
|
12
|
+
import type { MacroDefinition } from './macro_api.ts';
|
|
13
|
+
import { getLoadedMacroDefinitionMetadata } from './macro_api_internal.ts';
|
|
14
|
+
import {
|
|
15
|
+
MACRO_API_MODULE_SPECIFIER,
|
|
16
|
+
withMacroApiModuleResolution,
|
|
17
|
+
} from './macro_api_module_support.ts';
|
|
18
|
+
import {
|
|
19
|
+
collectNamedMacroDefinitions,
|
|
20
|
+
collectNamedMacroExports,
|
|
21
|
+
type LoadedNamedMacroExports,
|
|
22
|
+
} from './macro_loader.ts';
|
|
23
|
+
import { createMacroVmModuleEvaluator } from './macro_vm.ts';
|
|
24
|
+
import {
|
|
25
|
+
type ImportedMacroSiteKind,
|
|
26
|
+
macroSiteKindForFactoryForm,
|
|
27
|
+
scanMacroFactoryExports,
|
|
28
|
+
type ScannedMacroFactoryExport,
|
|
29
|
+
sourceTextLooksLikeMacroModule,
|
|
30
|
+
usesLegacyDefineMacroAuthoring,
|
|
31
|
+
} from './macro_factory_support.ts';
|
|
32
|
+
import { collectImportedNamedBindings } from './macro_site_kind_support.ts';
|
|
33
|
+
import { expandPreparedProgramWithFileRegistries } from './macro_expander.ts';
|
|
34
|
+
import {
|
|
35
|
+
classifyImportedBindingUsage,
|
|
36
|
+
type ImportedBindingUsage,
|
|
37
|
+
macroInvocationReferenceSpans,
|
|
38
|
+
stripCompileTimeOnlyImportedBindings,
|
|
39
|
+
} from './import_binding_usage.ts';
|
|
40
|
+
import {
|
|
41
|
+
type CachedMacroModuleArtifactEntry,
|
|
42
|
+
createPreparedCompilerHostReuseState,
|
|
43
|
+
createPreparedProgram,
|
|
44
|
+
isProjectedSoundscriptDeclarationFile,
|
|
45
|
+
isSoundscriptMacroSourceFile,
|
|
46
|
+
isSoundscriptSourceFile,
|
|
47
|
+
type PreparedProgram,
|
|
48
|
+
toProjectedDeclarationSourceFileName,
|
|
49
|
+
toSourceFileName,
|
|
50
|
+
} from './project_frontend.ts';
|
|
51
|
+
import { MacroError } from './macro_errors.ts';
|
|
52
|
+
|
|
53
|
+
type RewriteMacroExpander = LoadedNamedMacroExports['rewrite'] extends ReadonlyMap<string, infer T>
|
|
54
|
+
? T
|
|
55
|
+
: never;
|
|
56
|
+
type AdvancedMacroExpander = LoadedNamedMacroExports['advanced'] extends
|
|
57
|
+
ReadonlyMap<string, infer T> ? T
|
|
58
|
+
: never;
|
|
59
|
+
|
|
60
|
+
interface PerFileMacroBindings {
|
|
61
|
+
readonly advancedRegistry: ReadonlyMap<string, AdvancedMacroExpander>;
|
|
62
|
+
readonly definitions: ReadonlyMap<string, MacroDefinition>;
|
|
63
|
+
readonly importedBindingUsage: ReadonlyMap<string, ImportedBindingUsage>;
|
|
64
|
+
readonly registry: ReadonlyMap<string, RewriteMacroExpander>;
|
|
65
|
+
readonly siteKindsBySpecifier: ReadonlyMap<string, ReadonlyMap<string, ImportedMacroSiteKind>>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface MutableEvaluatedModule {
|
|
69
|
+
dependencySourceTexts?: ReadonlyMap<string, string>;
|
|
70
|
+
directDependencies: Set<string>;
|
|
71
|
+
exports: Record<string, unknown>;
|
|
72
|
+
initialized: boolean;
|
|
73
|
+
sourceText: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface ResolvedMacroBindingAuthority {
|
|
77
|
+
readonly exportName: string;
|
|
78
|
+
readonly resolvedFileName: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const PRESERVED_IMPORTED_MACRO_BINDINGS = new Set(['Do']);
|
|
82
|
+
const UNSUPPORTED_AMBIENT_MACRO_GLOBALS = new Set([
|
|
83
|
+
'Bun',
|
|
84
|
+
'Deno',
|
|
85
|
+
'Date',
|
|
86
|
+
'Function',
|
|
87
|
+
'console',
|
|
88
|
+
'clearInterval',
|
|
89
|
+
'clearTimeout',
|
|
90
|
+
'eval',
|
|
91
|
+
'fetch',
|
|
92
|
+
'performance',
|
|
93
|
+
'process',
|
|
94
|
+
'queueMicrotask',
|
|
95
|
+
'setInterval',
|
|
96
|
+
'setTimeout',
|
|
97
|
+
]);
|
|
98
|
+
const UNSUPPORTED_AMBIENT_MACRO_MEMBER_GLOBALS = new Map<string, ReadonlySet<string>>([
|
|
99
|
+
['Math', new Set(['random'])],
|
|
100
|
+
['crypto', new Set(['getRandomValues', 'randomUUID'])],
|
|
101
|
+
]);
|
|
102
|
+
const ARRAY_TOP_LEVEL_MUTATION_METHODS = new Set([
|
|
103
|
+
'copyWithin',
|
|
104
|
+
'fill',
|
|
105
|
+
'pop',
|
|
106
|
+
'push',
|
|
107
|
+
'reverse',
|
|
108
|
+
'shift',
|
|
109
|
+
'sort',
|
|
110
|
+
'splice',
|
|
111
|
+
'unshift',
|
|
112
|
+
]);
|
|
113
|
+
const TYPED_ARRAY_TOP_LEVEL_MUTATION_METHODS = new Set([
|
|
114
|
+
'copyWithin',
|
|
115
|
+
'fill',
|
|
116
|
+
'reverse',
|
|
117
|
+
'set',
|
|
118
|
+
'sort',
|
|
119
|
+
]);
|
|
120
|
+
const MAP_TOP_LEVEL_MUTATION_METHODS = new Set([
|
|
121
|
+
'clear',
|
|
122
|
+
'delete',
|
|
123
|
+
'set',
|
|
124
|
+
]);
|
|
125
|
+
const SET_TOP_LEVEL_MUTATION_METHODS = new Set([
|
|
126
|
+
'add',
|
|
127
|
+
'clear',
|
|
128
|
+
'delete',
|
|
129
|
+
]);
|
|
130
|
+
const TYPED_ARRAY_CONSTRUCTOR_NAMES = new Set([
|
|
131
|
+
'BigInt64Array',
|
|
132
|
+
'BigUint64Array',
|
|
133
|
+
'Float16Array',
|
|
134
|
+
'Float32Array',
|
|
135
|
+
'Float64Array',
|
|
136
|
+
'Int8Array',
|
|
137
|
+
'Int16Array',
|
|
138
|
+
'Int32Array',
|
|
139
|
+
'Uint8Array',
|
|
140
|
+
'Uint8ClampedArray',
|
|
141
|
+
'Uint16Array',
|
|
142
|
+
'Uint32Array',
|
|
143
|
+
]);
|
|
144
|
+
const MACRO_GRAPH_ERROR_CODES = {
|
|
145
|
+
forbiddenGlobal: 'SOUNDSCRIPT_MACRO_FORBIDDEN_GLOBAL',
|
|
146
|
+
forbiddenInterop: 'SOUNDSCRIPT_MACRO_INTEROP_GRAPH',
|
|
147
|
+
forbiddenInvocation: 'SOUNDSCRIPT_MACRO_FORBIDDEN_INVOCATION',
|
|
148
|
+
forbiddenTopLevelEffect: 'SOUNDSCRIPT_MACRO_FORBIDDEN_TOP_LEVEL_EFFECT',
|
|
149
|
+
nonSoundscriptDependency: 'SOUNDSCRIPT_MACRO_NON_SOUNDSCRIPT_DEPENDENCY',
|
|
150
|
+
unsupportedSourceKind: 'SOUNDSCRIPT_MACRO_UNSUPPORTED_SOURCE_KIND',
|
|
151
|
+
} as const;
|
|
152
|
+
|
|
153
|
+
function unsupportedAmbientMacroGlobalError(fileName: string, name: string): Error {
|
|
154
|
+
return new Error(
|
|
155
|
+
`Macro module "${fileName}" uses unsupported ambient host global "${name}". Portable macro modules must use ctx.host instead of runtime globals.`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getLineAndColumn(text: string, position: number): { column: number; line: number } {
|
|
160
|
+
let line = 1;
|
|
161
|
+
let column = 1;
|
|
162
|
+
for (let index = 0; index < position; index += 1) {
|
|
163
|
+
if (text[index] === '\n') {
|
|
164
|
+
line += 1;
|
|
165
|
+
column = 1;
|
|
166
|
+
} else {
|
|
167
|
+
column += 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { column, line };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function createMacroModuleError(
|
|
174
|
+
fileName: string,
|
|
175
|
+
sourceText: string,
|
|
176
|
+
message: string,
|
|
177
|
+
code: string,
|
|
178
|
+
start = 0,
|
|
179
|
+
end = start,
|
|
180
|
+
): MacroError {
|
|
181
|
+
const startPosition = getLineAndColumn(sourceText, start);
|
|
182
|
+
const endPosition = getLineAndColumn(sourceText, end);
|
|
183
|
+
return new MacroError(message, {
|
|
184
|
+
code,
|
|
185
|
+
column: startPosition.column,
|
|
186
|
+
endColumn: endPosition.column,
|
|
187
|
+
endLine: endPosition.line,
|
|
188
|
+
filePath: fileName,
|
|
189
|
+
line: startPosition.line,
|
|
190
|
+
macroName: '(macro module)',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface MacroModuleCacheStats {
|
|
195
|
+
evaluatedModules: number;
|
|
196
|
+
moduleCacheHits: number;
|
|
197
|
+
moduleCacheInvalidations: number;
|
|
198
|
+
moduleCacheMisses: number;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface ProjectMacroEnvironment {
|
|
202
|
+
cacheStats(): MacroModuleCacheStats;
|
|
203
|
+
definitionsForFile(sourceFile: ts.SourceFile): ReadonlyMap<string, MacroDefinition>;
|
|
204
|
+
dispose(): void;
|
|
205
|
+
registriesForFile(sourceFile: ts.SourceFile): {
|
|
206
|
+
advancedRegistry: ReadonlyMap<string, AdvancedMacroExpander>;
|
|
207
|
+
registry: ReadonlyMap<string, RewriteMacroExpander>;
|
|
208
|
+
};
|
|
209
|
+
siteKindsBySpecifierForFile(
|
|
210
|
+
sourceFile: ts.SourceFile,
|
|
211
|
+
): ReadonlyMap<string, ReadonlyMap<string, ImportedMacroSiteKind>>;
|
|
212
|
+
expandPreparedProgram(
|
|
213
|
+
preserveRemovedImportStatements?: boolean,
|
|
214
|
+
preserveMissingExpanders?: boolean,
|
|
215
|
+
annotateExpansions?: boolean,
|
|
216
|
+
): ReadonlyMap<string, ts.SourceFile>;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
type MacroMutableContainerKind =
|
|
220
|
+
| 'array'
|
|
221
|
+
| 'map'
|
|
222
|
+
| 'set'
|
|
223
|
+
| 'typedArray';
|
|
224
|
+
|
|
225
|
+
function isLoadableMacroModuleFile(fileName: string): boolean {
|
|
226
|
+
return isSoundscriptMacroSourceFile(fileName);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function unwrapMacroTransparentExpression(expression: ts.Expression): ts.Expression {
|
|
230
|
+
let current = expression;
|
|
231
|
+
|
|
232
|
+
while (true) {
|
|
233
|
+
if (
|
|
234
|
+
ts.isParenthesizedExpression(current) ||
|
|
235
|
+
ts.isSatisfiesExpression(current) ||
|
|
236
|
+
ts.isNonNullExpression(current)
|
|
237
|
+
) {
|
|
238
|
+
current = current.expression;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (ts.isAsExpression(current) || ts.isTypeAssertionExpression(current)) {
|
|
243
|
+
current = current.expression;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return current;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function getMacroTopLevelCallMemberName(expression: ts.LeftHandSideExpression): string | undefined {
|
|
252
|
+
const unwrapped = unwrapMacroTransparentExpression(expression);
|
|
253
|
+
|
|
254
|
+
if (ts.isPropertyAccessExpression(unwrapped)) {
|
|
255
|
+
return unwrapped.name.text;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!ts.isElementAccessExpression(unwrapped)) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const argumentExpression = unwrapped.argumentExpression
|
|
263
|
+
? unwrapMacroTransparentExpression(unwrapped.argumentExpression)
|
|
264
|
+
: undefined;
|
|
265
|
+
if (
|
|
266
|
+
argumentExpression &&
|
|
267
|
+
(
|
|
268
|
+
ts.isStringLiteral(argumentExpression) ||
|
|
269
|
+
ts.isNoSubstitutionTemplateLiteral(argumentExpression)
|
|
270
|
+
)
|
|
271
|
+
) {
|
|
272
|
+
return argumentExpression.text;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function macroTopLevelCallMethodMutatesContainer(
|
|
279
|
+
containerKind: MacroMutableContainerKind,
|
|
280
|
+
memberName: string | undefined,
|
|
281
|
+
): boolean {
|
|
282
|
+
if (!memberName) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
switch (containerKind) {
|
|
287
|
+
case 'array':
|
|
288
|
+
return ARRAY_TOP_LEVEL_MUTATION_METHODS.has(memberName);
|
|
289
|
+
case 'map':
|
|
290
|
+
return MAP_TOP_LEVEL_MUTATION_METHODS.has(memberName);
|
|
291
|
+
case 'set':
|
|
292
|
+
return SET_TOP_LEVEL_MUTATION_METHODS.has(memberName);
|
|
293
|
+
case 'typedArray':
|
|
294
|
+
return TYPED_ARRAY_TOP_LEVEL_MUTATION_METHODS.has(memberName);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function inferMacroMutableContainerKindFromNewTarget(
|
|
299
|
+
expression: ts.Expression,
|
|
300
|
+
): MacroMutableContainerKind | undefined {
|
|
301
|
+
const target = unwrapMacroTransparentExpression(expression);
|
|
302
|
+
|
|
303
|
+
if (!ts.isIdentifier(target)) {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (target.text === 'Array') {
|
|
308
|
+
return 'array';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (target.text === 'Map' || target.text === 'WeakMap') {
|
|
312
|
+
return 'map';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (target.text === 'Set' || target.text === 'WeakSet') {
|
|
316
|
+
return 'set';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (TYPED_ARRAY_CONSTRUCTOR_NAMES.has(target.text)) {
|
|
320
|
+
return 'typedArray';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function inferMacroMutableContainerKind(
|
|
327
|
+
expression: ts.Expression,
|
|
328
|
+
topLevelBindings: ReadonlyMap<string, ts.Expression>,
|
|
329
|
+
visitedBindings = new Set<string>(),
|
|
330
|
+
): MacroMutableContainerKind | undefined {
|
|
331
|
+
const unwrapped = unwrapMacroTransparentExpression(expression);
|
|
332
|
+
|
|
333
|
+
if (ts.isArrayLiteralExpression(unwrapped)) {
|
|
334
|
+
return 'array';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (ts.isNewExpression(unwrapped)) {
|
|
338
|
+
return inferMacroMutableContainerKindFromNewTarget(unwrapped.expression);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!ts.isIdentifier(unwrapped)) {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (visitedBindings.has(unwrapped.text)) {
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const initializer = topLevelBindings.get(unwrapped.text);
|
|
350
|
+
if (!initializer) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
visitedBindings.add(unwrapped.text);
|
|
355
|
+
return inferMacroMutableContainerKind(initializer, topLevelBindings, visitedBindings);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function createModuleResolutionHost(preparedProgram: PreparedProgram): ts.ModuleResolutionHost {
|
|
359
|
+
const baseHost = preparedProgram.preparedHost.host;
|
|
360
|
+
return {
|
|
361
|
+
directoryExists: baseHost.directoryExists?.bind(baseHost),
|
|
362
|
+
fileExists(fileName: string): boolean {
|
|
363
|
+
const sourceFileName = toSourceFileName(fileName);
|
|
364
|
+
return preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName) !== undefined ||
|
|
365
|
+
baseHost.fileExists(sourceFileName);
|
|
366
|
+
},
|
|
367
|
+
getCurrentDirectory: baseHost.getCurrentDirectory?.bind(baseHost) ??
|
|
368
|
+
(() => ts.sys.getCurrentDirectory()),
|
|
369
|
+
getDirectories: baseHost.getDirectories?.bind(baseHost),
|
|
370
|
+
readFile(fileName: string): string | undefined {
|
|
371
|
+
const sourceFileName = toSourceFileName(fileName);
|
|
372
|
+
return preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName)?.originalText ??
|
|
373
|
+
baseHost.readFile(sourceFileName);
|
|
374
|
+
},
|
|
375
|
+
realpath: baseHost.realpath?.bind(baseHost),
|
|
376
|
+
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function stripImportedMacroBindings(
|
|
381
|
+
sourceFile: ts.SourceFile,
|
|
382
|
+
strippedImportNames: ReadonlySet<string>,
|
|
383
|
+
preserveRemovedImportStatements = false,
|
|
384
|
+
): ts.SourceFile {
|
|
385
|
+
if (strippedImportNames.size === 0) {
|
|
386
|
+
return sourceFile;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const statements: ts.Statement[] = [];
|
|
390
|
+
for (const statement of sourceFile.statements) {
|
|
391
|
+
if (!ts.isImportDeclaration(statement) || !statement.importClause) {
|
|
392
|
+
statements.push(statement);
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const importClause = statement.importClause;
|
|
397
|
+
const keptDefaultImport = importClause.name && !strippedImportNames.has(importClause.name.text)
|
|
398
|
+
? importClause.name
|
|
399
|
+
: undefined;
|
|
400
|
+
const namedBindings = importClause.namedBindings;
|
|
401
|
+
let keptNamedBindings = namedBindings;
|
|
402
|
+
|
|
403
|
+
if (namedBindings && ts.isNamespaceImport(namedBindings)) {
|
|
404
|
+
keptNamedBindings = strippedImportNames.has(namedBindings.name.text) ? undefined : namedBindings;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
408
|
+
const remainingElements = namedBindings.elements.filter((element) =>
|
|
409
|
+
!strippedImportNames.has(element.name.text)
|
|
410
|
+
);
|
|
411
|
+
keptNamedBindings = remainingElements.length > 0
|
|
412
|
+
? ts.factory.updateNamedImports(namedBindings, remainingElements)
|
|
413
|
+
: undefined;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (keptDefaultImport === importClause.name && keptNamedBindings === namedBindings) {
|
|
417
|
+
statements.push(statement);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (!keptDefaultImport && !keptNamedBindings) {
|
|
422
|
+
if (preserveRemovedImportStatements) {
|
|
423
|
+
statements.push(ts.factory.createEmptyStatement());
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const updatedImportClause = ts.factory.updateImportClause(
|
|
429
|
+
importClause,
|
|
430
|
+
importClause.isTypeOnly,
|
|
431
|
+
keptDefaultImport,
|
|
432
|
+
keptNamedBindings,
|
|
433
|
+
);
|
|
434
|
+
statements.push(
|
|
435
|
+
ts.factory.updateImportDeclaration(
|
|
436
|
+
statement,
|
|
437
|
+
statement.modifiers,
|
|
438
|
+
updatedImportClause,
|
|
439
|
+
statement.moduleSpecifier,
|
|
440
|
+
statement.attributes,
|
|
441
|
+
),
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return ts.factory.updateSourceFile(sourceFile, statements);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function createSingleFileJavaScriptProgram(
|
|
449
|
+
fileName: string,
|
|
450
|
+
text: string,
|
|
451
|
+
): { checker: ts.TypeChecker; sourceFile: ts.SourceFile } {
|
|
452
|
+
const sourceFile = ts.createSourceFile(
|
|
453
|
+
fileName,
|
|
454
|
+
text,
|
|
455
|
+
ts.ScriptTarget.ES2022,
|
|
456
|
+
true,
|
|
457
|
+
ts.ScriptKind.JS,
|
|
458
|
+
);
|
|
459
|
+
const host = ts.createCompilerHost({
|
|
460
|
+
allowJs: true,
|
|
461
|
+
checkJs: true,
|
|
462
|
+
module: ts.ModuleKind.CommonJS,
|
|
463
|
+
noLib: true,
|
|
464
|
+
noResolve: true,
|
|
465
|
+
target: ts.ScriptTarget.ES2022,
|
|
466
|
+
});
|
|
467
|
+
host.fileExists = (candidate) => candidate === fileName;
|
|
468
|
+
host.readFile = (candidate) => candidate === fileName ? text : undefined;
|
|
469
|
+
host.getSourceFile = (candidate, languageVersion) =>
|
|
470
|
+
candidate === fileName
|
|
471
|
+
? ts.createSourceFile(candidate, text, languageVersion, true, ts.ScriptKind.JS)
|
|
472
|
+
: undefined;
|
|
473
|
+
const program = ts.createProgram(
|
|
474
|
+
[fileName],
|
|
475
|
+
{
|
|
476
|
+
allowJs: true,
|
|
477
|
+
checkJs: true,
|
|
478
|
+
module: ts.ModuleKind.CommonJS,
|
|
479
|
+
noLib: true,
|
|
480
|
+
noResolve: true,
|
|
481
|
+
target: ts.ScriptTarget.ES2022,
|
|
482
|
+
},
|
|
483
|
+
host,
|
|
484
|
+
);
|
|
485
|
+
return {
|
|
486
|
+
checker: program.getTypeChecker(),
|
|
487
|
+
sourceFile: program.getSourceFile(fileName) ?? sourceFile,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function isIdentifierReference(node: ts.Identifier): boolean {
|
|
492
|
+
const parent = node.parent;
|
|
493
|
+
if (!parent) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (
|
|
498
|
+
(ts.isPropertyAccessExpression(parent) && parent.name === node) ||
|
|
499
|
+
(ts.isPropertyAssignment(parent) && parent.name === node) ||
|
|
500
|
+
(ts.isMethodDeclaration(parent) && parent.name === node) ||
|
|
501
|
+
(ts.isMethodSignature(parent) && parent.name === node) ||
|
|
502
|
+
(ts.isPropertyDeclaration(parent) && parent.name === node) ||
|
|
503
|
+
(ts.isPropertySignature(parent) && parent.name === node) ||
|
|
504
|
+
(ts.isGetAccessorDeclaration(parent) && parent.name === node) ||
|
|
505
|
+
(ts.isSetAccessorDeclaration(parent) && parent.name === node) ||
|
|
506
|
+
(ts.isBindingElement(parent) && (parent.name === node || parent.propertyName === node)) ||
|
|
507
|
+
(ts.isVariableDeclaration(parent) && parent.name === node) ||
|
|
508
|
+
(ts.isParameter(parent) && parent.name === node) ||
|
|
509
|
+
(ts.isFunctionDeclaration(parent) && parent.name === node) ||
|
|
510
|
+
(ts.isFunctionExpression(parent) && parent.name === node) ||
|
|
511
|
+
(ts.isArrowFunction(parent) && parent.name === node) ||
|
|
512
|
+
(ts.isClassDeclaration(parent) && parent.name === node) ||
|
|
513
|
+
(ts.isClassExpression(parent) && parent.name === node) ||
|
|
514
|
+
(ts.isLabeledStatement(parent) && parent.label === node) ||
|
|
515
|
+
(ts.isBreakStatement(parent) && parent.label === node) ||
|
|
516
|
+
(ts.isContinueStatement(parent) && parent.label === node) ||
|
|
517
|
+
(ts.isImportClause(parent) && parent.name === node) ||
|
|
518
|
+
(ts.isImportSpecifier(parent) && (parent.name === node || parent.propertyName === node)) ||
|
|
519
|
+
(ts.isNamespaceImport(parent) && parent.name === node) ||
|
|
520
|
+
(ts.isImportEqualsDeclaration(parent) && parent.name === node) ||
|
|
521
|
+
(ts.isExportSpecifier(parent) && (parent.name === node || parent.propertyName === node)) ||
|
|
522
|
+
(ts.isTypeParameterDeclaration(parent) && parent.name === node)
|
|
523
|
+
) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function getPropertyAccessRootIdentifier(
|
|
531
|
+
expression: ts.Expression,
|
|
532
|
+
): ts.Identifier | null {
|
|
533
|
+
if (ts.isIdentifier(expression)) {
|
|
534
|
+
return expression;
|
|
535
|
+
}
|
|
536
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
537
|
+
return getPropertyAccessRootIdentifier(expression.expression);
|
|
538
|
+
}
|
|
539
|
+
if (ts.isElementAccessExpression(expression)) {
|
|
540
|
+
return getPropertyAccessRootIdentifier(expression.expression);
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function isAssignmentOperatorKind(kind: ts.SyntaxKind): boolean {
|
|
546
|
+
return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function findUnsupportedAmbientMacroGlobal(
|
|
550
|
+
fileName: string,
|
|
551
|
+
transpiledText: string,
|
|
552
|
+
): { kind: 'global' | 'member'; name: string } | null {
|
|
553
|
+
const { checker, sourceFile } = createSingleFileJavaScriptProgram(fileName, transpiledText);
|
|
554
|
+
let unsupportedGlobal: { kind: 'global' | 'member'; name: string } | null = null;
|
|
555
|
+
|
|
556
|
+
function visit(node: ts.Node): void {
|
|
557
|
+
if (unsupportedGlobal) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (ts.isIdentifier(node) && UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(node.text)) {
|
|
562
|
+
if (!isIdentifierReference(node)) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
567
|
+
if (!symbol) {
|
|
568
|
+
unsupportedGlobal = { kind: 'global', name: node.text };
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const declarations = symbol.getDeclarations() ?? [];
|
|
573
|
+
if (!declarations.some((declaration) => declaration.getSourceFile() === sourceFile)) {
|
|
574
|
+
unsupportedGlobal = { kind: 'global', name: node.text };
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (
|
|
580
|
+
ts.isPropertyAccessExpression(node) &&
|
|
581
|
+
ts.isIdentifier(node.expression) &&
|
|
582
|
+
node.expression.text === 'globalThis' &&
|
|
583
|
+
UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(node.name.text)
|
|
584
|
+
) {
|
|
585
|
+
unsupportedGlobal = { kind: 'global', name: node.name.text };
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (
|
|
590
|
+
ts.isElementAccessExpression(node) &&
|
|
591
|
+
ts.isIdentifier(node.expression) &&
|
|
592
|
+
node.expression.text === 'globalThis' &&
|
|
593
|
+
ts.isStringLiteral(node.argumentExpression) &&
|
|
594
|
+
UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(node.argumentExpression.text)
|
|
595
|
+
) {
|
|
596
|
+
unsupportedGlobal = { kind: 'global', name: node.argumentExpression.text };
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
601
|
+
const root = getPropertyAccessRootIdentifier(node.expression);
|
|
602
|
+
const unsupportedMembers = root
|
|
603
|
+
? UNSUPPORTED_AMBIENT_MACRO_MEMBER_GLOBALS.get(root.text)
|
|
604
|
+
: undefined;
|
|
605
|
+
if (unsupportedMembers?.has(node.name.text)) {
|
|
606
|
+
unsupportedGlobal = {
|
|
607
|
+
kind: 'member',
|
|
608
|
+
name: `${root!.text}.${node.name.text}`,
|
|
609
|
+
};
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (
|
|
615
|
+
ts.isElementAccessExpression(node) &&
|
|
616
|
+
ts.isStringLiteral(node.argumentExpression)
|
|
617
|
+
) {
|
|
618
|
+
const root = getPropertyAccessRootIdentifier(node.expression);
|
|
619
|
+
const unsupportedMembers = root
|
|
620
|
+
? UNSUPPORTED_AMBIENT_MACRO_MEMBER_GLOBALS.get(root.text)
|
|
621
|
+
: undefined;
|
|
622
|
+
if (unsupportedMembers?.has(node.argumentExpression.text)) {
|
|
623
|
+
unsupportedGlobal = {
|
|
624
|
+
kind: 'member',
|
|
625
|
+
name: `${root!.text}.${node.argumentExpression.text}`,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (
|
|
631
|
+
ts.isCallExpression(node) &&
|
|
632
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword
|
|
633
|
+
) {
|
|
634
|
+
unsupportedGlobal = { kind: 'member', name: 'import()' };
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
ts.forEachChild(node, visit);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
visit(sourceFile);
|
|
642
|
+
return unsupportedGlobal;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function validatePortableMacroModuleRuntime(fileName: string, transpiledText: string): void {
|
|
646
|
+
const unsupportedGlobal = findUnsupportedAmbientMacroGlobal(fileName, transpiledText);
|
|
647
|
+
if (!unsupportedGlobal) {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (unsupportedGlobal.kind === 'global') {
|
|
652
|
+
throw unsupportedAmbientMacroGlobalError(fileName, unsupportedGlobal.name);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
throw new Error(
|
|
656
|
+
`Macro module "${fileName}" uses unsupported ambient runtime API "${unsupportedGlobal.name}". Portable macro modules must be deterministic and use ctx.host for explicit IO.`,
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function createPortableMacroGlobalThis(
|
|
661
|
+
baseGlobal: typeof globalThis,
|
|
662
|
+
fileName: string,
|
|
663
|
+
): typeof globalThis {
|
|
664
|
+
let proxy!: typeof globalThis;
|
|
665
|
+
const portableMath = new Proxy(baseGlobal.Math ?? Math, {
|
|
666
|
+
get(target, property, receiver) {
|
|
667
|
+
if (property === 'random') {
|
|
668
|
+
throw new Error(
|
|
669
|
+
`Macro module "${fileName}" uses unsupported ambient runtime API "Math.random". Portable macro modules must be deterministic and use ctx.host for explicit IO.`,
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return Reflect.get(target, property, receiver);
|
|
673
|
+
},
|
|
674
|
+
});
|
|
675
|
+
const portableCrypto = new Proxy(baseGlobal.crypto ?? globalThis.crypto, {
|
|
676
|
+
get(target, property, receiver) {
|
|
677
|
+
if (property === 'randomUUID' || property === 'getRandomValues') {
|
|
678
|
+
throw new Error(
|
|
679
|
+
`Macro module "${fileName}" uses unsupported ambient runtime API "crypto.${
|
|
680
|
+
String(property)
|
|
681
|
+
}". Portable macro modules must be deterministic and use ctx.host for explicit IO.`,
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
return Reflect.get(target, property, receiver);
|
|
685
|
+
},
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
proxy = new Proxy(baseGlobal, {
|
|
689
|
+
defineProperty(_target, _property, _attributes) {
|
|
690
|
+
throw new Error(
|
|
691
|
+
`Macro module "${fileName}" cannot mutate globalThis. Macro execution only supports explicit capabilities on ctx.host.`,
|
|
692
|
+
);
|
|
693
|
+
},
|
|
694
|
+
deleteProperty() {
|
|
695
|
+
throw new Error(
|
|
696
|
+
`Macro module "${fileName}" cannot mutate globalThis. Macro execution only supports explicit capabilities on ctx.host.`,
|
|
697
|
+
);
|
|
698
|
+
},
|
|
699
|
+
get(target, property, receiver) {
|
|
700
|
+
if (property === 'globalThis') {
|
|
701
|
+
return proxy;
|
|
702
|
+
}
|
|
703
|
+
if (property === 'Math') {
|
|
704
|
+
return portableMath;
|
|
705
|
+
}
|
|
706
|
+
if (property === 'crypto') {
|
|
707
|
+
return portableCrypto;
|
|
708
|
+
}
|
|
709
|
+
if (typeof property === 'string' && UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(property)) {
|
|
710
|
+
throw unsupportedAmbientMacroGlobalError(fileName, property);
|
|
711
|
+
}
|
|
712
|
+
return Reflect.get(target, property, receiver);
|
|
713
|
+
},
|
|
714
|
+
getOwnPropertyDescriptor(target, property) {
|
|
715
|
+
if (property === 'globalThis') {
|
|
716
|
+
return {
|
|
717
|
+
configurable: true,
|
|
718
|
+
enumerable: false,
|
|
719
|
+
value: proxy,
|
|
720
|
+
writable: false,
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
if (property === 'Math') {
|
|
724
|
+
return {
|
|
725
|
+
configurable: false,
|
|
726
|
+
enumerable: false,
|
|
727
|
+
value: portableMath,
|
|
728
|
+
writable: false,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
if (property === 'crypto') {
|
|
732
|
+
return {
|
|
733
|
+
configurable: false,
|
|
734
|
+
enumerable: false,
|
|
735
|
+
value: portableCrypto,
|
|
736
|
+
writable: false,
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
if (typeof property === 'string' && UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(property)) {
|
|
740
|
+
return undefined;
|
|
741
|
+
}
|
|
742
|
+
return Reflect.getOwnPropertyDescriptor(target, property);
|
|
743
|
+
},
|
|
744
|
+
has(target, property) {
|
|
745
|
+
if (typeof property === 'string' && UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(property)) {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
return Reflect.has(target, property);
|
|
749
|
+
},
|
|
750
|
+
ownKeys(target) {
|
|
751
|
+
return Reflect.ownKeys(target).filter((property) =>
|
|
752
|
+
typeof property !== 'string' || !UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(property)
|
|
753
|
+
);
|
|
754
|
+
},
|
|
755
|
+
set() {
|
|
756
|
+
throw new Error(
|
|
757
|
+
`Macro module "${fileName}" cannot mutate globalThis. Macro execution only supports explicit capabilities on ctx.host.`,
|
|
758
|
+
);
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
return proxy;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function hasResolvedMacroBindings(bindings: PerFileMacroBindings): boolean {
|
|
766
|
+
return bindings.registry.size > 0 ||
|
|
767
|
+
bindings.advancedRegistry.size > 0 ||
|
|
768
|
+
[...bindings.importedBindingUsage.values()].some((usage) => usage !== 'runtimeOnly');
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function scriptKindForHostFile(fileName: string): ts.ScriptKind {
|
|
772
|
+
if (/\.[cm]?tsx$/iu.test(fileName)) {
|
|
773
|
+
return ts.ScriptKind.TSX;
|
|
774
|
+
}
|
|
775
|
+
if (/\.[cm]?jsx$/iu.test(fileName)) {
|
|
776
|
+
return ts.ScriptKind.JS;
|
|
777
|
+
}
|
|
778
|
+
return ts.ScriptKind.TS;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function buildAlwaysAvailableMacroSiteKinds(
|
|
782
|
+
alwaysAvailableDefinitions: ReadonlyMap<string, MacroDefinition>,
|
|
783
|
+
alwaysAvailableExports: LoadedNamedMacroExports,
|
|
784
|
+
): ReadonlyMap<string, ImportedMacroSiteKind> {
|
|
785
|
+
const alwaysAvailableMacroSiteKinds = new Map<string, ImportedMacroSiteKind>(
|
|
786
|
+
alwaysAvailableExports.siteKindsByExport,
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
for (const [macroName, definition] of alwaysAvailableDefinitions.entries()) {
|
|
790
|
+
const metadata = getLoadedMacroDefinitionMetadata(definition);
|
|
791
|
+
if (metadata) {
|
|
792
|
+
alwaysAvailableMacroSiteKinds.set(macroName, macroSiteKindForFactoryForm(metadata.form));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
return alwaysAvailableMacroSiteKinds;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
export function createProjectMacroEnvironment(
|
|
800
|
+
preparedProgram: PreparedProgram,
|
|
801
|
+
builtinDefinitionsBySpecifier: ReadonlyMap<string, ReadonlyMap<string, MacroDefinition>>,
|
|
802
|
+
builtinExportsBySpecifier: ReadonlyMap<string, LoadedNamedMacroExports>,
|
|
803
|
+
builtinFactoryModulesBySpecifier: ReadonlyMap<string, Readonly<Record<string, unknown>>>,
|
|
804
|
+
alwaysAvailableDefinitions: ReadonlyMap<string, MacroDefinition>,
|
|
805
|
+
alwaysAvailableExports: LoadedNamedMacroExports = {
|
|
806
|
+
advanced: new Map(),
|
|
807
|
+
rewrite: new Map(),
|
|
808
|
+
siteKindsByExport: new Map(),
|
|
809
|
+
},
|
|
810
|
+
): ProjectMacroEnvironment {
|
|
811
|
+
const resolutionHost = createModuleResolutionHost(preparedProgram);
|
|
812
|
+
const moduleResolutionCache = preparedProgram.preparedHost.reuseState.moduleResolutionCache ??
|
|
813
|
+
createPreparedCompilerHostReuseState().moduleResolutionCache;
|
|
814
|
+
const resolvedImportCache = new Map<string, string | null>();
|
|
815
|
+
const evaluatedModuleCache = new Map<string, MutableEvaluatedModule>();
|
|
816
|
+
const compiledArtifactCache = new Map<string, CachedMacroModuleArtifactEntry>();
|
|
817
|
+
const stableCompiledArtifactCache =
|
|
818
|
+
preparedProgram.preparedHost.reuseState.macroModuleArtifactCache;
|
|
819
|
+
const macroModuleCandidateCache = new Map<string, boolean>();
|
|
820
|
+
const macroReexportBridgeCache = new Map<string, boolean>();
|
|
821
|
+
const macroModuleScanCache = new Map<string, ReadonlyMap<string, ScannedMacroFactoryExport>>();
|
|
822
|
+
const macroModuleSourceTextCache = new Map<string, string>();
|
|
823
|
+
const validatedMacroModuleFiles = new Set<string>();
|
|
824
|
+
const definitionsByResolvedFile = new Map<string, ReadonlyMap<string, MacroDefinition>>();
|
|
825
|
+
const exportsByResolvedFile = new Map<string, LoadedNamedMacroExports>();
|
|
826
|
+
const resolvedMacroBindingAuthorityCache = new Map<
|
|
827
|
+
string,
|
|
828
|
+
ResolvedMacroBindingAuthority | null
|
|
829
|
+
>();
|
|
830
|
+
const macroModuleEvaluator = createMacroVmModuleEvaluator();
|
|
831
|
+
const macroNamesByFile = new Map<string, ReadonlySet<string>>();
|
|
832
|
+
const bindingsByFile = new Map<string, PerFileMacroBindings>();
|
|
833
|
+
const macroTargetReuseState = createPreparedCompilerHostReuseState(
|
|
834
|
+
preparedProgram.preparedHost.host.getCurrentDirectory?.() ?? ts.sys.getCurrentDirectory(),
|
|
835
|
+
);
|
|
836
|
+
const macroCacheStats: MacroModuleCacheStats = {
|
|
837
|
+
evaluatedModules: 0,
|
|
838
|
+
moduleCacheHits: 0,
|
|
839
|
+
moduleCacheInvalidations: 0,
|
|
840
|
+
moduleCacheMisses: 0,
|
|
841
|
+
};
|
|
842
|
+
const alwaysAvailableMacroSiteKinds = buildAlwaysAvailableMacroSiteKinds(
|
|
843
|
+
alwaysAvailableDefinitions,
|
|
844
|
+
alwaysAvailableExports,
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
function macroNamesForFile(sourceFile: ts.SourceFile): ReadonlySet<string> {
|
|
848
|
+
const cached = macroNamesByFile.get(sourceFile.fileName);
|
|
849
|
+
if (cached) {
|
|
850
|
+
return cached;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const names = new Set<string>();
|
|
854
|
+
const originalFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
855
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(originalFileName);
|
|
856
|
+
const invocations = preparedSource?.rewriteResult.macrosById.values() ?? [];
|
|
857
|
+
for (const invocation of invocations) {
|
|
858
|
+
names.add(invocation.nameText);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
macroNamesByFile.set(sourceFile.fileName, names);
|
|
862
|
+
return names;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function resolveImport(
|
|
866
|
+
containingFileName: string,
|
|
867
|
+
specifier: string,
|
|
868
|
+
options: { readonly fromMacroGraph?: boolean } = {},
|
|
869
|
+
): string | null {
|
|
870
|
+
const normalizedContainingFileName = toSourceFileName(containingFileName);
|
|
871
|
+
if (options.fromMacroGraph && isLoadableMacroModuleFile(normalizedContainingFileName)) {
|
|
872
|
+
validateMacroModuleSourcePolicy(normalizedContainingFileName);
|
|
873
|
+
}
|
|
874
|
+
if (specifier === MACRO_API_MODULE_SPECIFIER || builtinDefinitionsBySpecifier.has(specifier)) {
|
|
875
|
+
return specifier;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const cacheKey = `${normalizedContainingFileName}\u0000${specifier}`;
|
|
879
|
+
const cached = resolvedImportCache.get(cacheKey);
|
|
880
|
+
if (cached !== undefined) {
|
|
881
|
+
return cached;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const resolved =
|
|
885
|
+
resolvePreferredSoundscriptMacroModule(specifier, normalizedContainingFileName) ??
|
|
886
|
+
ts.resolveModuleName(
|
|
887
|
+
specifier,
|
|
888
|
+
normalizedContainingFileName,
|
|
889
|
+
preparedProgram.options,
|
|
890
|
+
resolutionHost,
|
|
891
|
+
moduleResolutionCache,
|
|
892
|
+
).resolvedModule;
|
|
893
|
+
const resolvedRuntimeFileName = resolved?.resolvedFileName;
|
|
894
|
+
if (!resolvedRuntimeFileName) {
|
|
895
|
+
resolvedImportCache.set(cacheKey, null);
|
|
896
|
+
return null;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
if (options.fromMacroGraph) {
|
|
900
|
+
const interopImportRange = findMacroGraphInteropImportRange(
|
|
901
|
+
normalizedContainingFileName,
|
|
902
|
+
specifier,
|
|
903
|
+
);
|
|
904
|
+
if (interopImportRange) {
|
|
905
|
+
throw createMacroModuleError(
|
|
906
|
+
normalizedContainingFileName,
|
|
907
|
+
sourceTextForMacroModule(normalizedContainingFileName),
|
|
908
|
+
`Macro module "${normalizedContainingFileName}" cannot use #[interop] anywhere in its dependency graph. Macro graphs must stay entirely inside soundscript source.`,
|
|
909
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenInterop,
|
|
910
|
+
interopImportRange.start,
|
|
911
|
+
interopImportRange.end,
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (isProjectedSoundscriptDeclarationFile(resolvedRuntimeFileName)) {
|
|
917
|
+
throw createMacroModuleError(
|
|
918
|
+
normalizedContainingFileName,
|
|
919
|
+
sourceTextForMacroModule(normalizedContainingFileName),
|
|
920
|
+
`Macro module "${normalizedContainingFileName}" cannot import "${specifier}" because macro graphs cannot cross projected declaration boundaries or #[interop] edges.`,
|
|
921
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenInterop,
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const packageMacroSourceEntry = getSoundScriptPackageExportInfoForResolvedModule(
|
|
926
|
+
specifier,
|
|
927
|
+
resolvedRuntimeFileName,
|
|
928
|
+
resolutionHost,
|
|
929
|
+
)?.sourceEntryPath;
|
|
930
|
+
const resolvedFileName = packageMacroSourceEntry
|
|
931
|
+
? toSourceFileName(packageMacroSourceEntry)
|
|
932
|
+
: toSourceFileName(resolvedRuntimeFileName);
|
|
933
|
+
if (!isLoadableMacroModuleFile(resolvedFileName)) {
|
|
934
|
+
if (isPureMacroReexportBridgeModule(resolvedFileName)) {
|
|
935
|
+
validateMacroModuleSourcePolicy(resolvedFileName);
|
|
936
|
+
resolvedImportCache.set(cacheKey, resolvedFileName);
|
|
937
|
+
return resolvedFileName;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
const resolvedSourceText =
|
|
941
|
+
preparedProgram.preparedHost.getPreparedSourceFile(resolvedFileName)?.originalText ??
|
|
942
|
+
resolutionHost.readFile(resolvedFileName) ??
|
|
943
|
+
'';
|
|
944
|
+
const looksLikeMacroModule = sourceTextLooksLikeMacroModule(resolvedSourceText) ||
|
|
945
|
+
usesLegacyDefineMacroAuthoring(resolvedSourceText);
|
|
946
|
+
if (looksLikeMacroModule) {
|
|
947
|
+
throw createMacroModuleError(
|
|
948
|
+
normalizedContainingFileName,
|
|
949
|
+
sourceTextForMacroModule(normalizedContainingFileName),
|
|
950
|
+
`Macro import "${specifier}" resolved to "${resolvedFileName}", but user-authored macro modules must come from a soundscript .macro.sts module.`,
|
|
951
|
+
MACRO_GRAPH_ERROR_CODES.unsupportedSourceKind,
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
throw createMacroModuleError(
|
|
955
|
+
normalizedContainingFileName,
|
|
956
|
+
sourceTextForMacroModule(normalizedContainingFileName),
|
|
957
|
+
`Macro module "${normalizedContainingFileName}" cannot import non-macro source "${specifier}". Macro graphs may only depend on .macro.sts modules.`,
|
|
958
|
+
MACRO_GRAPH_ERROR_CODES.nonSoundscriptDependency,
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
validateMacroModuleSourcePolicy(resolvedFileName);
|
|
963
|
+
resolvedImportCache.set(cacheKey, resolvedFileName);
|
|
964
|
+
return resolvedFileName;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function resolvePreferredSoundscriptMacroModule(
|
|
968
|
+
specifier: string,
|
|
969
|
+
containingFileName: string,
|
|
970
|
+
): ts.ResolvedModuleFull | undefined {
|
|
971
|
+
if (!specifier.startsWith('.')) {
|
|
972
|
+
return undefined;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
if (/\.(?:[cm]?[jt]sx?|[cm]?js)$/u.test(specifier)) {
|
|
976
|
+
return undefined;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
const candidates = specifier.endsWith('.macro.sts')
|
|
980
|
+
? [specifier]
|
|
981
|
+
: specifier.endsWith('.macro')
|
|
982
|
+
? [`${specifier}.sts`, `${specifier}/index.macro.sts`]
|
|
983
|
+
: specifier.endsWith('.sts')
|
|
984
|
+
? [specifier]
|
|
985
|
+
: [`${specifier}.sts`, `${specifier}/index.sts`]
|
|
986
|
+
;
|
|
987
|
+
for (const candidate of candidates) {
|
|
988
|
+
const absoluteCandidate = join(dirname(containingFileName), candidate);
|
|
989
|
+
if (
|
|
990
|
+
resolutionHost.fileExists(absoluteCandidate) &&
|
|
991
|
+
isSoundscriptSourceFile(absoluteCandidate)
|
|
992
|
+
) {
|
|
993
|
+
return {
|
|
994
|
+
extension: ts.Extension.Ts,
|
|
995
|
+
isExternalLibraryImport: false,
|
|
996
|
+
resolvedFileName: absoluteCandidate,
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
return undefined;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
function isLikelyMacroModule(fileName: string): boolean {
|
|
1005
|
+
const cached = macroModuleCandidateCache.get(fileName);
|
|
1006
|
+
if (cached !== undefined) {
|
|
1007
|
+
return cached;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1011
|
+
const result = sourceTextLooksLikeMacroModule(sourceText) ||
|
|
1012
|
+
usesLegacyDefineMacroAuthoring(sourceText) ||
|
|
1013
|
+
isPureMacroReexportBridgeModule(fileName);
|
|
1014
|
+
macroModuleCandidateCache.set(fileName, result);
|
|
1015
|
+
return result;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function sourceTextForMacroModule(fileName: string): string {
|
|
1019
|
+
const cached = macroModuleSourceTextCache.get(fileName);
|
|
1020
|
+
if (cached !== undefined) {
|
|
1021
|
+
return cached;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(fileName);
|
|
1025
|
+
const sourceText = preparedSource?.originalText;
|
|
1026
|
+
if (sourceText === undefined) {
|
|
1027
|
+
throw new Error(`Could not read macro module "${fileName}".`);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
macroModuleSourceTextCache.set(fileName, sourceText);
|
|
1031
|
+
return sourceText;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function isPureMacroReexportBridgeModule(fileName: string): boolean {
|
|
1035
|
+
const cached = macroReexportBridgeCache.get(fileName);
|
|
1036
|
+
if (cached !== undefined) {
|
|
1037
|
+
return cached;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (!isSoundscriptSourceFile(fileName) || isSoundscriptMacroSourceFile(fileName)) {
|
|
1041
|
+
macroReexportBridgeCache.set(fileName, false);
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1046
|
+
const sourceFile = ts.createSourceFile(
|
|
1047
|
+
fileName,
|
|
1048
|
+
sourceText,
|
|
1049
|
+
ts.ScriptTarget.Latest,
|
|
1050
|
+
true,
|
|
1051
|
+
scriptKindForHostFile(fileName),
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
let sawReexport = false;
|
|
1055
|
+
for (const statement of sourceFile.statements) {
|
|
1056
|
+
if (ts.isImportDeclaration(statement)) {
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (
|
|
1061
|
+
ts.isExportDeclaration(statement) &&
|
|
1062
|
+
(
|
|
1063
|
+
!statement.exportClause ||
|
|
1064
|
+
ts.isNamedExports(statement.exportClause)
|
|
1065
|
+
)
|
|
1066
|
+
) {
|
|
1067
|
+
sawReexport = true;
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
macroReexportBridgeCache.set(fileName, false);
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
macroReexportBridgeCache.set(fileName, sawReexport);
|
|
1076
|
+
return sawReexport;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function validateMacroModuleSourcePolicy(fileName: string): void {
|
|
1080
|
+
if (validatedMacroModuleFiles.has(fileName)) {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1085
|
+
const sourceFile = ts.createSourceFile(
|
|
1086
|
+
fileName,
|
|
1087
|
+
sourceText,
|
|
1088
|
+
ts.ScriptTarget.Latest,
|
|
1089
|
+
true,
|
|
1090
|
+
scriptKindForHostFile(fileName),
|
|
1091
|
+
);
|
|
1092
|
+
const interopIndex = sourceText.indexOf('#[interop]');
|
|
1093
|
+
if (interopIndex >= 0) {
|
|
1094
|
+
throw createMacroModuleError(
|
|
1095
|
+
fileName,
|
|
1096
|
+
sourceText,
|
|
1097
|
+
`Macro module "${fileName}" cannot use #[interop] anywhere in its dependency graph. Macro graphs must stay entirely inside soundscript source.`,
|
|
1098
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenInterop,
|
|
1099
|
+
interopIndex,
|
|
1100
|
+
interopIndex + '#[interop]'.length,
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
const annotationLookup = createAnnotationLookup(sourceFile);
|
|
1104
|
+
const topLevelBindings = new Map<string, ts.Expression>();
|
|
1105
|
+
|
|
1106
|
+
for (const block of annotationLookup.getBlocks()) {
|
|
1107
|
+
const interopAnnotation = block.annotations.find((annotation) =>
|
|
1108
|
+
annotation.name === 'interop'
|
|
1109
|
+
);
|
|
1110
|
+
if (!interopAnnotation) {
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
throw createMacroModuleError(
|
|
1114
|
+
fileName,
|
|
1115
|
+
sourceText,
|
|
1116
|
+
`Macro module "${fileName}" cannot use #[interop] anywhere in its dependency graph. Macro graphs must stay entirely inside soundscript source.`,
|
|
1117
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenInterop,
|
|
1118
|
+
block.range.start,
|
|
1119
|
+
block.range.end,
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
for (const statement of sourceFile.statements) {
|
|
1124
|
+
if (!ts.isVariableStatement(statement)) {
|
|
1125
|
+
continue;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1129
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
topLevelBindings.set(declaration.name.text, declaration.initializer);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function visit(node: ts.Node, functionDepth: number): void {
|
|
1137
|
+
if (ts.isClassStaticBlockDeclaration(node)) {
|
|
1138
|
+
throw createMacroModuleError(
|
|
1139
|
+
fileName,
|
|
1140
|
+
sourceText,
|
|
1141
|
+
`Macro module "${fileName}" cannot use class static blocks. Macro modules must stay deterministic and side-effect free at top level.`,
|
|
1142
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect,
|
|
1143
|
+
node.getStart(sourceFile),
|
|
1144
|
+
node.getEnd(),
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
if (ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) {
|
|
1149
|
+
const guidance = describeUnsupportedFeature('accessors');
|
|
1150
|
+
throw createMacroModuleError(
|
|
1151
|
+
fileName,
|
|
1152
|
+
sourceText,
|
|
1153
|
+
guidance.message,
|
|
1154
|
+
SOUND_DIAGNOSTIC_CODES.unsupportedJavaScriptFeature,
|
|
1155
|
+
node.name.getStart(sourceFile),
|
|
1156
|
+
node.name.getEnd(),
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const nextFunctionDepth = functionDepth + (ts.isFunctionLike(node) ? 1 : 0);
|
|
1161
|
+
if (
|
|
1162
|
+
functionDepth === 0 &&
|
|
1163
|
+
ts.isBinaryExpression(node) &&
|
|
1164
|
+
isAssignmentOperatorKind(node.operatorToken.kind)
|
|
1165
|
+
) {
|
|
1166
|
+
throw createMacroModuleError(
|
|
1167
|
+
fileName,
|
|
1168
|
+
sourceText,
|
|
1169
|
+
`Macro module "${fileName}" cannot perform top-level assignment or mutation. Macro module state must be derived from source and explicit ctx.host inputs.`,
|
|
1170
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect,
|
|
1171
|
+
node.getStart(sourceFile),
|
|
1172
|
+
node.getEnd(),
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if (
|
|
1177
|
+
functionDepth === 0 &&
|
|
1178
|
+
(
|
|
1179
|
+
ts.isPrefixUnaryExpression(node) ||
|
|
1180
|
+
ts.isPostfixUnaryExpression(node)
|
|
1181
|
+
) &&
|
|
1182
|
+
(
|
|
1183
|
+
node.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
1184
|
+
node.operator === ts.SyntaxKind.MinusMinusToken
|
|
1185
|
+
)
|
|
1186
|
+
) {
|
|
1187
|
+
throw createMacroModuleError(
|
|
1188
|
+
fileName,
|
|
1189
|
+
sourceText,
|
|
1190
|
+
`Macro module "${fileName}" cannot perform top-level assignment or mutation. Macro module state must be derived from source and explicit ctx.host inputs.`,
|
|
1191
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect,
|
|
1192
|
+
node.getStart(sourceFile),
|
|
1193
|
+
node.getEnd(),
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (
|
|
1198
|
+
ts.isCallExpression(node) &&
|
|
1199
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword
|
|
1200
|
+
) {
|
|
1201
|
+
throw createMacroModuleError(
|
|
1202
|
+
fileName,
|
|
1203
|
+
sourceText,
|
|
1204
|
+
`Macro module "${fileName}" cannot use dynamic import(). Macro graphs must be statically analyzable.`,
|
|
1205
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect,
|
|
1206
|
+
node.getStart(sourceFile),
|
|
1207
|
+
node.getEnd(),
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
if (functionDepth === 0 && ts.isCallExpression(node)) {
|
|
1212
|
+
const receiver = ts.isPropertyAccessExpression(node.expression) ||
|
|
1213
|
+
ts.isElementAccessExpression(node.expression)
|
|
1214
|
+
? node.expression.expression
|
|
1215
|
+
: undefined;
|
|
1216
|
+
const receiverKind = receiver
|
|
1217
|
+
? inferMacroMutableContainerKind(receiver, topLevelBindings)
|
|
1218
|
+
: undefined;
|
|
1219
|
+
if (
|
|
1220
|
+
receiverKind &&
|
|
1221
|
+
macroTopLevelCallMethodMutatesContainer(
|
|
1222
|
+
receiverKind,
|
|
1223
|
+
getMacroTopLevelCallMemberName(node.expression),
|
|
1224
|
+
)
|
|
1225
|
+
) {
|
|
1226
|
+
throw createMacroModuleError(
|
|
1227
|
+
fileName,
|
|
1228
|
+
sourceText,
|
|
1229
|
+
`Macro module "${fileName}" cannot perform top-level assignment or mutation. Macro module state must be derived from source and explicit ctx.host inputs.`,
|
|
1230
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect,
|
|
1231
|
+
node.getStart(sourceFile),
|
|
1232
|
+
node.getEnd(),
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
ts.forEachChild(node, (child) => visit(child, nextFunctionDepth));
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
visit(sourceFile, 0);
|
|
1241
|
+
validatedMacroModuleFiles.add(fileName);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
function findMacroGraphInteropImportRange(
|
|
1245
|
+
fileName: string,
|
|
1246
|
+
specifier: string,
|
|
1247
|
+
): { readonly start: number; readonly end: number } | null {
|
|
1248
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1249
|
+
const sourceFile = ts.createSourceFile(
|
|
1250
|
+
fileName,
|
|
1251
|
+
sourceText,
|
|
1252
|
+
ts.ScriptTarget.Latest,
|
|
1253
|
+
true,
|
|
1254
|
+
scriptKindForHostFile(fileName),
|
|
1255
|
+
);
|
|
1256
|
+
const annotationLookup = createAnnotationLookup(sourceFile);
|
|
1257
|
+
for (const statement of sourceFile.statements) {
|
|
1258
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
if (statement.moduleSpecifier.text !== specifier) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
const block = annotationLookup.getAttachedAnnotationBlock(statement);
|
|
1265
|
+
const interopAnnotation = block?.annotations.find((annotation) =>
|
|
1266
|
+
annotation.name === 'interop'
|
|
1267
|
+
);
|
|
1268
|
+
if (!interopAnnotation || !block) {
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
return { start: block.range.start, end: block.range.end };
|
|
1272
|
+
}
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
function cloneDependencySourceTexts(
|
|
1277
|
+
dependencySourceTexts: ReadonlyMap<string, string>,
|
|
1278
|
+
): Map<string, string> {
|
|
1279
|
+
return new Map(dependencySourceTexts);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function isCachedEvaluatedModuleValid(
|
|
1283
|
+
cached: CachedMacroModuleArtifactEntry,
|
|
1284
|
+
): boolean {
|
|
1285
|
+
for (const [dependencyFileName, sourceText] of cached.dependencySourceTexts.entries()) {
|
|
1286
|
+
if (sourceTextForMacroModule(dependencyFileName) !== sourceText) {
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
return true;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function collectImportedSpecifiersForMacroModule(fileName: string): string[] {
|
|
1294
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1295
|
+
const sourceFile = ts.createSourceFile(
|
|
1296
|
+
fileName,
|
|
1297
|
+
sourceText,
|
|
1298
|
+
ts.ScriptTarget.Latest,
|
|
1299
|
+
true,
|
|
1300
|
+
scriptKindForHostFile(fileName),
|
|
1301
|
+
);
|
|
1302
|
+
const specifiers: string[] = [];
|
|
1303
|
+
for (const statement of sourceFile.statements) {
|
|
1304
|
+
if (
|
|
1305
|
+
ts.isImportDeclaration(statement) &&
|
|
1306
|
+
ts.isStringLiteral(statement.moduleSpecifier)
|
|
1307
|
+
) {
|
|
1308
|
+
specifiers.push(statement.moduleSpecifier.text);
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (
|
|
1313
|
+
ts.isExportDeclaration(statement) &&
|
|
1314
|
+
statement.moduleSpecifier &&
|
|
1315
|
+
ts.isStringLiteral(statement.moduleSpecifier)
|
|
1316
|
+
) {
|
|
1317
|
+
specifiers.push(statement.moduleSpecifier.text);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return specifiers;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function collectDependencySourceTextsForCompilation(
|
|
1324
|
+
fileName: string,
|
|
1325
|
+
visited = new Set<string>(),
|
|
1326
|
+
): Map<string, string> {
|
|
1327
|
+
if (visited.has(fileName)) {
|
|
1328
|
+
return new Map([[fileName, sourceTextForMacroModule(fileName)]]);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
visited.add(fileName);
|
|
1332
|
+
validateMacroModuleSourcePolicy(fileName);
|
|
1333
|
+
const dependencySourceTexts = new Map<string, string>([[
|
|
1334
|
+
fileName,
|
|
1335
|
+
sourceTextForMacroModule(fileName),
|
|
1336
|
+
]]);
|
|
1337
|
+
for (const specifier of collectImportedSpecifiersForMacroModule(fileName)) {
|
|
1338
|
+
const resolved = resolveImport(fileName, specifier, { fromMacroGraph: true });
|
|
1339
|
+
if (
|
|
1340
|
+
!resolved || resolved === MACRO_API_MODULE_SPECIFIER ||
|
|
1341
|
+
builtinDefinitionsBySpecifier.has(specifier)
|
|
1342
|
+
) {
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
for (
|
|
1346
|
+
const [dependencyFileName, dependencySourceText]
|
|
1347
|
+
of collectDependencySourceTextsForCompilation(
|
|
1348
|
+
resolved,
|
|
1349
|
+
visited,
|
|
1350
|
+
).entries()
|
|
1351
|
+
) {
|
|
1352
|
+
dependencySourceTexts.set(dependencyFileName, dependencySourceText);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return dependencySourceTexts;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
function collectDependencySourceTextsForModule(
|
|
1359
|
+
fileName: string,
|
|
1360
|
+
visited = new Set<string>(),
|
|
1361
|
+
): Map<string, string> {
|
|
1362
|
+
const cached = evaluatedModuleCache.get(fileName);
|
|
1363
|
+
if (!cached) {
|
|
1364
|
+
return new Map();
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
if (cached.dependencySourceTexts) {
|
|
1368
|
+
return cloneDependencySourceTexts(cached.dependencySourceTexts);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
if (visited.has(fileName)) {
|
|
1372
|
+
return new Map([[fileName, cached.sourceText]]);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
visited.add(fileName);
|
|
1376
|
+
const dependencySourceTexts = new Map<string, string>([[fileName, cached.sourceText]]);
|
|
1377
|
+
for (const dependencyFileName of cached.directDependencies) {
|
|
1378
|
+
for (
|
|
1379
|
+
const [transitiveDependencyFileName, sourceText] of collectDependencySourceTextsForModule(
|
|
1380
|
+
dependencyFileName,
|
|
1381
|
+
visited,
|
|
1382
|
+
).entries()
|
|
1383
|
+
) {
|
|
1384
|
+
dependencySourceTexts.set(transitiveDependencyFileName, sourceText);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
return dependencySourceTexts;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
function scannedFactoriesForMacroModule(
|
|
1391
|
+
fileName: string,
|
|
1392
|
+
): ReadonlyMap<string, ScannedMacroFactoryExport> {
|
|
1393
|
+
const cached = macroModuleScanCache.get(fileName);
|
|
1394
|
+
if (cached) {
|
|
1395
|
+
return cached;
|
|
1396
|
+
}
|
|
1397
|
+
const scanned = scanMacroFactoryExports(fileName, sourceTextForMacroModule(fileName));
|
|
1398
|
+
macroModuleScanCache.set(fileName, scanned);
|
|
1399
|
+
return scanned;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function createMacroModuleErrorFromDiagnostic(
|
|
1403
|
+
diagnostic: ts.Diagnostic,
|
|
1404
|
+
fallbackFileName: string,
|
|
1405
|
+
fallbackMessage: string,
|
|
1406
|
+
fallbackCode = 'SOUNDSCRIPT_MACRO_EXPANSION',
|
|
1407
|
+
): MacroError {
|
|
1408
|
+
const filePath = diagnostic.file?.fileName ?? fallbackFileName;
|
|
1409
|
+
const sourceText = diagnostic.file?.text ?? sourceTextForMacroModule(filePath);
|
|
1410
|
+
const start = diagnostic.start ?? 0;
|
|
1411
|
+
const length = diagnostic.length ?? 0;
|
|
1412
|
+
const originalMessage = ts.flattenDiagnosticMessageText(
|
|
1413
|
+
diagnostic.messageText,
|
|
1414
|
+
'\n',
|
|
1415
|
+
) || fallbackMessage;
|
|
1416
|
+
const missingAmbientGlobalMatch = /^Cannot find name '([^']+)'\.?/u.exec(originalMessage) ??
|
|
1417
|
+
/^Cannot find name '([^']+)'.*$/u.exec(originalMessage);
|
|
1418
|
+
const missingAmbientGlobalName = missingAmbientGlobalMatch?.[1];
|
|
1419
|
+
const mappedMessage = missingAmbientGlobalName &&
|
|
1420
|
+
UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(missingAmbientGlobalName)
|
|
1421
|
+
? `Macro module "${filePath}" uses unsupported ambient host global "${missingAmbientGlobalName}". Portable macro modules must use ctx.host instead of runtime globals.`
|
|
1422
|
+
: originalMessage;
|
|
1423
|
+
return createMacroModuleError(
|
|
1424
|
+
filePath,
|
|
1425
|
+
sourceText,
|
|
1426
|
+
mappedMessage,
|
|
1427
|
+
missingAmbientGlobalName && UNSUPPORTED_AMBIENT_MACRO_GLOBALS.has(missingAmbientGlobalName)
|
|
1428
|
+
? MACRO_GRAPH_ERROR_CODES.forbiddenGlobal
|
|
1429
|
+
: fallbackCode,
|
|
1430
|
+
start,
|
|
1431
|
+
start + length,
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
function emitCommonJsMacroArtifactWithFallback(
|
|
1436
|
+
macroTargetProgram: PreparedProgram,
|
|
1437
|
+
sourceFile: ts.SourceFile,
|
|
1438
|
+
fileName: string,
|
|
1439
|
+
compilerOptions: ts.CompilerOptions,
|
|
1440
|
+
): string {
|
|
1441
|
+
let javaScriptText: string | undefined;
|
|
1442
|
+
const emitResult = macroTargetProgram.program.emit(
|
|
1443
|
+
sourceFile,
|
|
1444
|
+
(_outputFileName: string, text: string) => {
|
|
1445
|
+
javaScriptText = text;
|
|
1446
|
+
},
|
|
1447
|
+
undefined,
|
|
1448
|
+
false,
|
|
1449
|
+
);
|
|
1450
|
+
const emitDiagnostics = emitResult.diagnostics.filter((diagnostic: ts.Diagnostic) =>
|
|
1451
|
+
diagnostic.category === ts.DiagnosticCategory.Error
|
|
1452
|
+
);
|
|
1453
|
+
if (emitDiagnostics.length > 0) {
|
|
1454
|
+
throw createMacroModuleErrorFromDiagnostic(
|
|
1455
|
+
emitDiagnostics[0]!,
|
|
1456
|
+
fileName,
|
|
1457
|
+
`Failed to emit macro module "${fileName}".`,
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
if (javaScriptText !== undefined && !/^\s*(?:import|export)\b/mu.test(javaScriptText)) {
|
|
1461
|
+
return javaScriptText;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
const transpiled = ts.transpileModule(sourceFile.text, {
|
|
1465
|
+
compilerOptions: {
|
|
1466
|
+
...compilerOptions,
|
|
1467
|
+
module: ts.ModuleKind.CommonJS,
|
|
1468
|
+
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
1469
|
+
noEmit: false,
|
|
1470
|
+
target: ts.ScriptTarget.ES2022,
|
|
1471
|
+
},
|
|
1472
|
+
fileName: fileName.endsWith('.macro.sts') ? `${fileName}.cts` : `${fileName}.ts`,
|
|
1473
|
+
reportDiagnostics: true,
|
|
1474
|
+
});
|
|
1475
|
+
const transpileDiagnostics =
|
|
1476
|
+
transpiled.diagnostics?.filter((diagnostic) =>
|
|
1477
|
+
diagnostic.category === ts.DiagnosticCategory.Error
|
|
1478
|
+
) ?? [];
|
|
1479
|
+
if (transpileDiagnostics.length > 0) {
|
|
1480
|
+
throw createMacroModuleErrorFromDiagnostic(
|
|
1481
|
+
transpileDiagnostics[0]!,
|
|
1482
|
+
fileName,
|
|
1483
|
+
`Failed to emit macro module "${fileName}".`,
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
return transpiled.outputText;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function createMacroTargetBaseHost(): ts.CompilerHost {
|
|
1490
|
+
const baseHost = preparedProgram.preparedHost.host;
|
|
1491
|
+
return withMacroApiModuleResolution({
|
|
1492
|
+
...baseHost,
|
|
1493
|
+
fileExists(candidateFileName: string): boolean {
|
|
1494
|
+
if (isSoundscriptSourceFile(toSourceFileName(candidateFileName))) {
|
|
1495
|
+
const sourceFileName = toSourceFileName(candidateFileName);
|
|
1496
|
+
if (preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName)) {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return baseHost.fileExists(candidateFileName);
|
|
1501
|
+
},
|
|
1502
|
+
readFile(candidateFileName: string): string | undefined {
|
|
1503
|
+
if (isSoundscriptSourceFile(toSourceFileName(candidateFileName))) {
|
|
1504
|
+
const sourceFileName = toSourceFileName(candidateFileName);
|
|
1505
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
1506
|
+
if (preparedSource) {
|
|
1507
|
+
return preparedSource.originalText;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
return baseHost.readFile(candidateFileName);
|
|
1511
|
+
},
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
function compileResolvedMacroModuleArtifact(fileName: string): CachedMacroModuleArtifactEntry {
|
|
1516
|
+
const cached = compiledArtifactCache.get(fileName);
|
|
1517
|
+
if (cached) {
|
|
1518
|
+
return cached;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const stableCached = stableCompiledArtifactCache.get(fileName);
|
|
1522
|
+
if (stableCached && isCachedEvaluatedModuleValid(stableCached)) {
|
|
1523
|
+
macroCacheStats.moduleCacheHits += 1;
|
|
1524
|
+
compiledArtifactCache.set(fileName, stableCached);
|
|
1525
|
+
return stableCached;
|
|
1526
|
+
}
|
|
1527
|
+
if (stableCached) {
|
|
1528
|
+
macroCacheStats.moduleCacheInvalidations += 1;
|
|
1529
|
+
}
|
|
1530
|
+
stableCompiledArtifactCache.delete(fileName);
|
|
1531
|
+
macroCacheStats.moduleCacheMisses += 1;
|
|
1532
|
+
|
|
1533
|
+
const dependencySourceTexts = collectDependencySourceTextsForCompilation(fileName);
|
|
1534
|
+
const macroTargetProgram = createPreparedProgram({
|
|
1535
|
+
alwaysAvailableMacroSiteKinds,
|
|
1536
|
+
baseHost: createMacroTargetBaseHost(),
|
|
1537
|
+
expansionEnabled: false,
|
|
1538
|
+
options: {
|
|
1539
|
+
...preparedProgram.options,
|
|
1540
|
+
module: ts.ModuleKind.CommonJS,
|
|
1541
|
+
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
1542
|
+
noEmit: false,
|
|
1543
|
+
target: ts.ScriptTarget.ES2022,
|
|
1544
|
+
},
|
|
1545
|
+
preserveMacroAuthoring: true,
|
|
1546
|
+
reusableCompilerHostState: macroTargetReuseState,
|
|
1547
|
+
rootNames: [fileName],
|
|
1548
|
+
runtime: preparedProgram.runtime,
|
|
1549
|
+
});
|
|
1550
|
+
const frontendDiagnostics = macroTargetProgram.frontendDiagnostics().filter((diagnostic) =>
|
|
1551
|
+
diagnostic.category === 'error'
|
|
1552
|
+
);
|
|
1553
|
+
if (frontendDiagnostics.length > 0) {
|
|
1554
|
+
const expansionDisabledDiagnostic = frontendDiagnostics.find((diagnostic) =>
|
|
1555
|
+
diagnostic.code === 'SOUNDSCRIPT_EXPANSION_DISABLED'
|
|
1556
|
+
);
|
|
1557
|
+
if (expansionDisabledDiagnostic) {
|
|
1558
|
+
const diagnosticFilePath = expansionDisabledDiagnostic.filePath ?? fileName;
|
|
1559
|
+
throw createMacroModuleError(
|
|
1560
|
+
diagnosticFilePath,
|
|
1561
|
+
sourceTextForMacroModule(diagnosticFilePath),
|
|
1562
|
+
`Macro module "${diagnosticFilePath}" cannot contain macro invocations. Macro authoring modules compile as soundscript, but macro syntax is disabled inside the macro target.`,
|
|
1563
|
+
MACRO_GRAPH_ERROR_CODES.forbiddenInvocation,
|
|
1564
|
+
0,
|
|
1565
|
+
0,
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const diagnostic = frontendDiagnostics[0]!;
|
|
1570
|
+
const diagnosticFilePath = diagnostic.filePath ?? fileName;
|
|
1571
|
+
throw createMacroModuleError(
|
|
1572
|
+
diagnosticFilePath,
|
|
1573
|
+
sourceTextForMacroModule(diagnosticFilePath),
|
|
1574
|
+
diagnostic.message,
|
|
1575
|
+
'SOUNDSCRIPT_MACRO_EXPANSION',
|
|
1576
|
+
0,
|
|
1577
|
+
0,
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
const sourceFile = macroTargetProgram.program.getSourceFile(
|
|
1582
|
+
macroTargetProgram.toProgramFileName(fileName),
|
|
1583
|
+
);
|
|
1584
|
+
if (!sourceFile) {
|
|
1585
|
+
throw createMacroModuleError(
|
|
1586
|
+
fileName,
|
|
1587
|
+
sourceTextForMacroModule(fileName),
|
|
1588
|
+
`Failed to compile macro module "${fileName}".`,
|
|
1589
|
+
'SOUNDSCRIPT_MACRO_EXPANSION',
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
const tsDiagnostics = [
|
|
1594
|
+
...macroTargetProgram.program.getSyntacticDiagnostics(sourceFile),
|
|
1595
|
+
...macroTargetProgram.program.getSemanticDiagnostics(sourceFile),
|
|
1596
|
+
].filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
|
|
1597
|
+
if (tsDiagnostics.length > 0) {
|
|
1598
|
+
throw createMacroModuleErrorFromDiagnostic(
|
|
1599
|
+
tsDiagnostics[0]!,
|
|
1600
|
+
fileName,
|
|
1601
|
+
`Failed to compile macro module "${fileName}".`,
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
const javaScriptText = emitCommonJsMacroArtifactWithFallback(
|
|
1606
|
+
macroTargetProgram,
|
|
1607
|
+
sourceFile,
|
|
1608
|
+
fileName,
|
|
1609
|
+
macroTargetProgram.options,
|
|
1610
|
+
);
|
|
1611
|
+
|
|
1612
|
+
const artifact: CachedMacroModuleArtifactEntry = {
|
|
1613
|
+
dependencySourceTexts,
|
|
1614
|
+
javaScriptText,
|
|
1615
|
+
};
|
|
1616
|
+
compiledArtifactCache.set(fileName, artifact);
|
|
1617
|
+
stableCompiledArtifactCache.set(fileName, artifact);
|
|
1618
|
+
return artifact;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
function loadResolvedModuleValue(fileName: string): Record<string, unknown> {
|
|
1622
|
+
const cached = evaluatedModuleCache.get(fileName);
|
|
1623
|
+
if (cached) {
|
|
1624
|
+
return cached.exports;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1628
|
+
validateMacroModuleSourcePolicy(fileName);
|
|
1629
|
+
const compiledArtifact = compileResolvedMacroModuleArtifact(fileName);
|
|
1630
|
+
|
|
1631
|
+
const moduleRecord: MutableEvaluatedModule = {
|
|
1632
|
+
directDependencies: new Set(),
|
|
1633
|
+
exports: {},
|
|
1634
|
+
initialized: false,
|
|
1635
|
+
sourceText,
|
|
1636
|
+
};
|
|
1637
|
+
evaluatedModuleCache.set(fileName, moduleRecord);
|
|
1638
|
+
|
|
1639
|
+
try {
|
|
1640
|
+
validatePortableMacroModuleRuntime(fileName, compiledArtifact.javaScriptText);
|
|
1641
|
+
const portableGlobalThis = createPortableMacroGlobalThis(
|
|
1642
|
+
macroModuleEvaluator.globalObject,
|
|
1643
|
+
fileName,
|
|
1644
|
+
);
|
|
1645
|
+
const require = (specifier: string): unknown => {
|
|
1646
|
+
if (specifier === MACRO_API_MODULE_SPECIFIER) {
|
|
1647
|
+
return publicMacroApi;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const builtinFactoryModule = builtinFactoryModulesBySpecifier.get(specifier);
|
|
1651
|
+
if (builtinFactoryModule) {
|
|
1652
|
+
return builtinFactoryModule;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
const resolved = resolveImport(fileName, specifier, { fromMacroGraph: true });
|
|
1656
|
+
if (
|
|
1657
|
+
!resolved || resolved === MACRO_API_MODULE_SPECIFIER ||
|
|
1658
|
+
builtinDefinitionsBySpecifier.has(specifier)
|
|
1659
|
+
) {
|
|
1660
|
+
throw new Error(
|
|
1661
|
+
`Macro module "${fileName}" imports unsupported runtime dependency "${specifier}".`,
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
moduleRecord.directDependencies.add(resolved);
|
|
1666
|
+
return loadResolvedModuleValue(resolved);
|
|
1667
|
+
};
|
|
1668
|
+
moduleRecord.exports = macroModuleEvaluator.evaluateCommonJsModule(
|
|
1669
|
+
compiledArtifact.javaScriptText,
|
|
1670
|
+
{
|
|
1671
|
+
crypto: portableGlobalThis.crypto,
|
|
1672
|
+
exports: moduleRecord.exports,
|
|
1673
|
+
fileName,
|
|
1674
|
+
globalThis: portableGlobalThis,
|
|
1675
|
+
math: portableGlobalThis.Math,
|
|
1676
|
+
require,
|
|
1677
|
+
},
|
|
1678
|
+
);
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
if (error instanceof MacroError) {
|
|
1681
|
+
throw error;
|
|
1682
|
+
}
|
|
1683
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1684
|
+
const errorCode = message.includes('unsupported ambient host global') ||
|
|
1685
|
+
message.includes('unsupported ambient runtime API')
|
|
1686
|
+
? MACRO_GRAPH_ERROR_CODES.forbiddenGlobal
|
|
1687
|
+
: message.includes('cannot mutate globalThis')
|
|
1688
|
+
? MACRO_GRAPH_ERROR_CODES.forbiddenTopLevelEffect
|
|
1689
|
+
: 'SOUNDSCRIPT_MACRO_EXPANSION';
|
|
1690
|
+
throw createMacroModuleError(fileName, sourceText, message, errorCode);
|
|
1691
|
+
}
|
|
1692
|
+
macroCacheStats.evaluatedModules += 1;
|
|
1693
|
+
moduleRecord.initialized = true;
|
|
1694
|
+
moduleRecord.dependencySourceTexts = collectDependencySourceTextsForModule(fileName);
|
|
1695
|
+
return moduleRecord.exports;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
function definitionsForResolvedModule(fileName: string): ReadonlyMap<string, MacroDefinition> {
|
|
1699
|
+
const cached = definitionsByResolvedFile.get(fileName);
|
|
1700
|
+
if (cached) {
|
|
1701
|
+
return cached;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
let definitions: ReadonlyMap<string, MacroDefinition>;
|
|
1705
|
+
try {
|
|
1706
|
+
definitions = collectNamedMacroDefinitions(
|
|
1707
|
+
fileName,
|
|
1708
|
+
loadResolvedModuleValue(fileName),
|
|
1709
|
+
{
|
|
1710
|
+
moduleFileName: fileName,
|
|
1711
|
+
scannedFactoryExports: scannedFactoriesForMacroModule(fileName),
|
|
1712
|
+
sourceText: sourceTextForMacroModule(fileName),
|
|
1713
|
+
},
|
|
1714
|
+
);
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
if (error instanceof MacroError) {
|
|
1717
|
+
throw error;
|
|
1718
|
+
}
|
|
1719
|
+
throw createMacroModuleError(
|
|
1720
|
+
fileName,
|
|
1721
|
+
sourceTextForMacroModule(fileName),
|
|
1722
|
+
error instanceof Error ? error.message : String(error),
|
|
1723
|
+
'SOUNDSCRIPT_MACRO_EXPANSION',
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
definitionsByResolvedFile.set(fileName, definitions);
|
|
1727
|
+
return definitions;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
function exportsForResolvedModule(fileName: string): LoadedNamedMacroExports {
|
|
1731
|
+
const cached = exportsByResolvedFile.get(fileName);
|
|
1732
|
+
if (cached) {
|
|
1733
|
+
return cached;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
let exports: LoadedNamedMacroExports;
|
|
1737
|
+
try {
|
|
1738
|
+
exports = collectNamedMacroExports(
|
|
1739
|
+
fileName,
|
|
1740
|
+
loadResolvedModuleValue(fileName),
|
|
1741
|
+
preparedProgram,
|
|
1742
|
+
{
|
|
1743
|
+
moduleFileName: fileName,
|
|
1744
|
+
scannedFactoryExports: scannedFactoriesForMacroModule(fileName),
|
|
1745
|
+
sourceText: sourceTextForMacroModule(fileName),
|
|
1746
|
+
},
|
|
1747
|
+
);
|
|
1748
|
+
} catch (error) {
|
|
1749
|
+
if (error instanceof MacroError) {
|
|
1750
|
+
throw error;
|
|
1751
|
+
}
|
|
1752
|
+
throw createMacroModuleError(
|
|
1753
|
+
fileName,
|
|
1754
|
+
sourceTextForMacroModule(fileName),
|
|
1755
|
+
error instanceof Error ? error.message : String(error),
|
|
1756
|
+
'SOUNDSCRIPT_MACRO_EXPANSION',
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
exportsByResolvedFile.set(fileName, exports);
|
|
1760
|
+
return exports;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
function resolveMacroBindingAuthority(
|
|
1764
|
+
fileName: string,
|
|
1765
|
+
exportName: string,
|
|
1766
|
+
visiting = new Set<string>(),
|
|
1767
|
+
): ResolvedMacroBindingAuthority | null {
|
|
1768
|
+
const cacheKey = `${fileName}\u0000${exportName}`;
|
|
1769
|
+
const cached = resolvedMacroBindingAuthorityCache.get(cacheKey);
|
|
1770
|
+
if (cached !== undefined) {
|
|
1771
|
+
return cached;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
if (visiting.has(cacheKey)) {
|
|
1775
|
+
return null;
|
|
1776
|
+
}
|
|
1777
|
+
visiting.add(cacheKey);
|
|
1778
|
+
|
|
1779
|
+
try {
|
|
1780
|
+
const builtinDefinitions = builtinDefinitionsBySpecifier.get(fileName);
|
|
1781
|
+
if (builtinDefinitions?.has(exportName)) {
|
|
1782
|
+
const authority = { exportName, resolvedFileName: fileName };
|
|
1783
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, authority);
|
|
1784
|
+
return authority;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
if (definitionsForResolvedModule(fileName).has(exportName)) {
|
|
1788
|
+
const authority = { exportName, resolvedFileName: fileName };
|
|
1789
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, authority);
|
|
1790
|
+
return authority;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
const sourceText = sourceTextForMacroModule(fileName);
|
|
1794
|
+
const sourceFile = ts.createSourceFile(
|
|
1795
|
+
fileName,
|
|
1796
|
+
sourceText,
|
|
1797
|
+
ts.ScriptTarget.Latest,
|
|
1798
|
+
true,
|
|
1799
|
+
scriptKindForHostFile(fileName),
|
|
1800
|
+
);
|
|
1801
|
+
const importedBindingsByLocalName = new Map(
|
|
1802
|
+
collectImportedNamedBindings(fileName, sourceText)
|
|
1803
|
+
.map((binding) => [binding.localName, binding] as const),
|
|
1804
|
+
);
|
|
1805
|
+
|
|
1806
|
+
for (const statement of sourceFile.statements) {
|
|
1807
|
+
if (
|
|
1808
|
+
!ts.isExportDeclaration(statement) ||
|
|
1809
|
+
!statement.moduleSpecifier ||
|
|
1810
|
+
!ts.isStringLiteral(statement.moduleSpecifier)
|
|
1811
|
+
) {
|
|
1812
|
+
continue;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
const resolved = resolveImport(fileName, statement.moduleSpecifier.text, {
|
|
1816
|
+
fromMacroGraph: true,
|
|
1817
|
+
});
|
|
1818
|
+
if (!resolved || resolved === MACRO_API_MODULE_SPECIFIER) {
|
|
1819
|
+
continue;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
if (!statement.exportClause) {
|
|
1823
|
+
const authority = resolveMacroBindingAuthority(resolved, exportName, visiting);
|
|
1824
|
+
if (authority) {
|
|
1825
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, authority);
|
|
1826
|
+
return authority;
|
|
1827
|
+
}
|
|
1828
|
+
continue;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
if (!ts.isNamedExports(statement.exportClause)) {
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
for (const element of statement.exportClause.elements) {
|
|
1836
|
+
if (element.name.text !== exportName) {
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
const sourceName = element.propertyName?.text ?? element.name.text;
|
|
1840
|
+
const authority = resolveMacroBindingAuthority(resolved, sourceName, visiting);
|
|
1841
|
+
if (authority) {
|
|
1842
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, authority);
|
|
1843
|
+
return authority;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
for (const statement of sourceFile.statements) {
|
|
1849
|
+
if (
|
|
1850
|
+
!ts.isExportDeclaration(statement) ||
|
|
1851
|
+
!!statement.moduleSpecifier ||
|
|
1852
|
+
!statement.exportClause ||
|
|
1853
|
+
!ts.isNamedExports(statement.exportClause)
|
|
1854
|
+
) {
|
|
1855
|
+
continue;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
for (const element of statement.exportClause.elements) {
|
|
1859
|
+
if (element.name.text !== exportName) {
|
|
1860
|
+
continue;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
const localName = element.propertyName?.text ?? element.name.text;
|
|
1864
|
+
const binding = importedBindingsByLocalName.get(localName);
|
|
1865
|
+
if (!binding) {
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
const resolved = resolveImport(fileName, binding.specifier, {
|
|
1870
|
+
fromMacroGraph: true,
|
|
1871
|
+
});
|
|
1872
|
+
if (!resolved || resolved === MACRO_API_MODULE_SPECIFIER) {
|
|
1873
|
+
continue;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
const authority = resolveMacroBindingAuthority(resolved, binding.exportName, visiting);
|
|
1877
|
+
if (authority) {
|
|
1878
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, authority);
|
|
1879
|
+
return authority;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
} finally {
|
|
1884
|
+
visiting.delete(cacheKey);
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
resolvedMacroBindingAuthorityCache.set(cacheKey, null);
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
function bindingsForSourceFile(sourceFile: ts.SourceFile): PerFileMacroBindings {
|
|
1892
|
+
const cached = bindingsByFile.get(sourceFile.fileName);
|
|
1893
|
+
if (cached) {
|
|
1894
|
+
return cached;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
const macroNames = macroNamesForFile(sourceFile);
|
|
1898
|
+
const definitions = new Map<string, MacroDefinition>();
|
|
1899
|
+
const registry = new Map<string, RewriteMacroExpander>();
|
|
1900
|
+
const advancedRegistry = new Map<string, AdvancedMacroExpander>();
|
|
1901
|
+
const siteKindsBySpecifier = new Map<string, Map<string, ImportedMacroSiteKind>>();
|
|
1902
|
+
|
|
1903
|
+
for (const macroName of macroNames) {
|
|
1904
|
+
const alwaysAvailableDefinition = alwaysAvailableDefinitions.get(macroName);
|
|
1905
|
+
if (!alwaysAvailableDefinition) {
|
|
1906
|
+
continue;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
definitions.set(macroName, alwaysAvailableDefinition);
|
|
1910
|
+
const alwaysAvailableRewrite = alwaysAvailableExports.rewrite.get(macroName);
|
|
1911
|
+
const alwaysAvailableAdvanced = alwaysAvailableExports.advanced.get(macroName);
|
|
1912
|
+
if (alwaysAvailableRewrite) {
|
|
1913
|
+
registry.set(macroName, alwaysAvailableRewrite);
|
|
1914
|
+
}
|
|
1915
|
+
if (alwaysAvailableAdvanced) {
|
|
1916
|
+
advancedRegistry.set(macroName, alwaysAvailableAdvanced);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
for (const statement of sourceFile.statements) {
|
|
1921
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
1922
|
+
continue;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
const candidateBindings: { localName: string; exportName: string }[] = [];
|
|
1926
|
+
if (statement.importClause?.name && macroNames.has(statement.importClause.name.text)) {
|
|
1927
|
+
candidateBindings.push({
|
|
1928
|
+
localName: statement.importClause.name.text,
|
|
1929
|
+
exportName: 'default',
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
1934
|
+
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
1935
|
+
for (const element of namedBindings.elements) {
|
|
1936
|
+
if (!macroNames.has(element.name.text)) {
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
candidateBindings.push({
|
|
1940
|
+
localName: element.name.text,
|
|
1941
|
+
exportName: element.propertyName?.text ?? element.name.text,
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
if (candidateBindings.length === 0) {
|
|
1947
|
+
continue;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
const specifier = statement.moduleSpecifier.text;
|
|
1951
|
+
const builtinDefinitions = builtinDefinitionsBySpecifier.get(specifier) ?? null;
|
|
1952
|
+
const builtinExports = builtinExportsBySpecifier.get(specifier) ?? null;
|
|
1953
|
+
const resolved = builtinDefinitions
|
|
1954
|
+
? specifier
|
|
1955
|
+
: resolveImport(sourceFile.fileName, specifier);
|
|
1956
|
+
if (!resolved || resolved === MACRO_API_MODULE_SPECIFIER) {
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
if (!builtinDefinitions && !builtinExports && !isLikelyMacroModule(resolved)) {
|
|
1961
|
+
continue;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
for (const { localName, exportName } of candidateBindings) {
|
|
1965
|
+
const authority = builtinDefinitions
|
|
1966
|
+
? { exportName, resolvedFileName: specifier }
|
|
1967
|
+
: resolveMacroBindingAuthority(resolved, exportName);
|
|
1968
|
+
if (!authority) {
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
const authorityBuiltinDefinitions = builtinDefinitionsBySpecifier.get(
|
|
1973
|
+
authority.resolvedFileName,
|
|
1974
|
+
) ?? null;
|
|
1975
|
+
const authorityBuiltinExports = builtinExportsBySpecifier.get(authority.resolvedFileName) ??
|
|
1976
|
+
null;
|
|
1977
|
+
const availableDefinitions = authorityBuiltinDefinitions ?? builtinDefinitions ??
|
|
1978
|
+
definitionsForResolvedModule(authority.resolvedFileName);
|
|
1979
|
+
const availableExports = authorityBuiltinExports ?? builtinExports ??
|
|
1980
|
+
exportsForResolvedModule(authority.resolvedFileName);
|
|
1981
|
+
const definition = availableDefinitions.get(authority.exportName);
|
|
1982
|
+
if (!definition) {
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
definitions.set(localName, definition);
|
|
1987
|
+
const definitionMetadata = getLoadedMacroDefinitionMetadata(definition);
|
|
1988
|
+
if (definitionMetadata) {
|
|
1989
|
+
let siteKindsForSpecifier = siteKindsBySpecifier.get(specifier);
|
|
1990
|
+
if (!siteKindsForSpecifier) {
|
|
1991
|
+
siteKindsForSpecifier = new Map();
|
|
1992
|
+
siteKindsBySpecifier.set(specifier, siteKindsForSpecifier);
|
|
1993
|
+
}
|
|
1994
|
+
siteKindsForSpecifier.set(
|
|
1995
|
+
exportName,
|
|
1996
|
+
macroSiteKindForFactoryForm(definitionMetadata.form),
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
const rewriteExpander = availableExports.rewrite.get(authority.exportName);
|
|
2000
|
+
const advancedExpander = availableExports.advanced.get(authority.exportName);
|
|
2001
|
+
if (rewriteExpander) {
|
|
2002
|
+
registry.set(localName, rewriteExpander);
|
|
2003
|
+
}
|
|
2004
|
+
if (advancedExpander) {
|
|
2005
|
+
advancedRegistry.set(localName, advancedExpander);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
const originalFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
2011
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(originalFileName);
|
|
2012
|
+
const classificationSourceFile = ts.createSourceFile(
|
|
2013
|
+
originalFileName,
|
|
2014
|
+
preparedSource?.originalText ?? sourceFile.text,
|
|
2015
|
+
ts.ScriptTarget.Latest,
|
|
2016
|
+
true,
|
|
2017
|
+
scriptKindForHostFile(originalFileName),
|
|
2018
|
+
);
|
|
2019
|
+
const importedBindingUsage = new Map(
|
|
2020
|
+
classifyImportedBindingUsage(
|
|
2021
|
+
classificationSourceFile,
|
|
2022
|
+
macroNames,
|
|
2023
|
+
macroInvocationReferenceSpans(preparedSource?.rewriteResult.macrosById.values() ?? []),
|
|
2024
|
+
),
|
|
2025
|
+
);
|
|
2026
|
+
for (const localName of PRESERVED_IMPORTED_MACRO_BINDINGS) {
|
|
2027
|
+
if (importedBindingUsage.get(localName) === 'compileTimeOnly') {
|
|
2028
|
+
importedBindingUsage.set(localName, 'runtimeOnly');
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
const loaded = {
|
|
2033
|
+
advancedRegistry,
|
|
2034
|
+
definitions,
|
|
2035
|
+
importedBindingUsage,
|
|
2036
|
+
registry,
|
|
2037
|
+
siteKindsBySpecifier,
|
|
2038
|
+
};
|
|
2039
|
+
bindingsByFile.set(sourceFile.fileName, loaded);
|
|
2040
|
+
return loaded;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
return {
|
|
2044
|
+
cacheStats(): MacroModuleCacheStats {
|
|
2045
|
+
return { ...macroCacheStats };
|
|
2046
|
+
},
|
|
2047
|
+
dispose(): void {
|
|
2048
|
+
bindingsByFile.clear();
|
|
2049
|
+
},
|
|
2050
|
+
|
|
2051
|
+
definitionsForFile(sourceFile: ts.SourceFile): ReadonlyMap<string, MacroDefinition> {
|
|
2052
|
+
return bindingsForSourceFile(sourceFile).definitions;
|
|
2053
|
+
},
|
|
2054
|
+
|
|
2055
|
+
registriesForFile(sourceFile: ts.SourceFile) {
|
|
2056
|
+
const bindings = bindingsForSourceFile(sourceFile);
|
|
2057
|
+
return {
|
|
2058
|
+
advancedRegistry: bindings.advancedRegistry,
|
|
2059
|
+
registry: bindings.registry,
|
|
2060
|
+
};
|
|
2061
|
+
},
|
|
2062
|
+
|
|
2063
|
+
siteKindsBySpecifierForFile(
|
|
2064
|
+
sourceFile: ts.SourceFile,
|
|
2065
|
+
): ReadonlyMap<string, ReadonlyMap<string, ImportedMacroSiteKind>> {
|
|
2066
|
+
return bindingsForSourceFile(sourceFile).siteKindsBySpecifier;
|
|
2067
|
+
},
|
|
2068
|
+
|
|
2069
|
+
expandPreparedProgram(
|
|
2070
|
+
preserveRemovedImportStatements = false,
|
|
2071
|
+
preserveMissingExpanders = false,
|
|
2072
|
+
annotateExpansions = false,
|
|
2073
|
+
): ReadonlyMap<string, ts.SourceFile> {
|
|
2074
|
+
const sourceFiles = preparedProgram.program.getSourceFiles().filter((sourceFile) =>
|
|
2075
|
+
!sourceFile.isDeclarationFile
|
|
2076
|
+
);
|
|
2077
|
+
const registriesByFile = new Map<
|
|
2078
|
+
string,
|
|
2079
|
+
{
|
|
2080
|
+
registry: ReadonlyMap<string, RewriteMacroExpander>;
|
|
2081
|
+
advancedRegistry: ReadonlyMap<string, AdvancedMacroExpander>;
|
|
2082
|
+
siteKindsBySpecifier: ReadonlyMap<string, ReadonlyMap<string, ImportedMacroSiteKind>>;
|
|
2083
|
+
}
|
|
2084
|
+
>();
|
|
2085
|
+
const bindingUsageByFile = new Map<string, ReadonlyMap<string, ImportedBindingUsage>>();
|
|
2086
|
+
const hasBindingsByFile = new Map<string, boolean>();
|
|
2087
|
+
|
|
2088
|
+
for (const sourceFile of sourceFiles) {
|
|
2089
|
+
const bindings = bindingsForSourceFile(sourceFile);
|
|
2090
|
+
registriesByFile.set(sourceFile.fileName, {
|
|
2091
|
+
registry: bindings.registry,
|
|
2092
|
+
advancedRegistry: bindings.advancedRegistry,
|
|
2093
|
+
siteKindsBySpecifier: bindings.siteKindsBySpecifier,
|
|
2094
|
+
});
|
|
2095
|
+
bindingUsageByFile.set(sourceFile.fileName, bindings.importedBindingUsage);
|
|
2096
|
+
hasBindingsByFile.set(sourceFile.fileName, hasResolvedMacroBindings(bindings));
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
const expanded = expandPreparedProgramWithFileRegistries(
|
|
2100
|
+
preparedProgram,
|
|
2101
|
+
registriesByFile,
|
|
2102
|
+
preserveMissingExpanders,
|
|
2103
|
+
annotateExpansions,
|
|
2104
|
+
);
|
|
2105
|
+
const stripped = new Map<string, ts.SourceFile>();
|
|
2106
|
+
for (const [fileName, sourceFile] of expanded.entries()) {
|
|
2107
|
+
if (!hasBindingsByFile.get(fileName)) {
|
|
2108
|
+
const sourceFileName = preparedProgram.toSourceFileName(fileName);
|
|
2109
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
2110
|
+
stripped.set(
|
|
2111
|
+
fileName,
|
|
2112
|
+
preparedSource
|
|
2113
|
+
? ts.createSourceFile(
|
|
2114
|
+
fileName,
|
|
2115
|
+
preparedSource.originalText,
|
|
2116
|
+
preparedProgram.options.target ?? ts.ScriptTarget.Latest,
|
|
2117
|
+
true,
|
|
2118
|
+
scriptKindForHostFile(fileName),
|
|
2119
|
+
)
|
|
2120
|
+
: sourceFile,
|
|
2121
|
+
);
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
stripped.set(
|
|
2126
|
+
fileName,
|
|
2127
|
+
stripCompileTimeOnlyImportedBindings(
|
|
2128
|
+
sourceFile,
|
|
2129
|
+
bindingUsageByFile.get(fileName) ?? new Map(),
|
|
2130
|
+
preserveRemovedImportStatements,
|
|
2131
|
+
),
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
return stripped;
|
|
2135
|
+
},
|
|
2136
|
+
};
|
|
2137
|
+
}
|