mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer): report errors when options have unknown fields (#3322)
This commit is contained in:
parent
46cb5f97a0
commit
e2c6fe0cb1
9 changed files with 155 additions and 57 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1678,7 +1678,6 @@ dependencies = [
|
||||||
"oxc_tasks_common",
|
"oxc_tasks_common",
|
||||||
"oxc_transformer",
|
"oxc_transformer",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
"serde_json",
|
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,29 +6,52 @@ use serde::Deserialize;
|
||||||
///
|
///
|
||||||
/// See <https://babeljs.io/docs/assumptions>
|
/// See <https://babeljs.io/docs/assumptions>
|
||||||
#[derive(Debug, Default, Clone, Copy, Deserialize)]
|
#[derive(Debug, Default, Clone, Copy, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||||
pub struct CompilerAssumptions {
|
pub struct CompilerAssumptions {
|
||||||
|
#[serde(default)]
|
||||||
pub array_like_is_iterable: bool,
|
pub array_like_is_iterable: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub constant_reexports: bool,
|
pub constant_reexports: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub constant_super: bool,
|
pub constant_super: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub enumerable_module_meta: bool,
|
pub enumerable_module_meta: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub ignore_function_length: bool,
|
pub ignore_function_length: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub ignore_to_primitive_hint: bool,
|
pub ignore_to_primitive_hint: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub iterable_is_array: bool,
|
pub iterable_is_array: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub mutable_template_object: bool,
|
pub mutable_template_object: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub no_class_calls: bool,
|
pub no_class_calls: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub no_document_all: bool,
|
pub no_document_all: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub no_incomplete_ns_import_detection: bool,
|
pub no_incomplete_ns_import_detection: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub no_new_arrows: bool,
|
pub no_new_arrows: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub no_uninitialized_private_field_access: bool,
|
pub no_uninitialized_private_field_access: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub object_rest_no_symbols: bool,
|
pub object_rest_no_symbols: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub private_fields_as_symbols: bool,
|
pub private_fields_as_symbols: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub private_fields_as_properties: bool,
|
pub private_fields_as_properties: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub pure_getters: bool,
|
pub pure_getters: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub set_class_methods: bool,
|
pub set_class_methods: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub set_computed_properties: bool,
|
pub set_computed_properties: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub set_public_class_fields: bool,
|
pub set_public_class_fields: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub set_spread_properties: bool,
|
pub set_spread_properties: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub skip_for_of_iterator_closing: bool,
|
pub skip_for_of_iterator_closing: bool,
|
||||||
|
#[serde(default)]
|
||||||
pub super_is_callable_constructor: bool,
|
pub super_is_callable_constructor: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use serde::Deserialize;
|
||||||
use super::ArrowFunctionsOptions;
|
use super::ArrowFunctionsOptions;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
#[derive(Debug, Default, Clone, Deserialize)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
|
||||||
pub struct ES2015Options {
|
pub struct ES2015Options {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub arrow_function: Option<ArrowFunctionsOptions>,
|
pub arrow_function: Option<ArrowFunctionsOptions>,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use oxc_diagnostics::{Error, OxcDiagnostic};
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::{de::DeserializeOwned, Deserialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compiler_assumptions::CompilerAssumptions, es2015::ES2015Options, react::ReactOptions,
|
compiler_assumptions::CompilerAssumptions,
|
||||||
|
es2015::{ArrowFunctionsOptions, ES2015Options},
|
||||||
|
react::ReactOptions,
|
||||||
typescript::TypeScriptOptions,
|
typescript::TypeScriptOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -33,58 +36,94 @@ pub struct TransformOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransformOptions {
|
impl TransformOptions {
|
||||||
/// # Panics
|
|
||||||
/// Panics if the options are invalid.
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
pub fn from_babel_options(options: &BabelOptions) -> serde_json::Result<Self> {
|
///
|
||||||
|
pub fn from_babel_options(options: &BabelOptions) -> Result<Self, Vec<Error>> {
|
||||||
fn get_options<T: Default + DeserializeOwned>(
|
fn get_options<T: Default + DeserializeOwned>(
|
||||||
value: Option<Value>,
|
name: &str,
|
||||||
) -> serde_json::Result<T> {
|
babel_options: &BabelOptions,
|
||||||
match value {
|
errors: &mut Vec<Error>,
|
||||||
Some(v) => serde_json::from_value::<T>(v),
|
is_preset: bool,
|
||||||
None => Ok(T::default()),
|
) -> T {
|
||||||
}
|
let target = if is_preset {
|
||||||
|
babel_options.get_preset(name)
|
||||||
|
} else {
|
||||||
|
babel_options.get_plugin(name)
|
||||||
|
};
|
||||||
|
target
|
||||||
|
.and_then(|plugin_options| {
|
||||||
|
plugin_options.and_then(|options| match serde_json::from_value::<T>(options) {
|
||||||
|
Ok(options) => Some(options),
|
||||||
|
Err(err) => {
|
||||||
|
let kind_msg =
|
||||||
|
if is_preset { format!("preset-{name}") } else { name.to_string() };
|
||||||
|
errors.push(OxcDiagnostic::error(format!("{kind_msg}: {err}")).into());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| T::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
let react = if let Some(options) = options.get_preset("react") {
|
let mut errors = Vec::<Error>::new();
|
||||||
get_options::<ReactOptions>(options)?
|
|
||||||
|
let react = if options.has_preset("react") {
|
||||||
|
get_options::<ReactOptions>("react", options, &mut errors, true)
|
||||||
} else {
|
} else {
|
||||||
let jsx_plugin = options.get_plugin("transform-react-jsx");
|
let has_jsx_plugin = options.has_plugin("transform-react-jsx");
|
||||||
let jsx_development_plugin = options.get_plugin("transform-react-jsx-development");
|
let has_jsx_development_plugin = options.has_plugin("transform-react-jsx-development");
|
||||||
let has_jsx_plugin =
|
let mut react_options = if has_jsx_plugin {
|
||||||
jsx_plugin.as_ref().is_some() || jsx_development_plugin.as_ref().is_some();
|
get_options::<ReactOptions>("transform-react-jsx", options, &mut errors, false)
|
||||||
let mut react_options = jsx_plugin
|
} else {
|
||||||
.map(get_options::<ReactOptions>)
|
get_options::<ReactOptions>(
|
||||||
.or_else(|| jsx_development_plugin.map(get_options::<ReactOptions>))
|
"transform-react-jsx-development",
|
||||||
.transpose()?
|
options,
|
||||||
.unwrap_or_default();
|
&mut errors,
|
||||||
react_options.development =
|
false,
|
||||||
options.get_plugin("transform-react-jsx-development").is_some();
|
)
|
||||||
react_options.jsx_plugin = has_jsx_plugin;
|
};
|
||||||
react_options.display_name_plugin =
|
react_options.development = options.has_plugin("transform-react-jsx-development");
|
||||||
options.get_plugin("transform-react-display-name").is_some();
|
react_options.jsx_plugin = has_jsx_plugin || has_jsx_development_plugin;
|
||||||
react_options.jsx_self_plugin =
|
react_options.display_name_plugin = options.has_plugin("transform-react-display-name");
|
||||||
options.get_plugin("transform-react-jsx-self").is_some();
|
react_options.jsx_self_plugin = options.has_plugin("transform-react-jsx-self");
|
||||||
react_options.jsx_source_plugin =
|
react_options.jsx_source_plugin = options.has_plugin("transform-react-jsx-source");
|
||||||
options.get_plugin("transform-react-jsx-source").is_some();
|
|
||||||
react_options
|
react_options
|
||||||
};
|
};
|
||||||
|
|
||||||
let es2015 = ES2015Options {
|
let es2015 = ES2015Options {
|
||||||
arrow_function: options
|
arrow_function: options.has_plugin("transform-arrow-functions").then(|| {
|
||||||
.get_plugin("transform-arrow-functions")
|
get_options::<ArrowFunctionsOptions>(
|
||||||
.map(get_options)
|
"transform-arrow-functions",
|
||||||
.transpose()?,
|
options,
|
||||||
|
&mut errors,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let typescript =
|
||||||
|
get_options::<TypeScriptOptions>("transform-typescript", options, &mut errors, false);
|
||||||
|
|
||||||
|
let 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
return Err(errors);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
cwd: options.cwd.clone().unwrap(),
|
cwd: options.cwd.clone().unwrap_or_default(),
|
||||||
assumptions: serde_json::from_value(options.assumptions.clone()).unwrap_or_default(),
|
assumptions,
|
||||||
typescript: options
|
typescript,
|
||||||
.get_plugin("transform-typescript")
|
|
||||||
.map(get_options::<TypeScriptOptions>)
|
|
||||||
.transpose()?
|
|
||||||
.unwrap_or_default(),
|
|
||||||
react,
|
react,
|
||||||
es2015,
|
es2015,
|
||||||
})
|
})
|
||||||
|
|
@ -205,6 +244,14 @@ impl BabelOptions {
|
||||||
self.presets.iter().find_map(|v| Self::get_value(v, name))
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::option_option)]
|
#[allow(clippy::option_option)]
|
||||||
fn get_value(value: &Value, name: &str) -> Option<Option<Value>> {
|
fn get_value(value: &Value, name: &str) -> Option<Option<Value>> {
|
||||||
match value {
|
match value {
|
||||||
|
|
@ -216,3 +263,17 @@ impl BabelOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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::from_babel_options(&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`"));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ impl ReactJsxRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
|
||||||
pub struct ReactOptions {
|
pub struct ReactOptions {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub jsx_plugin: bool,
|
pub jsx_plugin: bool,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,12 @@ fn default_for_jsx_pragma_frag() -> Cow<'static, str> {
|
||||||
Cow::Borrowed("React.Fragment")
|
Cow::Borrowed("React.Fragment")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_as_true() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
|
||||||
pub struct TypeScriptOptions {
|
pub struct TypeScriptOptions {
|
||||||
/// Replace the function used when compiling JSX expressions.
|
/// Replace the function used when compiling JSX expressions.
|
||||||
/// This is so that we know that the import is not a type import, and should not be removed.
|
/// This is so that we know that the import is not a type import, and should not be removed.
|
||||||
|
|
@ -26,9 +30,18 @@ pub struct TypeScriptOptions {
|
||||||
/// defaults to React.Fragment
|
/// defaults to React.Fragment
|
||||||
#[serde(default = "default_for_jsx_pragma_frag")]
|
#[serde(default = "default_for_jsx_pragma_frag")]
|
||||||
pub jsx_pragma_frag: Cow<'static, str>,
|
pub jsx_pragma_frag: Cow<'static, str>,
|
||||||
|
|
||||||
/// When set to true, the transform will only remove type-only imports (introduced in TypeScript 3.8).
|
/// When set to true, the transform will only remove type-only imports (introduced in TypeScript 3.8).
|
||||||
/// This should only be used if you are using TypeScript >= 3.8.
|
/// This should only be used if you are using TypeScript >= 3.8.
|
||||||
pub only_remove_type_imports: bool,
|
pub only_remove_type_imports: bool,
|
||||||
|
|
||||||
|
// Enables compilation of TypeScript namespaces.
|
||||||
|
#[serde(default = "default_as_true")]
|
||||||
|
pub allow_namespaces: bool,
|
||||||
|
|
||||||
|
// When enabled, type-only class fields are only removed if they are prefixed with the declare modifier:
|
||||||
|
#[serde(default = "default_as_true")]
|
||||||
|
pub allow_declare_fields: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeScriptOptions {
|
impl TypeScriptOptions {
|
||||||
|
|
@ -74,6 +87,8 @@ impl Default for TypeScriptOptions {
|
||||||
jsx_pragma: default_for_jsx_pragma(),
|
jsx_pragma: default_for_jsx_pragma(),
|
||||||
jsx_pragma_frag: default_for_jsx_pragma_frag(),
|
jsx_pragma_frag: default_for_jsx_pragma_frag(),
|
||||||
only_remove_type_imports: false,
|
only_remove_type_imports: false,
|
||||||
|
allow_namespaces: default_as_true(),
|
||||||
|
allow_declare_fields: default_as_true(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,3 @@ oxc_diagnostics = { workspace = true }
|
||||||
walkdir = { workspace = true }
|
walkdir = { workspace = true }
|
||||||
pico-args = { workspace = true }
|
pico-args = { workspace = true }
|
||||||
indexmap = { workspace = true }
|
indexmap = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
commit: 4bd1b2c2
|
commit: 4bd1b2c2
|
||||||
|
|
||||||
Passed: 310/351
|
Passed: 309/351
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-preset-react
|
* babel-preset-react
|
||||||
|
|
@ -54,8 +54,9 @@ Passed: 310/351
|
||||||
* optimize-const-enums/merged-exported/input.ts
|
* optimize-const-enums/merged-exported/input.ts
|
||||||
* regression/15768/input.ts
|
* regression/15768/input.ts
|
||||||
|
|
||||||
# babel-plugin-transform-react-jsx (141/142)
|
# babel-plugin-transform-react-jsx (140/142)
|
||||||
* autoImport/complicated-scope-module/input.js
|
* autoImport/complicated-scope-module/input.js
|
||||||
|
* react-automatic/does-not-add-source-self-automatic/input.mjs
|
||||||
|
|
||||||
# babel-plugin-transform-react-jsx-development (9/10)
|
# babel-plugin-transform-react-jsx-development (9/10)
|
||||||
* cross-platform/within-ts-module-block/input.ts
|
* cross-platform/within-ts-module-block/input.ts
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ impl TestCaseKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(options: &BabelOptions) -> serde_json::Result<TransformOptions> {
|
fn transform_options(options: &BabelOptions) -> Result<TransformOptions, Vec<Error>> {
|
||||||
TransformOptions::from_babel_options(options)
|
TransformOptions::from_babel_options(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ pub trait TestCase {
|
||||||
|
|
||||||
fn options(&self) -> &BabelOptions;
|
fn options(&self) -> &BabelOptions;
|
||||||
|
|
||||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions>;
|
fn transform_options(&self) -> &Result<TransformOptions, Vec<Error>>;
|
||||||
|
|
||||||
fn test(&self, filtered: bool) -> bool;
|
fn test(&self, filtered: bool) -> bool;
|
||||||
|
|
||||||
|
|
@ -186,7 +186,7 @@ pub trait TestCase {
|
||||||
pub struct ConformanceTestCase {
|
pub struct ConformanceTestCase {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
options: BabelOptions,
|
options: BabelOptions,
|
||||||
transform_options: serde_json::Result<TransformOptions>,
|
transform_options: Result<TransformOptions, Vec<Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestCase for ConformanceTestCase {
|
impl TestCase for ConformanceTestCase {
|
||||||
|
|
@ -201,7 +201,7 @@ impl TestCase for ConformanceTestCase {
|
||||||
&self.options
|
&self.options
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
fn transform_options(&self) -> &Result<TransformOptions, Vec<Error>> {
|
||||||
&self.transform_options
|
&self.transform_options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,7 +287,7 @@ impl TestCase for ConformanceTestCase {
|
||||||
Some(transform_options.clone())
|
Some(transform_options.clone())
|
||||||
}
|
}
|
||||||
Err(json_err) => {
|
Err(json_err) => {
|
||||||
let error = json_err.to_string();
|
let error = json_err.iter().map(ToString::to_string).collect::<Vec<_>>().join("\n");
|
||||||
actual_errors = get_babel_error(&error);
|
actual_errors = get_babel_error(&error);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ impl TestCase for ConformanceTestCase {
|
||||||
pub struct ExecTestCase {
|
pub struct ExecTestCase {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
options: BabelOptions,
|
options: BabelOptions,
|
||||||
transform_options: serde_json::Result<TransformOptions>,
|
transform_options: Result<TransformOptions, Vec<Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecTestCase {
|
impl ExecTestCase {
|
||||||
|
|
@ -396,7 +396,7 @@ impl TestCase for ExecTestCase {
|
||||||
&self.options
|
&self.options
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_options(&self) -> &serde_json::Result<TransformOptions> {
|
fn transform_options(&self) -> &Result<TransformOptions, Vec<Error>> {
|
||||||
&self.transform_options
|
&self.transform_options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,7 +421,7 @@ impl TestCase for ExecTestCase {
|
||||||
|
|
||||||
fn get_babel_error(error: &str) -> String {
|
fn get_babel_error(error: &str) -> String {
|
||||||
match error {
|
match error {
|
||||||
"unknown variant `invalidOption`, expected `classic` or `automatic`" => "Runtime must be either \"classic\" or \"automatic\".",
|
"transform-react-jsx: unknown variant `invalidOption`, expected `classic` or `automatic`" => "Runtime must be either \"classic\" or \"automatic\".",
|
||||||
"Duplicate __self prop found." => "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self Babel plugin. Both __source and __self are automatically set when using the automatic runtime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.",
|
"Duplicate __self prop found." => "Duplicate __self prop found. You are most likely using the deprecated transform-react-jsx-self Babel plugin. Both __source and __self are automatically set when using the automatic runtime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.",
|
||||||
"Duplicate __source prop found." => "Duplicate __source prop found. You are most likely using the deprecated transform-react-jsx-source Babel plugin. Both __source and __self are automatically set when using the automatic runtime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.",
|
"Duplicate __source prop found." => "Duplicate __source prop found. You are most likely using the deprecated transform-react-jsx-source Babel plugin. Both __source and __self are automatically set when using the automatic runtime. Please remove transform-react-jsx-source and transform-react-jsx-self from your Babel config.",
|
||||||
"Expected `>` but found `/`" => "Unexpected token, expected \",\"",
|
"Expected `>` but found `/`" => "Unexpected token, expected \",\"",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue