Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions crates/oxc_transformer/examples/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use oxc_codegen::CodeGenerator;
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{ESTarget, TransformOptions, Transformer};
use oxc_transformer::{ESTarget, EnvOptions, TransformOptions, Transformer};
use pico_args::Arguments;

// Instruction:
Expand Down Expand Up @@ -55,14 +55,11 @@ fn main() {

let (symbols, scopes) = ret.semantic.into_symbol_table_and_scope_tree();

let transform_options = if let Some(_targets) = &targets {
// FIXME
TransformOptions::enable_all()
// TransformOptions::try_from(&BabelEnvOptions {
// targets: Targets::try_from_query(targets).unwrap(),
// ..BabelEnvOptions::default()
// })
// .unwrap()
let transform_options = if let Some(query) = &targets {
TransformOptions {
env: EnvOptions::from_browerslist_query(query).unwrap(),
..TransformOptions::default()
}
} else if let Some(target) = &target {
TransformOptions::from(ESTarget::from_str(target).unwrap())
} else {
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_transformer/src/options/babel/env/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl Targets {
/// # Errors
///
/// * Query is invalid.
pub fn try_from_query(query: &str) -> Result<Self, oxc_diagnostics::Error> {
pub fn try_from_query(query: &str) -> Result<Self, Error> {
Query::Single(query.to_string()).exec().map(|v| v.0).map(Self)
}

Expand Down
16 changes: 16 additions & 0 deletions crates/oxc_transformer/src/options/env.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::str::FromStr;

use cow_utils::CowUtils;
use oxc_diagnostics::Error;
use serde::Deserialize;

use crate::{
Expand All @@ -13,6 +14,7 @@ use crate::{
es2021::ES2021Options,
es2022::{ClassPropertiesOptions, ES2022Options},
regexp::RegExpOptions,
Targets,
};

use super::babel::BabelEnvOptions;
Expand Down Expand Up @@ -131,6 +133,20 @@ impl EnvOptions {
},
}
}

/// # Errors
///
/// * When the query failed to parse.
pub fn from_browerslist_query(query: &str) -> Result<Self, Error> {
Self::try_from(BabelEnvOptions {
targets: Targets::try_from_query(query)?,
// This option will be enabled by default in Babel 8.
// <https://babel.dev/docs/babel-preset-env#bugfixes>
bugfixes: true,
..BabelEnvOptions::default()
})
.map_err(|err| Error::msg(err))
}
}

impl From<ESTarget> for EnvOptions {
Expand Down
38 changes: 8 additions & 30 deletions crates/oxc_transformer/tests/es_target/mod.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
use std::{path::Path, str::FromStr};
use std::str::FromStr;

use oxc_allocator::Allocator;
use oxc_codegen::{CodeGenerator, CodegenOptions};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use crate::{codegen, test};
use oxc_span::SourceType;
use oxc_transformer::{ESTarget, TransformOptions, Transformer};

use crate::run;

pub(crate) fn test(source_text: &str, target: &str) -> String {
let source_type = SourceType::default();
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
let mut program = ret.program;
let (symbols, scopes) =
SemanticBuilder::new().build(&program).semantic.into_symbol_table_and_scope_tree();
let options = TransformOptions::from(ESTarget::from_str(target).unwrap());
Transformer::new(&allocator, Path::new(""), options).build_with_symbols_and_scopes(
symbols,
scopes,
&mut program,
);
CodeGenerator::new()
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
.build(&program)
.code
}
use oxc_transformer::{ESTarget, TransformOptions};

#[test]
fn es2015() {
fn es_target() {
use std::fmt::Write;

let cases = [
Expand All @@ -45,11 +21,13 @@ fn es2015() {

// Test no transformation for esnext.
for (_, case) in cases {
assert_eq!(run(case, SourceType::mjs()), test(case, "esnext"));
let options = TransformOptions::from(ESTarget::from_str("esnext").unwrap());
assert_eq!(codegen(case, SourceType::mjs()), test(case, options));
}

let snapshot = cases.iter().enumerate().fold(String::new(), |mut w, (i, (target, case))| {
let result = test(case, target);
let options = TransformOptions::from(ESTarget::from_str(target).unwrap());
let result = test(case, options);
write!(w, "########## {i} {target}\n{case}\n----------\n{result}\n").unwrap();
w
});
Expand Down
25 changes: 24 additions & 1 deletion crates/oxc_transformer/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
mod es_target;
mod plugins;
mod targets;

use std::path::Path;

use oxc_allocator::Allocator;
use oxc_codegen::{CodeGenerator, CodegenOptions};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{TransformOptions, Transformer};

pub fn run(source_text: &str, source_type: SourceType) -> String {
pub fn codegen(source_text: &str, source_type: SourceType) -> String {
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
CodeGenerator::new()
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
.build(&ret.program)
.code
}

pub(crate) fn test(source_text: &str, options: TransformOptions) -> String {
let source_type = SourceType::default();
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
let mut program = ret.program;
let (symbols, scopes) =
SemanticBuilder::new().build(&program).semantic.into_symbol_table_and_scope_tree();
Transformer::new(&allocator, Path::new(""), options).build_with_symbols_and_scopes(
symbols,
scopes,
&mut program,
);
CodeGenerator::new()
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
.build(&program)
.code
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{InjectGlobalVariables, InjectGlobalVariablesConfig, InjectImport};

use crate::run;
use crate::codegen;

pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariablesConfig) {
let source_type = SourceType::default();
Expand All @@ -23,7 +23,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariab
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
.build(&program)
.code;
let expected = run(expected, source_type);
let expected = codegen(expected, source_type);
assert_eq!(result, expected, "for source {source_text}");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{ReplaceGlobalDefines, ReplaceGlobalDefinesConfig};

use crate::run;
use crate::codegen;

pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefinesConfig) {
let source_type = SourceType::default();
Expand All @@ -19,7 +19,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefin
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
.build(&program)
.code;
let expected = run(expected, source_type);
let expected = codegen(expected, source_type);
assert_eq!(result, expected, "for source {source_text}");
}

Expand Down
36 changes: 36 additions & 0 deletions crates/oxc_transformer/tests/targets/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::{codegen, test};
use oxc_span::SourceType;
use oxc_transformer::{ESTarget, EnvOptions, TransformOptions};

#[test]
fn targets() {
let cases = [
("() => {}"),
("a ** b"),
// ("async function foo() {}"),
("({ ...x })"),
("try {} catch {}"),
("a ?? b"),
("a ||= b"),
// ("class foo { static {} }"),
];

// Test no transformation for default targets.
for case in cases {
let options = TransformOptions {
env: EnvOptions::from_browerslist_query("defaults").unwrap(),
..TransformOptions::default()
};
assert_eq!(codegen(case, SourceType::mjs()), test(case, options));
}

// Test transformation for very low targets.
for case in cases {
let options = TransformOptions::from(ESTarget::ES5);
let options_node = TransformOptions {
env: EnvOptions::from_browerslist_query("node 0.10").unwrap(),
..TransformOptions::default()
};
assert_eq!(test(case, options), test(case, options_node));
}
}