mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer): add babel conformance test suite (#920)
This commit is contained in:
parent
4bf329e1cf
commit
f4cea34534
10 changed files with 107 additions and 6 deletions
1
.github/workflows/conformance.yml
vendored
1
.github/workflows/conformance.yml
vendored
|
|
@ -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
13
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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' ');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
3
justfile
3
justfile
|
|
@ -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
|
||||
|
|
|
|||
21
tasks/transform_conformance/Cargo.toml
Normal file
21
tasks/transform_conformance/Cargo.toml
Normal 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 }
|
||||
46
tasks/transform_conformance/src/lib.rs
Normal file
46
tasks/transform_conformance/src/lib.rs
Normal 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:?}");
|
||||
}
|
||||
9
tasks/transform_conformance/src/main.rs
Normal file
9
tasks/transform_conformance/src/main.rs
Normal 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}");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue