@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,3338 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
// Internal bridge from frontend-owned macro wrappers to the current TypeScript host substrate.
|
|
4
|
+
// Macro authors should depend on macro_api.ts instead of this module.
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
BlockSyntax,
|
|
8
|
+
DeclSyntax,
|
|
9
|
+
ExprSyntax,
|
|
10
|
+
InvocationSyntax,
|
|
11
|
+
JsxSyntax,
|
|
12
|
+
MacroAnyClassMemberSyntax,
|
|
13
|
+
MacroAnyJsxAttributeSyntax,
|
|
14
|
+
MacroAnyJsxChildSyntax,
|
|
15
|
+
MacroArgumentView,
|
|
16
|
+
MacroArrayLiteralElementSyntax,
|
|
17
|
+
MacroArrayLiteralExprSyntax,
|
|
18
|
+
MacroBinaryExprPattern,
|
|
19
|
+
MacroBinaryOperator,
|
|
20
|
+
MacroBindingIdentifierSyntax,
|
|
21
|
+
MacroCallExprPattern,
|
|
22
|
+
MacroClassConstructorSyntax,
|
|
23
|
+
MacroClassDeclSyntax,
|
|
24
|
+
MacroClassFieldSyntax,
|
|
25
|
+
MacroClassMethodSyntax,
|
|
26
|
+
MacroConditionalExprPattern,
|
|
27
|
+
MacroDeclarationKind,
|
|
28
|
+
MacroFieldBuildOptions,
|
|
29
|
+
MacroForBuildOptions,
|
|
30
|
+
MacroFunctionBuildOptions,
|
|
31
|
+
MacroFunctionDeclSyntax,
|
|
32
|
+
MacroFunctionExprSyntax,
|
|
33
|
+
MacroIfBuildOptions,
|
|
34
|
+
MacroInterfaceDeclSyntax,
|
|
35
|
+
MacroInvocationForm,
|
|
36
|
+
MacroJsxAttributeSyntax,
|
|
37
|
+
MacroJsxElementSyntax,
|
|
38
|
+
MacroJsxExpressionSyntax,
|
|
39
|
+
MacroJsxFragmentSyntax,
|
|
40
|
+
MacroJsxSpreadAttributeSyntax,
|
|
41
|
+
MacroJsxTextSyntax,
|
|
42
|
+
MacroLiteralTypeSyntax,
|
|
43
|
+
MacroMethodBuildOptions,
|
|
44
|
+
MacroModifierName,
|
|
45
|
+
MacroObjectMemberBuildOptions,
|
|
46
|
+
MacroObjectTypeMemberSyntax,
|
|
47
|
+
MacroObjectTypeSyntax,
|
|
48
|
+
MacroParameterBuildOptions,
|
|
49
|
+
MacroParameterSyntax,
|
|
50
|
+
MacroPropertyAccessPattern,
|
|
51
|
+
MacroSetterBuildOptions,
|
|
52
|
+
MacroSyntaxNode,
|
|
53
|
+
MacroSyntaxRewriteOptions,
|
|
54
|
+
MacroTemplateOperand,
|
|
55
|
+
MacroTemplateQuasi,
|
|
56
|
+
MacroTypeAliasDeclSyntax,
|
|
57
|
+
MacroTypeParameterSyntax,
|
|
58
|
+
MacroUnaryOperator,
|
|
59
|
+
MacroUnionTypeSyntax,
|
|
60
|
+
StmtSyntax,
|
|
61
|
+
TypeSyntax,
|
|
62
|
+
} from './macro_api.ts';
|
|
63
|
+
import {
|
|
64
|
+
parseHostExpression,
|
|
65
|
+
parseHostStatements,
|
|
66
|
+
parseSingleHostStatement,
|
|
67
|
+
synthesizeHostNode,
|
|
68
|
+
} from './macro_host_ast_internal.ts';
|
|
69
|
+
import { parseMacroInvocationAt } from './macro_parser.ts';
|
|
70
|
+
import { scanMacroCandidates } from './macro_scanner.ts';
|
|
71
|
+
import type { SourceSpan } from './macro_types.ts';
|
|
72
|
+
|
|
73
|
+
const HOST_NODE = Symbol.for('soundscript.macro-syntax.host-node');
|
|
74
|
+
const HOST_SOURCE_FILE = Symbol.for('soundscript.macro-syntax.host-source-file');
|
|
75
|
+
const HOST_HINT = Symbol.for('soundscript.macro-syntax.host-hint');
|
|
76
|
+
const HOST_SOURCE_OFFSET = Symbol.for('soundscript.macro-syntax.host-source-offset');
|
|
77
|
+
|
|
78
|
+
type HostHint = ts.EmitHint;
|
|
79
|
+
|
|
80
|
+
interface HostBackedSyntaxNode {
|
|
81
|
+
readonly [HOST_HINT]: HostHint;
|
|
82
|
+
readonly [HOST_NODE]: ts.Node;
|
|
83
|
+
readonly [HOST_SOURCE_FILE]: ts.SourceFile;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type SourceFileWithOffset = ts.SourceFile & {
|
|
87
|
+
[HOST_SOURCE_OFFSET]?: number;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
91
|
+
|
|
92
|
+
function withHostNode<T extends MacroSyntaxNode>(
|
|
93
|
+
node: T,
|
|
94
|
+
hostNode: ts.Node,
|
|
95
|
+
sourceFile: ts.SourceFile,
|
|
96
|
+
hint: HostHint,
|
|
97
|
+
): T {
|
|
98
|
+
return Object.assign(node, {
|
|
99
|
+
[HOST_HINT]: hint,
|
|
100
|
+
[HOST_NODE]: hostNode,
|
|
101
|
+
[HOST_SOURCE_FILE]: sourceFile,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function printHostNode(node: ts.Node, sourceFile: ts.SourceFile, hint: HostHint): string {
|
|
106
|
+
return printer.printNode(hint, node, sourceFile);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function offsetSpan(baseSpan: SourceSpan, innerSpan: SourceSpan): SourceSpan {
|
|
110
|
+
return {
|
|
111
|
+
fileName: baseSpan.fileName,
|
|
112
|
+
start: baseSpan.start + innerSpan.start,
|
|
113
|
+
end: baseSpan.start + innerSpan.end,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setSourceFileOffset(sourceFile: ts.SourceFile, offset: number): ts.SourceFile {
|
|
118
|
+
(sourceFile as SourceFileWithOffset)[HOST_SOURCE_OFFSET] = offset;
|
|
119
|
+
return sourceFile;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function sourceFileOffset(sourceFile: ts.SourceFile): number {
|
|
123
|
+
return (sourceFile as SourceFileWithOffset)[HOST_SOURCE_OFFSET] ?? 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function scriptKindForHostFile(fileName: string): ts.ScriptKind {
|
|
127
|
+
const lowered = fileName.toLowerCase();
|
|
128
|
+
if (lowered.endsWith('.sts') || lowered.endsWith('.tsx') || lowered.endsWith('.jsx')) {
|
|
129
|
+
return ts.ScriptKind.TSX;
|
|
130
|
+
}
|
|
131
|
+
if (lowered.endsWith('.js') || lowered.endsWith('.mjs') || lowered.endsWith('.cjs')) {
|
|
132
|
+
return ts.ScriptKind.JS;
|
|
133
|
+
}
|
|
134
|
+
return ts.ScriptKind.TS;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function ensureNoParseDiagnostics(sourceFile: ts.SourceFile, message: string): void {
|
|
138
|
+
const parseDiagnostics = (sourceFile as ts.SourceFile & {
|
|
139
|
+
parseDiagnostics?: readonly ts.Diagnostic[];
|
|
140
|
+
}).parseDiagnostics ?? [];
|
|
141
|
+
if (parseDiagnostics.length > 0) {
|
|
142
|
+
throw new Error(message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function fallbackText(node: MacroSyntaxNode): string {
|
|
147
|
+
const hostBacked = node as MacroSyntaxNode & Partial<HostBackedSyntaxNode>;
|
|
148
|
+
if (hostBacked[HOST_NODE] && hostBacked[HOST_SOURCE_FILE]) {
|
|
149
|
+
return printHostNode(
|
|
150
|
+
hostBacked[HOST_NODE],
|
|
151
|
+
hostBacked[HOST_SOURCE_FILE],
|
|
152
|
+
hostBacked[HOST_HINT] ?? ts.EmitHint.Unspecified,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
return '';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function getHostNode(node: MacroSyntaxNode): ts.Node | null {
|
|
159
|
+
return (node as MacroSyntaxNode & Partial<HostBackedSyntaxNode>)[HOST_NODE] ?? null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function getHostExpression(node: ExprSyntax): ts.Expression {
|
|
163
|
+
const hostNode = getHostNode(node);
|
|
164
|
+
if (!hostNode || !ts.isExpression(hostNode)) {
|
|
165
|
+
throw new Error('Expected an expression-backed syntax node.');
|
|
166
|
+
}
|
|
167
|
+
return hostNode;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getHostStatement(node: StmtSyntax | DeclSyntax): ts.Statement {
|
|
171
|
+
const hostNode = getHostNode(node);
|
|
172
|
+
if (!hostNode || !ts.isStatement(hostNode)) {
|
|
173
|
+
throw new Error('Expected a statement-backed syntax node.');
|
|
174
|
+
}
|
|
175
|
+
return hostNode;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function getHostBlock(node: BlockSyntax): ts.Block {
|
|
179
|
+
const hostNode = getHostNode(node);
|
|
180
|
+
if (!hostNode || !ts.isBlock(hostNode)) {
|
|
181
|
+
throw new Error('Expected a block-backed syntax node.');
|
|
182
|
+
}
|
|
183
|
+
return hostNode;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function getHostDeclaration(
|
|
187
|
+
node: DeclSyntax,
|
|
188
|
+
):
|
|
189
|
+
| ts.ClassDeclaration
|
|
190
|
+
| ts.FunctionDeclaration
|
|
191
|
+
| ts.InterfaceDeclaration
|
|
192
|
+
| ts.TypeAliasDeclaration {
|
|
193
|
+
const hostNode = getHostNode(node);
|
|
194
|
+
if (
|
|
195
|
+
!hostNode ||
|
|
196
|
+
(!ts.isClassDeclaration(hostNode) && !ts.isFunctionDeclaration(hostNode) &&
|
|
197
|
+
!ts.isInterfaceDeclaration(hostNode) && !ts.isTypeAliasDeclaration(hostNode))
|
|
198
|
+
) {
|
|
199
|
+
throw new Error('Expected a declaration-backed syntax node.');
|
|
200
|
+
}
|
|
201
|
+
return hostNode;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function getHostJsx(
|
|
205
|
+
node: JsxSyntax,
|
|
206
|
+
): ts.JsxChild | ts.JsxOpeningLikeElement | ts.JsxAttributeLike {
|
|
207
|
+
const hostNode = getHostNode(node);
|
|
208
|
+
if (!hostNode) {
|
|
209
|
+
throw new Error('Expected a JSX-backed syntax node.');
|
|
210
|
+
}
|
|
211
|
+
return hostNode as ts.JsxChild | ts.JsxOpeningLikeElement | ts.JsxAttributeLike;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function nodeSpan(
|
|
215
|
+
node: ts.Node,
|
|
216
|
+
sourceFile: ts.SourceFile,
|
|
217
|
+
fallback: SourceSpan,
|
|
218
|
+
): SourceSpan {
|
|
219
|
+
if (node.pos >= 0 && node.end >= 0) {
|
|
220
|
+
const offset = sourceFileOffset(sourceFile);
|
|
221
|
+
return {
|
|
222
|
+
fileName: fallback.fileName,
|
|
223
|
+
start: offset + node.getStart(sourceFile, false),
|
|
224
|
+
end: offset + node.end,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
fileName: fallback.fileName,
|
|
229
|
+
start: fallback.start,
|
|
230
|
+
end: fallback.end,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function hasModifier(
|
|
235
|
+
node: { readonly modifiers?: readonly ts.ModifierLike[] },
|
|
236
|
+
name: MacroModifierName,
|
|
237
|
+
): boolean {
|
|
238
|
+
const expectedKind = (() => {
|
|
239
|
+
switch (name) {
|
|
240
|
+
case 'async':
|
|
241
|
+
return ts.SyntaxKind.AsyncKeyword;
|
|
242
|
+
case 'default':
|
|
243
|
+
return ts.SyntaxKind.DefaultKeyword;
|
|
244
|
+
case 'export':
|
|
245
|
+
return ts.SyntaxKind.ExportKeyword;
|
|
246
|
+
case 'private':
|
|
247
|
+
return ts.SyntaxKind.PrivateKeyword;
|
|
248
|
+
case 'protected':
|
|
249
|
+
return ts.SyntaxKind.ProtectedKeyword;
|
|
250
|
+
case 'public':
|
|
251
|
+
return ts.SyntaxKind.PublicKeyword;
|
|
252
|
+
case 'readonly':
|
|
253
|
+
return ts.SyntaxKind.ReadonlyKeyword;
|
|
254
|
+
case 'static':
|
|
255
|
+
return ts.SyntaxKind.StaticKeyword;
|
|
256
|
+
}
|
|
257
|
+
})();
|
|
258
|
+
return node.modifiers?.some((modifier) => modifier.kind === expectedKind) ?? false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function createModifierNodes(
|
|
262
|
+
names: readonly MacroModifierName[] | undefined,
|
|
263
|
+
): readonly ts.Modifier[] | undefined {
|
|
264
|
+
if (!names || names.length === 0) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
return names.map((name) => {
|
|
268
|
+
switch (name) {
|
|
269
|
+
case 'async':
|
|
270
|
+
return ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword);
|
|
271
|
+
case 'default':
|
|
272
|
+
return ts.factory.createModifier(ts.SyntaxKind.DefaultKeyword);
|
|
273
|
+
case 'export':
|
|
274
|
+
return ts.factory.createModifier(ts.SyntaxKind.ExportKeyword);
|
|
275
|
+
case 'private':
|
|
276
|
+
return ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword);
|
|
277
|
+
case 'protected':
|
|
278
|
+
return ts.factory.createModifier(ts.SyntaxKind.ProtectedKeyword);
|
|
279
|
+
case 'public':
|
|
280
|
+
return ts.factory.createModifier(ts.SyntaxKind.PublicKeyword);
|
|
281
|
+
case 'readonly':
|
|
282
|
+
return ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword);
|
|
283
|
+
case 'static':
|
|
284
|
+
return ts.factory.createModifier(ts.SyntaxKind.StaticKeyword);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function createBuildSourceFile(fileName: string): ts.SourceFile {
|
|
290
|
+
return ts.createSourceFile(
|
|
291
|
+
fileName,
|
|
292
|
+
'',
|
|
293
|
+
ts.ScriptTarget.Latest,
|
|
294
|
+
true,
|
|
295
|
+
scriptKindForHostFile(fileName),
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function cloneBlockNode(block: BlockSyntax): ts.Block {
|
|
300
|
+
return synthesizeHostNode(ts.factory.createBlock([...getHostBlock(block).statements], true));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function createBinaryOperatorToken(operator: MacroBinaryOperator): ts.BinaryOperatorToken {
|
|
304
|
+
switch (operator) {
|
|
305
|
+
case '&':
|
|
306
|
+
return ts.factory.createToken(ts.SyntaxKind.AmpersandToken);
|
|
307
|
+
case '<':
|
|
308
|
+
return ts.factory.createToken(ts.SyntaxKind.LessThanToken);
|
|
309
|
+
case '+':
|
|
310
|
+
return ts.factory.createToken(ts.SyntaxKind.PlusToken);
|
|
311
|
+
case '=':
|
|
312
|
+
return ts.factory.createToken(ts.SyntaxKind.EqualsToken);
|
|
313
|
+
case '!==':
|
|
314
|
+
return ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken);
|
|
315
|
+
case '===':
|
|
316
|
+
return ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken);
|
|
317
|
+
case '|':
|
|
318
|
+
return ts.factory.createToken(ts.SyntaxKind.BarToken);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function createUnaryOperatorToken(operator: MacroUnaryOperator): ts.PrefixUnaryOperator {
|
|
323
|
+
switch (operator) {
|
|
324
|
+
case '!':
|
|
325
|
+
return ts.SyntaxKind.ExclamationToken;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function createBuiltExprSyntax(
|
|
330
|
+
fileName: string,
|
|
331
|
+
node: ts.Expression,
|
|
332
|
+
): ExprSyntax {
|
|
333
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
334
|
+
return createExprSyntaxFromNode(synthesizeHostNode(node), sourceFile, {
|
|
335
|
+
fileName,
|
|
336
|
+
start: 0,
|
|
337
|
+
end: 0,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function createBuiltStmtSyntax(
|
|
342
|
+
fileName: string,
|
|
343
|
+
node: ts.Statement,
|
|
344
|
+
): StmtSyntax {
|
|
345
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
346
|
+
return createStmtSyntaxFromNode(synthesizeHostNode(node), sourceFile, {
|
|
347
|
+
fileName,
|
|
348
|
+
start: 0,
|
|
349
|
+
end: 0,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function createTypeNodeFromText(fileName: string, typeText: string): ts.TypeNode {
|
|
354
|
+
const sourceFile = ts.createSourceFile(
|
|
355
|
+
fileName,
|
|
356
|
+
`type __SoundscriptMacroParam = ${typeText};`,
|
|
357
|
+
ts.ScriptTarget.Latest,
|
|
358
|
+
true,
|
|
359
|
+
scriptKindForHostFile(fileName),
|
|
360
|
+
);
|
|
361
|
+
ensureNoParseDiagnostics(
|
|
362
|
+
sourceFile,
|
|
363
|
+
'Macro builder parameter types must parse as valid host-language types.',
|
|
364
|
+
);
|
|
365
|
+
const statement = sourceFile.statements[0];
|
|
366
|
+
if (!statement || !ts.isTypeAliasDeclaration(statement) || !statement.type) {
|
|
367
|
+
throw new Error('Macro builder parameter types must parse as valid host-language types.');
|
|
368
|
+
}
|
|
369
|
+
return synthesizeHostNode(statement.type);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function createParameterDeclarations(
|
|
373
|
+
fileName: string,
|
|
374
|
+
parameters: readonly (string | MacroParameterBuildOptions)[] | undefined,
|
|
375
|
+
): readonly ts.ParameterDeclaration[] {
|
|
376
|
+
return (parameters ?? []).map((parameter) => {
|
|
377
|
+
const normalized = typeof parameter === 'string' ? { name: parameter } : parameter;
|
|
378
|
+
return synthesizeHostNode(
|
|
379
|
+
ts.factory.createParameterDeclaration(
|
|
380
|
+
undefined,
|
|
381
|
+
undefined,
|
|
382
|
+
normalized.name,
|
|
383
|
+
undefined,
|
|
384
|
+
normalized.type ? createTypeNodeFromText(fileName, normalized.type) : undefined,
|
|
385
|
+
undefined,
|
|
386
|
+
),
|
|
387
|
+
);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function collectThisMemberReferences(node: ts.Node | null): readonly string[] {
|
|
392
|
+
if (!node) {
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const references = new Set<string>();
|
|
397
|
+
function visit(current: ts.Node): void {
|
|
398
|
+
if (
|
|
399
|
+
ts.isPropertyAccessExpression(current) &&
|
|
400
|
+
current.expression.kind === ts.SyntaxKind.ThisKeyword &&
|
|
401
|
+
ts.isIdentifier(current.name)
|
|
402
|
+
) {
|
|
403
|
+
references.add(current.name.text);
|
|
404
|
+
}
|
|
405
|
+
ts.forEachChild(current, visit);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
visit(node);
|
|
409
|
+
return [...references];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function containsCallNamed(node: ts.Node | null, name: string): boolean {
|
|
413
|
+
if (!node) {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
let found = false;
|
|
417
|
+
function visit(current: ts.Node): void {
|
|
418
|
+
if (found) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (ts.isCallExpression(current)) {
|
|
422
|
+
const callee = unwrapParenthesizedExpressionNode(current.expression);
|
|
423
|
+
if (ts.isIdentifier(callee) && callee.text === name) {
|
|
424
|
+
found = true;
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
ts.forEachChild(current, visit);
|
|
429
|
+
}
|
|
430
|
+
visit(node);
|
|
431
|
+
return found;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function unwrapParenthesizedExpressionNode(node: ts.Expression): ts.Expression {
|
|
435
|
+
let current = node;
|
|
436
|
+
while (ts.isParenthesizedExpression(current)) {
|
|
437
|
+
current = current.expression;
|
|
438
|
+
}
|
|
439
|
+
return current;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function expressionAsIdentifier(node: ts.Expression): string | null {
|
|
443
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
444
|
+
return ts.isIdentifier(unwrapped) ? unwrapped.text : null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function createArrayLiteralElementSyntaxFromNode(
|
|
448
|
+
node: ts.Expression | ts.SpreadElement | ts.OmittedExpression,
|
|
449
|
+
sourceFile: ts.SourceFile,
|
|
450
|
+
fallbackSpan: SourceSpan,
|
|
451
|
+
): MacroArrayLiteralElementSyntax {
|
|
452
|
+
if (ts.isOmittedExpression(node)) {
|
|
453
|
+
return withHostNode(
|
|
454
|
+
{
|
|
455
|
+
expression() {
|
|
456
|
+
return null;
|
|
457
|
+
},
|
|
458
|
+
isSpread: false,
|
|
459
|
+
kind: 'array_elision',
|
|
460
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
461
|
+
text() {
|
|
462
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
node,
|
|
466
|
+
sourceFile,
|
|
467
|
+
ts.EmitHint.Unspecified,
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const expression = ts.isSpreadElement(node) ? node.expression : node;
|
|
472
|
+
return withHostNode(
|
|
473
|
+
{
|
|
474
|
+
expression() {
|
|
475
|
+
return createExprSyntaxFromNode(
|
|
476
|
+
expression,
|
|
477
|
+
sourceFile,
|
|
478
|
+
nodeSpan(expression, sourceFile, fallbackSpan),
|
|
479
|
+
);
|
|
480
|
+
},
|
|
481
|
+
isSpread: ts.isSpreadElement(node),
|
|
482
|
+
kind: 'array_element',
|
|
483
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
484
|
+
text() {
|
|
485
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
node,
|
|
489
|
+
sourceFile,
|
|
490
|
+
ts.EmitHint.Unspecified,
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function expressionAsArrayLiteral(
|
|
495
|
+
node: ts.Expression,
|
|
496
|
+
sourceFile: ts.SourceFile,
|
|
497
|
+
span: SourceSpan,
|
|
498
|
+
): MacroArrayLiteralExprSyntax | null {
|
|
499
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
500
|
+
if (!ts.isArrayLiteralExpression(unwrapped)) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const base = createExprSyntaxFromNode(unwrapped, sourceFile, span);
|
|
505
|
+
return {
|
|
506
|
+
...base,
|
|
507
|
+
asArrayLiteral() {
|
|
508
|
+
return this;
|
|
509
|
+
},
|
|
510
|
+
elements: unwrapped.elements.map((element) =>
|
|
511
|
+
createArrayLiteralElementSyntaxFromNode(
|
|
512
|
+
element,
|
|
513
|
+
sourceFile,
|
|
514
|
+
nodeSpan(element, sourceFile, span),
|
|
515
|
+
)
|
|
516
|
+
),
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function expressionAsPropertyAccess(
|
|
521
|
+
node: ts.Expression,
|
|
522
|
+
sourceFile: ts.SourceFile,
|
|
523
|
+
span: SourceSpan,
|
|
524
|
+
): MacroPropertyAccessPattern | null {
|
|
525
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
526
|
+
if (!ts.isPropertyAccessExpression(unwrapped)) {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
name: unwrapped.name.text,
|
|
531
|
+
object: createExprSyntaxFromNode(
|
|
532
|
+
unwrapped.expression,
|
|
533
|
+
sourceFile,
|
|
534
|
+
nodeSpan(unwrapped.expression, sourceFile, span),
|
|
535
|
+
),
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function expressionAsCall(
|
|
540
|
+
node: ts.Expression,
|
|
541
|
+
sourceFile: ts.SourceFile,
|
|
542
|
+
span: SourceSpan,
|
|
543
|
+
): MacroCallExprPattern | null {
|
|
544
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
545
|
+
if (!ts.isCallExpression(unwrapped)) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
return {
|
|
549
|
+
args: unwrapped.arguments.map((argument) =>
|
|
550
|
+
createExprSyntaxFromNode(argument, sourceFile, nodeSpan(argument, sourceFile, span))
|
|
551
|
+
),
|
|
552
|
+
callee: createExprSyntaxFromNode(
|
|
553
|
+
unwrapped.expression,
|
|
554
|
+
sourceFile,
|
|
555
|
+
nodeSpan(unwrapped.expression, sourceFile, span),
|
|
556
|
+
),
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function expressionAsBinary(
|
|
561
|
+
node: ts.Expression,
|
|
562
|
+
sourceFile: ts.SourceFile,
|
|
563
|
+
span: SourceSpan,
|
|
564
|
+
): MacroBinaryExprPattern | null {
|
|
565
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
566
|
+
if (!ts.isBinaryExpression(unwrapped)) {
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
return {
|
|
570
|
+
left: createExprSyntaxFromNode(
|
|
571
|
+
unwrapped.left,
|
|
572
|
+
sourceFile,
|
|
573
|
+
nodeSpan(unwrapped.left, sourceFile, span),
|
|
574
|
+
),
|
|
575
|
+
operator: ts.tokenToString(unwrapped.operatorToken.kind) ??
|
|
576
|
+
unwrapped.operatorToken.getText(sourceFile),
|
|
577
|
+
right: createExprSyntaxFromNode(
|
|
578
|
+
unwrapped.right,
|
|
579
|
+
sourceFile,
|
|
580
|
+
nodeSpan(unwrapped.right, sourceFile, span),
|
|
581
|
+
),
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function expressionAsConditional(
|
|
586
|
+
node: ts.Expression,
|
|
587
|
+
sourceFile: ts.SourceFile,
|
|
588
|
+
span: SourceSpan,
|
|
589
|
+
): MacroConditionalExprPattern | null {
|
|
590
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
591
|
+
if (!ts.isConditionalExpression(unwrapped)) {
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
condition: createExprSyntaxFromNode(
|
|
596
|
+
unwrapped.condition,
|
|
597
|
+
sourceFile,
|
|
598
|
+
nodeSpan(unwrapped.condition, sourceFile, span),
|
|
599
|
+
),
|
|
600
|
+
whenFalse: createExprSyntaxFromNode(
|
|
601
|
+
unwrapped.whenFalse,
|
|
602
|
+
sourceFile,
|
|
603
|
+
nodeSpan(unwrapped.whenFalse, sourceFile, span),
|
|
604
|
+
),
|
|
605
|
+
whenTrue: createExprSyntaxFromNode(
|
|
606
|
+
unwrapped.whenTrue,
|
|
607
|
+
sourceFile,
|
|
608
|
+
nodeSpan(unwrapped.whenTrue, sourceFile, span),
|
|
609
|
+
),
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function expressionAsJsxElement(
|
|
614
|
+
node: ts.Expression,
|
|
615
|
+
sourceFile: ts.SourceFile,
|
|
616
|
+
span: SourceSpan,
|
|
617
|
+
): MacroJsxElementSyntax | null {
|
|
618
|
+
const current = unwrapParenthesizedExpressionNode(node);
|
|
619
|
+
if (ts.isJsxElement(current) || ts.isJsxSelfClosingElement(current)) {
|
|
620
|
+
return createJsxElementSyntaxFromNode(
|
|
621
|
+
current,
|
|
622
|
+
sourceFile,
|
|
623
|
+
nodeSpan(current, sourceFile, span),
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function expressionAsJsxFragment(
|
|
630
|
+
node: ts.Expression,
|
|
631
|
+
sourceFile: ts.SourceFile,
|
|
632
|
+
span: SourceSpan,
|
|
633
|
+
): MacroJsxFragmentSyntax | null {
|
|
634
|
+
const current = unwrapParenthesizedExpressionNode(node);
|
|
635
|
+
if (ts.isJsxFragment(current)) {
|
|
636
|
+
return createJsxFragmentSyntaxFromNode(
|
|
637
|
+
current,
|
|
638
|
+
sourceFile,
|
|
639
|
+
nodeSpan(current, sourceFile, span),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function replaceThisNode<T extends ts.Node>(
|
|
646
|
+
node: T,
|
|
647
|
+
replacement: ExprSyntax,
|
|
648
|
+
): T {
|
|
649
|
+
return rewriteNode(node, { replaceThisWith: replacement });
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function cloneExpressionNode(node: ts.Expression): ts.Expression {
|
|
653
|
+
return synthesizeHostNode(
|
|
654
|
+
(ts.factory as typeof ts.factory & { cloneNode(node: ts.Expression): ts.Expression }).cloneNode(
|
|
655
|
+
node,
|
|
656
|
+
),
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function compoundAssignmentOperatorTokenForRewrite(
|
|
661
|
+
kind: ts.SyntaxKind,
|
|
662
|
+
): ts.BinaryOperatorToken | null {
|
|
663
|
+
switch (kind) {
|
|
664
|
+
case ts.SyntaxKind.PlusEqualsToken:
|
|
665
|
+
return ts.factory.createToken(ts.SyntaxKind.PlusToken);
|
|
666
|
+
case ts.SyntaxKind.MinusEqualsToken:
|
|
667
|
+
return ts.factory.createToken(ts.SyntaxKind.MinusToken);
|
|
668
|
+
case ts.SyntaxKind.AsteriskEqualsToken:
|
|
669
|
+
return ts.factory.createToken(ts.SyntaxKind.AsteriskToken);
|
|
670
|
+
case ts.SyntaxKind.SlashEqualsToken:
|
|
671
|
+
return ts.factory.createToken(ts.SyntaxKind.SlashToken);
|
|
672
|
+
case ts.SyntaxKind.PercentEqualsToken:
|
|
673
|
+
return ts.factory.createToken(ts.SyntaxKind.PercentToken);
|
|
674
|
+
default:
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function updateOperatorTokenForRewrite(kind: ts.SyntaxKind): ts.BinaryOperatorToken | null {
|
|
680
|
+
switch (kind) {
|
|
681
|
+
case ts.SyntaxKind.PlusPlusToken:
|
|
682
|
+
return ts.factory.createToken(ts.SyntaxKind.PlusToken);
|
|
683
|
+
case ts.SyntaxKind.MinusMinusToken:
|
|
684
|
+
return ts.factory.createToken(ts.SyntaxKind.MinusToken);
|
|
685
|
+
default:
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function thisPropertyNameForRewrite(expression: ts.Expression): string | null {
|
|
691
|
+
return ts.isPropertyAccessExpression(expression) &&
|
|
692
|
+
expression.expression.kind === ts.SyntaxKind.ThisKeyword
|
|
693
|
+
? expression.name.text
|
|
694
|
+
: null;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function rewriteNode<T extends ts.Node>(
|
|
698
|
+
node: T,
|
|
699
|
+
options: MacroSyntaxRewriteOptions,
|
|
700
|
+
): T {
|
|
701
|
+
const replaceThisWith = options.replaceThisWith ? getHostExpression(options.replaceThisWith) : null;
|
|
702
|
+
const replaceCallNamed = new Map(
|
|
703
|
+
Object.entries(options.replaceCallNamed ?? {}).map(([name, replacement]) => [
|
|
704
|
+
name,
|
|
705
|
+
getHostExpression(replacement),
|
|
706
|
+
]),
|
|
707
|
+
);
|
|
708
|
+
const replaceThisMemberWriteNamed = new Map(
|
|
709
|
+
Object.entries(options.replaceThisMemberWriteNamed ?? {}).map(([name, replacement]) => [
|
|
710
|
+
name,
|
|
711
|
+
getHostExpression(replacement),
|
|
712
|
+
]),
|
|
713
|
+
);
|
|
714
|
+
let temporaryCount = 0;
|
|
715
|
+
const transformed = ts.transform(node, [(
|
|
716
|
+
context: ts.TransformationContext,
|
|
717
|
+
) =>
|
|
718
|
+
(root: ts.Node) =>
|
|
719
|
+
ts.visitNode(root, function visit(current): ts.Node {
|
|
720
|
+
if (ts.isBinaryExpression(current)) {
|
|
721
|
+
const targetName = thisPropertyNameForRewrite(current.left);
|
|
722
|
+
const setterExpression = targetName
|
|
723
|
+
? replaceThisMemberWriteNamed.get(targetName)
|
|
724
|
+
: undefined;
|
|
725
|
+
if (targetName && setterExpression) {
|
|
726
|
+
if (current.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
727
|
+
return synthesizeHostNode(
|
|
728
|
+
ts.factory.createCallExpression(
|
|
729
|
+
cloneExpressionNode(setterExpression),
|
|
730
|
+
undefined,
|
|
731
|
+
[ts.visitNode(current.right, visit) as ts.Expression],
|
|
732
|
+
),
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
const operator = compoundAssignmentOperatorTokenForRewrite(current.operatorToken.kind);
|
|
736
|
+
if (operator) {
|
|
737
|
+
const receiver = replaceThisWith
|
|
738
|
+
? cloneExpressionNode(replaceThisWith)
|
|
739
|
+
: ts.factory.createThis();
|
|
740
|
+
return synthesizeHostNode(
|
|
741
|
+
ts.factory.createCallExpression(
|
|
742
|
+
cloneExpressionNode(setterExpression),
|
|
743
|
+
undefined,
|
|
744
|
+
[
|
|
745
|
+
ts.factory.createBinaryExpression(
|
|
746
|
+
ts.factory.createPropertyAccessExpression(receiver, targetName),
|
|
747
|
+
operator,
|
|
748
|
+
ts.visitNode(current.right, visit) as ts.Expression,
|
|
749
|
+
),
|
|
750
|
+
],
|
|
751
|
+
),
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (ts.isPrefixUnaryExpression(current) || ts.isPostfixUnaryExpression(current)) {
|
|
757
|
+
const targetName = thisPropertyNameForRewrite(current.operand);
|
|
758
|
+
const setterExpression = targetName
|
|
759
|
+
? replaceThisMemberWriteNamed.get(targetName)
|
|
760
|
+
: undefined;
|
|
761
|
+
if (targetName && setterExpression) {
|
|
762
|
+
const operator = updateOperatorTokenForRewrite(current.operator);
|
|
763
|
+
if (operator) {
|
|
764
|
+
const receiver = replaceThisWith
|
|
765
|
+
? cloneExpressionNode(replaceThisWith)
|
|
766
|
+
: ts.factory.createThis();
|
|
767
|
+
const currentValue = ts.factory.createPropertyAccessExpression(receiver, targetName);
|
|
768
|
+
const nextValue = ts.factory.createBinaryExpression(
|
|
769
|
+
currentValue,
|
|
770
|
+
operator,
|
|
771
|
+
ts.factory.createNumericLiteral(1),
|
|
772
|
+
);
|
|
773
|
+
if (ts.isPrefixUnaryExpression(current)) {
|
|
774
|
+
return synthesizeHostNode(
|
|
775
|
+
ts.factory.createCallExpression(
|
|
776
|
+
cloneExpressionNode(setterExpression),
|
|
777
|
+
undefined,
|
|
778
|
+
[nextValue],
|
|
779
|
+
),
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
if (current.parent && ts.isExpressionStatement(current.parent)) {
|
|
783
|
+
return synthesizeHostNode(
|
|
784
|
+
ts.factory.createCallExpression(
|
|
785
|
+
cloneExpressionNode(setterExpression),
|
|
786
|
+
undefined,
|
|
787
|
+
[nextValue],
|
|
788
|
+
),
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const previousName = `__sts_prev_${temporaryCount++}`;
|
|
793
|
+
return synthesizeHostNode(
|
|
794
|
+
ts.factory.createCallExpression(
|
|
795
|
+
ts.factory.createParenthesizedExpression(
|
|
796
|
+
ts.factory.createArrowFunction(
|
|
797
|
+
undefined,
|
|
798
|
+
undefined,
|
|
799
|
+
[],
|
|
800
|
+
undefined,
|
|
801
|
+
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
|
|
802
|
+
ts.factory.createBlock([
|
|
803
|
+
ts.factory.createVariableStatement(
|
|
804
|
+
undefined,
|
|
805
|
+
ts.factory.createVariableDeclarationList([
|
|
806
|
+
ts.factory.createVariableDeclaration(
|
|
807
|
+
previousName,
|
|
808
|
+
undefined,
|
|
809
|
+
undefined,
|
|
810
|
+
currentValue,
|
|
811
|
+
),
|
|
812
|
+
], ts.NodeFlags.Const),
|
|
813
|
+
),
|
|
814
|
+
ts.factory.createExpressionStatement(
|
|
815
|
+
ts.factory.createCallExpression(
|
|
816
|
+
cloneExpressionNode(setterExpression),
|
|
817
|
+
undefined,
|
|
818
|
+
[
|
|
819
|
+
ts.factory.createBinaryExpression(
|
|
820
|
+
ts.factory.createIdentifier(previousName),
|
|
821
|
+
operator,
|
|
822
|
+
ts.factory.createNumericLiteral(1),
|
|
823
|
+
),
|
|
824
|
+
],
|
|
825
|
+
),
|
|
826
|
+
),
|
|
827
|
+
ts.factory.createReturnStatement(ts.factory.createIdentifier(previousName)),
|
|
828
|
+
], true),
|
|
829
|
+
),
|
|
830
|
+
),
|
|
831
|
+
undefined,
|
|
832
|
+
[],
|
|
833
|
+
),
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (replaceThisWith && current.kind === ts.SyntaxKind.ThisKeyword) {
|
|
839
|
+
return cloneExpressionNode(replaceThisWith);
|
|
840
|
+
}
|
|
841
|
+
if (ts.isCallExpression(current) && ts.isIdentifier(current.expression)) {
|
|
842
|
+
const replacementCallee = replaceCallNamed.get(current.expression.text);
|
|
843
|
+
if (replacementCallee) {
|
|
844
|
+
return synthesizeHostNode(
|
|
845
|
+
ts.factory.updateCallExpression(
|
|
846
|
+
current,
|
|
847
|
+
cloneExpressionNode(replacementCallee),
|
|
848
|
+
current.typeArguments,
|
|
849
|
+
current.arguments.map((argument) =>
|
|
850
|
+
ts.visitNode(argument, visit) as ts.Expression
|
|
851
|
+
),
|
|
852
|
+
),
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return ts.visitEachChild(current, visit, context);
|
|
857
|
+
})]);
|
|
858
|
+
try {
|
|
859
|
+
const [rewritten] = transformed.transformed;
|
|
860
|
+
if (!rewritten) {
|
|
861
|
+
throw new Error('Macro syntax transform produced an empty result.');
|
|
862
|
+
}
|
|
863
|
+
return rewritten as T;
|
|
864
|
+
} finally {
|
|
865
|
+
transformed.dispose();
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function rewriteExprSyntax(
|
|
870
|
+
node: ts.Expression,
|
|
871
|
+
sourceFile: ts.SourceFile,
|
|
872
|
+
span: SourceSpan,
|
|
873
|
+
options: MacroSyntaxRewriteOptions,
|
|
874
|
+
): ExprSyntax {
|
|
875
|
+
return createExprSyntaxFromNode(rewriteNode(node, options), sourceFile, span);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function rewriteBlockSyntax(
|
|
879
|
+
node: ts.Block,
|
|
880
|
+
sourceFile: ts.SourceFile,
|
|
881
|
+
span: SourceSpan,
|
|
882
|
+
options: MacroSyntaxRewriteOptions,
|
|
883
|
+
): BlockSyntax {
|
|
884
|
+
return createBlockSyntaxFromNode(rewriteNode(node, options), sourceFile, span);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function resolveThisDependenciesForClass(
|
|
888
|
+
node: ts.ClassDeclaration,
|
|
889
|
+
rootMemberNames: readonly string[],
|
|
890
|
+
target: ExprSyntax | BlockSyntax,
|
|
891
|
+
): readonly string[] {
|
|
892
|
+
const rootNames = new Set(rootMemberNames);
|
|
893
|
+
const getters = new Map<string, ts.GetAccessorDeclaration>();
|
|
894
|
+
for (const member of node.members) {
|
|
895
|
+
if (
|
|
896
|
+
ts.isGetAccessorDeclaration(member) && member.name && ts.isIdentifier(member.name) &&
|
|
897
|
+
member.body
|
|
898
|
+
) {
|
|
899
|
+
getters.set(member.name.text, member);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
const cache = new Map<string, ReadonlySet<string>>();
|
|
904
|
+
function resolveMember(
|
|
905
|
+
memberName: string,
|
|
906
|
+
seen: ReadonlySet<string> = new Set(),
|
|
907
|
+
): ReadonlySet<string> {
|
|
908
|
+
if (rootNames.has(memberName)) {
|
|
909
|
+
return new Set([memberName]);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const cached = cache.get(memberName);
|
|
913
|
+
if (cached) {
|
|
914
|
+
return cached;
|
|
915
|
+
}
|
|
916
|
+
if (seen.has(memberName)) {
|
|
917
|
+
return new Set();
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const getter = getters.get(memberName);
|
|
921
|
+
if (!getter?.body) {
|
|
922
|
+
return new Set();
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const nextSeen = new Set(seen);
|
|
926
|
+
nextSeen.add(memberName);
|
|
927
|
+
const dependencies = new Set<string>();
|
|
928
|
+
for (const reference of collectThisMemberReferences(getter.body)) {
|
|
929
|
+
for (const dependency of resolveMember(reference, nextSeen)) {
|
|
930
|
+
dependencies.add(dependency);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
cache.set(memberName, dependencies);
|
|
934
|
+
return dependencies;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const dependencies = new Set<string>();
|
|
938
|
+
for (const reference of target.thisMemberReferences()) {
|
|
939
|
+
for (const dependency of resolveMember(reference)) {
|
|
940
|
+
dependencies.add(dependency);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return [...dependencies];
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function returnedJsxNode(
|
|
947
|
+
node:
|
|
948
|
+
| ts.MethodDeclaration
|
|
949
|
+
| ts.GetAccessorDeclaration
|
|
950
|
+
| ts.SetAccessorDeclaration
|
|
951
|
+
| ts.FunctionDeclaration,
|
|
952
|
+
): ts.JsxElement | ts.JsxSelfClosingElement | null {
|
|
953
|
+
if (!node.body) {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
if (node.body.statements.length !== 1) {
|
|
957
|
+
return null;
|
|
958
|
+
}
|
|
959
|
+
const [statement] = node.body.statements;
|
|
960
|
+
if (!statement || !ts.isReturnStatement(statement) || !statement.expression) {
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
if (ts.isJsxElement(statement.expression) || ts.isJsxSelfClosingElement(statement.expression)) {
|
|
964
|
+
return statement.expression;
|
|
965
|
+
}
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function returnedExprNode(
|
|
970
|
+
node:
|
|
971
|
+
| ts.MethodDeclaration
|
|
972
|
+
| ts.GetAccessorDeclaration
|
|
973
|
+
| ts.SetAccessorDeclaration
|
|
974
|
+
| ts.FunctionDeclaration,
|
|
975
|
+
): ts.Expression | null {
|
|
976
|
+
if (!node.body) {
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
979
|
+
if (node.body.statements.length !== 1) {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
const [statement] = node.body.statements;
|
|
983
|
+
if (!statement || !ts.isReturnStatement(statement) || !statement.expression) {
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
986
|
+
return statement.expression;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
function typeElementNameText(name: ts.PropertyName | undefined): string | null {
|
|
990
|
+
if (!name) {
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
if (
|
|
994
|
+
ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNoSubstitutionTemplateLiteral(name) ||
|
|
995
|
+
ts.isNumericLiteral(name) || ts.isPrivateIdentifier(name)
|
|
996
|
+
) {
|
|
997
|
+
return name.text;
|
|
998
|
+
}
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function createObjectTypeMemberSyntaxFromNode(
|
|
1003
|
+
node: ts.TypeElement,
|
|
1004
|
+
sourceFile: ts.SourceFile,
|
|
1005
|
+
fallbackSpan: SourceSpan,
|
|
1006
|
+
): MacroObjectTypeMemberSyntax {
|
|
1007
|
+
const memberKind: MacroObjectTypeMemberSyntax['memberKind'] = ts.isPropertySignature(node)
|
|
1008
|
+
? 'property_signature'
|
|
1009
|
+
: ts.isMethodSignature(node)
|
|
1010
|
+
? 'method_signature'
|
|
1011
|
+
: ts.isIndexSignatureDeclaration(node)
|
|
1012
|
+
? 'index_signature'
|
|
1013
|
+
: ts.isConstructSignatureDeclaration(node)
|
|
1014
|
+
? 'construct_signature'
|
|
1015
|
+
: 'call_signature';
|
|
1016
|
+
|
|
1017
|
+
return withHostNode(
|
|
1018
|
+
{
|
|
1019
|
+
explicitType() {
|
|
1020
|
+
if (
|
|
1021
|
+
ts.isPropertySignature(node) ||
|
|
1022
|
+
ts.isMethodSignature(node) ||
|
|
1023
|
+
ts.isIndexSignatureDeclaration(node) ||
|
|
1024
|
+
ts.isConstructSignatureDeclaration(node) ||
|
|
1025
|
+
ts.isCallSignatureDeclaration(node)
|
|
1026
|
+
) {
|
|
1027
|
+
return node.type
|
|
1028
|
+
? createTypeSyntaxFromNode(
|
|
1029
|
+
node.type,
|
|
1030
|
+
sourceFile,
|
|
1031
|
+
nodeSpan(node.type, sourceFile, fallbackSpan),
|
|
1032
|
+
)
|
|
1033
|
+
: null;
|
|
1034
|
+
}
|
|
1035
|
+
return null;
|
|
1036
|
+
},
|
|
1037
|
+
hasExplicitType() {
|
|
1038
|
+
if (ts.isPropertySignature(node) || ts.isMethodSignature(node)) {
|
|
1039
|
+
return node.type !== undefined;
|
|
1040
|
+
}
|
|
1041
|
+
if (ts.isIndexSignatureDeclaration(node) || ts.isConstructSignatureDeclaration(node)) {
|
|
1042
|
+
return node.type !== undefined;
|
|
1043
|
+
}
|
|
1044
|
+
if (ts.isCallSignatureDeclaration(node)) {
|
|
1045
|
+
return node.type !== undefined;
|
|
1046
|
+
}
|
|
1047
|
+
return false;
|
|
1048
|
+
},
|
|
1049
|
+
isOptional() {
|
|
1050
|
+
return (
|
|
1051
|
+
(ts.isPropertySignature(node) || ts.isMethodSignature(node)) &&
|
|
1052
|
+
node.questionToken !== undefined
|
|
1053
|
+
);
|
|
1054
|
+
},
|
|
1055
|
+
kind: 'type_member',
|
|
1056
|
+
memberKind,
|
|
1057
|
+
name: 'name' in node ? typeElementNameText(node.name) : null,
|
|
1058
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1059
|
+
text() {
|
|
1060
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1061
|
+
},
|
|
1062
|
+
},
|
|
1063
|
+
node,
|
|
1064
|
+
sourceFile,
|
|
1065
|
+
ts.EmitHint.Unspecified,
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
function createTypeSyntaxFromNode(
|
|
1070
|
+
node: ts.TypeNode,
|
|
1071
|
+
sourceFile: ts.SourceFile,
|
|
1072
|
+
fallbackSpan: SourceSpan,
|
|
1073
|
+
): TypeSyntax {
|
|
1074
|
+
if (ts.isUnionTypeNode(node)) {
|
|
1075
|
+
const members = node.types.map((member) =>
|
|
1076
|
+
createTypeSyntaxFromNode(member, sourceFile, fallbackSpan)
|
|
1077
|
+
);
|
|
1078
|
+
let unionTypeSyntax!: MacroUnionTypeSyntax;
|
|
1079
|
+
unionTypeSyntax = withHostNode(
|
|
1080
|
+
{
|
|
1081
|
+
asLiteral() {
|
|
1082
|
+
return null;
|
|
1083
|
+
},
|
|
1084
|
+
asObjectLiteral() {
|
|
1085
|
+
return null;
|
|
1086
|
+
},
|
|
1087
|
+
asUnion() {
|
|
1088
|
+
return unionTypeSyntax;
|
|
1089
|
+
},
|
|
1090
|
+
kind: 'type',
|
|
1091
|
+
members,
|
|
1092
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1093
|
+
text() {
|
|
1094
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
node,
|
|
1098
|
+
sourceFile,
|
|
1099
|
+
ts.EmitHint.Unspecified,
|
|
1100
|
+
);
|
|
1101
|
+
return unionTypeSyntax;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
1105
|
+
const literal = (() => {
|
|
1106
|
+
if (ts.isStringLiteral(node.literal) || ts.isNoSubstitutionTemplateLiteral(node.literal)) {
|
|
1107
|
+
return {
|
|
1108
|
+
literalKind: 'string' as const,
|
|
1109
|
+
value: node.literal.text,
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
if (ts.isNumericLiteral(node.literal)) {
|
|
1113
|
+
return {
|
|
1114
|
+
literalKind: 'number' as const,
|
|
1115
|
+
value: Number(node.literal.text),
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
if (node.literal.kind === ts.SyntaxKind.TrueKeyword) {
|
|
1119
|
+
return {
|
|
1120
|
+
literalKind: 'boolean' as const,
|
|
1121
|
+
value: true,
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (node.literal.kind === ts.SyntaxKind.FalseKeyword) {
|
|
1125
|
+
return {
|
|
1126
|
+
literalKind: 'boolean' as const,
|
|
1127
|
+
value: false,
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
if (
|
|
1131
|
+
ts.isPrefixUnaryExpression(node.literal) &&
|
|
1132
|
+
node.literal.operator === ts.SyntaxKind.MinusToken &&
|
|
1133
|
+
ts.isNumericLiteral(node.literal.operand)
|
|
1134
|
+
) {
|
|
1135
|
+
return {
|
|
1136
|
+
literalKind: 'number' as const,
|
|
1137
|
+
value: -Number(node.literal.operand.text),
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
return null;
|
|
1141
|
+
})();
|
|
1142
|
+
|
|
1143
|
+
if (literal) {
|
|
1144
|
+
let literalTypeSyntax!: MacroLiteralTypeSyntax;
|
|
1145
|
+
literalTypeSyntax = withHostNode(
|
|
1146
|
+
{
|
|
1147
|
+
asLiteral() {
|
|
1148
|
+
return literalTypeSyntax;
|
|
1149
|
+
},
|
|
1150
|
+
asObjectLiteral() {
|
|
1151
|
+
return null;
|
|
1152
|
+
},
|
|
1153
|
+
asUnion() {
|
|
1154
|
+
return null;
|
|
1155
|
+
},
|
|
1156
|
+
kind: 'type',
|
|
1157
|
+
literalKind: literal.literalKind,
|
|
1158
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1159
|
+
text() {
|
|
1160
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1161
|
+
},
|
|
1162
|
+
value: literal.value,
|
|
1163
|
+
},
|
|
1164
|
+
node,
|
|
1165
|
+
sourceFile,
|
|
1166
|
+
ts.EmitHint.Unspecified,
|
|
1167
|
+
);
|
|
1168
|
+
return literalTypeSyntax;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
if (ts.isTypeLiteralNode(node)) {
|
|
1173
|
+
const members = node.members.map((member) =>
|
|
1174
|
+
createObjectTypeMemberSyntaxFromNode(member, sourceFile, fallbackSpan)
|
|
1175
|
+
);
|
|
1176
|
+
let objectTypeSyntax!: MacroObjectTypeSyntax;
|
|
1177
|
+
objectTypeSyntax = withHostNode(
|
|
1178
|
+
{
|
|
1179
|
+
asLiteral() {
|
|
1180
|
+
return null;
|
|
1181
|
+
},
|
|
1182
|
+
asObjectLiteral() {
|
|
1183
|
+
return objectTypeSyntax;
|
|
1184
|
+
},
|
|
1185
|
+
asUnion() {
|
|
1186
|
+
return null;
|
|
1187
|
+
},
|
|
1188
|
+
kind: 'type',
|
|
1189
|
+
members,
|
|
1190
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1191
|
+
text() {
|
|
1192
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1193
|
+
},
|
|
1194
|
+
},
|
|
1195
|
+
node,
|
|
1196
|
+
sourceFile,
|
|
1197
|
+
ts.EmitHint.Unspecified,
|
|
1198
|
+
);
|
|
1199
|
+
return objectTypeSyntax;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
return withHostNode(
|
|
1203
|
+
{
|
|
1204
|
+
asLiteral() {
|
|
1205
|
+
return null;
|
|
1206
|
+
},
|
|
1207
|
+
asObjectLiteral() {
|
|
1208
|
+
return null;
|
|
1209
|
+
},
|
|
1210
|
+
asUnion() {
|
|
1211
|
+
return null;
|
|
1212
|
+
},
|
|
1213
|
+
kind: 'type',
|
|
1214
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1215
|
+
text() {
|
|
1216
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1217
|
+
},
|
|
1218
|
+
},
|
|
1219
|
+
node,
|
|
1220
|
+
sourceFile,
|
|
1221
|
+
ts.EmitHint.Unspecified,
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
function createTypeSyntaxFromText(
|
|
1226
|
+
fileName: string,
|
|
1227
|
+
span: SourceSpan,
|
|
1228
|
+
text: string,
|
|
1229
|
+
): TypeSyntax {
|
|
1230
|
+
const sourceFile = ts.createSourceFile(
|
|
1231
|
+
fileName,
|
|
1232
|
+
`type __MacroType = ${text};`,
|
|
1233
|
+
ts.ScriptTarget.Latest,
|
|
1234
|
+
true,
|
|
1235
|
+
scriptKindForHostFile(fileName),
|
|
1236
|
+
);
|
|
1237
|
+
ensureNoParseDiagnostics(
|
|
1238
|
+
sourceFile,
|
|
1239
|
+
'Generated macro type syntax must parse as a valid type expression.',
|
|
1240
|
+
);
|
|
1241
|
+
const statement = sourceFile.statements[0];
|
|
1242
|
+
if (!statement || !ts.isTypeAliasDeclaration(statement)) {
|
|
1243
|
+
throw new Error('Generated macro type syntax must parse as a valid type expression.');
|
|
1244
|
+
}
|
|
1245
|
+
return createTypeSyntaxFromNode(
|
|
1246
|
+
statement.type,
|
|
1247
|
+
setSourceFileOffset(sourceFile, span.start - statement.type.getStart(sourceFile, false)),
|
|
1248
|
+
span,
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function createTypeParameterSyntaxFromNode(
|
|
1253
|
+
node: ts.TypeParameterDeclaration,
|
|
1254
|
+
sourceFile: ts.SourceFile,
|
|
1255
|
+
fallbackSpan: SourceSpan,
|
|
1256
|
+
): MacroTypeParameterSyntax {
|
|
1257
|
+
return withHostNode(
|
|
1258
|
+
{
|
|
1259
|
+
constraint() {
|
|
1260
|
+
return node.constraint
|
|
1261
|
+
? createTypeSyntaxFromNode(
|
|
1262
|
+
node.constraint,
|
|
1263
|
+
sourceFile,
|
|
1264
|
+
nodeSpan(node.constraint, sourceFile, fallbackSpan),
|
|
1265
|
+
)
|
|
1266
|
+
: null;
|
|
1267
|
+
},
|
|
1268
|
+
defaultType() {
|
|
1269
|
+
return node.default
|
|
1270
|
+
? createTypeSyntaxFromNode(
|
|
1271
|
+
node.default,
|
|
1272
|
+
sourceFile,
|
|
1273
|
+
nodeSpan(node.default, sourceFile, fallbackSpan),
|
|
1274
|
+
)
|
|
1275
|
+
: null;
|
|
1276
|
+
},
|
|
1277
|
+
kind: 'type_parameter',
|
|
1278
|
+
name: node.name.text,
|
|
1279
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1280
|
+
text() {
|
|
1281
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1282
|
+
},
|
|
1283
|
+
},
|
|
1284
|
+
node,
|
|
1285
|
+
sourceFile,
|
|
1286
|
+
ts.EmitHint.Unspecified,
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
function createParameterSyntaxFromNode(
|
|
1291
|
+
node: ts.ParameterDeclaration,
|
|
1292
|
+
sourceFile: ts.SourceFile,
|
|
1293
|
+
fallbackSpan: SourceSpan,
|
|
1294
|
+
): MacroParameterSyntax {
|
|
1295
|
+
function collectBindingIdentifiers(
|
|
1296
|
+
name: ts.BindingName,
|
|
1297
|
+
): readonly MacroBindingIdentifierSyntax[] {
|
|
1298
|
+
if (ts.isIdentifier(name)) {
|
|
1299
|
+
return [withHostNode(
|
|
1300
|
+
{
|
|
1301
|
+
kind: 'binding_identifier',
|
|
1302
|
+
name: name.text,
|
|
1303
|
+
span: nodeSpan(name, sourceFile, fallbackSpan),
|
|
1304
|
+
},
|
|
1305
|
+
name,
|
|
1306
|
+
sourceFile,
|
|
1307
|
+
ts.EmitHint.Unspecified,
|
|
1308
|
+
)];
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
const bindings: MacroBindingIdentifierSyntax[] = [];
|
|
1312
|
+
for (const element of name.elements) {
|
|
1313
|
+
if (!ts.isBindingElement(element)) {
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
bindings.push(...collectBindingIdentifiers(element.name));
|
|
1317
|
+
}
|
|
1318
|
+
return bindings;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
return withHostNode(
|
|
1322
|
+
{
|
|
1323
|
+
bindingIdentifiers() {
|
|
1324
|
+
return collectBindingIdentifiers(node.name);
|
|
1325
|
+
},
|
|
1326
|
+
explicitType() {
|
|
1327
|
+
return node.type ? createTypeSyntaxFromNode(node.type, sourceFile, fallbackSpan) : null;
|
|
1328
|
+
},
|
|
1329
|
+
hasDefault() {
|
|
1330
|
+
return node.initializer !== undefined;
|
|
1331
|
+
},
|
|
1332
|
+
hasExplicitType() {
|
|
1333
|
+
return node.type !== undefined;
|
|
1334
|
+
},
|
|
1335
|
+
isRest() {
|
|
1336
|
+
return node.dotDotDotToken !== undefined;
|
|
1337
|
+
},
|
|
1338
|
+
kind: 'parameter',
|
|
1339
|
+
name: ts.isIdentifier(node.name) ? node.name.text : null,
|
|
1340
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1341
|
+
text() {
|
|
1342
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1343
|
+
},
|
|
1344
|
+
},
|
|
1345
|
+
node,
|
|
1346
|
+
sourceFile,
|
|
1347
|
+
ts.EmitHint.Unspecified,
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
function createJsxTextSyntaxFromNode(
|
|
1352
|
+
node: ts.JsxText,
|
|
1353
|
+
sourceFile: ts.SourceFile,
|
|
1354
|
+
fallbackSpan: SourceSpan,
|
|
1355
|
+
): MacroJsxTextSyntax {
|
|
1356
|
+
return withHostNode(
|
|
1357
|
+
{
|
|
1358
|
+
kind: 'jsx_text',
|
|
1359
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1360
|
+
text() {
|
|
1361
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1362
|
+
},
|
|
1363
|
+
value: node.getText(sourceFile),
|
|
1364
|
+
},
|
|
1365
|
+
node,
|
|
1366
|
+
sourceFile,
|
|
1367
|
+
ts.EmitHint.Unspecified,
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
function createJsxExpressionSyntaxFromNode(
|
|
1372
|
+
node: ts.JsxExpression,
|
|
1373
|
+
sourceFile: ts.SourceFile,
|
|
1374
|
+
fallbackSpan: SourceSpan,
|
|
1375
|
+
): MacroJsxExpressionSyntax {
|
|
1376
|
+
return withHostNode(
|
|
1377
|
+
{
|
|
1378
|
+
kind: 'jsx_expr',
|
|
1379
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1380
|
+
expression() {
|
|
1381
|
+
return node.expression
|
|
1382
|
+
? createExprSyntaxFromNode(
|
|
1383
|
+
node.expression,
|
|
1384
|
+
sourceFile,
|
|
1385
|
+
nodeSpan(node.expression, sourceFile, fallbackSpan),
|
|
1386
|
+
)
|
|
1387
|
+
: null;
|
|
1388
|
+
},
|
|
1389
|
+
text() {
|
|
1390
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1391
|
+
},
|
|
1392
|
+
},
|
|
1393
|
+
node,
|
|
1394
|
+
sourceFile,
|
|
1395
|
+
ts.EmitHint.Unspecified,
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
function createJsxChildSyntaxFromNode(
|
|
1400
|
+
node: ts.JsxChild,
|
|
1401
|
+
sourceFile: ts.SourceFile,
|
|
1402
|
+
fallbackSpan: SourceSpan,
|
|
1403
|
+
): readonly MacroAnyJsxChildSyntax[] {
|
|
1404
|
+
if (ts.isJsxText(node)) {
|
|
1405
|
+
return [createJsxTextSyntaxFromNode(node, sourceFile, fallbackSpan)];
|
|
1406
|
+
}
|
|
1407
|
+
if (ts.isJsxExpression(node)) {
|
|
1408
|
+
return [createJsxExpressionSyntaxFromNode(node, sourceFile, fallbackSpan)];
|
|
1409
|
+
}
|
|
1410
|
+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
1411
|
+
return [createJsxElementSyntaxFromNode(node, sourceFile, fallbackSpan)];
|
|
1412
|
+
}
|
|
1413
|
+
if (ts.isJsxFragment(node)) {
|
|
1414
|
+
return [createJsxFragmentSyntaxFromNode(node, sourceFile, fallbackSpan)];
|
|
1415
|
+
}
|
|
1416
|
+
return [];
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
function createJsxChildren(
|
|
1420
|
+
children: readonly ts.JsxChild[],
|
|
1421
|
+
sourceFile: ts.SourceFile,
|
|
1422
|
+
fallbackSpan: SourceSpan,
|
|
1423
|
+
): readonly MacroAnyJsxChildSyntax[] {
|
|
1424
|
+
return children.flatMap((child) => createJsxChildSyntaxFromNode(child, sourceFile, fallbackSpan));
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
function createJsxAttributeSyntaxFromNode(
|
|
1428
|
+
node: ts.JsxAttribute,
|
|
1429
|
+
sourceFile: ts.SourceFile,
|
|
1430
|
+
fallbackSpan: SourceSpan,
|
|
1431
|
+
): MacroJsxAttributeSyntax {
|
|
1432
|
+
return withHostNode(
|
|
1433
|
+
{
|
|
1434
|
+
kind: 'jsx_attribute',
|
|
1435
|
+
name: ts.isIdentifier(node.name) ? node.name.text : node.name.getText(sourceFile),
|
|
1436
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1437
|
+
expression() {
|
|
1438
|
+
if (
|
|
1439
|
+
!node.initializer || !ts.isJsxExpression(node.initializer) || !node.initializer.expression
|
|
1440
|
+
) {
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
return createExprSyntaxFromNode(
|
|
1444
|
+
node.initializer.expression,
|
|
1445
|
+
sourceFile,
|
|
1446
|
+
nodeSpan(node.initializer.expression, sourceFile, fallbackSpan),
|
|
1447
|
+
);
|
|
1448
|
+
},
|
|
1449
|
+
stringValue() {
|
|
1450
|
+
return node.initializer && ts.isStringLiteral(node.initializer)
|
|
1451
|
+
? node.initializer.text
|
|
1452
|
+
: null;
|
|
1453
|
+
},
|
|
1454
|
+
text() {
|
|
1455
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1456
|
+
},
|
|
1457
|
+
},
|
|
1458
|
+
node,
|
|
1459
|
+
sourceFile,
|
|
1460
|
+
ts.EmitHint.Unspecified,
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
function createJsxSpreadAttributeSyntaxFromNode(
|
|
1465
|
+
node: ts.JsxSpreadAttribute,
|
|
1466
|
+
sourceFile: ts.SourceFile,
|
|
1467
|
+
fallbackSpan: SourceSpan,
|
|
1468
|
+
): MacroJsxSpreadAttributeSyntax {
|
|
1469
|
+
return withHostNode(
|
|
1470
|
+
{
|
|
1471
|
+
kind: 'jsx_spread_attribute',
|
|
1472
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1473
|
+
expression() {
|
|
1474
|
+
return createExprSyntaxFromNode(
|
|
1475
|
+
node.expression,
|
|
1476
|
+
sourceFile,
|
|
1477
|
+
nodeSpan(node.expression, sourceFile, fallbackSpan),
|
|
1478
|
+
);
|
|
1479
|
+
},
|
|
1480
|
+
text() {
|
|
1481
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1482
|
+
},
|
|
1483
|
+
},
|
|
1484
|
+
node,
|
|
1485
|
+
sourceFile,
|
|
1486
|
+
ts.EmitHint.Unspecified,
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
export function createJsxElementSyntaxFromNode(
|
|
1491
|
+
node: ts.JsxElement | ts.JsxSelfClosingElement,
|
|
1492
|
+
sourceFile: ts.SourceFile,
|
|
1493
|
+
fallbackSpan: SourceSpan,
|
|
1494
|
+
): MacroJsxElementSyntax {
|
|
1495
|
+
const opening = ts.isJsxElement(node) ? node.openingElement : node;
|
|
1496
|
+
const tagName = ts.isIdentifier(opening.tagName) ? opening.tagName.text : null;
|
|
1497
|
+
const attributes = () =>
|
|
1498
|
+
opening.attributes.properties.map((property): MacroAnyJsxAttributeSyntax =>
|
|
1499
|
+
ts.isJsxAttribute(property)
|
|
1500
|
+
? createJsxAttributeSyntaxFromNode(property, sourceFile, fallbackSpan)
|
|
1501
|
+
: createJsxSpreadAttributeSyntaxFromNode(property, sourceFile, fallbackSpan)
|
|
1502
|
+
);
|
|
1503
|
+
return withHostNode(
|
|
1504
|
+
{
|
|
1505
|
+
attribute(name: string) {
|
|
1506
|
+
return attributes().find((attribute) =>
|
|
1507
|
+
attribute.kind === 'jsx_attribute' && attribute.name === name
|
|
1508
|
+
) ?? null;
|
|
1509
|
+
},
|
|
1510
|
+
attributes,
|
|
1511
|
+
children() {
|
|
1512
|
+
if (ts.isJsxSelfClosingElement(node)) {
|
|
1513
|
+
return [];
|
|
1514
|
+
}
|
|
1515
|
+
return createJsxChildren(node.children, sourceFile, fallbackSpan);
|
|
1516
|
+
},
|
|
1517
|
+
kind: 'jsx_element',
|
|
1518
|
+
selfClosing: ts.isJsxSelfClosingElement(node),
|
|
1519
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1520
|
+
tagName,
|
|
1521
|
+
text() {
|
|
1522
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1523
|
+
},
|
|
1524
|
+
},
|
|
1525
|
+
node,
|
|
1526
|
+
sourceFile,
|
|
1527
|
+
ts.EmitHint.Unspecified,
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
function createJsxFragmentSyntaxFromNode(
|
|
1532
|
+
node: ts.JsxFragment,
|
|
1533
|
+
sourceFile: ts.SourceFile,
|
|
1534
|
+
fallbackSpan: SourceSpan,
|
|
1535
|
+
): MacroJsxFragmentSyntax {
|
|
1536
|
+
return withHostNode(
|
|
1537
|
+
{
|
|
1538
|
+
children() {
|
|
1539
|
+
return createJsxChildren(node.children, sourceFile, fallbackSpan);
|
|
1540
|
+
},
|
|
1541
|
+
kind: 'jsx_fragment',
|
|
1542
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1543
|
+
text() {
|
|
1544
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1545
|
+
},
|
|
1546
|
+
},
|
|
1547
|
+
node,
|
|
1548
|
+
sourceFile,
|
|
1549
|
+
ts.EmitHint.Unspecified,
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
function createFunctionExprSyntaxFromNode(
|
|
1554
|
+
node: ts.ArrowFunction | ts.FunctionExpression,
|
|
1555
|
+
sourceFile: ts.SourceFile,
|
|
1556
|
+
fallbackSpan: SourceSpan,
|
|
1557
|
+
): MacroFunctionExprSyntax {
|
|
1558
|
+
const span = nodeSpan(node, sourceFile, fallbackSpan);
|
|
1559
|
+
const syntax: MacroFunctionExprSyntax = withHostNode(
|
|
1560
|
+
{
|
|
1561
|
+
asArrayLiteral() {
|
|
1562
|
+
return null;
|
|
1563
|
+
},
|
|
1564
|
+
asBinary() {
|
|
1565
|
+
return null;
|
|
1566
|
+
},
|
|
1567
|
+
asCall() {
|
|
1568
|
+
return null;
|
|
1569
|
+
},
|
|
1570
|
+
asConditional() {
|
|
1571
|
+
return null;
|
|
1572
|
+
},
|
|
1573
|
+
asFunction() {
|
|
1574
|
+
return syntax;
|
|
1575
|
+
},
|
|
1576
|
+
asIdentifier() {
|
|
1577
|
+
return null;
|
|
1578
|
+
},
|
|
1579
|
+
asInvocation() {
|
|
1580
|
+
return null;
|
|
1581
|
+
},
|
|
1582
|
+
asJsxElement() {
|
|
1583
|
+
return null;
|
|
1584
|
+
},
|
|
1585
|
+
asJsxFragment() {
|
|
1586
|
+
return null;
|
|
1587
|
+
},
|
|
1588
|
+
asPropertyAccess() {
|
|
1589
|
+
return null;
|
|
1590
|
+
},
|
|
1591
|
+
body() {
|
|
1592
|
+
return ts.isBlock(node.body)
|
|
1593
|
+
? createBlockSyntaxFromNode(node.body, sourceFile, nodeSpan(node.body, sourceFile, span))
|
|
1594
|
+
: null;
|
|
1595
|
+
},
|
|
1596
|
+
containsCallNamed(name: string) {
|
|
1597
|
+
return containsCallNamed(node, name);
|
|
1598
|
+
},
|
|
1599
|
+
functionKind: ts.isArrowFunction(node) ? 'arrow' : 'function',
|
|
1600
|
+
hasAsyncModifier() {
|
|
1601
|
+
return node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ??
|
|
1602
|
+
false;
|
|
1603
|
+
},
|
|
1604
|
+
isBooleanLiteral() {
|
|
1605
|
+
return false;
|
|
1606
|
+
},
|
|
1607
|
+
isNullLiteral() {
|
|
1608
|
+
return false;
|
|
1609
|
+
},
|
|
1610
|
+
kind: 'expr',
|
|
1611
|
+
parameters: node.parameters.map((parameter) =>
|
|
1612
|
+
createParameterSyntaxFromNode(parameter, sourceFile, nodeSpan(parameter, sourceFile, span))
|
|
1613
|
+
),
|
|
1614
|
+
replaceThis(replacement: ExprSyntax) {
|
|
1615
|
+
return createExprSyntaxFromNode(replaceThisNode(node, replacement), sourceFile, span);
|
|
1616
|
+
},
|
|
1617
|
+
rewrite(options: MacroSyntaxRewriteOptions) {
|
|
1618
|
+
return rewriteExprSyntax(node, sourceFile, span, options);
|
|
1619
|
+
},
|
|
1620
|
+
returnedExpr() {
|
|
1621
|
+
if (ts.isBlock(node.body)) {
|
|
1622
|
+
if (node.body.statements.length !== 1) {
|
|
1623
|
+
return null;
|
|
1624
|
+
}
|
|
1625
|
+
const [statement] = node.body.statements;
|
|
1626
|
+
if (!statement || !ts.isReturnStatement(statement) || !statement.expression) {
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
return createExprSyntaxFromNode(
|
|
1630
|
+
statement.expression,
|
|
1631
|
+
sourceFile,
|
|
1632
|
+
nodeSpan(statement.expression, sourceFile, span),
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
return createExprSyntaxFromNode(
|
|
1636
|
+
node.body,
|
|
1637
|
+
sourceFile,
|
|
1638
|
+
nodeSpan(node.body, sourceFile, span),
|
|
1639
|
+
);
|
|
1640
|
+
},
|
|
1641
|
+
returnedJsx() {
|
|
1642
|
+
return syntax.returnedExpr()?.asJsxElement() ?? null;
|
|
1643
|
+
},
|
|
1644
|
+
span,
|
|
1645
|
+
text() {
|
|
1646
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Expression);
|
|
1647
|
+
},
|
|
1648
|
+
thisMemberReferences() {
|
|
1649
|
+
return collectThisMemberReferences(node);
|
|
1650
|
+
},
|
|
1651
|
+
typeParameterCount() {
|
|
1652
|
+
return node.typeParameters?.length ?? 0;
|
|
1653
|
+
},
|
|
1654
|
+
unparenthesized() {
|
|
1655
|
+
return syntax;
|
|
1656
|
+
},
|
|
1657
|
+
},
|
|
1658
|
+
node,
|
|
1659
|
+
sourceFile,
|
|
1660
|
+
ts.EmitHint.Expression,
|
|
1661
|
+
);
|
|
1662
|
+
return syntax;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
function createClassFieldSyntaxFromNode(
|
|
1666
|
+
node: ts.PropertyDeclaration,
|
|
1667
|
+
sourceFile: ts.SourceFile,
|
|
1668
|
+
fallbackSpan: SourceSpan,
|
|
1669
|
+
): MacroClassFieldSyntax {
|
|
1670
|
+
return withHostNode(
|
|
1671
|
+
{
|
|
1672
|
+
explicitType() {
|
|
1673
|
+
return node.type
|
|
1674
|
+
? createTypeSyntaxFromNode(
|
|
1675
|
+
node.type,
|
|
1676
|
+
sourceFile,
|
|
1677
|
+
nodeSpan(node.type, sourceFile, fallbackSpan),
|
|
1678
|
+
)
|
|
1679
|
+
: null;
|
|
1680
|
+
},
|
|
1681
|
+
hasExplicitType() {
|
|
1682
|
+
return node.type !== undefined;
|
|
1683
|
+
},
|
|
1684
|
+
hasModifier(name: MacroModifierName) {
|
|
1685
|
+
return hasModifier(node, name);
|
|
1686
|
+
},
|
|
1687
|
+
initializer() {
|
|
1688
|
+
return node.initializer
|
|
1689
|
+
? createExprSyntaxFromNode(
|
|
1690
|
+
node.initializer,
|
|
1691
|
+
sourceFile,
|
|
1692
|
+
nodeSpan(node.initializer, sourceFile, fallbackSpan),
|
|
1693
|
+
)
|
|
1694
|
+
: null;
|
|
1695
|
+
},
|
|
1696
|
+
isOptional() {
|
|
1697
|
+
return node.questionToken !== undefined;
|
|
1698
|
+
},
|
|
1699
|
+
kind: 'class_member',
|
|
1700
|
+
memberKind: 'field',
|
|
1701
|
+
name: ts.isIdentifier(node.name) ? node.name.text : null,
|
|
1702
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1703
|
+
text() {
|
|
1704
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1705
|
+
},
|
|
1706
|
+
withInitializer(initializer: ExprSyntax | null) {
|
|
1707
|
+
return createClassFieldSyntaxFromNode(
|
|
1708
|
+
ts.factory.updatePropertyDeclaration(
|
|
1709
|
+
node,
|
|
1710
|
+
node.modifiers,
|
|
1711
|
+
node.name,
|
|
1712
|
+
node.questionToken ?? node.exclamationToken,
|
|
1713
|
+
node.type,
|
|
1714
|
+
initializer ? getHostExpression(initializer) : undefined,
|
|
1715
|
+
),
|
|
1716
|
+
sourceFile,
|
|
1717
|
+
fallbackSpan,
|
|
1718
|
+
);
|
|
1719
|
+
},
|
|
1720
|
+
},
|
|
1721
|
+
node,
|
|
1722
|
+
sourceFile,
|
|
1723
|
+
ts.EmitHint.Unspecified,
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
function createClassMethodSyntaxFromNode(
|
|
1728
|
+
node: ts.MethodDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration,
|
|
1729
|
+
sourceFile: ts.SourceFile,
|
|
1730
|
+
fallbackSpan: SourceSpan,
|
|
1731
|
+
): MacroClassMethodSyntax {
|
|
1732
|
+
return withHostNode(
|
|
1733
|
+
{
|
|
1734
|
+
body() {
|
|
1735
|
+
return node.body
|
|
1736
|
+
? createBlockSyntaxFromNode(
|
|
1737
|
+
node.body,
|
|
1738
|
+
sourceFile,
|
|
1739
|
+
nodeSpan(node.body, sourceFile, fallbackSpan),
|
|
1740
|
+
)
|
|
1741
|
+
: null;
|
|
1742
|
+
},
|
|
1743
|
+
hasModifier(name: MacroModifierName) {
|
|
1744
|
+
return hasModifier(node, name);
|
|
1745
|
+
},
|
|
1746
|
+
kind: 'class_member',
|
|
1747
|
+
memberKind: ts.isGetAccessorDeclaration(node)
|
|
1748
|
+
? 'getter'
|
|
1749
|
+
: ts.isSetAccessorDeclaration(node)
|
|
1750
|
+
? 'setter'
|
|
1751
|
+
: 'method',
|
|
1752
|
+
name: ts.isIdentifier(node.name) ? node.name.text : null,
|
|
1753
|
+
parameters: node.parameters.map((parameter) =>
|
|
1754
|
+
createParameterSyntaxFromNode(parameter, sourceFile, fallbackSpan)
|
|
1755
|
+
),
|
|
1756
|
+
returnedExpr() {
|
|
1757
|
+
const returned = returnedExprNode(node);
|
|
1758
|
+
return returned
|
|
1759
|
+
? createExprSyntaxFromNode(
|
|
1760
|
+
returned,
|
|
1761
|
+
sourceFile,
|
|
1762
|
+
nodeSpan(returned, sourceFile, fallbackSpan),
|
|
1763
|
+
)
|
|
1764
|
+
: null;
|
|
1765
|
+
},
|
|
1766
|
+
returnedJsx() {
|
|
1767
|
+
const jsx = returnedJsxNode(node);
|
|
1768
|
+
return jsx
|
|
1769
|
+
? createJsxElementSyntaxFromNode(jsx, sourceFile, nodeSpan(jsx, sourceFile, fallbackSpan))
|
|
1770
|
+
: null;
|
|
1771
|
+
},
|
|
1772
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1773
|
+
text() {
|
|
1774
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1775
|
+
},
|
|
1776
|
+
withBody(body: BlockSyntax) {
|
|
1777
|
+
const hostBody = getHostBlock(body);
|
|
1778
|
+
const updated = ts.isGetAccessorDeclaration(node)
|
|
1779
|
+
? ts.factory.updateGetAccessorDeclaration(
|
|
1780
|
+
node,
|
|
1781
|
+
node.modifiers,
|
|
1782
|
+
node.name,
|
|
1783
|
+
node.parameters,
|
|
1784
|
+
node.type,
|
|
1785
|
+
hostBody,
|
|
1786
|
+
)
|
|
1787
|
+
: ts.isSetAccessorDeclaration(node)
|
|
1788
|
+
? ts.factory.updateSetAccessorDeclaration(
|
|
1789
|
+
node,
|
|
1790
|
+
node.modifiers,
|
|
1791
|
+
node.name,
|
|
1792
|
+
node.parameters,
|
|
1793
|
+
hostBody,
|
|
1794
|
+
)
|
|
1795
|
+
: ts.factory.updateMethodDeclaration(
|
|
1796
|
+
node,
|
|
1797
|
+
node.modifiers,
|
|
1798
|
+
node.asteriskToken,
|
|
1799
|
+
node.name,
|
|
1800
|
+
node.questionToken,
|
|
1801
|
+
node.typeParameters,
|
|
1802
|
+
node.parameters,
|
|
1803
|
+
node.type,
|
|
1804
|
+
hostBody,
|
|
1805
|
+
);
|
|
1806
|
+
return createClassMethodSyntaxFromNode(updated, sourceFile, fallbackSpan);
|
|
1807
|
+
},
|
|
1808
|
+
},
|
|
1809
|
+
node,
|
|
1810
|
+
sourceFile,
|
|
1811
|
+
ts.EmitHint.Unspecified,
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
function createClassConstructorSyntaxFromNode(
|
|
1816
|
+
node: ts.ConstructorDeclaration,
|
|
1817
|
+
sourceFile: ts.SourceFile,
|
|
1818
|
+
fallbackSpan: SourceSpan,
|
|
1819
|
+
): MacroClassConstructorSyntax {
|
|
1820
|
+
return withHostNode(
|
|
1821
|
+
{
|
|
1822
|
+
body() {
|
|
1823
|
+
return node.body
|
|
1824
|
+
? createBlockSyntaxFromNode(
|
|
1825
|
+
node.body,
|
|
1826
|
+
sourceFile,
|
|
1827
|
+
nodeSpan(node.body, sourceFile, fallbackSpan),
|
|
1828
|
+
)
|
|
1829
|
+
: null;
|
|
1830
|
+
},
|
|
1831
|
+
hasModifier(name: MacroModifierName) {
|
|
1832
|
+
return hasModifier(node, name);
|
|
1833
|
+
},
|
|
1834
|
+
kind: 'class_member',
|
|
1835
|
+
memberKind: 'constructor',
|
|
1836
|
+
name: null,
|
|
1837
|
+
parameters: node.parameters.map((parameter) =>
|
|
1838
|
+
createParameterSyntaxFromNode(parameter, sourceFile, fallbackSpan)
|
|
1839
|
+
),
|
|
1840
|
+
span: nodeSpan(node, sourceFile, fallbackSpan),
|
|
1841
|
+
text() {
|
|
1842
|
+
return printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
1843
|
+
},
|
|
1844
|
+
withBody(body: BlockSyntax) {
|
|
1845
|
+
return createClassConstructorSyntaxFromNode(
|
|
1846
|
+
ts.factory.updateConstructorDeclaration(
|
|
1847
|
+
node,
|
|
1848
|
+
node.modifiers,
|
|
1849
|
+
node.parameters,
|
|
1850
|
+
getHostBlock(body),
|
|
1851
|
+
),
|
|
1852
|
+
sourceFile,
|
|
1853
|
+
fallbackSpan,
|
|
1854
|
+
);
|
|
1855
|
+
},
|
|
1856
|
+
},
|
|
1857
|
+
node,
|
|
1858
|
+
sourceFile,
|
|
1859
|
+
ts.EmitHint.Unspecified,
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
function createClassMemberSyntaxFromNode(
|
|
1864
|
+
node: ts.ClassElement,
|
|
1865
|
+
sourceFile: ts.SourceFile,
|
|
1866
|
+
fallbackSpan: SourceSpan,
|
|
1867
|
+
): MacroAnyClassMemberSyntax | null {
|
|
1868
|
+
if (ts.isPropertyDeclaration(node)) {
|
|
1869
|
+
return createClassFieldSyntaxFromNode(node, sourceFile, fallbackSpan);
|
|
1870
|
+
}
|
|
1871
|
+
if (
|
|
1872
|
+
ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) ||
|
|
1873
|
+
ts.isSetAccessorDeclaration(node)
|
|
1874
|
+
) {
|
|
1875
|
+
return createClassMethodSyntaxFromNode(node, sourceFile, fallbackSpan);
|
|
1876
|
+
}
|
|
1877
|
+
if (ts.isConstructorDeclaration(node)) {
|
|
1878
|
+
return createClassConstructorSyntaxFromNode(node, sourceFile, fallbackSpan);
|
|
1879
|
+
}
|
|
1880
|
+
return null;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
export function createExprSyntaxFromNode(
|
|
1884
|
+
node: ts.Expression,
|
|
1885
|
+
sourceFile: ts.SourceFile,
|
|
1886
|
+
span: SourceSpan,
|
|
1887
|
+
text?: string,
|
|
1888
|
+
): ExprSyntax {
|
|
1889
|
+
const unwrapped = unwrapParenthesizedExpressionNode(node);
|
|
1890
|
+
if (ts.isArrowFunction(unwrapped) || ts.isFunctionExpression(unwrapped)) {
|
|
1891
|
+
return createFunctionExprSyntaxFromNode(unwrapped, sourceFile, span);
|
|
1892
|
+
}
|
|
1893
|
+
return withHostNode(
|
|
1894
|
+
{
|
|
1895
|
+
asArrayLiteral() {
|
|
1896
|
+
return expressionAsArrayLiteral(node, sourceFile, span);
|
|
1897
|
+
},
|
|
1898
|
+
asBinary() {
|
|
1899
|
+
return expressionAsBinary(node, sourceFile, span);
|
|
1900
|
+
},
|
|
1901
|
+
asCall() {
|
|
1902
|
+
return expressionAsCall(node, sourceFile, span);
|
|
1903
|
+
},
|
|
1904
|
+
asConditional() {
|
|
1905
|
+
return expressionAsConditional(node, sourceFile, span);
|
|
1906
|
+
},
|
|
1907
|
+
asFunction() {
|
|
1908
|
+
return null;
|
|
1909
|
+
},
|
|
1910
|
+
asIdentifier() {
|
|
1911
|
+
return expressionAsIdentifier(node);
|
|
1912
|
+
},
|
|
1913
|
+
asInvocation() {
|
|
1914
|
+
return expressionAsInvocation(
|
|
1915
|
+
span.fileName,
|
|
1916
|
+
span,
|
|
1917
|
+
text ?? printHostNode(node, sourceFile, ts.EmitHint.Expression),
|
|
1918
|
+
);
|
|
1919
|
+
},
|
|
1920
|
+
asJsxElement() {
|
|
1921
|
+
return expressionAsJsxElement(node, sourceFile, span);
|
|
1922
|
+
},
|
|
1923
|
+
asJsxFragment() {
|
|
1924
|
+
return expressionAsJsxFragment(node, sourceFile, span);
|
|
1925
|
+
},
|
|
1926
|
+
asPropertyAccess() {
|
|
1927
|
+
return expressionAsPropertyAccess(node, sourceFile, span);
|
|
1928
|
+
},
|
|
1929
|
+
containsCallNamed(name: string) {
|
|
1930
|
+
return containsCallNamed(node, name);
|
|
1931
|
+
},
|
|
1932
|
+
isBooleanLiteral(value: boolean) {
|
|
1933
|
+
const current = unwrapParenthesizedExpressionNode(node);
|
|
1934
|
+
return value
|
|
1935
|
+
? current.kind === ts.SyntaxKind.TrueKeyword
|
|
1936
|
+
: current.kind === ts.SyntaxKind.FalseKeyword;
|
|
1937
|
+
},
|
|
1938
|
+
isNullLiteral() {
|
|
1939
|
+
return unwrapParenthesizedExpressionNode(node).kind === ts.SyntaxKind.NullKeyword;
|
|
1940
|
+
},
|
|
1941
|
+
kind: 'expr',
|
|
1942
|
+
replaceThis(replacement: ExprSyntax) {
|
|
1943
|
+
return createExprSyntaxFromNode(
|
|
1944
|
+
replaceThisNode(node, replacement),
|
|
1945
|
+
sourceFile,
|
|
1946
|
+
span,
|
|
1947
|
+
);
|
|
1948
|
+
},
|
|
1949
|
+
rewrite(options: MacroSyntaxRewriteOptions) {
|
|
1950
|
+
return rewriteExprSyntax(node, sourceFile, span, options);
|
|
1951
|
+
},
|
|
1952
|
+
span,
|
|
1953
|
+
text() {
|
|
1954
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Expression);
|
|
1955
|
+
},
|
|
1956
|
+
thisMemberReferences() {
|
|
1957
|
+
return collectThisMemberReferences(node);
|
|
1958
|
+
},
|
|
1959
|
+
unparenthesized() {
|
|
1960
|
+
return createExprSyntaxFromNode(unwrapParenthesizedExpressionNode(node), sourceFile, span);
|
|
1961
|
+
},
|
|
1962
|
+
},
|
|
1963
|
+
node,
|
|
1964
|
+
sourceFile,
|
|
1965
|
+
ts.EmitHint.Expression,
|
|
1966
|
+
);
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
export function createBareExprSyntax(
|
|
1970
|
+
span: SourceSpan,
|
|
1971
|
+
text: string,
|
|
1972
|
+
): ExprSyntax {
|
|
1973
|
+
return {
|
|
1974
|
+
asArrayLiteral() {
|
|
1975
|
+
return null;
|
|
1976
|
+
},
|
|
1977
|
+
asBinary() {
|
|
1978
|
+
return null;
|
|
1979
|
+
},
|
|
1980
|
+
asCall() {
|
|
1981
|
+
return null;
|
|
1982
|
+
},
|
|
1983
|
+
asConditional() {
|
|
1984
|
+
return null;
|
|
1985
|
+
},
|
|
1986
|
+
asFunction() {
|
|
1987
|
+
return null;
|
|
1988
|
+
},
|
|
1989
|
+
asIdentifier() {
|
|
1990
|
+
return null;
|
|
1991
|
+
},
|
|
1992
|
+
asInvocation() {
|
|
1993
|
+
return expressionAsInvocation(span.fileName, span, text);
|
|
1994
|
+
},
|
|
1995
|
+
asJsxElement() {
|
|
1996
|
+
return null;
|
|
1997
|
+
},
|
|
1998
|
+
asJsxFragment() {
|
|
1999
|
+
return null;
|
|
2000
|
+
},
|
|
2001
|
+
asPropertyAccess() {
|
|
2002
|
+
return null;
|
|
2003
|
+
},
|
|
2004
|
+
containsCallNamed() {
|
|
2005
|
+
return false;
|
|
2006
|
+
},
|
|
2007
|
+
isBooleanLiteral() {
|
|
2008
|
+
return false;
|
|
2009
|
+
},
|
|
2010
|
+
isNullLiteral() {
|
|
2011
|
+
return false;
|
|
2012
|
+
},
|
|
2013
|
+
kind: 'expr',
|
|
2014
|
+
replaceThis() {
|
|
2015
|
+
return this;
|
|
2016
|
+
},
|
|
2017
|
+
rewrite() {
|
|
2018
|
+
return this;
|
|
2019
|
+
},
|
|
2020
|
+
span,
|
|
2021
|
+
text() {
|
|
2022
|
+
return text;
|
|
2023
|
+
},
|
|
2024
|
+
thisMemberReferences() {
|
|
2025
|
+
return [];
|
|
2026
|
+
},
|
|
2027
|
+
unparenthesized() {
|
|
2028
|
+
return this;
|
|
2029
|
+
},
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
export function createArgumentSyntax(
|
|
2034
|
+
index: number,
|
|
2035
|
+
node: ts.Expression,
|
|
2036
|
+
sourceFile: ts.SourceFile,
|
|
2037
|
+
span: SourceSpan,
|
|
2038
|
+
text: string,
|
|
2039
|
+
): MacroArgumentView {
|
|
2040
|
+
return withHostNode(
|
|
2041
|
+
{
|
|
2042
|
+
asArrayLiteral() {
|
|
2043
|
+
return expressionAsArrayLiteral(node, sourceFile, span);
|
|
2044
|
+
},
|
|
2045
|
+
asBinary() {
|
|
2046
|
+
return expressionAsBinary(node, sourceFile, span);
|
|
2047
|
+
},
|
|
2048
|
+
asCall() {
|
|
2049
|
+
return expressionAsCall(node, sourceFile, span);
|
|
2050
|
+
},
|
|
2051
|
+
asConditional() {
|
|
2052
|
+
return expressionAsConditional(node, sourceFile, span);
|
|
2053
|
+
},
|
|
2054
|
+
asFunction() {
|
|
2055
|
+
const current = unwrapParenthesizedExpressionNode(node);
|
|
2056
|
+
return ts.isArrowFunction(current) || ts.isFunctionExpression(current)
|
|
2057
|
+
? createFunctionExprSyntaxFromNode(current, sourceFile, span)
|
|
2058
|
+
: null;
|
|
2059
|
+
},
|
|
2060
|
+
asIdentifier() {
|
|
2061
|
+
return expressionAsIdentifier(node);
|
|
2062
|
+
},
|
|
2063
|
+
asInvocation() {
|
|
2064
|
+
return expressionAsInvocation(span.fileName, span, text);
|
|
2065
|
+
},
|
|
2066
|
+
asJsxElement() {
|
|
2067
|
+
return expressionAsJsxElement(node, sourceFile, span);
|
|
2068
|
+
},
|
|
2069
|
+
asJsxFragment() {
|
|
2070
|
+
return expressionAsJsxFragment(node, sourceFile, span);
|
|
2071
|
+
},
|
|
2072
|
+
asPropertyAccess() {
|
|
2073
|
+
return expressionAsPropertyAccess(node, sourceFile, span);
|
|
2074
|
+
},
|
|
2075
|
+
containsCallNamed(name: string) {
|
|
2076
|
+
return containsCallNamed(node, name);
|
|
2077
|
+
},
|
|
2078
|
+
index,
|
|
2079
|
+
isBooleanLiteral(value: boolean) {
|
|
2080
|
+
const current = unwrapParenthesizedExpressionNode(node);
|
|
2081
|
+
return value
|
|
2082
|
+
? current.kind === ts.SyntaxKind.TrueKeyword
|
|
2083
|
+
: current.kind === ts.SyntaxKind.FalseKeyword;
|
|
2084
|
+
},
|
|
2085
|
+
isNullLiteral() {
|
|
2086
|
+
return unwrapParenthesizedExpressionNode(node).kind === ts.SyntaxKind.NullKeyword;
|
|
2087
|
+
},
|
|
2088
|
+
kind: 'expr',
|
|
2089
|
+
replaceThis(replacement: ExprSyntax) {
|
|
2090
|
+
return createExprSyntaxFromNode(
|
|
2091
|
+
replaceThisNode(node, replacement),
|
|
2092
|
+
sourceFile,
|
|
2093
|
+
span,
|
|
2094
|
+
);
|
|
2095
|
+
},
|
|
2096
|
+
rewrite(options: MacroSyntaxRewriteOptions) {
|
|
2097
|
+
return rewriteExprSyntax(node, sourceFile, span, options);
|
|
2098
|
+
},
|
|
2099
|
+
span,
|
|
2100
|
+
text() {
|
|
2101
|
+
return text;
|
|
2102
|
+
},
|
|
2103
|
+
thisMemberReferences() {
|
|
2104
|
+
return collectThisMemberReferences(node);
|
|
2105
|
+
},
|
|
2106
|
+
unparenthesized() {
|
|
2107
|
+
return createExprSyntaxFromNode(unwrapParenthesizedExpressionNode(node), sourceFile, span);
|
|
2108
|
+
},
|
|
2109
|
+
},
|
|
2110
|
+
node,
|
|
2111
|
+
sourceFile,
|
|
2112
|
+
ts.EmitHint.Expression,
|
|
2113
|
+
);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
export function createBareArgumentSyntax(
|
|
2117
|
+
index: number,
|
|
2118
|
+
span: SourceSpan,
|
|
2119
|
+
text: string,
|
|
2120
|
+
): MacroArgumentView {
|
|
2121
|
+
const expr = createBareExprSyntax(span, text);
|
|
2122
|
+
return {
|
|
2123
|
+
asArrayLiteral: expr.asArrayLiteral,
|
|
2124
|
+
asBinary: expr.asBinary,
|
|
2125
|
+
asCall: expr.asCall,
|
|
2126
|
+
asConditional: expr.asConditional,
|
|
2127
|
+
asFunction: expr.asFunction,
|
|
2128
|
+
asIdentifier: expr.asIdentifier,
|
|
2129
|
+
asInvocation: expr.asInvocation,
|
|
2130
|
+
asJsxElement: expr.asJsxElement,
|
|
2131
|
+
asJsxFragment: expr.asJsxFragment,
|
|
2132
|
+
asPropertyAccess: expr.asPropertyAccess,
|
|
2133
|
+
containsCallNamed: expr.containsCallNamed,
|
|
2134
|
+
index,
|
|
2135
|
+
isBooleanLiteral: expr.isBooleanLiteral,
|
|
2136
|
+
isNullLiteral: expr.isNullLiteral,
|
|
2137
|
+
kind: 'expr',
|
|
2138
|
+
replaceThis: expr.replaceThis,
|
|
2139
|
+
rewrite: expr.rewrite,
|
|
2140
|
+
span,
|
|
2141
|
+
text() {
|
|
2142
|
+
return text;
|
|
2143
|
+
},
|
|
2144
|
+
thisMemberReferences: expr.thisMemberReferences,
|
|
2145
|
+
unparenthesized: expr.unparenthesized,
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
function parseHostExpressionWithNestedMacroFallback(
|
|
2150
|
+
fileName: string,
|
|
2151
|
+
text: string,
|
|
2152
|
+
message: string,
|
|
2153
|
+
): ts.Expression {
|
|
2154
|
+
try {
|
|
2155
|
+
return parseHostExpression(fileName, text, message);
|
|
2156
|
+
} catch {
|
|
2157
|
+
return parseHostExpression(
|
|
2158
|
+
fileName,
|
|
2159
|
+
neutralizeNestedMacrosForHostParse(fileName, text),
|
|
2160
|
+
message,
|
|
2161
|
+
);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
export function createArgumentSyntaxFromText(
|
|
2166
|
+
index: number,
|
|
2167
|
+
fileName: string,
|
|
2168
|
+
span: SourceSpan,
|
|
2169
|
+
text: string,
|
|
2170
|
+
): MacroArgumentView {
|
|
2171
|
+
try {
|
|
2172
|
+
const node = parseHostExpressionWithNestedMacroFallback(
|
|
2173
|
+
fileName,
|
|
2174
|
+
text,
|
|
2175
|
+
'Macro expression operands must parse as exactly one host-language expression.',
|
|
2176
|
+
);
|
|
2177
|
+
const sourceFile = setSourceFileOffset(
|
|
2178
|
+
node.getSourceFile(),
|
|
2179
|
+
span.start - node.getStart(node.getSourceFile(), false),
|
|
2180
|
+
);
|
|
2181
|
+
return createArgumentSyntax(index, node, sourceFile, span, text);
|
|
2182
|
+
} catch {
|
|
2183
|
+
return createBareArgumentSyntax(index, span, text);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
export function createStmtSyntaxFromNode(
|
|
2188
|
+
node: ts.Statement,
|
|
2189
|
+
sourceFile: ts.SourceFile,
|
|
2190
|
+
span: SourceSpan,
|
|
2191
|
+
text?: string,
|
|
2192
|
+
): StmtSyntax {
|
|
2193
|
+
return withHostNode(
|
|
2194
|
+
{
|
|
2195
|
+
kind: 'stmt',
|
|
2196
|
+
span,
|
|
2197
|
+
text() {
|
|
2198
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2199
|
+
},
|
|
2200
|
+
},
|
|
2201
|
+
node,
|
|
2202
|
+
sourceFile,
|
|
2203
|
+
ts.EmitHint.Unspecified,
|
|
2204
|
+
);
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
export function createBlockSyntaxFromNode(
|
|
2208
|
+
node: ts.Block,
|
|
2209
|
+
sourceFile: ts.SourceFile,
|
|
2210
|
+
span: SourceSpan,
|
|
2211
|
+
text?: string,
|
|
2212
|
+
): BlockSyntax {
|
|
2213
|
+
return withHostNode(
|
|
2214
|
+
{
|
|
2215
|
+
containsCallNamed(name: string) {
|
|
2216
|
+
return containsCallNamed(node, name);
|
|
2217
|
+
},
|
|
2218
|
+
kind: 'block',
|
|
2219
|
+
replaceThis(replacement: ExprSyntax) {
|
|
2220
|
+
return createBlockSyntaxFromNode(
|
|
2221
|
+
replaceThisNode(node, replacement),
|
|
2222
|
+
sourceFile,
|
|
2223
|
+
span,
|
|
2224
|
+
);
|
|
2225
|
+
},
|
|
2226
|
+
rewrite(options: MacroSyntaxRewriteOptions) {
|
|
2227
|
+
return rewriteBlockSyntax(node, sourceFile, span, options);
|
|
2228
|
+
},
|
|
2229
|
+
span,
|
|
2230
|
+
statements: node.statements.map((statement) =>
|
|
2231
|
+
createStmtSyntaxFromNode(statement, sourceFile, span)
|
|
2232
|
+
),
|
|
2233
|
+
text() {
|
|
2234
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2235
|
+
},
|
|
2236
|
+
thisMemberReferences() {
|
|
2237
|
+
return collectThisMemberReferences(node);
|
|
2238
|
+
},
|
|
2239
|
+
},
|
|
2240
|
+
node,
|
|
2241
|
+
sourceFile,
|
|
2242
|
+
ts.EmitHint.Unspecified,
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
export function buildBlockSyntax(
|
|
2247
|
+
fileName: string,
|
|
2248
|
+
statements: readonly StmtSyntax[],
|
|
2249
|
+
): BlockSyntax {
|
|
2250
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
2251
|
+
const block = synthesizeHostNode(ts.factory.createBlock(
|
|
2252
|
+
statements.map((statement) => synthesizeHostNode(getHostStatement(statement))),
|
|
2253
|
+
true,
|
|
2254
|
+
));
|
|
2255
|
+
return createBlockSyntaxFromNode(block, sourceFile, {
|
|
2256
|
+
fileName,
|
|
2257
|
+
start: 0,
|
|
2258
|
+
end: 0,
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
export function buildIdentifierExprSyntax(fileName: string, name: string): ExprSyntax {
|
|
2263
|
+
return createBuiltExprSyntax(fileName, ts.factory.createIdentifier(name));
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
export function buildThisExprSyntax(fileName: string): ExprSyntax {
|
|
2267
|
+
return createBuiltExprSyntax(fileName, ts.factory.createThis());
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
export function buildStringLiteralExprSyntax(fileName: string, value: string): ExprSyntax {
|
|
2271
|
+
return createBuiltExprSyntax(fileName, ts.factory.createStringLiteral(value));
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
export function buildNumberLiteralExprSyntax(fileName: string, value: number): ExprSyntax {
|
|
2275
|
+
if (value < 0) {
|
|
2276
|
+
return createBuiltExprSyntax(
|
|
2277
|
+
fileName,
|
|
2278
|
+
ts.factory.createPrefixUnaryExpression(
|
|
2279
|
+
ts.SyntaxKind.MinusToken,
|
|
2280
|
+
ts.factory.createNumericLiteral(Math.abs(value)),
|
|
2281
|
+
),
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
return createBuiltExprSyntax(fileName, ts.factory.createNumericLiteral(value));
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
export function buildBooleanLiteralExprSyntax(fileName: string, value: boolean): ExprSyntax {
|
|
2288
|
+
return createBuiltExprSyntax(
|
|
2289
|
+
fileName,
|
|
2290
|
+
value ? ts.factory.createTrue() : ts.factory.createFalse(),
|
|
2291
|
+
);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
export function buildNullLiteralExprSyntax(fileName: string): ExprSyntax {
|
|
2295
|
+
return createBuiltExprSyntax(fileName, ts.factory.createNull());
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
export function buildPropertyAccessExprSyntax(
|
|
2299
|
+
fileName: string,
|
|
2300
|
+
object: ExprSyntax,
|
|
2301
|
+
name: string,
|
|
2302
|
+
): ExprSyntax {
|
|
2303
|
+
return createBuiltExprSyntax(
|
|
2304
|
+
fileName,
|
|
2305
|
+
ts.factory.createPropertyAccessExpression(getHostExpression(object), name),
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
export function buildCallExprSyntax(
|
|
2310
|
+
fileName: string,
|
|
2311
|
+
callee: ExprSyntax,
|
|
2312
|
+
args: readonly ExprSyntax[],
|
|
2313
|
+
): ExprSyntax {
|
|
2314
|
+
return createBuiltExprSyntax(
|
|
2315
|
+
fileName,
|
|
2316
|
+
ts.factory.createCallExpression(
|
|
2317
|
+
getHostExpression(callee),
|
|
2318
|
+
undefined,
|
|
2319
|
+
args.map((arg) => getHostExpression(arg)),
|
|
2320
|
+
),
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
export function buildElementAccessExprSyntax(
|
|
2325
|
+
fileName: string,
|
|
2326
|
+
object: ExprSyntax,
|
|
2327
|
+
index: ExprSyntax,
|
|
2328
|
+
): ExprSyntax {
|
|
2329
|
+
return createBuiltExprSyntax(
|
|
2330
|
+
fileName,
|
|
2331
|
+
ts.factory.createElementAccessExpression(
|
|
2332
|
+
getHostExpression(object),
|
|
2333
|
+
getHostExpression(index),
|
|
2334
|
+
),
|
|
2335
|
+
);
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
export function buildNewExprSyntax(
|
|
2339
|
+
fileName: string,
|
|
2340
|
+
callee: ExprSyntax,
|
|
2341
|
+
args: readonly ExprSyntax[],
|
|
2342
|
+
): ExprSyntax {
|
|
2343
|
+
return createBuiltExprSyntax(
|
|
2344
|
+
fileName,
|
|
2345
|
+
ts.factory.createNewExpression(
|
|
2346
|
+
getHostExpression(callee),
|
|
2347
|
+
undefined,
|
|
2348
|
+
args.map((arg) => getHostExpression(arg)),
|
|
2349
|
+
),
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
export function buildBinaryExprSyntax(
|
|
2354
|
+
fileName: string,
|
|
2355
|
+
left: ExprSyntax,
|
|
2356
|
+
operator: MacroBinaryOperator,
|
|
2357
|
+
right: ExprSyntax,
|
|
2358
|
+
): ExprSyntax {
|
|
2359
|
+
return createBuiltExprSyntax(
|
|
2360
|
+
fileName,
|
|
2361
|
+
ts.factory.createBinaryExpression(
|
|
2362
|
+
getHostExpression(left),
|
|
2363
|
+
createBinaryOperatorToken(operator),
|
|
2364
|
+
getHostExpression(right),
|
|
2365
|
+
),
|
|
2366
|
+
);
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
export function buildAssignmentExprSyntax(
|
|
2370
|
+
fileName: string,
|
|
2371
|
+
target: ExprSyntax,
|
|
2372
|
+
value: ExprSyntax,
|
|
2373
|
+
): ExprSyntax {
|
|
2374
|
+
return buildBinaryExprSyntax(fileName, target, '=', value);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
export function buildUnaryExprSyntax(
|
|
2378
|
+
fileName: string,
|
|
2379
|
+
operator: MacroUnaryOperator,
|
|
2380
|
+
value: ExprSyntax,
|
|
2381
|
+
): ExprSyntax {
|
|
2382
|
+
return createBuiltExprSyntax(
|
|
2383
|
+
fileName,
|
|
2384
|
+
ts.factory.createPrefixUnaryExpression(
|
|
2385
|
+
createUnaryOperatorToken(operator),
|
|
2386
|
+
getHostExpression(value),
|
|
2387
|
+
),
|
|
2388
|
+
);
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
export function buildArrowFunctionExprSyntax(
|
|
2392
|
+
fileName: string,
|
|
2393
|
+
parameters: readonly (string | MacroParameterBuildOptions)[],
|
|
2394
|
+
body: BlockSyntax | ExprSyntax,
|
|
2395
|
+
): ExprSyntax {
|
|
2396
|
+
return createBuiltExprSyntax(
|
|
2397
|
+
fileName,
|
|
2398
|
+
ts.factory.createArrowFunction(
|
|
2399
|
+
undefined,
|
|
2400
|
+
undefined,
|
|
2401
|
+
createParameterDeclarations(fileName, parameters),
|
|
2402
|
+
undefined,
|
|
2403
|
+
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
|
|
2404
|
+
body.kind === 'block' ? cloneBlockNode(body) : getHostExpression(body),
|
|
2405
|
+
),
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
export function buildObjectLiteralExprSyntax(
|
|
2410
|
+
fileName: string,
|
|
2411
|
+
members: readonly MacroObjectMemberBuildOptions[],
|
|
2412
|
+
): ExprSyntax {
|
|
2413
|
+
return createBuiltExprSyntax(
|
|
2414
|
+
fileName,
|
|
2415
|
+
ts.factory.createObjectLiteralExpression(
|
|
2416
|
+
members.map((member): ts.ObjectLiteralElementLike => {
|
|
2417
|
+
if (member.kind === 'property') {
|
|
2418
|
+
return ts.factory.createPropertyAssignment(member.name, getHostExpression(member.value));
|
|
2419
|
+
}
|
|
2420
|
+
return ts.factory.createMethodDeclaration(
|
|
2421
|
+
undefined,
|
|
2422
|
+
undefined,
|
|
2423
|
+
member.name,
|
|
2424
|
+
undefined,
|
|
2425
|
+
undefined,
|
|
2426
|
+
createParameterDeclarations(fileName, member.parameters),
|
|
2427
|
+
member.returnType ? createTypeNodeFromText(fileName, member.returnType) : undefined,
|
|
2428
|
+
cloneBlockNode(member.body),
|
|
2429
|
+
);
|
|
2430
|
+
}),
|
|
2431
|
+
true,
|
|
2432
|
+
),
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
export function buildOptionalMethodCallExprSyntax(
|
|
2437
|
+
fileName: string,
|
|
2438
|
+
receiver: ExprSyntax,
|
|
2439
|
+
name: string,
|
|
2440
|
+
args: readonly ExprSyntax[],
|
|
2441
|
+
): ExprSyntax {
|
|
2442
|
+
return createBuiltExprSyntax(
|
|
2443
|
+
fileName,
|
|
2444
|
+
ts.factory.createCallChain(
|
|
2445
|
+
ts.factory.createPropertyAccessChain(
|
|
2446
|
+
getHostExpression(receiver),
|
|
2447
|
+
ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),
|
|
2448
|
+
name,
|
|
2449
|
+
),
|
|
2450
|
+
undefined,
|
|
2451
|
+
undefined,
|
|
2452
|
+
args.map((arg) => getHostExpression(arg)),
|
|
2453
|
+
),
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
export function buildExprStmtSyntax(
|
|
2458
|
+
fileName: string,
|
|
2459
|
+
expression: ExprSyntax,
|
|
2460
|
+
): StmtSyntax {
|
|
2461
|
+
return createBuiltStmtSyntax(
|
|
2462
|
+
fileName,
|
|
2463
|
+
ts.factory.createExpressionStatement(getHostExpression(expression)),
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
export function buildConstDeclStmtSyntax(
|
|
2468
|
+
fileName: string,
|
|
2469
|
+
name: string,
|
|
2470
|
+
initializer: ExprSyntax,
|
|
2471
|
+
): StmtSyntax {
|
|
2472
|
+
return createBuiltStmtSyntax(
|
|
2473
|
+
fileName,
|
|
2474
|
+
ts.factory.createVariableStatement(
|
|
2475
|
+
undefined,
|
|
2476
|
+
ts.factory.createVariableDeclarationList(
|
|
2477
|
+
[ts.factory.createVariableDeclaration(
|
|
2478
|
+
name,
|
|
2479
|
+
undefined,
|
|
2480
|
+
undefined,
|
|
2481
|
+
getHostExpression(initializer),
|
|
2482
|
+
)],
|
|
2483
|
+
ts.NodeFlags.Const,
|
|
2484
|
+
),
|
|
2485
|
+
),
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
export function buildLetDeclStmtSyntax(
|
|
2490
|
+
fileName: string,
|
|
2491
|
+
name: string,
|
|
2492
|
+
initializer: ExprSyntax,
|
|
2493
|
+
): StmtSyntax {
|
|
2494
|
+
return createBuiltStmtSyntax(
|
|
2495
|
+
fileName,
|
|
2496
|
+
ts.factory.createVariableStatement(
|
|
2497
|
+
undefined,
|
|
2498
|
+
ts.factory.createVariableDeclarationList(
|
|
2499
|
+
[ts.factory.createVariableDeclaration(
|
|
2500
|
+
name,
|
|
2501
|
+
undefined,
|
|
2502
|
+
undefined,
|
|
2503
|
+
getHostExpression(initializer),
|
|
2504
|
+
)],
|
|
2505
|
+
ts.NodeFlags.Let,
|
|
2506
|
+
),
|
|
2507
|
+
),
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
export function buildReturnStmtSyntax(
|
|
2512
|
+
fileName: string,
|
|
2513
|
+
expression?: ExprSyntax,
|
|
2514
|
+
): StmtSyntax {
|
|
2515
|
+
return createBuiltStmtSyntax(
|
|
2516
|
+
fileName,
|
|
2517
|
+
ts.factory.createReturnStatement(expression ? getHostExpression(expression) : undefined),
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
export function buildIfStmtSyntax(
|
|
2522
|
+
fileName: string,
|
|
2523
|
+
options: MacroIfBuildOptions,
|
|
2524
|
+
): StmtSyntax {
|
|
2525
|
+
return createBuiltStmtSyntax(
|
|
2526
|
+
fileName,
|
|
2527
|
+
ts.factory.createIfStatement(
|
|
2528
|
+
getHostExpression(options.condition),
|
|
2529
|
+
getHostBlock(buildBlockSyntax(fileName, options.thenStatements)),
|
|
2530
|
+
options.elseStatements
|
|
2531
|
+
? getHostBlock(buildBlockSyntax(fileName, options.elseStatements))
|
|
2532
|
+
: undefined,
|
|
2533
|
+
),
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
function createForInitializer(
|
|
2538
|
+
initializer: ExprSyntax | {
|
|
2539
|
+
readonly kind: 'const' | 'let';
|
|
2540
|
+
readonly name: string;
|
|
2541
|
+
readonly value: ExprSyntax;
|
|
2542
|
+
} | undefined,
|
|
2543
|
+
): ts.ForInitializer | undefined {
|
|
2544
|
+
if (!initializer) {
|
|
2545
|
+
return undefined;
|
|
2546
|
+
}
|
|
2547
|
+
if (
|
|
2548
|
+
typeof initializer === 'object' &&
|
|
2549
|
+
'kind' in initializer &&
|
|
2550
|
+
(initializer.kind === 'const' || initializer.kind === 'let')
|
|
2551
|
+
) {
|
|
2552
|
+
const flags = initializer.kind === 'const' ? ts.NodeFlags.Const : ts.NodeFlags.Let;
|
|
2553
|
+
return ts.factory.createVariableDeclarationList(
|
|
2554
|
+
[ts.factory.createVariableDeclaration(
|
|
2555
|
+
initializer.name,
|
|
2556
|
+
undefined,
|
|
2557
|
+
undefined,
|
|
2558
|
+
getHostExpression(initializer.value),
|
|
2559
|
+
)],
|
|
2560
|
+
flags,
|
|
2561
|
+
);
|
|
2562
|
+
}
|
|
2563
|
+
return getHostExpression(initializer as ExprSyntax);
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
export function buildForStmtSyntax(
|
|
2567
|
+
fileName: string,
|
|
2568
|
+
options: MacroForBuildOptions,
|
|
2569
|
+
): StmtSyntax {
|
|
2570
|
+
return createBuiltStmtSyntax(
|
|
2571
|
+
fileName,
|
|
2572
|
+
ts.factory.createForStatement(
|
|
2573
|
+
createForInitializer(options.initializer),
|
|
2574
|
+
options.condition ? getHostExpression(options.condition) : undefined,
|
|
2575
|
+
options.increment ? getHostExpression(options.increment) : undefined,
|
|
2576
|
+
getHostBlock(buildBlockSyntax(fileName, options.statements)),
|
|
2577
|
+
),
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
export function buildThrowStmtSyntax(
|
|
2582
|
+
fileName: string,
|
|
2583
|
+
expression: ExprSyntax,
|
|
2584
|
+
): StmtSyntax {
|
|
2585
|
+
return createBuiltStmtSyntax(
|
|
2586
|
+
fileName,
|
|
2587
|
+
ts.factory.createThrowStatement(getHostExpression(expression)),
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
export function createDeclSyntaxFromNode(
|
|
2592
|
+
node:
|
|
2593
|
+
| ts.ClassDeclaration
|
|
2594
|
+
| ts.FunctionDeclaration
|
|
2595
|
+
| ts.InterfaceDeclaration
|
|
2596
|
+
| ts.TypeAliasDeclaration,
|
|
2597
|
+
sourceFile: ts.SourceFile,
|
|
2598
|
+
span: SourceSpan,
|
|
2599
|
+
text?: string,
|
|
2600
|
+
): DeclSyntax {
|
|
2601
|
+
if (ts.isClassDeclaration(node)) {
|
|
2602
|
+
const members = () =>
|
|
2603
|
+
node.members.flatMap((member) => {
|
|
2604
|
+
const wrapped = createClassMemberSyntaxFromNode(member, sourceFile, span);
|
|
2605
|
+
return wrapped ? [wrapped] : [];
|
|
2606
|
+
});
|
|
2607
|
+
const syntax: MacroClassDeclSyntax = withHostNode(
|
|
2608
|
+
{
|
|
2609
|
+
asClass() {
|
|
2610
|
+
return syntax;
|
|
2611
|
+
},
|
|
2612
|
+
asFunction() {
|
|
2613
|
+
return null;
|
|
2614
|
+
},
|
|
2615
|
+
asInterface() {
|
|
2616
|
+
return null;
|
|
2617
|
+
},
|
|
2618
|
+
asTypeAlias() {
|
|
2619
|
+
return null;
|
|
2620
|
+
},
|
|
2621
|
+
declarationKind: 'class',
|
|
2622
|
+
hasModifier(name: MacroModifierName) {
|
|
2623
|
+
return hasModifier(node, name);
|
|
2624
|
+
},
|
|
2625
|
+
kind: 'decl',
|
|
2626
|
+
member(name: string) {
|
|
2627
|
+
return members().find((member) => member.name === name) ?? null;
|
|
2628
|
+
},
|
|
2629
|
+
members,
|
|
2630
|
+
name: node.name?.text ?? null,
|
|
2631
|
+
resolveThisDependencies(
|
|
2632
|
+
target: ExprSyntax | BlockSyntax,
|
|
2633
|
+
rootMemberNames: readonly string[],
|
|
2634
|
+
) {
|
|
2635
|
+
return resolveThisDependenciesForClass(node, rootMemberNames, target);
|
|
2636
|
+
},
|
|
2637
|
+
span,
|
|
2638
|
+
text() {
|
|
2639
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2640
|
+
},
|
|
2641
|
+
},
|
|
2642
|
+
node,
|
|
2643
|
+
sourceFile,
|
|
2644
|
+
ts.EmitHint.Unspecified,
|
|
2645
|
+
);
|
|
2646
|
+
return syntax;
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
2650
|
+
const syntax: MacroFunctionDeclSyntax = withHostNode(
|
|
2651
|
+
{
|
|
2652
|
+
asClass() {
|
|
2653
|
+
return null;
|
|
2654
|
+
},
|
|
2655
|
+
asFunction() {
|
|
2656
|
+
return syntax;
|
|
2657
|
+
},
|
|
2658
|
+
asInterface() {
|
|
2659
|
+
return null;
|
|
2660
|
+
},
|
|
2661
|
+
asTypeAlias() {
|
|
2662
|
+
return null;
|
|
2663
|
+
},
|
|
2664
|
+
body() {
|
|
2665
|
+
return node.body
|
|
2666
|
+
? createBlockSyntaxFromNode(
|
|
2667
|
+
node.body,
|
|
2668
|
+
sourceFile,
|
|
2669
|
+
nodeSpan(node.body, sourceFile, span),
|
|
2670
|
+
)
|
|
2671
|
+
: null;
|
|
2672
|
+
},
|
|
2673
|
+
declarationKind: 'function',
|
|
2674
|
+
hasModifier(name: MacroModifierName) {
|
|
2675
|
+
return hasModifier(node, name);
|
|
2676
|
+
},
|
|
2677
|
+
kind: 'decl',
|
|
2678
|
+
name: node.name?.text ?? null,
|
|
2679
|
+
parameters: node.parameters.map((parameter) =>
|
|
2680
|
+
createParameterSyntaxFromNode(parameter, sourceFile, span)
|
|
2681
|
+
),
|
|
2682
|
+
returnedExpr() {
|
|
2683
|
+
const returned = returnedExprNode(node);
|
|
2684
|
+
return returned
|
|
2685
|
+
? createExprSyntaxFromNode(
|
|
2686
|
+
returned,
|
|
2687
|
+
sourceFile,
|
|
2688
|
+
nodeSpan(returned, sourceFile, span),
|
|
2689
|
+
)
|
|
2690
|
+
: null;
|
|
2691
|
+
},
|
|
2692
|
+
returnedJsx() {
|
|
2693
|
+
const jsx = returnedJsxNode(node);
|
|
2694
|
+
return jsx
|
|
2695
|
+
? createJsxElementSyntaxFromNode(jsx, sourceFile, nodeSpan(jsx, sourceFile, span))
|
|
2696
|
+
: null;
|
|
2697
|
+
},
|
|
2698
|
+
span,
|
|
2699
|
+
text() {
|
|
2700
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2701
|
+
},
|
|
2702
|
+
},
|
|
2703
|
+
node,
|
|
2704
|
+
sourceFile,
|
|
2705
|
+
ts.EmitHint.Unspecified,
|
|
2706
|
+
);
|
|
2707
|
+
return syntax;
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
2711
|
+
const members = node.members.map((member) =>
|
|
2712
|
+
createObjectTypeMemberSyntaxFromNode(member, sourceFile, nodeSpan(member, sourceFile, span))
|
|
2713
|
+
);
|
|
2714
|
+
const typeParameters = node.typeParameters?.map((parameter) =>
|
|
2715
|
+
createTypeParameterSyntaxFromNode(
|
|
2716
|
+
parameter,
|
|
2717
|
+
sourceFile,
|
|
2718
|
+
nodeSpan(parameter, sourceFile, span),
|
|
2719
|
+
)
|
|
2720
|
+
) ?? [];
|
|
2721
|
+
const extendsTypes = node.heritageClauses
|
|
2722
|
+
?.filter((clause) =>
|
|
2723
|
+
clause.token === ts.SyntaxKind.ExtendsKeyword
|
|
2724
|
+
)
|
|
2725
|
+
.flatMap((clause) =>
|
|
2726
|
+
clause.types.map((type) =>
|
|
2727
|
+
createTypeSyntaxFromText(
|
|
2728
|
+
sourceFile.fileName,
|
|
2729
|
+
nodeSpan(type, sourceFile, span),
|
|
2730
|
+
printHostNode(type, sourceFile, ts.EmitHint.Unspecified),
|
|
2731
|
+
)
|
|
2732
|
+
)
|
|
2733
|
+
) ?? [];
|
|
2734
|
+
const syntax: MacroInterfaceDeclSyntax = withHostNode(
|
|
2735
|
+
{
|
|
2736
|
+
asClass() {
|
|
2737
|
+
return null;
|
|
2738
|
+
},
|
|
2739
|
+
asFunction() {
|
|
2740
|
+
return null;
|
|
2741
|
+
},
|
|
2742
|
+
asInterface() {
|
|
2743
|
+
return syntax;
|
|
2744
|
+
},
|
|
2745
|
+
asTypeAlias() {
|
|
2746
|
+
return null;
|
|
2747
|
+
},
|
|
2748
|
+
declarationKind: 'interface',
|
|
2749
|
+
extendsTypes,
|
|
2750
|
+
hasModifier(name: MacroModifierName) {
|
|
2751
|
+
return hasModifier(node, name);
|
|
2752
|
+
},
|
|
2753
|
+
kind: 'decl',
|
|
2754
|
+
members,
|
|
2755
|
+
name: node.name.text,
|
|
2756
|
+
span,
|
|
2757
|
+
text() {
|
|
2758
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2759
|
+
},
|
|
2760
|
+
typeParameters,
|
|
2761
|
+
},
|
|
2762
|
+
node,
|
|
2763
|
+
sourceFile,
|
|
2764
|
+
ts.EmitHint.Unspecified,
|
|
2765
|
+
);
|
|
2766
|
+
return syntax;
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
2770
|
+
const typeParameters = node.typeParameters?.map((parameter) =>
|
|
2771
|
+
createTypeParameterSyntaxFromNode(
|
|
2772
|
+
parameter,
|
|
2773
|
+
sourceFile,
|
|
2774
|
+
nodeSpan(parameter, sourceFile, span),
|
|
2775
|
+
)
|
|
2776
|
+
) ?? [];
|
|
2777
|
+
const syntax: MacroTypeAliasDeclSyntax = withHostNode(
|
|
2778
|
+
{
|
|
2779
|
+
asClass() {
|
|
2780
|
+
return null;
|
|
2781
|
+
},
|
|
2782
|
+
asFunction() {
|
|
2783
|
+
return null;
|
|
2784
|
+
},
|
|
2785
|
+
asInterface() {
|
|
2786
|
+
return null;
|
|
2787
|
+
},
|
|
2788
|
+
asTypeAlias() {
|
|
2789
|
+
return syntax;
|
|
2790
|
+
},
|
|
2791
|
+
declarationKind: 'typeAlias',
|
|
2792
|
+
hasModifier(name: MacroModifierName) {
|
|
2793
|
+
return hasModifier(node, name);
|
|
2794
|
+
},
|
|
2795
|
+
kind: 'decl',
|
|
2796
|
+
name: node.name.text,
|
|
2797
|
+
span,
|
|
2798
|
+
text() {
|
|
2799
|
+
return text ?? printHostNode(node, sourceFile, ts.EmitHint.Unspecified);
|
|
2800
|
+
},
|
|
2801
|
+
type: createTypeSyntaxFromNode(
|
|
2802
|
+
node.type,
|
|
2803
|
+
sourceFile,
|
|
2804
|
+
nodeSpan(node.type, sourceFile, span),
|
|
2805
|
+
),
|
|
2806
|
+
typeParameters,
|
|
2807
|
+
},
|
|
2808
|
+
node,
|
|
2809
|
+
sourceFile,
|
|
2810
|
+
ts.EmitHint.Unspecified,
|
|
2811
|
+
);
|
|
2812
|
+
return syntax;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
throw new Error('Expected a declaration-backed syntax node.');
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
export function createInvocationSyntax(options: {
|
|
2819
|
+
readonly args: readonly MacroArgumentView[];
|
|
2820
|
+
readonly block: BlockSyntax | null;
|
|
2821
|
+
readonly declaration: DeclSyntax | null;
|
|
2822
|
+
readonly form: MacroInvocationForm;
|
|
2823
|
+
readonly hasBlock: boolean;
|
|
2824
|
+
readonly name: string;
|
|
2825
|
+
readonly span: SourceSpan;
|
|
2826
|
+
readonly text: string;
|
|
2827
|
+
}): InvocationSyntax {
|
|
2828
|
+
return {
|
|
2829
|
+
args: options.args,
|
|
2830
|
+
block: options.block,
|
|
2831
|
+
declaration: options.declaration,
|
|
2832
|
+
form: options.form,
|
|
2833
|
+
hasBlock: options.hasBlock,
|
|
2834
|
+
kind: 'invocation',
|
|
2835
|
+
name: options.name,
|
|
2836
|
+
span: options.span,
|
|
2837
|
+
text() {
|
|
2838
|
+
return options.text;
|
|
2839
|
+
},
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
function expressionAsInvocation(
|
|
2844
|
+
fileName: string,
|
|
2845
|
+
span: SourceSpan,
|
|
2846
|
+
text: string,
|
|
2847
|
+
): InvocationSyntax | null {
|
|
2848
|
+
const trimmed = text.trim();
|
|
2849
|
+
if (!trimmed.startsWith('#')) {
|
|
2850
|
+
return null;
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
const leadingWhitespace = text.length - text.trimStart().length;
|
|
2854
|
+
const parsed = parseMacroInvocationAt(fileName, text, leadingWhitespace);
|
|
2855
|
+
if ('reason' in parsed || parsed.span.end !== text.length) {
|
|
2856
|
+
return null;
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
const args = parsed.argumentSpans
|
|
2860
|
+
.filter((argument) => argument.kind === 'ExprArg')
|
|
2861
|
+
.map((argument, index) =>
|
|
2862
|
+
createArgumentSyntaxFromText(
|
|
2863
|
+
index,
|
|
2864
|
+
fileName,
|
|
2865
|
+
offsetSpan(span, argument.span),
|
|
2866
|
+
text.slice(argument.span.start, argument.span.end),
|
|
2867
|
+
)
|
|
2868
|
+
);
|
|
2869
|
+
const block = parsed.trailingBlockSpan
|
|
2870
|
+
? createBlockSyntaxFromText(
|
|
2871
|
+
fileName,
|
|
2872
|
+
offsetSpan(span, parsed.trailingBlockSpan),
|
|
2873
|
+
text.slice(parsed.trailingBlockSpan.start, parsed.trailingBlockSpan.end),
|
|
2874
|
+
)
|
|
2875
|
+
: parsed.invocationKind === 'block' && parsed.argumentSpans[0]?.kind === 'BlockArg'
|
|
2876
|
+
? createBlockSyntaxFromText(
|
|
2877
|
+
fileName,
|
|
2878
|
+
offsetSpan(span, parsed.argumentSpans[0].span),
|
|
2879
|
+
text.slice(parsed.argumentSpans[0].span.start, parsed.argumentSpans[0].span.end),
|
|
2880
|
+
)
|
|
2881
|
+
: null;
|
|
2882
|
+
const declaration = parsed.declarationSpan
|
|
2883
|
+
? createDeclSyntaxFromText(
|
|
2884
|
+
fileName,
|
|
2885
|
+
offsetSpan(span, parsed.declarationSpan),
|
|
2886
|
+
text.slice(parsed.declarationSpan.start, parsed.declarationSpan.end),
|
|
2887
|
+
)
|
|
2888
|
+
: null;
|
|
2889
|
+
|
|
2890
|
+
return createInvocationSyntax({
|
|
2891
|
+
args,
|
|
2892
|
+
block,
|
|
2893
|
+
declaration,
|
|
2894
|
+
form: parsed.invocationKind === 'decl'
|
|
2895
|
+
? 'decl'
|
|
2896
|
+
: parsed.invocationKind === 'arglist+decl'
|
|
2897
|
+
? 'arglist_decl'
|
|
2898
|
+
: parsed.invocationKind === 'block'
|
|
2899
|
+
? 'block'
|
|
2900
|
+
: 'arglist',
|
|
2901
|
+
hasBlock: block !== null,
|
|
2902
|
+
name: parsed.nameText,
|
|
2903
|
+
span,
|
|
2904
|
+
text,
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
export function createClassMemberSyntaxListFromCode(
|
|
2909
|
+
fileName: string,
|
|
2910
|
+
code: string,
|
|
2911
|
+
): readonly MacroAnyClassMemberSyntax[] {
|
|
2912
|
+
const sourceFile = ts.createSourceFile(
|
|
2913
|
+
fileName.endsWith('.tsx') || fileName.endsWith('.jsx') || fileName.endsWith('.sts')
|
|
2914
|
+
? fileName
|
|
2915
|
+
: `${fileName}.tsx`,
|
|
2916
|
+
`class __SoundscriptQuotedMembers {${code}}`,
|
|
2917
|
+
ts.ScriptTarget.Latest,
|
|
2918
|
+
true,
|
|
2919
|
+
scriptKindForHostFile(fileName),
|
|
2920
|
+
);
|
|
2921
|
+
ensureNoParseDiagnostics(sourceFile, '// #[component] generated invalid class members.');
|
|
2922
|
+
const statement = sourceFile.statements[0];
|
|
2923
|
+
if (!statement || !ts.isClassDeclaration(statement)) {
|
|
2924
|
+
throw new Error('// #[component] generated invalid class members.');
|
|
2925
|
+
}
|
|
2926
|
+
return statement.members.flatMap((member) => {
|
|
2927
|
+
const wrapped = createClassMemberSyntaxFromNode(
|
|
2928
|
+
synthesizeHostNode(member),
|
|
2929
|
+
sourceFile,
|
|
2930
|
+
{
|
|
2931
|
+
fileName,
|
|
2932
|
+
start: 0,
|
|
2933
|
+
end: code.length,
|
|
2934
|
+
},
|
|
2935
|
+
);
|
|
2936
|
+
return wrapped ? [wrapped] : [];
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
export function createTemplateSyntaxFromPieces(
|
|
2941
|
+
span: SourceSpan,
|
|
2942
|
+
text: string,
|
|
2943
|
+
quasis: readonly MacroTemplateQuasi[],
|
|
2944
|
+
expressions: readonly ExprSyntax[],
|
|
2945
|
+
): MacroTemplateOperand {
|
|
2946
|
+
return {
|
|
2947
|
+
expressions,
|
|
2948
|
+
kind: 'template',
|
|
2949
|
+
quasis,
|
|
2950
|
+
span,
|
|
2951
|
+
text() {
|
|
2952
|
+
return text;
|
|
2953
|
+
},
|
|
2954
|
+
};
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
export function createExprSyntaxFromText(
|
|
2958
|
+
fileName: string,
|
|
2959
|
+
span: SourceSpan,
|
|
2960
|
+
text: string,
|
|
2961
|
+
): ExprSyntax {
|
|
2962
|
+
const node = parseHostExpressionWithNestedMacroFallback(
|
|
2963
|
+
fileName,
|
|
2964
|
+
text,
|
|
2965
|
+
'Macro expression operands must parse as exactly one host-language expression.',
|
|
2966
|
+
);
|
|
2967
|
+
const parsedSourceFile = node.getSourceFile?.() ?? ts.createSourceFile(
|
|
2968
|
+
fileName,
|
|
2969
|
+
text,
|
|
2970
|
+
ts.ScriptTarget.Latest,
|
|
2971
|
+
true,
|
|
2972
|
+
ts.ScriptKind.TSX,
|
|
2973
|
+
);
|
|
2974
|
+
const sourceFile = setSourceFileOffset(
|
|
2975
|
+
parsedSourceFile,
|
|
2976
|
+
span.start - node.getStart(parsedSourceFile, false),
|
|
2977
|
+
);
|
|
2978
|
+
return createExprSyntaxFromNode(node, sourceFile, span, text);
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
export function createBlockSyntaxFromText(
|
|
2982
|
+
fileName: string,
|
|
2983
|
+
span: SourceSpan,
|
|
2984
|
+
text: string,
|
|
2985
|
+
): BlockSyntax {
|
|
2986
|
+
try {
|
|
2987
|
+
const statement = parseSingleHostStatement(
|
|
2988
|
+
fileName,
|
|
2989
|
+
'macro_block_operand',
|
|
2990
|
+
text,
|
|
2991
|
+
'Macro block operands must parse as exactly one host-language block statement.',
|
|
2992
|
+
);
|
|
2993
|
+
if (!ts.isBlock(statement)) {
|
|
2994
|
+
throw new Error(
|
|
2995
|
+
'Macro block operands must parse as exactly one host-language block statement.',
|
|
2996
|
+
);
|
|
2997
|
+
}
|
|
2998
|
+
const sourceFile = setSourceFileOffset(
|
|
2999
|
+
statement.getSourceFile(),
|
|
3000
|
+
span.start - statement.getStart(statement.getSourceFile(), false),
|
|
3001
|
+
);
|
|
3002
|
+
return createBlockSyntaxFromNode(statement, sourceFile, span, text);
|
|
3003
|
+
} catch {
|
|
3004
|
+
try {
|
|
3005
|
+
const statement = parseSingleHostStatement(
|
|
3006
|
+
fileName,
|
|
3007
|
+
'macro_block_operand',
|
|
3008
|
+
neutralizeNestedMacrosForHostParse(fileName, text),
|
|
3009
|
+
'Macro block operands must parse as exactly one host-language block statement.',
|
|
3010
|
+
);
|
|
3011
|
+
if (!ts.isBlock(statement)) {
|
|
3012
|
+
throw new Error(
|
|
3013
|
+
'Macro block operands must parse as exactly one host-language block statement.',
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
const sourceFile = setSourceFileOffset(
|
|
3017
|
+
statement.getSourceFile(),
|
|
3018
|
+
span.start - statement.getStart(statement.getSourceFile(), false),
|
|
3019
|
+
);
|
|
3020
|
+
return createBlockSyntaxFromNode(statement, sourceFile, span, text);
|
|
3021
|
+
} catch {
|
|
3022
|
+
return {
|
|
3023
|
+
containsCallNamed() {
|
|
3024
|
+
return false;
|
|
3025
|
+
},
|
|
3026
|
+
kind: 'block',
|
|
3027
|
+
replaceThis() {
|
|
3028
|
+
return this;
|
|
3029
|
+
},
|
|
3030
|
+
rewrite() {
|
|
3031
|
+
return this;
|
|
3032
|
+
},
|
|
3033
|
+
span,
|
|
3034
|
+
statements: [],
|
|
3035
|
+
text() {
|
|
3036
|
+
return text;
|
|
3037
|
+
},
|
|
3038
|
+
thisMemberReferences() {
|
|
3039
|
+
return [];
|
|
3040
|
+
},
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
export function createDeclSyntaxFromText(
|
|
3047
|
+
fileName: string,
|
|
3048
|
+
span: SourceSpan,
|
|
3049
|
+
text: string,
|
|
3050
|
+
): DeclSyntax {
|
|
3051
|
+
const parseText = (() => {
|
|
3052
|
+
try {
|
|
3053
|
+
const sourceFile = ts.createSourceFile(
|
|
3054
|
+
fileName,
|
|
3055
|
+
text,
|
|
3056
|
+
ts.ScriptTarget.Latest,
|
|
3057
|
+
true,
|
|
3058
|
+
scriptKindForHostFile(fileName),
|
|
3059
|
+
);
|
|
3060
|
+
ensureNoParseDiagnostics(
|
|
3061
|
+
sourceFile,
|
|
3062
|
+
'Macro declaration operands must parse as exactly one class, function, interface, or type alias declaration.',
|
|
3063
|
+
);
|
|
3064
|
+
return { sourceFile, statement: sourceFile.statements[0] };
|
|
3065
|
+
} catch {
|
|
3066
|
+
const neutralized = neutralizeNestedMacrosForHostParse(fileName, text);
|
|
3067
|
+
const sourceFile = ts.createSourceFile(
|
|
3068
|
+
fileName,
|
|
3069
|
+
neutralized,
|
|
3070
|
+
ts.ScriptTarget.Latest,
|
|
3071
|
+
true,
|
|
3072
|
+
scriptKindForHostFile(fileName),
|
|
3073
|
+
);
|
|
3074
|
+
ensureNoParseDiagnostics(
|
|
3075
|
+
sourceFile,
|
|
3076
|
+
'Macro declaration operands must parse as exactly one class, function, interface, or type alias declaration.',
|
|
3077
|
+
);
|
|
3078
|
+
return { sourceFile, statement: sourceFile.statements[0] };
|
|
3079
|
+
}
|
|
3080
|
+
})();
|
|
3081
|
+
|
|
3082
|
+
const statement = parseText.statement;
|
|
3083
|
+
if (
|
|
3084
|
+
!ts.isClassDeclaration(statement) && !ts.isFunctionDeclaration(statement) &&
|
|
3085
|
+
!ts.isInterfaceDeclaration(statement) && !ts.isTypeAliasDeclaration(statement)
|
|
3086
|
+
) {
|
|
3087
|
+
throw new Error(
|
|
3088
|
+
'Macro declaration operands must parse as exactly one class, function, interface, or type alias declaration.',
|
|
3089
|
+
);
|
|
3090
|
+
}
|
|
3091
|
+
return createDeclSyntaxFromNode(
|
|
3092
|
+
statement,
|
|
3093
|
+
setSourceFileOffset(
|
|
3094
|
+
parseText.sourceFile,
|
|
3095
|
+
span.start - statement.getStart(parseText.sourceFile, false),
|
|
3096
|
+
),
|
|
3097
|
+
span,
|
|
3098
|
+
text,
|
|
3099
|
+
);
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
export function createStmtListSyntaxFromCode(
|
|
3103
|
+
fileName: string,
|
|
3104
|
+
suffix: string,
|
|
3105
|
+
code: string,
|
|
3106
|
+
): readonly StmtSyntax[] {
|
|
3107
|
+
const statements = parseHostStatements(
|
|
3108
|
+
fileName,
|
|
3109
|
+
suffix,
|
|
3110
|
+
code,
|
|
3111
|
+
'Quoted macro statements must parse as host-language statements.',
|
|
3112
|
+
);
|
|
3113
|
+
const sourceFile = statements[0]?.getSourceFile() ??
|
|
3114
|
+
ts.createSourceFile(fileName, code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
3115
|
+
return statements.map((statement) =>
|
|
3116
|
+
createStmtSyntaxFromNode(statement, sourceFile, {
|
|
3117
|
+
fileName,
|
|
3118
|
+
start: 0,
|
|
3119
|
+
end: code.length,
|
|
3120
|
+
})
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
export function updateClassSyntax(
|
|
3125
|
+
base: MacroClassDeclSyntax,
|
|
3126
|
+
members: readonly MacroAnyClassMemberSyntax[],
|
|
3127
|
+
): MacroClassDeclSyntax {
|
|
3128
|
+
const hostClassDecl = getHostNode(base);
|
|
3129
|
+
if (!hostClassDecl || !ts.isClassDeclaration(hostClassDecl)) {
|
|
3130
|
+
throw new Error('Expected a class declaration-backed syntax node.');
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
const updatedClass = synthesizeHostNode(ts.factory.updateClassDeclaration(
|
|
3134
|
+
hostClassDecl,
|
|
3135
|
+
hostClassDecl.modifiers,
|
|
3136
|
+
hostClassDecl.name,
|
|
3137
|
+
hostClassDecl.typeParameters,
|
|
3138
|
+
hostClassDecl.heritageClauses,
|
|
3139
|
+
members.map((member) => synthesizeHostNode(getHostNode(member) as ts.ClassElement)),
|
|
3140
|
+
));
|
|
3141
|
+
return createDeclSyntaxFromNode(
|
|
3142
|
+
updatedClass,
|
|
3143
|
+
hostClassDecl.getSourceFile(),
|
|
3144
|
+
base.span,
|
|
3145
|
+
).asClass()!;
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
export function buildClassFieldSyntax(
|
|
3149
|
+
fileName: string,
|
|
3150
|
+
options: MacroFieldBuildOptions,
|
|
3151
|
+
): MacroClassFieldSyntax {
|
|
3152
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
3153
|
+
const initializer = options.initializer ? getHostExpression(options.initializer) : undefined;
|
|
3154
|
+
const field = synthesizeHostNode(ts.factory.createPropertyDeclaration(
|
|
3155
|
+
createModifierNodes(options.modifiers),
|
|
3156
|
+
options.name,
|
|
3157
|
+
undefined,
|
|
3158
|
+
options.type ? createTypeNodeFromText(fileName, options.type) : undefined,
|
|
3159
|
+
initializer,
|
|
3160
|
+
));
|
|
3161
|
+
return createClassFieldSyntaxFromNode(field, sourceFile, {
|
|
3162
|
+
fileName,
|
|
3163
|
+
start: 0,
|
|
3164
|
+
end: 0,
|
|
3165
|
+
});
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
export function buildClassGetterSyntax(
|
|
3169
|
+
fileName: string,
|
|
3170
|
+
options: Omit<MacroMethodBuildOptions, 'parameters'>,
|
|
3171
|
+
): MacroClassMethodSyntax {
|
|
3172
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
3173
|
+
const getter = synthesizeHostNode(ts.factory.createGetAccessorDeclaration(
|
|
3174
|
+
createModifierNodes(options.modifiers),
|
|
3175
|
+
options.name,
|
|
3176
|
+
[],
|
|
3177
|
+
undefined,
|
|
3178
|
+
cloneBlockNode(options.body),
|
|
3179
|
+
));
|
|
3180
|
+
return createClassMethodSyntaxFromNode(getter, sourceFile, {
|
|
3181
|
+
fileName,
|
|
3182
|
+
start: 0,
|
|
3183
|
+
end: 0,
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
export function buildClassSetterSyntax(
|
|
3188
|
+
fileName: string,
|
|
3189
|
+
options: MacroSetterBuildOptions,
|
|
3190
|
+
): MacroClassMethodSyntax {
|
|
3191
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
3192
|
+
const parameter = typeof options.parameter === 'string'
|
|
3193
|
+
? { name: options.parameter }
|
|
3194
|
+
: options.parameter;
|
|
3195
|
+
const setter = synthesizeHostNode(ts.factory.createSetAccessorDeclaration(
|
|
3196
|
+
createModifierNodes(options.modifiers),
|
|
3197
|
+
options.name,
|
|
3198
|
+
[
|
|
3199
|
+
synthesizeHostNode(ts.factory.createParameterDeclaration(
|
|
3200
|
+
undefined,
|
|
3201
|
+
undefined,
|
|
3202
|
+
parameter.name,
|
|
3203
|
+
undefined,
|
|
3204
|
+
parameter.type ? createTypeNodeFromText(fileName, parameter.type) : undefined,
|
|
3205
|
+
undefined,
|
|
3206
|
+
)),
|
|
3207
|
+
],
|
|
3208
|
+
cloneBlockNode(options.body),
|
|
3209
|
+
));
|
|
3210
|
+
return createClassMethodSyntaxFromNode(setter, sourceFile, {
|
|
3211
|
+
fileName,
|
|
3212
|
+
start: 0,
|
|
3213
|
+
end: 0,
|
|
3214
|
+
});
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
export function buildClassMethodSyntax(
|
|
3218
|
+
fileName: string,
|
|
3219
|
+
options: MacroMethodBuildOptions,
|
|
3220
|
+
): MacroClassMethodSyntax {
|
|
3221
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
3222
|
+
const method = synthesizeHostNode(ts.factory.createMethodDeclaration(
|
|
3223
|
+
createModifierNodes(options.modifiers),
|
|
3224
|
+
undefined,
|
|
3225
|
+
options.name,
|
|
3226
|
+
undefined,
|
|
3227
|
+
undefined,
|
|
3228
|
+
createParameterDeclarations(fileName, options.parameters),
|
|
3229
|
+
options.returnType ? createTypeNodeFromText(fileName, options.returnType) : undefined,
|
|
3230
|
+
cloneBlockNode(options.body),
|
|
3231
|
+
));
|
|
3232
|
+
return createClassMethodSyntaxFromNode(method, sourceFile, {
|
|
3233
|
+
fileName,
|
|
3234
|
+
start: 0,
|
|
3235
|
+
end: 0,
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
export function buildFunctionDeclSyntax(
|
|
3240
|
+
fileName: string,
|
|
3241
|
+
options: MacroFunctionBuildOptions,
|
|
3242
|
+
): MacroFunctionDeclSyntax {
|
|
3243
|
+
const sourceFile = createBuildSourceFile(fileName);
|
|
3244
|
+
const declaration = synthesizeHostNode(ts.factory.createFunctionDeclaration(
|
|
3245
|
+
createModifierNodes(options.modifiers),
|
|
3246
|
+
undefined,
|
|
3247
|
+
options.name,
|
|
3248
|
+
undefined,
|
|
3249
|
+
createParameterDeclarations(fileName, options.parameters),
|
|
3250
|
+
options.returnType ? createTypeNodeFromText(fileName, options.returnType) : undefined,
|
|
3251
|
+
cloneBlockNode(options.body),
|
|
3252
|
+
));
|
|
3253
|
+
return createDeclSyntaxFromNode(declaration, sourceFile, {
|
|
3254
|
+
fileName,
|
|
3255
|
+
start: 0,
|
|
3256
|
+
end: 0,
|
|
3257
|
+
}).asFunction()!;
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
export function syntaxText(node: MacroSyntaxNode): string {
|
|
3261
|
+
if ('text' in node && typeof node.text === 'function') {
|
|
3262
|
+
return node.text();
|
|
3263
|
+
}
|
|
3264
|
+
return fallbackText(node);
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
export function quoteText(value: unknown): string {
|
|
3268
|
+
if (Array.isArray(value)) {
|
|
3269
|
+
return value.map((entry) => quoteText(entry)).join('\n');
|
|
3270
|
+
}
|
|
3271
|
+
if (value && typeof value === 'object' && 'kind' in value) {
|
|
3272
|
+
return syntaxText(value as MacroSyntaxNode);
|
|
3273
|
+
}
|
|
3274
|
+
if (typeof value === 'string') {
|
|
3275
|
+
return value;
|
|
3276
|
+
}
|
|
3277
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
3278
|
+
return String(value);
|
|
3279
|
+
}
|
|
3280
|
+
if (value === null) {
|
|
3281
|
+
return 'null';
|
|
3282
|
+
}
|
|
3283
|
+
if (value === undefined) {
|
|
3284
|
+
return 'undefined';
|
|
3285
|
+
}
|
|
3286
|
+
throw new Error(`Unsupported macro quote interpolation value: ${String(value)}`);
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
function neutralizeNestedMacrosForHostParse(fileName: string, text: string): string {
|
|
3290
|
+
const hashes = scanMacroCandidates(fileName, text).hashes
|
|
3291
|
+
.filter((hash) => hash.kind === 'macro-start')
|
|
3292
|
+
.sort((left, right) => right.span.start - left.span.start);
|
|
3293
|
+
if (hashes.length === 0) {
|
|
3294
|
+
return text;
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
let rewritten = text;
|
|
3298
|
+
for (const hash of hashes) {
|
|
3299
|
+
const parsed = parseMacroInvocationAt(fileName, rewritten, hash.span.start);
|
|
3300
|
+
if ('reason' in parsed) {
|
|
3301
|
+
continue;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
const args = parsed.argumentSpans
|
|
3305
|
+
.filter((argument) => argument.kind === 'ExprArg')
|
|
3306
|
+
.map((argument) => rewritten.slice(argument.span.start, argument.span.end));
|
|
3307
|
+
const block = parsed.trailingBlockSpan
|
|
3308
|
+
? rewritten.slice(parsed.trailingBlockSpan.start, parsed.trailingBlockSpan.end)
|
|
3309
|
+
: (
|
|
3310
|
+
parsed.invocationKind === 'block' &&
|
|
3311
|
+
parsed.argumentSpans[0]?.kind === 'BlockArg'
|
|
3312
|
+
)
|
|
3313
|
+
? rewritten.slice(parsed.argumentSpans[0].span.start, parsed.argumentSpans[0].span.end)
|
|
3314
|
+
: null;
|
|
3315
|
+
|
|
3316
|
+
let replacement = `__sts_macro_${parsed.nameText}`;
|
|
3317
|
+
switch (parsed.invocationKind) {
|
|
3318
|
+
case 'arglist':
|
|
3319
|
+
replacement += `(${args.join(', ')})`;
|
|
3320
|
+
break;
|
|
3321
|
+
case 'block':
|
|
3322
|
+
replacement += `(() => ${block ?? '{}'})`;
|
|
3323
|
+
break;
|
|
3324
|
+
case 'arglist+block':
|
|
3325
|
+
replacement += `(${[...args, `() => ${block ?? '{}'}`].join(', ')})`;
|
|
3326
|
+
break;
|
|
3327
|
+
case 'decl':
|
|
3328
|
+
case 'arglist+decl':
|
|
3329
|
+
replacement = 'undefined';
|
|
3330
|
+
break;
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3333
|
+
rewritten = rewritten.slice(0, parsed.span.start) + replacement +
|
|
3334
|
+
rewritten.slice(parsed.span.end);
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
return rewritten;
|
|
3338
|
+
}
|