mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
refactor(transformer): deserialize BabelOptions::plugins (#7045)
This commit is contained in:
parent
4bef99c80b
commit
52c20d633c
9 changed files with 287 additions and 219 deletions
|
|
@ -136,7 +136,7 @@ use oxc_syntax::{
|
|||
};
|
||||
use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, TraverseCtx};
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize)]
|
||||
pub struct ArrowFunctionsOptions {
|
||||
/// This option enables the following:
|
||||
/// * Wrap the generated function in .bind(this) and keeps uses of this inside the function as-is, instead of using a renamed this.
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ pub struct ES2015<'a> {
|
|||
impl<'a> ES2015<'a> {
|
||||
pub fn new(options: ES2015Options) -> Self {
|
||||
Self {
|
||||
arrow_functions: ArrowFunctions::new(
|
||||
options.arrow_function.clone().unwrap_or_default(),
|
||||
),
|
||||
arrow_functions: ArrowFunctions::new(options.arrow_function.unwrap_or_default()),
|
||||
options,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,14 @@ mod env;
|
|||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
es2015::ArrowFunctionsOptions, es2018::ObjectRestSpreadOptions, es2022::ClassPropertiesOptions,
|
||||
jsx::JsxOptions, TypeScriptOptions,
|
||||
};
|
||||
|
||||
pub use env::{BabelEnvOptions, Targets};
|
||||
|
||||
/// Babel options
|
||||
|
|
@ -20,7 +25,7 @@ pub struct BabelOptions {
|
|||
|
||||
// Plugin and Preset options
|
||||
#[serde(default)]
|
||||
pub plugins: Vec<Value>, // Can be a string or an array
|
||||
pub plugins: BabelPlugins,
|
||||
|
||||
#[serde(default)]
|
||||
pub presets: Vec<Value>, // Can be a string or an array
|
||||
|
|
@ -77,61 +82,62 @@ impl BabelOptions {
|
|||
/// Read options.json and merge them with options.json from ancestors directories.
|
||||
/// # Panics
|
||||
pub fn from_test_path(path: &Path) -> Self {
|
||||
let mut options_json: Option<Self> = None;
|
||||
let mut babel_options: Option<Self> = None;
|
||||
let mut plugins_json = None;
|
||||
|
||||
for path in path.ancestors().take(3) {
|
||||
let file = path.join("options.json");
|
||||
if !file.exists() {
|
||||
continue;
|
||||
}
|
||||
let file = std::fs::read_to_string(&file).unwrap();
|
||||
let new_json: Self = serde_json::from_str(&file).unwrap();
|
||||
if let Some(existing_json) = options_json.as_mut() {
|
||||
if existing_json.source_type.is_none() {
|
||||
if let Some(source_type) = new_json.source_type {
|
||||
existing_json.source_type = Some(source_type);
|
||||
|
||||
let content = std::fs::read_to_string(&file).unwrap();
|
||||
let mut new_value = serde_json::from_str::<serde_json::Value>(&content).unwrap();
|
||||
|
||||
let new_plugins = new_value.as_object_mut().unwrap().remove("plugins");
|
||||
if plugins_json.is_none() {
|
||||
plugins_json = new_plugins;
|
||||
}
|
||||
|
||||
let new_options: Self = serde_json::from_value::<BabelOptions>(new_value)
|
||||
.unwrap_or_else(|err| panic!("{err:?}\n{file:?}\n{content}"));
|
||||
|
||||
if let Some(existing_options) = babel_options.as_mut() {
|
||||
if existing_options.source_type.is_none() {
|
||||
if let Some(source_type) = new_options.source_type {
|
||||
existing_options.source_type = Some(source_type);
|
||||
}
|
||||
}
|
||||
if existing_json.throws.is_none() {
|
||||
if let Some(throws) = new_json.throws {
|
||||
existing_json.throws = Some(throws);
|
||||
if existing_options.throws.is_none() {
|
||||
if let Some(throws) = new_options.throws {
|
||||
existing_options.throws = Some(throws);
|
||||
}
|
||||
}
|
||||
if existing_json.plugins.is_empty() {
|
||||
existing_json.plugins = new_json.plugins;
|
||||
}
|
||||
if existing_json.presets.is_empty() {
|
||||
existing_json.presets = new_json.presets;
|
||||
if existing_options.presets.is_empty() {
|
||||
existing_options.presets = new_options.presets;
|
||||
}
|
||||
} else {
|
||||
options_json = Some(new_json);
|
||||
babel_options = Some(new_options);
|
||||
}
|
||||
}
|
||||
options_json.unwrap_or_default()
|
||||
|
||||
let mut options = babel_options.unwrap_or_default();
|
||||
if let Some(plugins_json) = plugins_json {
|
||||
options.plugins = serde_json::from_value::<BabelPlugins>(plugins_json).unwrap();
|
||||
}
|
||||
options
|
||||
}
|
||||
|
||||
pub fn is_jsx(&self) -> bool {
|
||||
self.plugins.iter().any(|v| v.as_str().is_some_and(|v| v == "jsx"))
|
||||
self.plugins.syntax_jsx
|
||||
}
|
||||
|
||||
pub fn is_typescript(&self) -> bool {
|
||||
self.plugins.iter().any(|v| {
|
||||
let string_value = v.as_str().is_some_and(|v| v == "typescript");
|
||||
let array_value = v.get(0).and_then(Value::as_str).is_some_and(|s| s == "typescript");
|
||||
string_value || array_value
|
||||
})
|
||||
self.plugins.syntax_typescript.is_some()
|
||||
}
|
||||
|
||||
pub fn is_typescript_definition(&self) -> bool {
|
||||
self.plugins.iter().filter_map(Value::as_array).any(|p| {
|
||||
let typescript = p.first().and_then(Value::as_str).is_some_and(|s| s == "typescript");
|
||||
let dts = p
|
||||
.get(1)
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|v| v.get("dts"))
|
||||
.and_then(Value::as_bool)
|
||||
.is_some_and(|v| v);
|
||||
typescript && dts
|
||||
})
|
||||
self.plugins.syntax_typescript.is_some_and(|o| o.dts)
|
||||
}
|
||||
|
||||
pub fn is_module(&self) -> bool {
|
||||
|
|
@ -142,22 +148,10 @@ impl BabelOptions {
|
|||
self.source_type.as_ref().map_or(false, |s| s.as_str() == "unambiguous")
|
||||
}
|
||||
|
||||
/// Returns
|
||||
/// * `Some<None>` if the plugin exists without a config
|
||||
/// * `Some<Some<Value>>` if the plugin exists with a config
|
||||
/// * `None` if the plugin does not exist
|
||||
pub fn get_plugin(&self, name: &str) -> Option<Option<Value>> {
|
||||
self.plugins.iter().find_map(|v| Self::get_value(v, name))
|
||||
}
|
||||
|
||||
pub fn get_preset(&self, name: &str) -> Option<Option<Value>> {
|
||||
self.presets.iter().find_map(|v| Self::get_value(v, name))
|
||||
}
|
||||
|
||||
pub fn has_plugin(&self, name: &str) -> bool {
|
||||
self.get_plugin(name).is_some()
|
||||
}
|
||||
|
||||
pub fn has_preset(&self, name: &str) -> bool {
|
||||
self.get_preset(name).is_some()
|
||||
}
|
||||
|
|
@ -173,3 +167,167 @@ impl BabelOptions {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize)]
|
||||
pub struct SyntaxTypeScriptOptions {
|
||||
#[serde(default)]
|
||||
pub dts: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
pub struct SyntaxDecoratorOptions {
|
||||
#[serde(default)]
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[serde(try_from = "PluginPresetEntries")]
|
||||
pub struct BabelPlugins {
|
||||
pub errors: Vec<String>,
|
||||
pub unsupported: Vec<String>,
|
||||
// syntax
|
||||
pub syntax_typescript: Option<SyntaxTypeScriptOptions>,
|
||||
pub syntax_jsx: bool,
|
||||
// decorators
|
||||
pub syntax_decorators: Option<SyntaxDecoratorOptions>,
|
||||
pub proposal_decorators: Option<SyntaxDecoratorOptions>,
|
||||
// ts
|
||||
pub typescript: Option<TypeScriptOptions>,
|
||||
// jsx
|
||||
pub react_jsx: Option<JsxOptions>,
|
||||
pub react_jsx_dev: Option<JsxOptions>,
|
||||
pub react_jsx_self: bool,
|
||||
pub react_jsx_source: bool,
|
||||
pub react_display_name: bool,
|
||||
// regexp
|
||||
pub sticky_flag: bool,
|
||||
pub unicode_flag: bool,
|
||||
pub dot_all_flag: bool,
|
||||
pub look_behind_assertions: bool,
|
||||
pub named_capture_groups: bool,
|
||||
pub unicode_property_escapes: bool,
|
||||
pub match_indices: bool,
|
||||
/// Enables plugin to transform the RegExp literal has `v` flag
|
||||
pub set_notation: bool,
|
||||
// ES2015
|
||||
pub arrow_function: Option<ArrowFunctionsOptions>,
|
||||
// ES2016
|
||||
pub exponentiation_operator: bool,
|
||||
// ES2017
|
||||
pub async_to_generator: bool,
|
||||
// ES2018
|
||||
pub object_rest_spread: Option<ObjectRestSpreadOptions>,
|
||||
pub async_generator_functions: bool,
|
||||
// ES2019
|
||||
pub optional_catch_binding: bool,
|
||||
// ES2020
|
||||
pub nullish_coalescing_operator: bool,
|
||||
// ES2021
|
||||
pub logical_assignment_operators: bool,
|
||||
// ES2022
|
||||
pub class_static_block: bool,
|
||||
pub class_properties: Option<ClassPropertiesOptions>,
|
||||
}
|
||||
|
||||
/// <https://babeljs.io/docs/options#pluginpreset-entries>
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PluginPresetEntries(Vec<PluginPresetEntry>);
|
||||
|
||||
impl TryFrom<PluginPresetEntries> for BabelPlugins {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(entries: PluginPresetEntries) -> Result<Self, Self::Error> {
|
||||
let mut p = BabelPlugins::default();
|
||||
for entry in entries.0 {
|
||||
match entry.name() {
|
||||
"typescript" | "syntax-typescript" => {
|
||||
p.syntax_typescript = Some(entry.value::<SyntaxTypeScriptOptions>()?);
|
||||
}
|
||||
"jsx" | "syntax-jsx" => p.syntax_jsx = true,
|
||||
"syntax-decorators" => {
|
||||
p.syntax_decorators = Some(entry.value::<SyntaxDecoratorOptions>()?);
|
||||
}
|
||||
"proposal-decorators" => {
|
||||
p.proposal_decorators = Some(entry.value::<SyntaxDecoratorOptions>()?);
|
||||
}
|
||||
"transform-typescript" => {
|
||||
p.typescript =
|
||||
entry.value::<TypeScriptOptions>().map_err(|err| p.errors.push(err)).ok();
|
||||
}
|
||||
"transform-react-jsx" => {
|
||||
p.react_jsx =
|
||||
entry.value::<JsxOptions>().map_err(|err| p.errors.push(err)).ok();
|
||||
}
|
||||
"transform-react-jsx-development" => {
|
||||
p.react_jsx_dev =
|
||||
entry.value::<JsxOptions>().map_err(|err| p.errors.push(err)).ok();
|
||||
}
|
||||
"transform-react-display-name" => p.react_display_name = true,
|
||||
"transform-react-jsx-self" => p.react_jsx_self = true,
|
||||
"transform-react-jsx-source" => p.react_jsx_source = true,
|
||||
"transform-sticky-regex" => p.sticky_flag = true,
|
||||
"transform-unicode-regex" => p.unicode_flag = true,
|
||||
"transform-dotall-regex" => p.dot_all_flag = true,
|
||||
"esbuild-regexp-lookbehind-assertions" => p.look_behind_assertions = true,
|
||||
"transform-named-capturing-groups-regex" => p.named_capture_groups = true,
|
||||
"transform-unicode-property-regex" => p.unicode_property_escapes = true,
|
||||
"esbuild-regexp-match-indices" => p.match_indices = true,
|
||||
"transform-unicode-sets-regex" => p.set_notation = true,
|
||||
"transform-arrow-functions" => {
|
||||
p.arrow_function = entry
|
||||
.value::<ArrowFunctionsOptions>()
|
||||
.map_err(|err| p.errors.push(err))
|
||||
.ok();
|
||||
}
|
||||
"transform-exponentiation-operator" => p.exponentiation_operator = true,
|
||||
"transform-async-to-generator" => p.async_to_generator = true,
|
||||
"transform-object-rest-spread" => {
|
||||
p.object_rest_spread = entry
|
||||
.value::<ObjectRestSpreadOptions>()
|
||||
.inspect_err(|err| p.errors.push(err.to_string()))
|
||||
.ok();
|
||||
}
|
||||
"transform-async-generator-functions" => p.async_generator_functions = true,
|
||||
"transform-optional-catch-binding" => p.optional_catch_binding = true,
|
||||
"transform-nullish-coalescing-operator" => p.nullish_coalescing_operator = true,
|
||||
"transform-logical-assignment-operators" => p.logical_assignment_operators = true,
|
||||
"transform-class-static-block" => p.class_static_block = true,
|
||||
"transform-class-properties" => {
|
||||
p.class_properties = entry
|
||||
.value::<ClassPropertiesOptions>()
|
||||
.inspect_err(|err| p.errors.push(err.to_string()))
|
||||
.ok();
|
||||
}
|
||||
s => p.unsupported.push(s.to_string()),
|
||||
}
|
||||
}
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://babeljs.io/docs/options#pluginpreset-entries>
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum PluginPresetEntry {
|
||||
String(String),
|
||||
Vec1([String; 1]),
|
||||
Tuple(String, serde_json::Value),
|
||||
}
|
||||
|
||||
impl PluginPresetEntry {
|
||||
fn name(&self) -> &str {
|
||||
match self {
|
||||
Self::String(s) | Self::Tuple(s, _) => s,
|
||||
Self::Vec1(s) => &s[0],
|
||||
}
|
||||
}
|
||||
|
||||
fn value<T: DeserializeOwned + Default>(self) -> Result<T, String> {
|
||||
match self {
|
||||
Self::String(_) | Self::Vec1(_) => Ok(T::default()),
|
||||
Self::Tuple(name, v) => {
|
||||
serde_json::from_value::<T>(v).map_err(|err| format!("{name}: {err}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
use oxc_diagnostics::{Error, OxcDiagnostic};
|
||||
|
||||
use crate::{
|
||||
es2015::{ArrowFunctionsOptions, ES2015Options},
|
||||
es2016::ES2016Options,
|
||||
es2017::ES2017Options,
|
||||
es2018::{ES2018Options, ObjectRestSpreadOptions},
|
||||
es2019::ES2019Options,
|
||||
es2020::ES2020Options,
|
||||
es2021::ES2021Options,
|
||||
es2022::{ClassPropertiesOptions, ES2022Options},
|
||||
es2015::ES2015Options, es2016::ES2016Options, es2017::ES2017Options, es2018::ES2018Options,
|
||||
es2019::ES2019Options, es2020::ES2020Options, es2021::ES2021Options, es2022::ES2022Options,
|
||||
regexp::RegExpOptions,
|
||||
};
|
||||
|
||||
|
|
@ -146,117 +140,59 @@ impl TryFrom<&BabelOptions> for EnvOptions {
|
|||
.unwrap_or_default();
|
||||
|
||||
let regexp = RegExpOptions {
|
||||
sticky_flag: env.regexp.sticky_flag || options.has_plugin("transform-sticky-regex"),
|
||||
unicode_flag: env.regexp.unicode_flag || options.has_plugin("transform-unicode-regex"),
|
||||
dot_all_flag: env.regexp.dot_all_flag || options.has_plugin("transform-dotall-regex"),
|
||||
look_behind_assertions: env.regexp.look_behind_assertions,
|
||||
sticky_flag: env.regexp.sticky_flag || options.plugins.sticky_flag,
|
||||
unicode_flag: env.regexp.unicode_flag || options.plugins.unicode_flag,
|
||||
dot_all_flag: env.regexp.dot_all_flag || options.plugins.dot_all_flag,
|
||||
look_behind_assertions: env.regexp.look_behind_assertions
|
||||
|| options.plugins.look_behind_assertions,
|
||||
named_capture_groups: env.regexp.named_capture_groups
|
||||
|| options.has_plugin("transform-named-capturing-groups-regex"),
|
||||
|| options.plugins.named_capture_groups,
|
||||
unicode_property_escapes: env.regexp.unicode_property_escapes
|
||||
|| options.has_plugin("transform-unicode-property-regex"),
|
||||
|| options.plugins.unicode_property_escapes,
|
||||
match_indices: env.regexp.match_indices,
|
||||
set_notation: env.regexp.set_notation
|
||||
|| options.has_plugin("transform-unicode-sets-regex"),
|
||||
set_notation: env.regexp.set_notation || options.plugins.set_notation,
|
||||
};
|
||||
|
||||
let es2015 = ES2015Options {
|
||||
arrow_function: {
|
||||
let plugin_name = "transform-arrow-functions";
|
||||
options
|
||||
.get_plugin(plugin_name)
|
||||
.map(|o| {
|
||||
o.and_then(|options| {
|
||||
serde_json::from_value::<ArrowFunctionsOptions>(options)
|
||||
.inspect_err(|err| {
|
||||
report_error(plugin_name, err, false, &mut errors);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.or(env.es2015.arrow_function)
|
||||
},
|
||||
arrow_function: options.plugins.arrow_function.or(env.es2015.arrow_function),
|
||||
};
|
||||
|
||||
let es2016 = ES2016Options {
|
||||
exponentiation_operator: {
|
||||
let plugin_name = "transform-exponentiation-operator";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2016.exponentiation_operator
|
||||
},
|
||||
exponentiation_operator: options.plugins.exponentiation_operator
|
||||
|| env.es2016.exponentiation_operator,
|
||||
};
|
||||
|
||||
let es2017 = ES2017Options {
|
||||
async_to_generator: {
|
||||
let plugin_name = "transform-async-to-generator";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2017.async_to_generator
|
||||
},
|
||||
async_to_generator: options.plugins.async_to_generator || env.es2017.async_to_generator,
|
||||
};
|
||||
|
||||
let es2018 = ES2018Options {
|
||||
object_rest_spread: {
|
||||
let plugin_name = "transform-object-rest-spread";
|
||||
options
|
||||
.get_plugin(plugin_name)
|
||||
.map(|o| {
|
||||
o.and_then(|options| {
|
||||
serde_json::from_value::<ObjectRestSpreadOptions>(options)
|
||||
.inspect_err(|err| {
|
||||
report_error(plugin_name, err, false, &mut errors);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.or(env.es2018.object_rest_spread)
|
||||
},
|
||||
async_generator_functions: {
|
||||
let plugin_name = "transform-async-generator-functions";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2018.async_generator_functions
|
||||
},
|
||||
object_rest_spread: options
|
||||
.plugins
|
||||
.object_rest_spread
|
||||
.or(env.es2018.object_rest_spread),
|
||||
async_generator_functions: options.plugins.async_generator_functions
|
||||
|| env.es2018.async_generator_functions,
|
||||
};
|
||||
|
||||
let es2019 = ES2019Options {
|
||||
optional_catch_binding: {
|
||||
let plugin_name = "transform-optional-catch-binding";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2019.optional_catch_binding
|
||||
},
|
||||
optional_catch_binding: options.plugins.optional_catch_binding
|
||||
|| env.es2019.optional_catch_binding,
|
||||
};
|
||||
|
||||
let es2020 = ES2020Options {
|
||||
nullish_coalescing_operator: {
|
||||
let plugin_name = "transform-nullish-coalescing-operator";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2020.nullish_coalescing_operator
|
||||
},
|
||||
nullish_coalescing_operator: options.plugins.nullish_coalescing_operator
|
||||
|| env.es2020.nullish_coalescing_operator,
|
||||
};
|
||||
|
||||
let es2021 = ES2021Options {
|
||||
logical_assignment_operators: {
|
||||
let plugin_name = "transform-logical-assignment-operators";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2021.logical_assignment_operators
|
||||
},
|
||||
logical_assignment_operators: options.plugins.logical_assignment_operators
|
||||
|| env.es2021.logical_assignment_operators,
|
||||
};
|
||||
|
||||
let es2022 = ES2022Options {
|
||||
class_static_block: {
|
||||
let plugin_name = "transform-class-static-block";
|
||||
options.get_plugin(plugin_name).is_some() || env.es2022.class_static_block
|
||||
},
|
||||
class_properties: {
|
||||
let plugin_name = "transform-class-properties";
|
||||
options
|
||||
.get_plugin(plugin_name)
|
||||
.map(|o| {
|
||||
o.and_then(|options| {
|
||||
serde_json::from_value::<ClassPropertiesOptions>(options)
|
||||
.inspect_err(|err| {
|
||||
report_error(plugin_name, err, false, &mut errors);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.or(env.es2022.class_properties)
|
||||
},
|
||||
class_static_block: options.plugins.class_static_block || env.es2022.class_static_block,
|
||||
class_properties: options.plugins.class_properties.or(env.es2022.class_properties),
|
||||
};
|
||||
|
||||
if !errors.is_empty() {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ impl TryFrom<&BabelOptions> for TransformOptions {
|
|||
/// If the `options` contains any unknown fields, they will be returned as a list of errors.
|
||||
fn try_from(options: &BabelOptions) -> Result<Self, Self::Error> {
|
||||
let mut errors = Vec::<Error>::new();
|
||||
errors.extend(options.plugins.errors.iter().map(|err| Error::msg(err.clone())));
|
||||
|
||||
let assumptions = if options.assumptions.is_null() {
|
||||
CompilerAssumptions::default()
|
||||
|
|
@ -92,15 +93,7 @@ impl TryFrom<&BabelOptions> for TransformOptions {
|
|||
.unwrap_or_default()
|
||||
})
|
||||
} else {
|
||||
options.get_plugin("transform-typescript").and_then(|options| {
|
||||
options
|
||||
.map(|options| {
|
||||
serde_json::from_value::<TypeScriptOptions>(options)
|
||||
.inspect_err(|err| report_error("typescript", err, false, &mut errors))
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
options.plugins.typescript.clone()
|
||||
}
|
||||
.unwrap_or_default();
|
||||
|
||||
|
|
@ -109,35 +102,19 @@ impl TryFrom<&BabelOptions> for TransformOptions {
|
|||
.inspect_err(|err| report_error("react", err, true, &mut errors))
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
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 {
|
||||
options.get_plugin(jsx_plugin_name).and_then(|options| {
|
||||
options.and_then(|options| {
|
||||
serde_json::from_value::<JsxOptions>(options)
|
||||
.inspect_err(|err| {
|
||||
report_error(jsx_plugin_name, err, false, &mut errors);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
})
|
||||
let mut jsx_options = if let Some(options) = &options.plugins.react_jsx_dev {
|
||||
options.clone()
|
||||
} else if let Some(options) = &options.plugins.react_jsx {
|
||||
options.clone()
|
||||
} else {
|
||||
options.get_plugin(jsx_dev_name).and_then(|options| {
|
||||
options.and_then(|options| {
|
||||
serde_json::from_value::<JsxOptions>(options)
|
||||
.inspect_err(|err| report_error(jsx_dev_name, err, false, &mut errors))
|
||||
.ok()
|
||||
})
|
||||
})
|
||||
}
|
||||
.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");
|
||||
react_options.jsx_source_plugin = options.has_plugin("transform-react-jsx-source");
|
||||
react_options
|
||||
JsxOptions::default()
|
||||
};
|
||||
jsx_options.development = options.plugins.react_jsx_dev.is_some();
|
||||
jsx_options.jsx_plugin = options.plugins.react_jsx.is_some();
|
||||
jsx_options.display_name_plugin = options.plugins.react_display_name;
|
||||
jsx_options.jsx_self_plugin = options.plugins.react_jsx_self;
|
||||
jsx_options.jsx_source_plugin = options.plugins.react_jsx_source;
|
||||
jsx_options
|
||||
};
|
||||
|
||||
let env = match EnvOptions::try_from(options) {
|
||||
|
|
@ -177,17 +154,3 @@ fn report_error(name: &str, err: &serde_json::Error, is_preset: bool, errors: &m
|
|||
if is_preset { format!("preset-{name}: {err}",) } else { format!("{name}: {err}",) };
|
||||
errors.push(OxcDiagnostic::error(message).into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deny_unknown_fields() {
|
||||
let options = serde_json::json!({
|
||||
"plugins": [["transform-react-jsx", { "runtime": "automatic", "filter": 1 }]],
|
||||
"sourceType": "module"
|
||||
});
|
||||
let babel_options = serde_json::from_value::<BabelOptions>(options).unwrap();
|
||||
let result = TransformOptions::try_from(&babel_options);
|
||||
assert!(result.is_err());
|
||||
let err_message =
|
||||
result.err().unwrap().iter().map(ToString::to_string).collect::<Vec<_>>().join("\n");
|
||||
assert!(err_message.contains("transform-react-jsx: unknown field `filter`"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ commit: d20b314c
|
|||
parser_babel Summary:
|
||||
AST Parsed : 2126/2136 (99.53%)
|
||||
Positive Passed: 2116/2136 (99.06%)
|
||||
Negative Passed: 1387/1500 (92.47%)
|
||||
Negative Passed: 1389/1506 (92.23%)
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/annex-b/enabled/3.1-sloppy-labeled-functions-if-body/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-loop/input.js
|
||||
|
|
@ -33,6 +33,10 @@ Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es
|
|||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0276/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/flow/expect-plugin/export-interface/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/flow/expect-plugin/export-type/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-fragment/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-jsx-expression/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/jsx/errors/_no_plugin-non-BMP-identifier/input.js
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/satisfies-const-error/input.ts
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/unparenthesized-assert-and-assign/input.ts
|
||||
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/unparenthesized-type-assertion-and-assign/input.ts
|
||||
|
|
@ -9732,11 +9736,22 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
|
|||
· ─
|
||||
╰────
|
||||
|
||||
× Expected `<` but found `EOF`
|
||||
╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/_no-plugin-type-param/input.js:2:1]
|
||||
1 │ <div>() => {}
|
||||
╰────
|
||||
|
||||
× Expected `<` but found `EOF`
|
||||
╭─[babel/packages/babel-parser/test/fixtures/jsx/errors/unclosed-jsx-element/input.js:2:1]
|
||||
1 │ <div>() => {}
|
||||
╰────
|
||||
|
||||
× Unexpected token
|
||||
╭─[babel/packages/babel-parser/test/fixtures/placeholders/_errors/no-plugin/input.js:1:1]
|
||||
1 │ %%FOO%%
|
||||
· ─
|
||||
╰────
|
||||
|
||||
× Bad escape sequence in untagged template literal
|
||||
╭─[babel/packages/babel-parser/test/fixtures/tokens/template-string/invalid-octal/input.js:1:2]
|
||||
1 │ `\1`;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use oxc::{span::SourceType, transformer::BabelOptions};
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
suite::{Case, Suite, TestResult},
|
||||
|
|
@ -167,15 +166,12 @@ impl Case for BabelCase {
|
|||
fn skip_test_case(&self) -> bool {
|
||||
let not_supported_plugins =
|
||||
["async-do-expression", "flow", "placeholders", "decorators-legacy", "recordAndTuple"];
|
||||
let has_not_supported_plugins = self.options.plugins.iter().any(|p| {
|
||||
let plugin_name = match p {
|
||||
Value::String(plugin_name) => Some(plugin_name.as_str()),
|
||||
Value::Array(a) => a.first().and_then(|plugin_name| plugin_name.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
let plugin_name = plugin_name.expect("Failed to parse plugins config");
|
||||
not_supported_plugins.contains(&plugin_name)
|
||||
});
|
||||
let has_not_supported_plugins = self
|
||||
.options
|
||||
.plugins
|
||||
.unsupported
|
||||
.iter()
|
||||
.any(|p| not_supported_plugins.iter().any(|plugin| plugin == p));
|
||||
has_not_supported_plugins
|
||||
|| self.options.allow_await_outside_function
|
||||
|| self.options.allow_undeclared_exports
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
commit: d20b314c
|
||||
|
||||
Passed: 376/1077
|
||||
Passed: 377/1078
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-class-static-block
|
||||
|
|
@ -1734,7 +1734,7 @@ rebuilt : ScopeId(1): []
|
|||
x Output mismatch
|
||||
|
||||
|
||||
# babel-plugin-transform-typescript (39/152)
|
||||
# babel-plugin-transform-typescript (40/153)
|
||||
* cast/as-expression/input.ts
|
||||
Unresolved references mismatch:
|
||||
after transform: ["T", "x"]
|
||||
|
|
|
|||
|
|
@ -101,7 +101,10 @@ pub trait TestCase {
|
|||
let options = self.options();
|
||||
|
||||
// Skip plugins we don't support yet
|
||||
if PLUGINS_NOT_SUPPORTED_YET.iter().any(|plugin| options.get_plugin(plugin).is_some()) {
|
||||
if PLUGINS_NOT_SUPPORTED_YET
|
||||
.iter()
|
||||
.any(|plugin| options.plugins.unsupported.iter().any(|p| plugin == p))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -118,14 +121,13 @@ pub trait TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
// Legacy decorators is not supported by the parser
|
||||
// Legacy decorators is not supported
|
||||
if options
|
||||
.get_plugin("syntax-decorators")
|
||||
.flatten()
|
||||
.plugins
|
||||
.proposal_decorators
|
||||
.as_ref()
|
||||
.and_then(|o| o.as_object())
|
||||
.and_then(|o| o.get("version"))
|
||||
.is_some_and(|s| s == "legacy")
|
||||
.or(options.plugins.syntax_decorators.as_ref())
|
||||
.is_some_and(|o| o.version == "legacy")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -171,8 +173,8 @@ pub trait TestCase {
|
|||
// Some babel test cases have a js extension, but contain typescript code.
|
||||
// Therefore, if the typescript plugin exists, enable typescript.
|
||||
let source_type = SourceType::from_path(path).unwrap().with_typescript(
|
||||
self.options().get_plugin("transform-typescript").is_some()
|
||||
|| self.options().get_plugin("syntax-typescript").is_some(),
|
||||
self.options().plugins.syntax_typescript.is_some()
|
||||
|| self.options().plugins.typescript.is_some(),
|
||||
);
|
||||
|
||||
let driver =
|
||||
|
|
@ -228,7 +230,7 @@ impl TestCase for ConformanceTestCase {
|
|||
let mut source_type = SourceType::from_path(&self.path)
|
||||
.unwrap()
|
||||
.with_script(true)
|
||||
.with_jsx(self.options.get_plugin("syntax-jsx").is_some());
|
||||
.with_jsx(self.options.plugins.syntax_jsx);
|
||||
|
||||
source_type = match self.options.source_type.as_deref() {
|
||||
Some("unambiguous") => source_type.with_unambiguous(true),
|
||||
|
|
@ -239,8 +241,8 @@ impl TestCase for ConformanceTestCase {
|
|||
};
|
||||
|
||||
source_type = source_type.with_typescript(
|
||||
self.options.get_plugin("transform-typescript").is_some()
|
||||
|| self.options.get_plugin("syntax-typescript").is_some(),
|
||||
self.options.plugins.typescript.is_some()
|
||||
|| self.options.plugins.syntax_typescript.is_some(),
|
||||
);
|
||||
|
||||
source_type
|
||||
|
|
|
|||
Loading…
Reference in a new issue