diff --git a/crates/oxc_syntax/src/identifier.rs b/crates/oxc_syntax/src/identifier.rs index dfa757eb8deba..6ede6c3048788 100644 --- a/crates/oxc_syntax/src/identifier.rs +++ b/crates/oxc_syntax/src/identifier.rs @@ -28,17 +28,47 @@ pub const VT: char = '\u{b}'; /// U+000C FORM FEED, abbreviated ``. pub const FF: char = '\u{c}'; +/// U+0020 SPACE, abbreviated ``. +pub const SP: char = '\u{20}'; + /// U+00A0 NON-BREAKING SPACE, abbreviated ``. pub const NBSP: char = '\u{a0}'; +// U+0085 NEXT LINE, abbreviated ``. +const NEL: char = '\u{85}'; + +const OGHAM_SPACE_MARK: char = '\u{1680}'; + +const EN_QUAD: char = '\u{2000}'; + +// U+200B ZERO WIDTH SPACE, abbreviated ``. +const ZWSP: char = '\u{200b}'; + +// Narrow NO-BREAK SPACE, abbreviated ``. +const NNBSP: char = '\u{202f}'; + +// U+205F MEDIUM MATHEMATICAL SPACE, abbreviated ``. +const MMSP: char = '\u{205f}'; + +const IDEOGRAPHIC_SPACE: char = '\u{3000}'; + pub fn is_irregular_whitespace(c: char) -> bool { matches!( c, - VT | FF | NBSP | ZWNBSP | '\u{85}' | '\u{1680}' | '\u{2000}' - ..='\u{200a}' | '\u{202f}' | '\u{205f}' | '\u{3000}' + VT | FF | NBSP | ZWNBSP | NEL | OGHAM_SPACE_MARK | EN_QUAD + ..ZWSP | NNBSP | MMSP | IDEOGRAPHIC_SPACE ) } +// https://github.com/microsoft/TypeScript/blob/b8e4ed8aeb0b228f544c5736908c31f136a9f7e3/src/compiler/scanner.ts#L556 +// TODO: Unclear why we match `ZWSP` here, and not in `is_irregular_whitespace`. +// https://github.com/oxc-project/oxc/pull/6639 +pub fn is_white_space_single_line(c: char) -> bool { + // Note: nextLine is in the Zs space, and should be considered to be a whitespace. + // It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript. + matches!(c, SP | TAB | ZWSP) || is_irregular_whitespace(c) +} + // 11.3 Line Terminators /// U+000A LINE FEED, abbreviated in the spec as ``. diff --git a/crates/oxc_transformer/src/react/jsx.rs b/crates/oxc_transformer/src/react/jsx.rs index c61c908366760..a236579eb9d46 100644 --- a/crates/oxc_transformer/src/react/jsx.rs +++ b/crates/oxc_transformer/src/react/jsx.rs @@ -93,7 +93,7 @@ use oxc_ast::{ast::*, AstBuilder, NONE}; use oxc_ecmascript::PropName; use oxc_span::{Atom, GetSpan, Span, SPAN}; use oxc_syntax::{ - identifier::{is_irregular_whitespace, is_line_terminator}, + identifier::{is_line_terminator, is_white_space_single_line}, reference::ReferenceFlags, symbol::SymbolFlags, xml_entities::XML_ENTITIES, @@ -909,7 +909,7 @@ impl<'a, 'ctx> ReactJsx<'a, 'ctx> { acc = Some(Self::add_line_of_jsx_text(acc, &text[first..last])); } first_non_whitespace = None; - } else if c != ' ' && !is_irregular_whitespace(c) { + } else if !is_white_space_single_line(c) { last_non_whitespace = Some(index + c.len_utf8()); if first_non_whitespace.is_none() { first_non_whitespace.replace(index); diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 3fae10349d2e5..ad214054f1492 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 3bcfee23 -Passed: 60/69 +Passed: 61/70 # All Passed: * babel-plugin-transform-nullish-coalescing-operator @@ -165,7 +165,7 @@ rebuilt : SymbolId(2): [] x Output mismatch -# babel-plugin-transform-react-jsx (29/31) +# babel-plugin-transform-react-jsx (30/32) * refresh/does-not-transform-it-because-it-is-not-used-in-the-AST/input.jsx x Output mismatch diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/input.jsx b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/input.jsx new file mode 100644 index 0000000000000..35d316640cbb5 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/input.jsx @@ -0,0 +1,16 @@ +export function App() { + return ( + + + + + + + + + + + + + ); +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/options.json b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/options.json new file mode 100644 index 0000000000000..e3c59a596fd59 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["transform-react-jsx"]], + "sourceType": "module" +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/output.js new file mode 100644 index 0000000000000..bf8a13b8313ad --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-react-jsx/test/fixtures/issues/issue-6638/output.js @@ -0,0 +1,20 @@ +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; +export function App() { + return _jsxs(Suspense, { + fallback: "Loading...", + children: [_jsx(Init, {}), _jsxs(PanelGroup, { + direction: "horizontal", + className: "app-main", + children: [ + _jsx(Panel, { + defaultSize: 50, + minSize: 33, + maxSize: 66, + children: _jsx(Input, {}) + }), + _jsx(PanelResizeHandle, { className: "divider" }), + _jsx(Panel, { children: _jsx(Output, {}) }) + ] + })] + }); +} \ No newline at end of file