From 51a27022b9a3fa8767797813b23803ea1ecad3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sat, 22 Jun 2024 08:46:37 +0900 Subject: [PATCH] feat(es/transform): Add experimental `.d.ts` generation (#9093) --- Cargo.lock | 1 + crates/swc/Cargo.toml | 1 + crates/swc/src/config/mod.rs | 10 ++ crates/swc/src/lib.rs | 34 +++- .../2020/case1/input/index.swc-stderr | 11 ++ .../8935/input/src/button.swc-stderr | 12 ++ .../ignore-dynamic/1/input/index.swc-stderr | 12 ++ crates/swc/tests/projects.rs | 160 +++++++++++------- .../ts-isolated-declaration/error/.swcrc | 10 ++ .../ts-isolated-declaration/oxc/README.md | 3 + .../ts-isolated-declaration/oxc/input/.swcrc | 11 ++ .../oxc/input/arrow-function-return-type.ts | 9 + .../oxc/input/as-const.swc-stderr | 16 ++ .../oxc/input/as-const.ts | 16 ++ .../oxc/input/async-function.ts | 16 ++ .../oxc/input/eliminate-imports.ts | 7 + .../oxc/input/empty-export.ts | 4 + .../oxc/input/function-overloads.swc-stderr | 11 ++ .../oxc/input/function-overloads.ts | 7 + .../oxc/input/function-parameters.ts | 24 +++ .../oxc/input/generator.ts | 10 ++ .../oxc/input/infer-expression.swc-stderr | 31 ++++ .../oxc/input/infer-expression.ts | 5 + .../oxc/input/infer-return-type.ts | 27 +++ .../input/infer-template-literal.swc-stderr | 28 +++ .../oxc/input/infer-template-literal.ts | 10 ++ .../non-exported-binding-elements.swc-stderr | 24 +++ .../input/non-exported-binding-elements.ts | 10 ++ .../oxc/input/readonly.ts | 4 + .../output/arrow-function-return-type.d.ts | 3 + .../oxc/output/arrow-function-return-type.ts | 9 + .../oxc/output/as-const.d.ts | 17 ++ .../oxc/output/as-const.ts | 22 +++ .../oxc/output/async-function.d.ts | 4 + .../oxc/output/async-function.ts | 58 +++++++ .../oxc/output/eliminate-imports.d.ts | 9 + .../oxc/output/eliminate-imports.ts | 20 +++ .../oxc/output/empty-export.d.ts | 2 + .../oxc/output/empty-export.ts | 3 + .../oxc/output/function-overloads.d.ts | 5 + .../oxc/output/function-overloads.ts | 3 + .../oxc/output/function-parameters.d.ts | 15 ++ .../oxc/output/function-parameters.ts | 46 +++++ .../oxc/output/generator.d.ts | 2 + .../oxc/output/generator.ts | 28 +++ .../oxc/output/infer-expression.d.ts | 4 + .../oxc/output/infer-expression.ts | 5 + .../oxc/output/infer-return-type.d.ts | 4 + .../oxc/output/infer-return-type.ts | 24 +++ .../oxc/output/infer-template-literal.d.ts | 7 + .../oxc/output/infer-template-literal.ts | 11 ++ .../output/non-exported-binding-elements.d.ts | 5 + .../output/non-exported-binding-elements.ts | 16 ++ .../oxc/output/readonly.d.ts | 4 + .../oxc/output/readonly.ts | 2 + .../ts-isolated-declaration/simple/.swcrc | 10 ++ .../ts-isolated-declaration/simple/input/1.ts | 4 + .../ts-isolated-declaration/simple/input/2.ts | 1 + .../ts-isolated-declaration/simple/input/3.ts | 1 + .../simple/output/1.d.ts | 1 + .../simple/output/1.ts | 1 + .../simple/output/2.d.ts | 1 + .../simple/output/2.ts | 1 + .../simple/output/3.d.ts | 4 + .../simple/output/3.ts | 5 + crates/swc_typescript/src/diagnostic.rs | 14 +- crates/swc_typescript/src/fast_dts/mod.rs | 2 +- 67 files changed, 825 insertions(+), 72 deletions(-) create mode 100644 crates/swc/tests/fixture/issues-2xxx/2020/case1/input/index.swc-stderr create mode 100644 crates/swc/tests/fixture/issues-8xxx/8935/input/src/button.swc-stderr create mode 100644 crates/swc/tests/fixture/module/ignore-dynamic/1/input/index.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/error/.swcrc create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/README.md create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/.swcrc create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/arrow-function-return-type.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/as-const.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/as-const.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/async-function.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/eliminate-imports.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/empty-export.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/function-overloads.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/function-overloads.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/function-parameters.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/generator.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/infer-expression.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/infer-expression.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/infer-return-type.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/infer-template-literal.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/infer-template-literal.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/non-exported-binding-elements.swc-stderr create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/non-exported-binding-elements.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/input/readonly.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/arrow-function-return-type.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/arrow-function-return-type.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/as-const.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/as-const.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/async-function.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/async-function.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/eliminate-imports.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/eliminate-imports.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/empty-export.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/empty-export.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/function-overloads.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/function-overloads.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/function-parameters.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/function-parameters.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/generator.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/generator.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-expression.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-expression.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-return-type.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-return-type.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-template-literal.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/infer-template-literal.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/non-exported-binding-elements.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/non-exported-binding-elements.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/readonly.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/oxc/output/readonly.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/.swcrc create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/input/1.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/input/2.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/input/3.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/1.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/1.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/2.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/2.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/3.d.ts create mode 100644 crates/swc/tests/ts-isolated-declaration/simple/output/3.ts diff --git a/Cargo.lock b/Cargo.lock index 62ce8e21205d..613086248ca1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3744,6 +3744,7 @@ dependencies = [ "swc_plugin_runner", "swc_timer", "swc_transform_common", + "swc_typescript", "swc_visit", "testing", "tokio", diff --git a/crates/swc/Cargo.toml b/crates/swc/Cargo.toml index 9a38ea24db9a..af8daedcc1d6 100644 --- a/crates/swc/Cargo.toml +++ b/crates/swc/Cargo.toml @@ -107,6 +107,7 @@ swc_plugin_proxy = { version = "0.44.0", path = "../swc_plugin_proxy", optional swc_plugin_runner = { version = "0.109.0", path = "../swc_plugin_runner", optional = true, default-features = false } swc_timer = { version = "0.22.0", path = "../swc_timer" } swc_transform_common = { version = "0.1.1", path = "../swc_transform_common" } +swc_typescript = { version = "0.1.1", path = "../swc_typescript" } swc_visit = { version = "0.5.14", path = "../swc_visit" } [dependencies.tokio] diff --git a/crates/swc/src/config/mod.rs b/crates/swc/src/config/mod.rs index aaf7cc9a5079..96bb7a2521aa 100644 --- a/crates/swc/src/config/mod.rs +++ b/crates/swc/src/config/mod.rs @@ -782,6 +782,7 @@ impl Options { emit_assert_for_import_attributes: experimental .emit_assert_for_import_attributes .into_bool(), + emit_isolated_dts: experimental.emit_isolated_dts.into_bool(), }) } } @@ -1088,6 +1089,8 @@ pub struct BuiltInput { pub output: JscOutputConfig, pub emit_assert_for_import_attributes: bool, + + pub emit_isolated_dts: bool, } impl

BuiltInput

@@ -1117,6 +1120,7 @@ where emit_source_map_columns: self.emit_source_map_columns, output: self.output, emit_assert_for_import_attributes: self.emit_assert_for_import_attributes, + emit_isolated_dts: self.emit_isolated_dts, } } } @@ -1211,6 +1215,12 @@ pub struct JscExperimental { #[serde(default)] pub disable_builtin_transforms_for_internal_testing: BoolConfig, + + /// Emit TypeScript definitions for `.ts`, `.tsx` files. + /// + /// This requires `isolatedDeclartion` feature of TypeScript 5.5. + #[serde(default)] + pub emit_isolated_dts: BoolConfig, } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs index 576016539cd9..a529608a7544 100644 --- a/crates/swc/src/lib.rs +++ b/crates/swc/src/lib.rs @@ -136,7 +136,7 @@ use swc_common::{ pub use swc_compiler_base::{PrintArgs, TransformOutput}; pub use swc_config::config_types::{BoolConfig, BoolOr, BoolOrDataConfig}; use swc_ecma_ast::{EsVersion, Program}; -use swc_ecma_codegen::Node; +use swc_ecma_codegen::{to_code, Node}; use swc_ecma_loader::resolvers::{ lru::CachingResolver, node::NodeModulesResolver, tsc::TsConfigResolver, }; @@ -155,6 +155,8 @@ use swc_ecma_visit::{FoldWith, VisitMutWith, VisitWith}; pub use swc_error_reporters::handler::{try_with_handler, HandlerOpts}; pub use swc_node_comments::SwcComments; use swc_timer::timer; +use swc_transform_common::output::emit; +use swc_typescript::fast_dts::FastDts; use tracing::warn; use url::Url; @@ -731,7 +733,7 @@ impl Compiler { None }; - self.apply_transforms(handler, orig, config) + self.apply_transforms(handler, fm.clone(), orig, config) }) } @@ -949,11 +951,13 @@ impl Compiler { fn apply_transforms( &self, handler: &Handler, + fm: Arc, orig: Option, config: BuiltInput, ) -> Result { self.run(|| { let program = config.program; + let emit_dts = config.syntax.typescript() && config.emit_isolated_dts; let source_map_names = if config.source_maps.enabled() { let mut v = swc_compiler_base::IdentCollector { names: Default::default(), @@ -966,8 +970,34 @@ impl Compiler { Default::default() }; + let dts_code = if emit_dts && program.is_module() { + let mut checker = FastDts::new(fm.name.clone().into()); + let mut module = program.clone().expect_module(); + + let issues = checker.transform(&mut module); + + for issue in issues { + let range = issue.range(); + + handler + .struct_span_err(range.span, &issue.to_string()) + .emit(); + } + let dts_code = to_code(&module); + Some(dts_code) + } else { + None + }; + let mut pass = config.pass; let (program, output) = swc_transform_common::output::capture(|| { + if let Some(dts_code) = dts_code { + emit( + "__swc_isolated_declarations__".into(), + serde_json::Value::String(dts_code), + ); + } + helpers::HELPERS.set(&Helpers::new(config.external_helpers), || { HANDLER.set(handler, || { // Fold module diff --git a/crates/swc/tests/fixture/issues-2xxx/2020/case1/input/index.swc-stderr b/crates/swc/tests/fixture/issues-2xxx/2020/case1/input/index.swc-stderr new file mode 100644 index 000000000000..ca3c223d80b7 --- /dev/null +++ b/crates/swc/tests/fixture/issues-2xxx/2020/case1/input/index.swc-stderr @@ -0,0 +1,11 @@ + + x cannot reassign to a variable declared with `const` + ,-[$DIR/tests/fixture/issues-2xxx/2020/case1/input/index.js:1:1] + 1 | const createRegisterItems = (registerType) => async (a, b) => { + : | + : `-- cannot reassign + 2 | const a = root?.test; + : | + : `-- const variable was declared here + 3 | }; + `---- diff --git a/crates/swc/tests/fixture/issues-8xxx/8935/input/src/button.swc-stderr b/crates/swc/tests/fixture/issues-8xxx/8935/input/src/button.swc-stderr new file mode 100644 index 000000000000..df5e54f0bf35 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8935/input/src/button.swc-stderr @@ -0,0 +1,12 @@ + + x the name `Button` is defined multiple times + ,-[$DIR/tests/fixture/issues-8xxx/8935/input/src/button.jsx:1:1] + 1 | export function Button(props) { + : ^^^|^^ + : `-- previous definition of `Button` here + 2 | return