From b6b63ac9bc8b74e188d504813eb92fa2258c4dd5 Mon Sep 17 00:00:00 2001 From: Boshen Date: Sun, 14 Apr 2024 21:55:32 +0800 Subject: [PATCH] feat(transform_conformance): skip tests with plugin.js (#2978) --- crates/oxc_transformer/src/react/mod.rs | 10 +-- crates/oxc_transformer/src/react/options.rs | 92 ++++++++++++++++----- tasks/transform_conformance/babel.snap.md | 22 +---- 3 files changed, 79 insertions(+), 45 deletions(-) diff --git a/crates/oxc_transformer/src/react/mod.rs b/crates/oxc_transformer/src/react/mod.rs index f1050de99..e50598ca9 100644 --- a/crates/oxc_transformer/src/react/mod.rs +++ b/crates/oxc_transformer/src/react/mod.rs @@ -23,30 +23,28 @@ pub use self::{ /// * [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self) /// * [plugin-transform-react-jsx-source](https://babel.dev/docs/babel-plugin-transform-react-jsx-source) /// * [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name) -#[allow(unused)] pub struct React<'a> { options: Rc, - ctx: Ctx<'a>, jsx: ReactJsx<'a>, jsx_self: ReactJsxSelf<'a>, jsx_source: ReactJsxSource<'a>, display_name: ReactDisplayName<'a>, - development: bool, } // Constructors impl<'a> React<'a> { pub fn new(options: ReactOptions, ctx: &Ctx<'a>) -> Self { - let development = options.development; + let mut options = options; + if options.jsx_plugin { + options.update_with_comments(ctx); + } let options = Rc::new(options); Self { options: Rc::clone(&options), - ctx: Rc::clone(ctx), jsx: ReactJsx::new(&options, ctx), jsx_self: ReactJsxSelf::new(ctx), jsx_source: ReactJsxSource::new(ctx), display_name: ReactDisplayName::new(ctx), - development, } } } diff --git a/crates/oxc_transformer/src/react/options.rs b/crates/oxc_transformer/src/react/options.rs index eede23090..c7afd3bfc 100644 --- a/crates/oxc_transformer/src/react/options.rs +++ b/crates/oxc_transformer/src/react/options.rs @@ -2,6 +2,8 @@ use std::borrow::Cow; use serde::Deserialize; +use crate::Ctx; + #[inline] fn default_as_true() -> bool { true @@ -20,6 +22,29 @@ fn default_for_pragma_frag() -> Cow<'static, str> { Cow::Borrowed("React.Fragment") } +/// Decides which runtime to use. +/// +/// Auto imports the functions that JSX transpiles to. +/// classic does not automatic import anything. +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ReactJsxRuntime { + Classic, + /// The default runtime is switched to automatic in Babel 8. + #[default] + Automatic, +} + +impl ReactJsxRuntime { + pub fn is_classic(self) -> bool { + self == Self::Classic + } + + pub fn is_automatic(self) -> bool { + self == Self::Automatic + } +} + #[derive(Debug, Clone, Deserialize)] #[serde(default, rename_all = "camelCase")] pub struct ReactOptions { @@ -125,27 +150,56 @@ impl ReactOptions { pub fn is_jsx_source_plugin_enabled(&self) -> bool { self.jsx_source_plugin && self.development } -} -/// Decides which runtime to use. -/// -/// Auto imports the functions that JSX transpiles to. -/// classic does not automatic import anything. -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum ReactJsxRuntime { - Classic, - /// The default runtime is switched to automatic in Babel 8. - #[default] - Automatic, -} + /// Scan through all comments and find the following pragmas + /// + /// * @jsxRuntime classic / automatic + /// + /// The comment does not need to be a jsdoc, + /// otherwise `JSDoc` could be used instead. + /// + /// This behavior is aligned with babel. + pub(crate) fn update_with_comments(&mut self, ctx: &Ctx) { + let semantic = &ctx.semantic; + for (_, span) in semantic.trivias().comments() { + let mut comment = span.source_text(semantic.source_text()).trim_start(); + // strip leading jsdoc comment `*` and then whitespaces + while let Some(cur_comment) = comment.strip_prefix('*') { + comment = cur_comment.trim_start(); + } + // strip leading `@` + let Some(comment) = comment.strip_prefix('@') else { continue }; -impl ReactJsxRuntime { - pub fn is_classic(self) -> bool { - self == Self::Classic - } + // read jsxRuntime + match comment.strip_prefix("jsxRuntime").map(str::trim) { + Some("classic") => { + self.runtime = ReactJsxRuntime::Classic; + continue; + } + Some("automatic") => { + self.runtime = ReactJsxRuntime::Automatic; + continue; + } + _ => {} + } - pub fn is_automatic(self) -> bool { - self == Self::Automatic + // read jsxImportSource + if let Some(import_source) = comment.strip_prefix("jsxImportSource").map(str::trim) { + self.import_source = Cow::from(import_source.to_string()); + continue; + } + + // read jsxFrag + if let Some(pragma_frag) = comment.strip_prefix("jsxFrag").map(str::trim) { + self.pragma_frag = Cow::from(pragma_frag.to_string()); + continue; + } + + // Put this condition at the end to avoid breaking @jsxXX + // read jsx + if let Some(pragma) = comment.strip_prefix("jsx").map(str::trim) { + self.pragma = Cow::from(pragma.to_string()); + } + } } } diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 95b597f01..b4e40e02d 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,4 +1,4 @@ -Passed: 203/408 +Passed: 221/408 # All Passed: * babel-plugin-transform-react-jsx-source @@ -137,33 +137,18 @@ Passed: 203/408 * regression/another-preset-with-custom-jsx-keep-source-self/input.mjs * regression/runtime-classic-allow-multiple-source-self/input.mjs -# babel-plugin-transform-react-jsx (112/161) +# babel-plugin-transform-react-jsx (130/161) * autoImport/auto-import-react-source-type-module/input.js * autoImport/complicated-scope-module/input.js -* autoImport/import-source-pragma/input.js * autoImport/react-defined/input.js -* pure/false-pragma-comment-automatic-runtime/input.js -* pure/false-pragma-comment-classic-runtime/input.js -* pure/true-pragma-comment-automatic-runtime/input.js -* pure/true-pragma-comment-classic-runtime/input.js -* pure/unset-pragma-comment-automatic-runtime/input.js -* pure/unset-pragma-comment-classic-runtime/input.js * react/adds-appropriate-newlines-when-using-spread-attribute-babel-7/input.js * react/arrow-functions/input.js * react/assignment-babel-7/input.js * react/avoids-spread-babel-7/input.js * react/does-not-add-source-self-babel-7/input.mjs * react/handle-spread-with-proto-babel-7/input.js -* react/honor-custom-jsx-comment/input.js -* react/honor-custom-jsx-comment-if-jsx-pragma-option-set/input.js * react/optimisation.react.constant-elements/input.js -* react/pragma-works-with-no-space-at-the-end/input.js * react/should-add-quotes-es3/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-pragmafrag-and-frag/input.js -* react/should-warn-when-importSource-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-last-spread-attributes-babel-7/input.js * react/wraps-props-in-react-spread-for-middle-spread-attributes-babel-7/input.js @@ -174,7 +159,6 @@ Passed: 203/408 * react-automatic/handle-fragments-with-no-children/input.js * react-automatic/handle-static-children/input.js * react-automatic/optimisation.react.constant-elements/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-allow-nested-fragments/input.js * react-automatic/should-escape-xhtml-jsxtext/input.js @@ -183,10 +167,8 @@ Passed: 203/408 * react-automatic/should-have-correct-comma-in-nested-children/input.js * react-automatic/should-properly-handle-keys/input.js * react-automatic/should-throw-when-filter-is-specified/input.js -* regression/pragma-frag-set-default-classic-runtime/input.js * runtime/defaults-to-classis-babel-7/input.js * runtime/invalid-runtime/input.js -* runtime/pragma-runtime-classsic/input.js # babel-plugin-transform-react-display-name (15/16) * display-name/nested/input.js