refactor(transformer): clean up TransformerOptions (#7005)

This is a work towards https://github.com/oxc-project/oxc/issues/6982

Next PR will try and make sense of env options vs babel options vs targets and bugfixes, I'm super confused right now.
This commit is contained in:
Boshen 2024-10-30 09:09:38 +00:00
parent caaf00e081
commit 5b11cdf611
12 changed files with 286 additions and 392 deletions

View file

@ -1,9 +1,7 @@
use serde::Deserialize;
use serde_json::Value;
use oxc_diagnostics::Error;
use super::targets::{query::Targets, Versions};
use super::targets::query::Targets;
fn default_as_true() -> bool {
true
@ -54,11 +52,3 @@ pub struct EnvOptions {
#[deprecated = "Not Implemented"]
pub shipped_proposals: bool,
}
impl EnvOptions {
/// # Errors
///
pub fn get_targets(&self) -> Result<Versions, Error> {
self.targets.clone().get_targets()
}
}

View file

@ -1,7 +1,5 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
use super::ArrowFunctionsOptions;
#[derive(Debug, Default, Clone, Deserialize)]
@ -10,21 +8,3 @@ pub struct ES2015Options {
#[serde(skip)]
pub arrow_function: Option<ArrowFunctionsOptions>,
}
impl ES2015Options {
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,28 +1,8 @@
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 {
#[serde(skip)]
pub exponentiation_operator: bool,
}
impl ES2016Options {
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,28 +1,8 @@
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 ES2017Options {
#[serde(skip)]
pub async_to_generator: bool,
}
impl ES2017Options {
pub fn with_async_to_generator(&mut self, enable: bool) -> &mut Self {
self.async_to_generator = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
async_to_generator: can_enable_plugin(
"transform-async-to-generator",
targets,
bugfixes,
),
}
}
}

View file

@ -1,7 +1,5 @@
use serde::Deserialize;
use crate::env::{can_enable_plugin, Versions};
use super::ObjectRestSpreadOptions;
#[derive(Debug, Default, Clone, Deserialize)]
@ -10,25 +8,3 @@ pub struct ES2018Options {
#[serde(skip)]
pub object_rest_spread: Option<ObjectRestSpreadOptions>,
}
impl ES2018Options {
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,28 +1,8 @@
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 {
#[serde(skip)]
pub optional_catch_binding: bool,
}
impl ES2019Options {
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,28 +1,8 @@
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 {
#[serde(skip)]
pub nullish_coalescing_operator: bool,
}
impl ES2020Options {
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,28 +1,8 @@
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 {
#[serde(skip)]
pub logical_assignment_operators: bool,
}
impl ES2021Options {
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

@ -1,28 +1,8 @@
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 ES2022Options {
#[serde(skip)]
pub class_static_block: bool,
}
impl ES2022Options {
pub fn with_class_static_block(&mut self, enable: bool) -> &mut Self {
self.class_static_block = enable;
self
}
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
class_static_block: can_enable_plugin(
"transform-class-static-block",
targets,
bugfixes,
),
}
}
}

View file

@ -4,30 +4,48 @@ use serde::Deserialize;
use serde_json::Value;
/// Babel options
///
/// <https://babel.dev/docs/options#plugin-and-preset-options>
#[derive(Debug, Default, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BabelOptions {
// Primary options
pub cwd: Option<PathBuf>,
pub source_type: Option<String>,
// Config Loading options
// Plugin and Preset options
#[serde(default)]
pub plugins: Vec<Value>, // Can be a string or an array
#[serde(default)]
pub presets: Vec<Value>, // Can be a string or an array
// Misc options
pub source_type: Option<String>,
#[serde(default)]
pub assumptions: Value,
// Test options
pub throws: Option<String>,
#[serde(rename = "BABEL_8_BREAKING")]
pub babel_8_breaking: Option<bool>,
/// Babel test helper for running tests on specific operating systems
pub os: Option<Vec<TestOs>>,
// Parser options for babel-parser
#[serde(default)]
pub allow_return_outside_function: bool,
#[serde(default)]
pub allow_await_outside_function: bool,
#[serde(default)]
pub allow_undeclared_exports: bool,
#[serde(default = "default_as_true")]
pub external_helpers: bool,
}

View file

@ -1,6 +1,6 @@
use std::path::PathBuf;
use serde_json::{from_value, json, Value};
use serde_json::{json, Value};
use oxc_diagnostics::{Error, OxcDiagnostic};
@ -110,36 +110,95 @@ 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),
es2017: ES2017Options::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),
es2022: ES2022Options::from_targets_and_bugfixes(targets, bugfixes),
regexp: RegExpOptions::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 targets = match env_options.targets.clone().get_targets() {
Ok(targets) => Some(targets),
Err(err) => return Err(vec![err]),
};
let bugfixes = env_options.bugfixes;
Ok(Self::from_targets_and_bugfixes(targets.as_ref(), bugfixes))
let targets = targets.as_ref();
Ok(Self {
regexp: RegExpOptions {
sticky_flag: can_enable_plugin("transform-sticky-regex", targets, bugfixes),
unicode_flag: can_enable_plugin("transform-unicode-regex", targets, bugfixes),
dot_all_flag: can_enable_plugin("transform-dotall-regex", targets, bugfixes),
look_behind_assertions: can_enable_plugin(
"esbuild-regexp-lookbehind-assertions",
targets,
bugfixes,
),
named_capture_groups: can_enable_plugin(
"transform-named-capturing-groups-regex",
targets,
bugfixes,
),
unicode_property_escapes: can_enable_plugin(
"transform-unicode-property-regex",
targets,
bugfixes,
),
match_indices: can_enable_plugin("esbuild-regexp-match-indices", targets, bugfixes),
set_notation: can_enable_plugin("transform-unicode-sets-regex", targets, bugfixes),
},
es2015: ES2015Options {
arrow_function: can_enable_plugin("transform-arrow-functions", targets, bugfixes)
.then(Default::default),
},
es2016: ES2016Options {
exponentiation_operator: can_enable_plugin(
"transform-exponentiation-operator",
targets,
bugfixes,
),
},
es2017: ES2017Options {
async_to_generator: can_enable_plugin(
"transform-async-to-generator",
targets,
bugfixes,
),
},
es2018: ES2018Options {
object_rest_spread: can_enable_plugin(
"transform-object-rest-spread",
targets,
bugfixes,
)
.then(Default::default),
},
es2019: ES2019Options {
optional_catch_binding: can_enable_plugin(
"transform-optional-catch-binding",
targets,
bugfixes,
),
},
es2020: ES2020Options {
nullish_coalescing_operator: can_enable_plugin(
"transform-nullish-coalescing-operator",
targets,
bugfixes,
),
},
es2021: ES2021Options {
logical_assignment_operators: can_enable_plugin(
"transform-logical-assignment-operators",
targets,
bugfixes,
),
},
es2022: ES2022Options {
class_static_block: can_enable_plugin(
"transform-class-static-block",
targets,
bugfixes,
),
},
..Default::default()
})
}
/// # Errors
@ -148,63 +207,45 @@ impl TransformOptions {
pub fn from_babel_options(options: &BabelOptions) -> Result<Self, Vec<Error>> {
let mut errors = Vec::<Error>::new();
let env_options = {
let preset_name = "env";
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 assumptions = if options.assumptions.is_null() {
CompilerAssumptions::default()
} else {
serde_json::from_value::<CompilerAssumptions>(options.assumptions.clone())
.inspect_err(|err| errors.push(OxcDiagnostic::error(err.to_string()).into()))
.unwrap_or_default()
};
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());
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)
let typescript = if options.has_preset("typescript") {
serde_json::from_value::<TypeScriptOptions>(
options.get_preset("typescript").flatten().unwrap_or_else(|| json!({})),
)
.inspect_err(|err| report_error("typescript", err, true, &mut errors))
} else {
TransformOptions::default()
};
serde_json::from_value::<TypeScriptOptions>(get_plugin_options(
"transform-typescript",
options,
))
.inspect_err(|err| report_error("typescript", err, false, &mut errors))
}
.unwrap_or_default();
let preset_name = "react";
transformer_options.jsx = if let Some(value) = get_preset_options(preset_name, options) {
match from_value::<JsxOptions>(value) {
Ok(res) => res,
Err(err) => {
report_error(preset_name, &err, true, &mut errors);
JsxOptions::default()
}
}
let jsx = if let Some(value) = options.get_preset("react").flatten() {
serde_json::from_value::<JsxOptions>(value)
.inspect_err(|err| report_error("react", err, true, &mut errors))
.unwrap_or_default()
} else {
let has_jsx_plugin = options.has_plugin("transform-react-jsx");
let has_jsx_development_plugin = options.has_plugin("transform-react-jsx-development");
let mut react_options =
if has_jsx_plugin {
let plugin_name = "transform-react-jsx";
from_value::<JsxOptions>(get_plugin_options(plugin_name, options))
.unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
JsxOptions::default()
})
} else {
let plugin_name = "transform-react-jsx-development";
from_value::<JsxOptions>(get_plugin_options(plugin_name, options))
.unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
JsxOptions::default()
})
};
react_options.development = has_jsx_development_plugin;
let jsx_plugin_name = "transform-react-jsx";
let jsx_dev_name = "transform-react-jsx-development";
let has_jsx_plugin = options.has_plugin(jsx_plugin_name);
let mut react_options = if has_jsx_plugin {
serde_json::from_value::<JsxOptions>(get_plugin_options(jsx_plugin_name, options))
.inspect_err(|err| report_error(jsx_plugin_name, err, false, &mut errors))
} else {
serde_json::from_value::<JsxOptions>(get_plugin_options(jsx_dev_name, options))
.inspect_err(|err| report_error(jsx_dev_name, err, false, &mut errors))
}
.unwrap_or_default();
react_options.development = options.has_plugin(jsx_dev_name);
react_options.jsx_plugin = has_jsx_plugin;
react_options.display_name_plugin = options.has_plugin("transform-react-display-name");
react_options.jsx_self_plugin = options.has_plugin("transform-react-jsx-self");
@ -212,137 +253,169 @@ impl TransformOptions {
react_options
};
transformer_options.es2015.with_arrow_function({
let plugin_name = "transform-arrow-functions";
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 env = options.get_preset("env").flatten().and_then(|value| {
serde_json::from_value::<EnvOptions>(value)
.inspect_err(|err| report_error("env", err, true, &mut errors))
.ok()
});
transformer_options.es2016.with_exponentiation_operator({
let plugin_name = "transform-exponentiation-operator";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
let targets = env.as_ref().and_then(|env| {
env.targets
.clone()
.get_targets()
.inspect_err(|err| errors.push(OxcDiagnostic::error(err.to_string()).into()))
.ok()
});
transformer_options.es2017.with_async_to_generator({
let plugin_name = "transform-async-to-generator";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let bugfixes = env.as_ref().is_some_and(|o| o.bugfixes);
transformer_options.es2018.with_object_rest_spread({
let plugin_name = "transform-object-rest-spread";
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 targets = targets.as_ref();
transformer_options.es2019.with_optional_catch_binding({
let plugin_name = "transform-optional-catch-binding";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
let regexp = RegExpOptions {
sticky_flag: can_enable_plugin("transform-sticky-regex", targets, bugfixes)
|| options.has_plugin("transform-sticky-regex"),
unicode_flag: can_enable_plugin("transform-unicode-regex", targets, bugfixes)
|| options.has_plugin("transform-unicode-regex"),
dot_all_flag: can_enable_plugin("transform-dotall-regex", targets, bugfixes)
|| options.has_plugin("transform-dotall-regex"),
look_behind_assertions: can_enable_plugin(
"esbuild-regexp-lookbehind-assertions",
targets,
bugfixes,
),
named_capture_groups: can_enable_plugin(
"transform-named-capturing-groups-regex",
targets,
bugfixes,
) || options.has_plugin("transform-named-capturing-groups-regex"),
unicode_property_escapes: can_enable_plugin(
"transform-unicode-property-regex",
targets,
bugfixes,
) || options.has_plugin("transform-unicode-property-regex"),
match_indices: can_enable_plugin("esbuild-regexp-match-indices", targets, bugfixes),
set_notation: can_enable_plugin("transform-unicode-sets-regex", targets, bugfixes)
|| options.has_plugin("transform-unicode-sets-regex"),
};
transformer_options.es2020.with_nullish_coalescing_operator({
let plugin_name = "transform-nullish-coalescing-operator";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
transformer_options.es2021.with_logical_assignment_operators({
let plugin_name = "transform-logical-assignment-operators";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
transformer_options.es2022.with_class_static_block({
let plugin_name = "transform-class-static-block";
get_enabled_plugin_options(plugin_name, options, targets.as_ref(), bugfixes).is_some()
});
transformer_options.typescript = {
let preset_name = "typescript";
if options.has_preset("typescript") {
from_value::<TypeScriptOptions>(
get_preset_options("typescript", options).unwrap_or_else(|| json!({})),
)
.unwrap_or_else(|err| {
report_error(preset_name, &err, true, &mut errors);
TypeScriptOptions::default()
let es2015 = ES2015Options {
arrow_function: {
let plugin_name = "transform-arrow-functions";
get_enabled_plugin_options(plugin_name, options, targets, bugfixes).map(|options| {
serde_json::from_value::<ArrowFunctionsOptions>(options)
.inspect_err(|err| report_error(plugin_name, err, false, &mut errors))
.unwrap_or_default()
})
} else {
let plugin_name = "transform-typescript";
from_value::<TypeScriptOptions>(get_plugin_options(plugin_name, options))
.unwrap_or_else(|err| {
report_error(plugin_name, &err, false, &mut errors);
TypeScriptOptions::default()
})
}
},
};
let regexp = transformer_options.regexp;
if !regexp.sticky_flag {
transformer_options.regexp.sticky_flag = options.has_plugin("transform-sticky-regex");
}
if !regexp.unicode_flag {
transformer_options.regexp.unicode_flag = options.has_plugin("transform-unicode-regex");
}
if !regexp.dot_all_flag {
transformer_options.regexp.dot_all_flag = options.has_plugin("transform-dotall-regex");
}
if !regexp.named_capture_groups {
transformer_options.regexp.named_capture_groups =
options.has_plugin("transform-named-capturing-groups-regex");
}
if !regexp.unicode_property_escapes {
transformer_options.regexp.unicode_property_escapes =
options.has_plugin("transform-unicode-property-regex");
}
if !regexp.set_notation {
transformer_options.regexp.set_notation =
options.has_plugin("transform-unicode-sets-regex");
}
transformer_options.assumptions = if options.assumptions.is_null() {
CompilerAssumptions::default()
} else {
match serde_json::from_value::<CompilerAssumptions>(options.assumptions.clone()) {
Ok(value) => value,
Err(err) => {
errors.push(OxcDiagnostic::error(err.to_string()).into());
CompilerAssumptions::default()
}
}
let es2016 = ES2016Options {
exponentiation_operator: get_enabled_plugin_options(
"transform-exponentiation-operator",
options,
targets,
bugfixes,
)
.is_some(),
};
if options.external_helpers {
transformer_options.helper_loader.mode = HelperLoaderMode::External;
}
let es2017 = ES2017Options {
async_to_generator: get_enabled_plugin_options(
"transform-async-to-generator",
options,
targets,
bugfixes,
)
.is_some(),
};
transformer_options.cwd = options.cwd.clone().unwrap_or_default();
let es2018 = ES2018Options {
object_rest_spread: {
let plugin_name = "transform-object-rest-spread";
get_enabled_plugin_options(plugin_name, options, targets, bugfixes).map(|options| {
serde_json::from_value::<ObjectRestSpreadOptions>(options)
.inspect_err(|err| report_error(plugin_name, err, false, &mut errors))
.unwrap_or_default()
})
},
};
let es2019 = ES2019Options {
optional_catch_binding: {
get_enabled_plugin_options(
"transform-optional-catch-binding",
options,
targets,
bugfixes,
)
.is_some()
},
};
let es2020 = ES2020Options {
nullish_coalescing_operator: get_enabled_plugin_options(
"transform-nullish-coalescing-operator",
options,
targets,
bugfixes,
)
.is_some(),
};
let es2021 = ES2021Options {
logical_assignment_operators: get_enabled_plugin_options(
"transform-logical-assignment-operators",
options,
targets,
bugfixes,
)
.is_some(),
};
let es2022 = ES2022Options {
class_static_block: get_enabled_plugin_options(
"transform-class-static-block",
options,
targets,
bugfixes,
)
.is_some(),
};
if !errors.is_empty() {
return Err(errors);
}
Ok(transformer_options)
let helper_loader = HelperLoaderOptions {
mode: if options.external_helpers {
HelperLoaderMode::External
} else {
HelperLoaderMode::default()
},
..HelperLoaderOptions::default()
};
Ok(Self {
cwd: options.cwd.clone().unwrap_or_default(),
assumptions,
typescript,
jsx,
regexp,
es2015,
es2016,
es2017,
es2018,
es2019,
es2020,
es2021,
es2022,
helper_loader,
})
}
}
fn get_plugin_options(name: &str, babel_options: &BabelOptions) -> Value {
let plugin = babel_options.get_plugin(name);
plugin.and_then(|options| options).unwrap_or_else(|| json!({}))
}
fn get_preset_options(name: &str, babel_options: &BabelOptions) -> Option<Value> {
let preset = babel_options.get_preset(name);
preset.and_then(|options| options)
babel_options.get_plugin(name).and_then(|options| options).unwrap_or_else(|| json!({}))
}
fn get_enabled_plugin_options(

View file

@ -1,49 +1,26 @@
use crate::env::{can_enable_plugin, Versions};
#[derive(Default, Debug, Clone, Copy)]
pub struct RegExpOptions {
/// Enables plugin to transform the RegExp literal has `y` flag
pub sticky_flag: bool,
/// Enables plugin to transform the RegExp literal has `u` flag
pub unicode_flag: bool,
/// Enables plugin to transform the RegExp literal has `s` flag
pub dot_all_flag: bool,
/// Enables plugin to transform the RegExp literal has `(?<=)` or `(?<!)` lookbehind assertions
pub look_behind_assertions: bool,
/// Enables plugin to transform the RegExp literal has `(?<name>x)` named capture groups
pub named_capture_groups: bool,
/// Enables plugin to transform the RegExp literal has `\p{}` and `\P{}` unicode property escapes
pub unicode_property_escapes: bool,
/// Enables plugin to transform `d` flag
pub match_indices: bool,
/// Enables plugin to transform the RegExp literal has `v` flag
pub set_notation: bool,
}
impl RegExpOptions {
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
sticky_flag: can_enable_plugin("transform-sticky-regex", targets, bugfixes),
unicode_flag: can_enable_plugin("transform-unicode-regex", targets, bugfixes),
dot_all_flag: can_enable_plugin("transform-dotall-regex", targets, bugfixes),
look_behind_assertions: can_enable_plugin(
"esbuild-regexp-lookbehind-assertions",
targets,
bugfixes,
),
named_capture_groups: can_enable_plugin(
"transform-named-capturing-groups-regex",
targets,
bugfixes,
),
unicode_property_escapes: can_enable_plugin(
"transform-unicode-property-regex",
targets,
bugfixes,
),
match_indices: can_enable_plugin("esbuild-regexp-match-indices", targets, bugfixes),
set_notation: can_enable_plugin("transform-unicode-sets-regex", targets, bugfixes),
}
}
}