mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer): add diagnostics to react transform (#2974)
This commit is contained in:
parent
ef602af4cc
commit
c211f1e57f
4 changed files with 57 additions and 25 deletions
30
crates/oxc_transformer/src/react/jsx/diagnostics.rs
Normal file
30
crates/oxc_transformer/src/react/jsx/diagnostics.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
use oxc_diagnostics::{
|
||||||
|
miette::{self, Diagnostic},
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
use oxc_span::Span;
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("pragma and pragmaFrag cannot be set when runtime is automatic.")]
|
||||||
|
#[diagnostic(severity(warning), help("Remove `pragma` and `pragmaFrag` options."))]
|
||||||
|
pub struct PragmaAndPragmaFragCannotBeSet;
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("importSource cannot be set when runtime is classic.")]
|
||||||
|
#[diagnostic(severity(warning), help("Remove `importSource` option."))]
|
||||||
|
pub struct ImportSourceCannotBeSet;
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("Namespace tags are not supported by default. React's JSX doesn't support namespace tags. You can set `throwIfNamespace: false` to bypass this warning.")]
|
||||||
|
#[diagnostic(severity(warning))]
|
||||||
|
pub struct NamespaceDoesNotSupport(#[label] pub Span);
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("Please provide an explicit key value. Using \"key\" as a shorthand for \"key={{true}}\" is not allowed.")]
|
||||||
|
#[diagnostic(severity(warning))]
|
||||||
|
pub struct ValuelessKey(#[label] pub Span);
|
||||||
|
|
||||||
|
#[derive(Debug, Error, Diagnostic)]
|
||||||
|
#[error("Spread children are not supported in React.")]
|
||||||
|
#[diagnostic(severity(warning))]
|
||||||
|
pub struct SpreadChildrenAreNotSupported(#[label] pub Span);
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
mod diagnostics;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use oxc_allocator::Vec;
|
use oxc_allocator::Vec;
|
||||||
use oxc_ast::{ast::*, AstBuilder};
|
use oxc_ast::{ast::*, AstBuilder};
|
||||||
use oxc_span::{CompactStr, SPAN};
|
use oxc_span::{CompactStr, GetSpan, SPAN};
|
||||||
use oxc_syntax::{
|
use oxc_syntax::{
|
||||||
identifier::{is_irregular_whitespace, is_line_terminator},
|
identifier::{is_irregular_whitespace, is_line_terminator},
|
||||||
xml_entities::XML_ENTITIES,
|
xml_entities::XML_ENTITIES,
|
||||||
|
|
@ -16,6 +18,11 @@ pub use super::{
|
||||||
options::{ReactJsxRuntime, ReactOptions},
|
options::{ReactJsxRuntime, ReactOptions},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::diagnostics::{
|
||||||
|
ImportSourceCannotBeSet, NamespaceDoesNotSupport, PragmaAndPragmaFragCannotBeSet,
|
||||||
|
SpreadChildrenAreNotSupported, ValuelessKey,
|
||||||
|
};
|
||||||
|
|
||||||
/// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
/// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
||||||
///
|
///
|
||||||
/// This plugin generates production-ready JS code.
|
/// This plugin generates production-ready JS code.
|
||||||
|
|
@ -99,7 +106,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
pub fn add_runtime_imports(&mut self, program: &mut Program<'a>) {
|
pub fn add_runtime_imports(&mut self, program: &mut Program<'a>) {
|
||||||
if self.options.runtime.is_classic() {
|
if self.options.runtime.is_classic() {
|
||||||
if self.options.import_source != "react" {
|
if self.options.import_source != "react" {
|
||||||
// self.ctx.error(ImportSourceCannotBeSet);
|
self.ctx.error(ImportSourceCannotBeSet);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +114,7 @@ impl<'a> ReactJsx<'a> {
|
||||||
if self.options.pragma != "React.createElement"
|
if self.options.pragma != "React.createElement"
|
||||||
|| self.options.pragma_frag != "React.Fragment"
|
|| self.options.pragma_frag != "React.Fragment"
|
||||||
{
|
{
|
||||||
// self.ctx.error(PragmaAndPragmaFragCannotBeSet);
|
self.ctx.error(PragmaAndPragmaFragCannotBeSet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,9 +339,9 @@ impl<'a> ReactJsx<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JSXAttributeItem::Attribute(attr) if attr.is_key() => {
|
JSXAttributeItem::Attribute(attr) if attr.is_key() => {
|
||||||
// if attr.value.is_none() {
|
if attr.value.is_none() {
|
||||||
// self.ctx.error(ValuelessKey(attr.name.span()));
|
self.ctx.error(ValuelessKey(attr.name.span()));
|
||||||
// }
|
}
|
||||||
// In automatic mode, extract the key before spread prop,
|
// In automatic mode, extract the key before spread prop,
|
||||||
// and add it to the third argument later.
|
// and add it to the third argument later.
|
||||||
if is_automatic && !has_key_after_props_spread {
|
if is_automatic && !has_key_after_props_spread {
|
||||||
|
|
@ -431,9 +438,9 @@ impl<'a> ReactJsx<'a> {
|
||||||
self.transform_jsx_member_expression(member_expr)
|
self.transform_jsx_member_expression(member_expr)
|
||||||
}
|
}
|
||||||
JSXElementName::NamespacedName(name) => {
|
JSXElementName::NamespacedName(name) => {
|
||||||
// if self.options.throw_if_namespace {
|
if self.options.throw_if_namespace {
|
||||||
// self.ctx.error(NamespaceDoesNotSupport(name.span));
|
self.ctx.error(NamespaceDoesNotSupport(name.span));
|
||||||
// }
|
}
|
||||||
let name = self.ast().new_atom(&name.to_string());
|
let name = self.ast().new_atom(&name.to_string());
|
||||||
let string_literal = StringLiteral::new(SPAN, name);
|
let string_literal = StringLiteral::new(SPAN, name);
|
||||||
self.ast().literal_string_expression(string_literal)
|
self.ast().literal_string_expression(string_literal)
|
||||||
|
|
@ -610,8 +617,8 @@ impl<'a> ReactJsx<'a> {
|
||||||
},
|
},
|
||||||
JSXChild::Element(e) => Some(self.transform_jsx(&JSXElementOrFragment::Element(e))),
|
JSXChild::Element(e) => Some(self.transform_jsx(&JSXElementOrFragment::Element(e))),
|
||||||
JSXChild::Fragment(e) => Some(self.transform_jsx(&JSXElementOrFragment::Fragment(e))),
|
JSXChild::Fragment(e) => Some(self.transform_jsx(&JSXElementOrFragment::Fragment(e))),
|
||||||
JSXChild::Spread(_e) => {
|
JSXChild::Spread(e) => {
|
||||||
// self.ctx.error(SpreadChildrenAreNotSupported(e.span));
|
self.ctx.error(SpreadChildrenAreNotSupported(e.span));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,12 @@ pub struct ReactOptions {
|
||||||
#[serde(default = "default_as_true")]
|
#[serde(default = "default_as_true")]
|
||||||
pub development: bool,
|
pub development: bool,
|
||||||
|
|
||||||
|
/// Toggles whether or not to throw an error if a XML namespaced tag name is used.
|
||||||
|
///
|
||||||
|
/// Though the JSX spec allows this, it is disabled by default since React's JSX does not currently have support for it.
|
||||||
|
#[serde(default = "default_as_true")]
|
||||||
|
pub throw_if_namespace: bool,
|
||||||
|
|
||||||
/// Enables `@babel/plugin-transform-react-pure-annotations`.
|
/// Enables `@babel/plugin-transform-react-pure-annotations`.
|
||||||
///
|
///
|
||||||
/// It will mark top-level React method calls as pure for tree shaking.
|
/// It will mark top-level React method calls as pure for tree shaking.
|
||||||
|
|
@ -100,6 +106,7 @@ impl Default for ReactOptions {
|
||||||
jsx_source_plugin: true,
|
jsx_source_plugin: true,
|
||||||
runtime: ReactJsxRuntime::default(),
|
runtime: ReactJsxRuntime::default(),
|
||||||
development: default_as_true(),
|
development: default_as_true(),
|
||||||
|
throw_if_namespace: default_as_true(),
|
||||||
pure: default_as_true(),
|
pure: default_as_true(),
|
||||||
import_source: default_for_import_source(),
|
import_source: default_for_import_source(),
|
||||||
pragma: default_for_pragma(),
|
pragma: default_for_pragma(),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Passed: 191/415
|
Passed: 203/415
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-react-jsx-source
|
* babel-plugin-transform-react-jsx-source
|
||||||
|
|
@ -141,20 +141,17 @@ Passed: 191/415
|
||||||
* regression/another-preset-with-custom-jsx-keep-source-self/input.mjs
|
* regression/another-preset-with-custom-jsx-keep-source-self/input.mjs
|
||||||
* regression/runtime-classic-allow-multiple-source-self/input.mjs
|
* regression/runtime-classic-allow-multiple-source-self/input.mjs
|
||||||
|
|
||||||
# babel-plugin-transform-react-jsx (100/163)
|
# babel-plugin-transform-react-jsx (112/163)
|
||||||
* autoImport/auto-import-react-source-type-module/input.js
|
* autoImport/auto-import-react-source-type-module/input.js
|
||||||
* autoImport/complicated-scope-module/input.js
|
* autoImport/complicated-scope-module/input.js
|
||||||
* autoImport/import-source-pragma/input.js
|
* autoImport/import-source-pragma/input.js
|
||||||
* autoImport/react-defined/input.js
|
* autoImport/react-defined/input.js
|
||||||
* pure/false-pragma-comment-automatic-runtime/input.js
|
* pure/false-pragma-comment-automatic-runtime/input.js
|
||||||
* pure/false-pragma-comment-classic-runtime/input.js
|
* pure/false-pragma-comment-classic-runtime/input.js
|
||||||
* pure/false-pragma-option-automatic-runtime/input.js
|
|
||||||
* pure/true-pragma-comment-automatic-runtime/input.js
|
* pure/true-pragma-comment-automatic-runtime/input.js
|
||||||
* pure/true-pragma-comment-classic-runtime/input.js
|
* pure/true-pragma-comment-classic-runtime/input.js
|
||||||
* pure/true-pragma-option-automatic-runtime/input.js
|
|
||||||
* pure/unset-pragma-comment-automatic-runtime/input.js
|
* pure/unset-pragma-comment-automatic-runtime/input.js
|
||||||
* pure/unset-pragma-comment-classic-runtime/input.js
|
* pure/unset-pragma-comment-classic-runtime/input.js
|
||||||
* pure/unset-pragma-option-automatic-runtime/input.js
|
|
||||||
* react/adds-appropriate-newlines-when-using-spread-attribute-babel-7/input.js
|
* react/adds-appropriate-newlines-when-using-spread-attribute-babel-7/input.js
|
||||||
* react/arrow-functions/input.js
|
* react/arrow-functions/input.js
|
||||||
* react/assignment-babel-7/input.js
|
* react/assignment-babel-7/input.js
|
||||||
|
|
@ -169,10 +166,6 @@ Passed: 191/415
|
||||||
* react/should-allow-jsx-docs-comment-with-pragma/input.js
|
* react/should-allow-jsx-docs-comment-with-pragma/input.js
|
||||||
* react/should-allow-no-pragmafrag-if-frag-unused/input.js
|
* react/should-allow-no-pragmafrag-if-frag-unused/input.js
|
||||||
* react/should-allow-pragmafrag-and-frag/input.js
|
* react/should-allow-pragmafrag-and-frag/input.js
|
||||||
* react/should-disallow-spread-children/input.js
|
|
||||||
* react/should-disallow-valueless-key/input.js
|
|
||||||
* react/should-disallow-xml-namespacing/input.js
|
|
||||||
* react/should-throw-error-namespaces-if-not-flag/input.js
|
|
||||||
* react/should-warn-when-importSource-is-set/input.js
|
* react/should-warn-when-importSource-is-set/input.js
|
||||||
* react/should-warn-when-importSource-pragma-is-set/input.js
|
* react/should-warn-when-importSource-pragma-is-set/input.js
|
||||||
* react/wraps-props-in-react-spread-for-first-spread-attributes-babel-7/input.js
|
* react/wraps-props-in-react-spread-for-first-spread-attributes-babel-7/input.js
|
||||||
|
|
@ -188,17 +181,12 @@ Passed: 191/415
|
||||||
* react-automatic/pragma-works-with-no-space-at-the-end/input.js
|
* react-automatic/pragma-works-with-no-space-at-the-end/input.js
|
||||||
* react-automatic/should-add-quotes-es3/input.js
|
* react-automatic/should-add-quotes-es3/input.js
|
||||||
* react-automatic/should-allow-nested-fragments/input.js
|
* react-automatic/should-allow-nested-fragments/input.js
|
||||||
* react-automatic/should-disallow-spread-children/input.js
|
|
||||||
* react-automatic/should-disallow-valueless-key/input.js
|
|
||||||
* react-automatic/should-disallow-xml-namespacing/input.js
|
|
||||||
* react-automatic/should-escape-xhtml-jsxtext/input.js
|
* react-automatic/should-escape-xhtml-jsxtext/input.js
|
||||||
* react-automatic/should-escape-xhtml-jsxtext-babel-7/input.js
|
* react-automatic/should-escape-xhtml-jsxtext-babel-7/input.js
|
||||||
* react-automatic/should-handle-attributed-elements/input.js
|
* react-automatic/should-handle-attributed-elements/input.js
|
||||||
* react-automatic/should-have-correct-comma-in-nested-children/input.js
|
* react-automatic/should-have-correct-comma-in-nested-children/input.js
|
||||||
* react-automatic/should-properly-handle-keys/input.js
|
* react-automatic/should-properly-handle-keys/input.js
|
||||||
* react-automatic/should-throw-error-namespaces-if-not-flag/input.js
|
|
||||||
* react-automatic/should-throw-when-filter-is-specified/input.js
|
* react-automatic/should-throw-when-filter-is-specified/input.js
|
||||||
* react-automatic/should-warn-when-pragma-or-pragmaFrag-is-set/input.js
|
|
||||||
* regression/issue-12478-automatic/input.js
|
* regression/issue-12478-automatic/input.js
|
||||||
* regression/issue-12478-classic/input.js
|
* regression/issue-12478-classic/input.js
|
||||||
* regression/pragma-frag-set-default-classic-runtime/input.js
|
* regression/pragma-frag-set-default-classic-runtime/input.js
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue