mirror of
https://github.com/danbulant/oxc
synced 2026-05-20 20:58:48 +00:00
feat(transformer): add EnvOptions::from_browerslist_query API (#7098)
This commit is contained in:
parent
21b8e4988f
commit
bfdbcf1c6a
8 changed files with 95 additions and 45 deletions
|
|
@ -6,7 +6,7 @@ use oxc_codegen::CodeGenerator;
|
||||||
use oxc_parser::Parser;
|
use oxc_parser::Parser;
|
||||||
use oxc_semantic::SemanticBuilder;
|
use oxc_semantic::SemanticBuilder;
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
use oxc_transformer::{ESTarget, TransformOptions, Transformer};
|
use oxc_transformer::{ESTarget, EnvOptions, TransformOptions, Transformer};
|
||||||
use pico_args::Arguments;
|
use pico_args::Arguments;
|
||||||
|
|
||||||
// Instruction:
|
// Instruction:
|
||||||
|
|
@ -55,14 +55,11 @@ fn main() {
|
||||||
|
|
||||||
let (symbols, scopes) = ret.semantic.into_symbol_table_and_scope_tree();
|
let (symbols, scopes) = ret.semantic.into_symbol_table_and_scope_tree();
|
||||||
|
|
||||||
let transform_options = if let Some(_targets) = &targets {
|
let transform_options = if let Some(query) = &targets {
|
||||||
// FIXME
|
TransformOptions {
|
||||||
TransformOptions::enable_all()
|
env: EnvOptions::from_browerslist_query(query).unwrap(),
|
||||||
// TransformOptions::try_from(&BabelEnvOptions {
|
..TransformOptions::default()
|
||||||
// targets: Targets::try_from_query(targets).unwrap(),
|
}
|
||||||
// ..BabelEnvOptions::default()
|
|
||||||
// })
|
|
||||||
// .unwrap()
|
|
||||||
} else if let Some(target) = &target {
|
} else if let Some(target) = &target {
|
||||||
TransformOptions::from(ESTarget::from_str(target).unwrap())
|
TransformOptions::from(ESTarget::from_str(target).unwrap())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ impl Targets {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// * Query is invalid.
|
/// * 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)
|
Query::Single(query.to_string()).exec().map(|v| v.0).map(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use cow_utils::CowUtils;
|
use cow_utils::CowUtils;
|
||||||
|
use oxc_diagnostics::Error;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -13,6 +14,7 @@ use crate::{
|
||||||
es2021::ES2021Options,
|
es2021::ES2021Options,
|
||||||
es2022::{ClassPropertiesOptions, ES2022Options},
|
es2022::{ClassPropertiesOptions, ES2022Options},
|
||||||
regexp::RegExpOptions,
|
regexp::RegExpOptions,
|
||||||
|
Targets,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::babel::BabelEnvOptions;
|
use super::babel::BabelEnvOptions;
|
||||||
|
|
@ -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 {
|
impl From<ESTarget> for EnvOptions {
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,11 @@
|
||||||
use std::{path::Path, str::FromStr};
|
use std::str::FromStr;
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use crate::{codegen, test};
|
||||||
use oxc_codegen::{CodeGenerator, CodegenOptions};
|
|
||||||
use oxc_parser::Parser;
|
|
||||||
use oxc_semantic::SemanticBuilder;
|
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
use oxc_transformer::{ESTarget, TransformOptions, Transformer};
|
use oxc_transformer::{ESTarget, TransformOptions};
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn es2015() {
|
fn es_target() {
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
let cases = [
|
let cases = [
|
||||||
|
|
@ -45,11 +21,13 @@ fn es2015() {
|
||||||
|
|
||||||
// Test no transformation for esnext.
|
// Test no transformation for esnext.
|
||||||
for (_, case) in cases {
|
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 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();
|
write!(w, "########## {i} {target}\n{case}\n----------\n{result}\n").unwrap();
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
mod es_target;
|
mod es_target;
|
||||||
mod plugins;
|
mod plugins;
|
||||||
|
mod targets;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::Allocator;
|
||||||
use oxc_codegen::{CodeGenerator, CodegenOptions};
|
use oxc_codegen::{CodeGenerator, CodegenOptions};
|
||||||
use oxc_parser::Parser;
|
use oxc_parser::Parser;
|
||||||
|
use oxc_semantic::SemanticBuilder;
|
||||||
use oxc_span::SourceType;
|
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 allocator = Allocator::default();
|
||||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||||
CodeGenerator::new()
|
CodeGenerator::new()
|
||||||
|
|
@ -14,3 +19,21 @@ pub fn run(source_text: &str, source_type: SourceType) -> String {
|
||||||
.build(&ret.program)
|
.build(&ret.program)
|
||||||
.code
|
.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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use oxc_semantic::SemanticBuilder;
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
use oxc_transformer::{InjectGlobalVariables, InjectGlobalVariablesConfig, InjectImport};
|
use oxc_transformer::{InjectGlobalVariables, InjectGlobalVariablesConfig, InjectImport};
|
||||||
|
|
||||||
use crate::run;
|
use crate::codegen;
|
||||||
|
|
||||||
pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariablesConfig) {
|
pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariablesConfig) {
|
||||||
let source_type = SourceType::default();
|
let source_type = SourceType::default();
|
||||||
|
|
@ -23,7 +23,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: InjectGlobalVariab
|
||||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||||
.build(&program)
|
.build(&program)
|
||||||
.code;
|
.code;
|
||||||
let expected = run(expected, source_type);
|
let expected = codegen(expected, source_type);
|
||||||
assert_eq!(result, expected, "for source {source_text}");
|
assert_eq!(result, expected, "for source {source_text}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use oxc_semantic::SemanticBuilder;
|
||||||
use oxc_span::SourceType;
|
use oxc_span::SourceType;
|
||||||
use oxc_transformer::{ReplaceGlobalDefines, ReplaceGlobalDefinesConfig};
|
use oxc_transformer::{ReplaceGlobalDefines, ReplaceGlobalDefinesConfig};
|
||||||
|
|
||||||
use crate::run;
|
use crate::codegen;
|
||||||
|
|
||||||
pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefinesConfig) {
|
pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefinesConfig) {
|
||||||
let source_type = SourceType::default();
|
let source_type = SourceType::default();
|
||||||
|
|
@ -19,7 +19,7 @@ pub(crate) fn test(source_text: &str, expected: &str, config: ReplaceGlobalDefin
|
||||||
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
.with_options(CodegenOptions { single_quote: true, ..CodegenOptions::default() })
|
||||||
.build(&program)
|
.build(&program)
|
||||||
.code;
|
.code;
|
||||||
let expected = run(expected, source_type);
|
let expected = codegen(expected, source_type);
|
||||||
assert_eq!(result, expected, "for source {source_text}");
|
assert_eq!(result, expected, "for source {source_text}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
36
crates/oxc_transformer/tests/targets/mod.rs
Normal file
36
crates/oxc_transformer/tests/targets/mod.rs
Normal file
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue