From 8e4f33557d082a0969ff0885bcd9f9d6503cfebf Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Mon, 3 Jun 2024 13:25:02 +0100 Subject: [PATCH] fix(transformer): output empty file for TS definition files (#3500) As discussed in https://github.com/oxc-project/oxc/pull/3489#issuecomment-2143482458, transformer should output an empty file for TS definition files. --- crates/oxc_transformer/src/typescript/mod.rs | 9 ++++- tasks/transform_conformance/oxc.snap.md | 2 +- tasks/transform_conformance/src/test_case.rs | 35 ++++++++++++------- .../ts-declaration-empty-output/input.d.ts | 14 ++++++++ .../ts-declaration-empty-output/output.js | 0 5 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/input.d.ts create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/output.js diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index 535550a68..4ac320018 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -69,7 +69,14 @@ impl<'a> TypeScript<'a> { // Transforms impl<'a> TypeScript<'a> { pub fn transform_program(&self, program: &mut Program<'a>, ctx: &mut TraverseCtx) { - self.transform_program_for_namespace(program, ctx); + if self.ctx.source_type.is_typescript_definition() { + // Output empty file for TS definitions + program.directives.clear(); + program.hashbang = None; + program.body.clear(); + } else { + self.transform_program_for_namespace(program, ctx); + } } pub fn transform_program_on_exit(&self, program: &mut Program<'a>) { diff --git a/tasks/transform_conformance/oxc.snap.md b/tasks/transform_conformance/oxc.snap.md index a3f43767a..7e3e0fd20 100644 --- a/tasks/transform_conformance/oxc.snap.md +++ b/tasks/transform_conformance/oxc.snap.md @@ -1,6 +1,6 @@ commit: 4bd1b2c2 -Passed: 2/2 +Passed: 3/3 # All Passed: * babel-plugin-transform-typescript diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs index 078fa7207..11051dfa4 100644 --- a/tasks/transform_conformance/src/test_case.rs +++ b/tasks/transform_conformance/src/test_case.rs @@ -37,9 +37,12 @@ impl TestCaseKind { return Some(Self::Exec(ExecTestCase::new(cwd, path))); } - // named `input.[ext]`` - if path.file_stem().is_some_and(|name| name == "input") - && path.extension().is_some_and(|ext| VALID_EXTENSIONS.contains(&ext.to_str().unwrap())) + // named `input.[ext]` or `input.d.ts` + if (path.file_stem().is_some_and(|name| name == "input") + && path + .extension() + .is_some_and(|ext| VALID_EXTENSIONS.contains(&ext.to_str().unwrap()))) + || path.file_name().is_some_and(|name| name == "input.d.ts") { return Some(Self::Transform(ConformanceTestCase::new(cwd, path))); } @@ -156,11 +159,15 @@ pub trait TestCase { let allocator = Allocator::default(); let source_text = fs::read_to_string(path).unwrap(); - let source_type = SourceType::from_path(path).unwrap().with_typescript( - // Some babel test cases have a js extension, but contain typescript code. - // Therefore, if the typescript plugin exists, enable the typescript. - self.options().get_plugin("transform-typescript").is_some(), - ); + // Some babel test cases have a js extension, but contain typescript code. + // Therefore, if the typescript plugin exists, enable typescript. + let mut source_type = SourceType::from_path(path).unwrap(); + if !source_type.is_typescript() + && (self.options().get_plugin("transform-typescript").is_some() + || self.options().get_plugin("syntax-typescript").is_some()) + { + source_type = source_type.with_typescript(true); + } let ret = Parser::new(&allocator, &source_text, source_type).parse(); let mut program = ret.program; @@ -224,18 +231,20 @@ impl TestCase for ConformanceTestCase { .as_ref() .is_some_and(|path| path.extension().and_then(std::ffi::OsStr::to_str) == Some("js")); - let source_type = SourceType::from_path(&self.path) + let mut source_type = SourceType::from_path(&self.path) .unwrap() .with_script(if self.options.source_type.is_some() { !self.options.is_module() } else { input_is_js && output_is_js }) - .with_typescript( - self.options.get_plugin("transform-typescript").is_some() - || self.options.get_plugin("syntax-typescript").is_some(), - ) .with_jsx(self.options.get_plugin("syntax-jsx").is_some()); + if !source_type.is_typescript() + && (self.options.get_plugin("transform-typescript").is_some() + || self.options.get_plugin("syntax-typescript").is_some()) + { + source_type = source_type.with_typescript(true); + } if filtered { println!("input_path: {:?}", &self.path); diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/input.d.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/input.d.ts new file mode 100644 index 000000000..42d4b8a98 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/input.d.ts @@ -0,0 +1,14 @@ +export interface Things { + p: P; + t: T; +} + +export interface Props { +} + +export default class MyComponent { + props: Props; +} +export namespace Something { + export const foo = 123; +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/ts-declaration-empty-output/output.js new file mode 100644 index 000000000..e69de29bb