feat(transformer): add babel conformance test suite (#920)

This commit is contained in:
Boshen 2023-09-16 18:50:51 +08:00 committed by GitHub
parent 4bf329e1cf
commit f4cea34534
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 107 additions and 6 deletions

View file

@ -49,6 +49,7 @@ jobs:
uses: ./.github/actions/rustup
- run: cargo coverage
- run: cargo run --release -p oxc_transform_conformance
# - run: cargo minsize

13
Cargo.lock generated
View file

@ -1719,6 +1719,19 @@ dependencies = [
"url",
]
[[package]]
name = "oxc_transform_conformance"
version = "0.0.0"
dependencies = [
"oxc_allocator",
"oxc_formatter",
"oxc_parser",
"oxc_span",
"oxc_tasks_common",
"oxc_transformer",
"walkdir",
]
[[package]]
name = "oxc_transformer"
version = "0.2.0"

View file

@ -848,11 +848,11 @@ impl Gen for RegExpLiteral {
impl Gen for StringLiteral {
fn gen(&self, p: &mut Formatter) {
p.print(b'\'');
p.print_quote();
for c in self.value.chars() {
p.print_str(c.escape_default().to_string().as_bytes());
}
p.print(b'\'');
p.print_quote();
}
}

View file

@ -54,12 +54,14 @@ pub enum FinalEndOfLine {
#[derive(Debug, Clone)]
pub struct FormatterOptions {
pub indentation: u8,
// <https://prettier.io/docs/en/options#quotes>
pub single_quote: bool,
pub end_of_line: EndOfLine,
}
impl Default for FormatterOptions {
fn default() -> Self {
Self { indentation: 4, end_of_line: EndOfLine::LF }
Self { indentation: 4, single_quote: false, end_of_line: EndOfLine::LF }
}
}
@ -68,12 +70,14 @@ impl Default for FormatterOptions {
pub struct InnerOptions {
pub indentation: u8,
pub end_of_line: FinalEndOfLine,
pub single_quote: bool,
}
impl From<FormatterOptions> for InnerOptions {
fn from(options: FormatterOptions) -> Self {
Self {
indentation: options.indentation,
single_quote: options.single_quote,
end_of_line: options.end_of_line.get_final_end_of_line(),
}
}
@ -208,6 +212,11 @@ impl Formatter {
self.print(b'=');
}
#[inline]
pub fn print_quote(&mut self) {
self.print(if self.options.single_quote { b'\'' } else { b'"' });
}
pub fn print_indent(&mut self) {
for _ in 0..self.indentation {
self.print(b' ');

View file

@ -21,7 +21,7 @@ impl<'a> OptionalCatchBinding<'a> {
if clause.param.is_some() {
return;
}
let binding_identifier = BindingIdentifier::new(Span::default(), "unused".into());
let binding_identifier = BindingIdentifier::new(Span::default(), "_unused".into());
let binding_pattern_kind = self.ast.binding_identifier(binding_identifier);
let binding_pattern = self.ast.binding_pattern(binding_pattern_kind, None, false);
clause.param = Some(binding_pattern);

View file

@ -19,12 +19,13 @@ use es2019::OptionalCatchBinding;
#[derive(Debug, Default, Clone)]
pub struct TransformOptions {
target: TransformTarget,
pub target: TransformTarget,
}
/// See <https://www.typescriptlang.org/tsconfig#target>
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum TransformTarget {
ES2015,
ES2016,
ES2019,
#[default]

View file

@ -56,9 +56,10 @@ test:
lint:
cargo lint -- --deny warnings
# Run all the conformance tests. See `tasks/coverage`, `tasks/minsize`
# Run all the conformance tests. See `tasks/coverage`, `tasks/transform_conformance`, `tasks/minsize`
coverage:
cargo coverage
cargo run --release -p oxc_transform_conformance
# cargo minsize
# Get code coverage

View file

@ -0,0 +1,21 @@
[package]
name = "oxc_transform_conformance"
version = "0.0.0"
publish = false
authors.workspace = true
description.workspace = true
edition.workspace = true
homepage.workspace = true
keywords.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
oxc_span = { workspace = true }
oxc_allocator = { workspace = true }
oxc_parser = { workspace = true }
oxc_formatter = { workspace = true }
oxc_transformer = { workspace = true }
oxc_tasks_common = { workspace = true }
walkdir = { workspace = true }

View file

@ -0,0 +1,46 @@
use std::{fs, path::Path};
use walkdir::WalkDir;
use oxc_allocator::Allocator;
use oxc_formatter::{Formatter, FormatterOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;
use oxc_tasks_common::project_root;
use oxc_transformer::{TransformOptions, TransformTarget, Transformer};
/// # Panics
pub fn babel(name: &str) {
let root = project_root().join("tasks/coverage/babel/packages");
let root = root.join(name).join("test/fixtures");
let paths = WalkDir::new(root)
.into_iter()
.filter_map(Result::ok)
.filter(|e| e.file_name() == "input.js")
.map(|e| e.path().parent().unwrap().to_path_buf())
.collect::<Vec<_>>();
for path in paths {
babel_test(&path);
}
}
fn babel_test(path: &Path) {
let input_path = path.join("input.js");
let output_path = path.join("output.js");
let source_text = fs::read_to_string(&input_path).unwrap();
let expected = fs::read_to_string(output_path).unwrap();
let allocator = Allocator::default();
let source_type = SourceType::from_path(&input_path).unwrap();
let ret = Parser::new(&allocator, &source_text, source_type).parse();
let transform_options = TransformOptions { target: TransformTarget::ES2015 };
let program = allocator.alloc(ret.program);
Transformer::new(&allocator, &transform_options).build(program);
let formatter_options = FormatterOptions::default();
let printed = Formatter::new(source_text.len(), formatter_options).build(program);
let printed = printed.replace(|c: char| c.is_ascii_whitespace(), "");
let expected = expected.replace(|c: char| c.is_ascii_whitespace(), "");
assert_eq!(printed, expected, "{path:?}");
}

View file

@ -0,0 +1,9 @@
use oxc_transform_conformance::babel;
fn main() {
let names = ["babel-plugin-transform-optional-catch-binding"];
for name in names {
babel(name);
println!("Passed: {name}");
}
}