feat(transformer): support TransformOptions::from_preset_env API (#5323)

This commit is contained in:
Dunqing 2024-08-29 15:20:50 +00:00
parent b1037372b7
commit 0eb7602e18
8 changed files with 186 additions and 72 deletions

View file

@ -43,11 +43,11 @@ fn bugfix_features() -> &'static FxHashMap<String, Versions> {
})
}
pub fn can_enable_plugin(name: &str, targets: &Versions, bugfixes: bool) -> bool {
pub fn can_enable_plugin(name: &str, targets: Option<&Versions>, bugfixes: bool) -> bool {
let versions = if bugfixes {
bugfix_features().get(name).unwrap_or_else(|| &features()[name])
} else {
&features()[name]
};
targets.should_enable(versions)
targets.is_some_and(|v| v.should_enable(versions))
}

View file

@ -1,5 +1,7 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
use super::ArrowFunctionsOptions;
#[derive(Debug, Default, Clone, Deserialize)]
@ -10,9 +12,19 @@ pub struct ES2015Options {
}
impl ES2015Options {
#[must_use]
pub fn with_arrow_function(mut self, arrow_function: Option<ArrowFunctionsOptions>) -> Self {
pub fn with_arrow_function(
&mut self,
arrow_function: Option<ArrowFunctionsOptions>,
) -> &mut Self {
self.arrow_function = arrow_function;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
arrow_function: can_enable_plugin("transform-arrow-functions", targets, bugfixes)
.then(Default::default),
}
}
}

View file

@ -1,5 +1,7 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2016Options {
@ -8,9 +10,19 @@ pub struct ES2016Options {
}
impl ES2016Options {
#[must_use]
pub fn with_exponentiation_operator(mut self, enable: bool) -> Self {
pub fn with_exponentiation_operator(&mut self, enable: bool) -> &mut Self {
self.exponentiation_operator = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
exponentiation_operator: can_enable_plugin(
"transform-exponentiation-operator",
targets,
bugfixes,
),
}
}
}

View file

@ -1,6 +1,9 @@
use super::object_rest_spread::ObjectRestSpreadOptions;
use crate::env::{can_enable_plugin, Versions};
use serde::Deserialize;
use super::ObjectRestSpreadOptions;
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2018Options {
@ -9,9 +12,23 @@ pub struct ES2018Options {
}
impl ES2018Options {
#[must_use]
pub fn with_object_rest_spread(mut self, option: Option<ObjectRestSpreadOptions>) -> Self {
pub fn with_object_rest_spread(
&mut self,
option: Option<ObjectRestSpreadOptions>,
) -> &mut Self {
self.object_rest_spread = option;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
object_rest_spread: can_enable_plugin(
"transform-object-rest-spread",
targets,
bugfixes,
)
.then(Default::default),
}
}
}

View file

@ -1,5 +1,7 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2019Options {
@ -8,9 +10,19 @@ pub struct ES2019Options {
}
impl ES2019Options {
#[must_use]
pub fn with_optional_catch_binding(mut self, enable: bool) -> Self {
pub fn with_optional_catch_binding(&mut self, enable: bool) -> &mut Self {
self.optional_catch_binding = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
optional_catch_binding: can_enable_plugin(
"transform-optional-catch-binding",
targets,
bugfixes,
),
}
}
}

View file

@ -1,5 +1,7 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2020Options {
@ -8,9 +10,19 @@ pub struct ES2020Options {
}
impl ES2020Options {
#[must_use]
pub fn with_nullish_coalescing_operator(mut self, enable: bool) -> Self {
pub fn with_nullish_coalescing_operator(&mut self, enable: bool) -> &mut Self {
self.nullish_coalescing_operator = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
nullish_coalescing_operator: can_enable_plugin(
"transform-nullish-coalescing-operator",
targets,
bugfixes,
),
}
}
}

View file

@ -1,5 +1,7 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2021Options {
@ -8,9 +10,19 @@ pub struct ES2021Options {
}
impl ES2021Options {
#[must_use]
pub fn with_logical_assignment_operators(mut self, enable: bool) -> Self {
pub fn with_logical_assignment_operators(&mut self, enable: bool) -> &mut Self {
self.logical_assignment_operators = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
logical_assignment_operators: can_enable_plugin(
"transform-logical-assignment-operators",
targets,
bugfixes,
),
}
}
}

View file

@ -52,36 +52,78 @@ pub struct TransformOptions {
}
impl TransformOptions {
fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
es2015: ES2015Options::from_targets_and_bugfixes(targets, bugfixes),
es2016: ES2016Options::from_targets_and_bugfixes(targets, bugfixes),
es2018: ES2018Options::from_targets_and_bugfixes(targets, bugfixes),
es2019: ES2019Options::from_targets_and_bugfixes(targets, bugfixes),
es2020: ES2020Options::from_targets_and_bugfixes(targets, bugfixes),
es2021: ES2021Options::from_targets_and_bugfixes(targets, bugfixes),
..Default::default()
}
}
/// # Errors
///
/// If there are any errors in the `options.targets``, they will be returned as a list of errors.
pub fn from_preset_env(env_options: &EnvOptions) -> Result<Self, Vec<Error>> {
let mut errors = Vec::<Error>::new();
let targets = match env_options.get_targets() {
Ok(t) => Some(t),
Err(err) => {
errors.push(OxcDiagnostic::error(err.to_string()).into());
None
}
};
let bugfixes = env_options.bugfixes;
Ok(Self::from_targets_and_bugfixes(targets.as_ref(), bugfixes))
}
/// # Errors
///
/// If the `options` contains any unknown fields, they will be returned as a list of errors.
pub fn from_babel_options(options: &BabelOptions) -> Result<Self, Vec<Error>> {
let mut errors = Vec::<Error>::new();
let env_options = {
let preset_name = "env";
from_value::<EnvOptions>(get_preset_options(preset_name, options)).unwrap_or_else(
|err| {
report_error(preset_name, &err, true, &mut errors);
EnvOptions::default()
},
)
get_preset_options(preset_name, options).and_then(|value| {
match from_value::<EnvOptions>(value) {
Ok(res) => Some(res),
Err(err) => {
report_error(preset_name, &err, true, &mut errors);
None
}
}
})
};
let targets = match env_options.get_targets() {
Ok(t) => t,
let targets = env_options.as_ref().and_then(|env| match env.get_targets() {
Ok(res) => Some(res),
Err(err) => {
errors.push(OxcDiagnostic::error(err.to_string()).into());
return Err(errors);
None
}
});
let bugfixes = env_options.as_ref().is_some_and(|o| o.bugfixes);
let mut transformer_options = if env_options.is_some() {
TransformOptions::from_targets_and_bugfixes(targets.as_ref(), bugfixes)
} else {
TransformOptions::default()
};
let preset_name = "react";
let react = if options.has_preset(preset_name) {
from_value::<ReactOptions>(get_preset_options(preset_name, options)).unwrap_or_else(
|err| {
transformer_options.react = if let Some(value) = get_preset_options(preset_name, options) {
match from_value::<ReactOptions>(value) {
Ok(res) => res,
Err(err) => {
report_error(preset_name, &err, true, &mut errors);
ReactOptions::default()
},
)
}
}
} else {
let has_jsx_plugin = options.has_plugin("transform-react-jsx");
let has_jsx_development_plugin = options.has_plugin("transform-react-jsx-development");
@ -109,47 +151,51 @@ impl TransformOptions {
react_options
};
let es2015 = ES2015Options::default().with_arrow_function({
transformer_options.es2015.with_arrow_function({
let plugin_name = "transform-arrow-functions";
enable_plugin(plugin_name, options, &env_options, &targets).map(|options| {
from_value::<ArrowFunctionsOptions>(options).unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
ArrowFunctionsOptions::default()
})
})
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).map(
|options| {
from_value::<ArrowFunctionsOptions>(options).unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
ArrowFunctionsOptions::default()
})
},
)
});
let es2016 = ES2016Options::default().with_exponentiation_operator({
transformer_options.es2016.with_exponentiation_operator({
let plugin_name = "transform-exponentiation-operator";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let es2018 = ES2018Options::default().with_object_rest_spread({
transformer_options.es2018.with_object_rest_spread({
let plugin_name = "transform-object-rest-spread";
enable_plugin(plugin_name, options, &env_options, &targets).map(|options| {
from_value::<ObjectRestSpreadOptions>(options).unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
ObjectRestSpreadOptions::default()
})
})
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).map(
|options| {
from_value::<ObjectRestSpreadOptions>(options).unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
ObjectRestSpreadOptions::default()
})
},
)
});
let es2019 = ES2019Options::default().with_optional_catch_binding({
transformer_options.es2019.with_optional_catch_binding({
let plugin_name = "transform-optional-catch-binding";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let es2020 = ES2020Options::default().with_nullish_coalescing_operator({
transformer_options.es2020.with_nullish_coalescing_operator({
let plugin_name = "transform-nullish-coalescing-operator";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let es2021 = ES2021Options::default().with_logical_assignment_operators({
transformer_options.es2021.with_logical_assignment_operators({
let plugin_name = "transform-logical-assignment-operators";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let typescript = {
transformer_options.typescript = {
let plugin_name = "transform-typescript";
from_value::<TypeScriptOptions>(get_plugin_options(plugin_name, options))
.unwrap_or_else(|err| {
@ -158,7 +204,7 @@ impl TransformOptions {
})
};
let assumptions = if options.assumptions.is_null() {
transformer_options.assumptions = if options.assumptions.is_null() {
CompilerAssumptions::default()
} else {
match serde_json::from_value::<CompilerAssumptions>(options.assumptions.clone()) {
@ -170,22 +216,13 @@ impl TransformOptions {
}
};
transformer_options.cwd = options.cwd.clone().unwrap_or_default();
if !errors.is_empty() {
return Err(errors);
}
Ok(Self {
cwd: options.cwd.clone().unwrap_or_default(),
assumptions,
typescript,
react,
es2015,
es2016,
es2018,
es2019,
es2020,
es2021,
})
Ok(transformer_options)
}
}
@ -194,19 +231,19 @@ fn get_plugin_options(name: &str, babel_options: &BabelOptions) -> Value {
plugin.and_then(|options| options).unwrap_or_else(|| json!({}))
}
fn get_preset_options(name: &str, babel_options: &BabelOptions) -> Value {
fn get_preset_options(name: &str, babel_options: &BabelOptions) -> Option<Value> {
let preset = babel_options.get_preset(name);
preset.and_then(|options| options).unwrap_or_else(|| json!({}))
preset.and_then(|options| options)
}
fn enable_plugin(
fn get_enabled_plugin_options(
plugin_name: &str,
babel_options: &BabelOptions,
env_options: &EnvOptions,
targets: &Versions,
targets: Option<&Versions>,
bugfixes: bool,
) -> Option<Value> {
let can_enable = can_enable_plugin(plugin_name, targets, env_options.bugfixes)
|| babel_options.has_plugin(plugin_name);
let can_enable =
can_enable_plugin(plugin_name, targets, bugfixes) || babel_options.has_plugin(plugin_name);
if can_enable {
get_plugin_options(plugin_name, babel_options).into()