diff --git a/Cargo.lock b/Cargo.lock index 42044dcf870f3..6f88e7ba507c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,6 +1333,7 @@ dependencies = [ "oxc_sourcemap", "oxc_span", "oxc_tasks_common", + "oxc_transformer", "phf", "pico-args", "project-root", diff --git a/tasks/coverage/Cargo.toml b/tasks/coverage/Cargo.toml index 89b42154b2ab2..4021bb3c7dc2b 100644 --- a/tasks/coverage/Cargo.toml +++ b/tasks/coverage/Cargo.toml @@ -32,6 +32,7 @@ oxc_prettier = { workspace = true } oxc_span = { workspace = true } oxc_tasks_common = { workspace = true } oxc_sourcemap = { workspace = true } +oxc_transformer = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/tasks/coverage/src/lib.rs b/tasks/coverage/src/lib.rs index 22c13d9dabcdb..5ff01a152ea01 100644 --- a/tasks/coverage/src/lib.rs +++ b/tasks/coverage/src/lib.rs @@ -1,13 +1,17 @@ +// Core +mod runtime; +mod suite; +// Suites mod babel; +mod misc; +mod test262; +mod typescript; +// Tools mod codegen; mod minifier; -mod misc; mod prettier; -mod runtime; mod sourcemap; -mod suite; -mod test262; -mod typescript; +mod transformer; use std::{fs, path::PathBuf, process::Command, time::Duration}; @@ -24,6 +28,10 @@ use crate::{ prettier::{PrettierBabelCase, PrettierMiscCase, PrettierTest262Case, PrettierTypeScriptCase}, suite::Suite, test262::{Test262Case, Test262Suite}, + transformer::{ + TransformerBabelCase, TransformerMiscCase, TransformerTest262Case, + TransformerTypeScriptCase, + }, typescript::{TypeScriptCase, TypeScriptSuite}, }; @@ -50,6 +58,7 @@ impl AppArgs { self.run_parser(); self.run_codegen(); self.run_prettier(); + self.run_transformer(); // self.run_codegen_runtime(); self.run_minifier(); } @@ -76,6 +85,13 @@ impl AppArgs { MiscSuite::::new().run("prettier_misc", self); } + pub fn run_transformer(&self) { + Test262Suite::::new().run("transformer_test262", self); + BabelSuite::::new().run("transformer_babel", self); + TypeScriptSuite::::new().run("transformer_typescript", self); + MiscSuite::::new().run("transformer_misc", self); + } + /// # Panics pub fn run_codegen_runtime(&self) { // Run runtime.js to test codegen runtime diff --git a/tasks/coverage/src/main.rs b/tasks/coverage/src/main.rs index 2b1694f02ec2e..31f63fbec0aa6 100644 --- a/tasks/coverage/src/main.rs +++ b/tasks/coverage/src/main.rs @@ -18,6 +18,7 @@ fn main() { "codegen" => args.run_codegen(), "codegen-runtime" => args.run_codegen_runtime(), "prettier" => args.run_prettier(), + "transformer" => args.run_transformer(), "minifier" => args.run_minifier(), "v8_test262_status" => args.run_sync_v8_test262_status(), _ => args.run_all(), diff --git a/tasks/coverage/src/transformer.rs b/tasks/coverage/src/transformer.rs new file mode 100644 index 0000000000000..7ab24e0eb3a39 --- /dev/null +++ b/tasks/coverage/src/transformer.rs @@ -0,0 +1,163 @@ +use std::path::{Path, PathBuf}; + +use oxc_allocator::Allocator; +use oxc_parser::Parser; +use oxc_semantic::SemanticBuilder; +use oxc_span::SourceType; +use oxc_transformer::{TransformOptions, Transformer}; + +use crate::{ + babel::BabelCase, + misc::MiscCase, + suite::{Case, TestResult}, + test262::{Test262Case, TestFlag}, + typescript::TypeScriptCase, +}; + +/// Runs the transformer and make sure it doesn't crash. +/// TODO: add codegen to turn on idempotency test. +fn get_result(source_text: &str, source_type: SourceType, source_path: &Path) -> TestResult { + let allocator = Allocator::default(); + + let parser_ret = Parser::new(&allocator, source_text, source_type).parse(); + + let semantic_ret = SemanticBuilder::new(source_text, source_type) + .with_trivias(parser_ret.trivias) + .with_check_syntax_error(true) + .build(&parser_ret.program); + + let mut program = parser_ret.program; + let options = TransformOptions::default(); + let _ = Transformer::new(&allocator, source_path, semantic_ret.semantic, options) + .build(&mut program); + TestResult::Passed +} + +pub struct TransformerTest262Case { + base: Test262Case, +} + +impl Case for TransformerTest262Case { + fn new(path: PathBuf, code: String) -> Self { + Self { base: Test262Case::new(path, code) } + } + + fn code(&self) -> &str { + self.base.code() + } + + fn path(&self) -> &Path { + self.base.path() + } + + fn test_result(&self) -> &TestResult { + self.base.test_result() + } + + fn skip_test_case(&self) -> bool { + self.base.should_fail() + } + + fn run(&mut self) { + let source_text = self.base.code(); + let is_module = self.base.meta().flags.contains(&TestFlag::Module); + let source_type = SourceType::default().with_module(is_module); + let result = get_result(source_text, source_type, self.path()); + self.base.set_result(result); + } +} + +pub struct TransformerBabelCase { + base: BabelCase, +} + +impl Case for TransformerBabelCase { + fn new(path: PathBuf, code: String) -> Self { + Self { base: BabelCase::new(path, code) } + } + + fn code(&self) -> &str { + self.base.code() + } + + fn path(&self) -> &Path { + self.base.path() + } + + fn test_result(&self) -> &TestResult { + self.base.test_result() + } + + fn skip_test_case(&self) -> bool { + self.base.skip_test_case() || self.base.should_fail() + } + + fn run(&mut self) { + let source_text = self.base.code(); + let source_type = self.base.source_type(); + let result = get_result(source_text, source_type, self.path()); + self.base.set_result(result); + } +} + +pub struct TransformerTypeScriptCase { + base: TypeScriptCase, +} + +impl Case for TransformerTypeScriptCase { + fn new(path: PathBuf, code: String) -> Self { + Self { base: TypeScriptCase::new(path, code) } + } + + fn code(&self) -> &str { + self.base.code() + } + + fn path(&self) -> &Path { + self.base.path() + } + + fn test_result(&self) -> &TestResult { + self.base.test_result() + } + + fn skip_test_case(&self) -> bool { + self.base.skip_test_case() || self.base.should_fail() + } + + fn run(&mut self) { + let result = get_result(self.base.code(), self.base.source_type(), self.path()); + self.base.set_result(result); + } +} + +pub struct TransformerMiscCase { + base: MiscCase, +} + +impl Case for TransformerMiscCase { + fn new(path: PathBuf, code: String) -> Self { + Self { base: MiscCase::new(path, code) } + } + + fn code(&self) -> &str { + self.base.code() + } + + fn path(&self) -> &Path { + self.base.path() + } + + fn test_result(&self) -> &TestResult { + self.base.test_result() + } + + fn skip_test_case(&self) -> bool { + self.base.skip_test_case() || self.base.should_fail() + } + + fn run(&mut self) { + let result = get_result(self.base.code(), self.base.source_type(), self.path()); + self.base.set_result(result); + } +} diff --git a/tasks/coverage/transformer_babel.snap b/tasks/coverage/transformer_babel.snap new file mode 100644 index 0000000000000..70f588b7ffe38 --- /dev/null +++ b/tasks/coverage/transformer_babel.snap @@ -0,0 +1,3 @@ +transformer_babel Summary: +AST Parsed : 2097/2097 (100.00%) +Positive Passed: 2097/2097 (100.00%) diff --git a/tasks/coverage/transformer_misc.snap b/tasks/coverage/transformer_misc.snap new file mode 100644 index 0000000000000..0fda3ca94d8e2 --- /dev/null +++ b/tasks/coverage/transformer_misc.snap @@ -0,0 +1,3 @@ +transformer_misc Summary: +AST Parsed : 15/15 (100.00%) +Positive Passed: 15/15 (100.00%) diff --git a/tasks/coverage/transformer_test262.snap b/tasks/coverage/transformer_test262.snap new file mode 100644 index 0000000000000..1c2bd07d0d2c4 --- /dev/null +++ b/tasks/coverage/transformer_test262.snap @@ -0,0 +1,3 @@ +transformer_test262 Summary: +AST Parsed : 45836/45836 (100.00%) +Positive Passed: 45836/45836 (100.00%) diff --git a/tasks/coverage/transformer_typescript.snap b/tasks/coverage/transformer_typescript.snap new file mode 100644 index 0000000000000..22524946c441d --- /dev/null +++ b/tasks/coverage/transformer_typescript.snap @@ -0,0 +1,3 @@ +transformer_typescript Summary: +AST Parsed : 5243/5243 (100.00%) +Positive Passed: 5243/5243 (100.00%)