From 3adca7a477f7dd025ea02599b59433b86ac8fd59 Mon Sep 17 00:00:00 2001 From: Joseph Savona <6425824+josephsavona@users.noreply.github.com> Date: Wed, 15 May 2024 14:40:33 -0700 Subject: [PATCH] compiler: fix jsx text attributes with double quotes (#29079) Fixes #29069 by detecting the presence of double-quotes in JSX attribute strings and falling back to using an expression container. --- .../ReactiveScopes/CodegenReactiveFunction.ts | 3 ++ ...strings-in-jsx-attribute-escaped.expect.md | 48 ++++++++++++++++++ ...quoted-strings-in-jsx-attribute-escaped.js | 12 +++++ .../quoted-strings-in-jsx-attribute.expect.md | 48 ++++++++++++++++++ .../quoted-strings-in-jsx-attribute.js | 12 +++++ ...ute-escaped-constant-propagation.expect.md | 50 +++++++++++++++++++ ...-attribute-escaped-constant-propagation.js | 14 ++++++ compiler/yarn.lock | 5 ++ 8 files changed, 192 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index 072b290fe9..9ff169346b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -2040,6 +2040,9 @@ function codegenJsxAttribute( switch (innerValue.type) { case "StringLiteral": { value = innerValue; + if (value.value.indexOf('"') !== -1) { + value = createJsxExpressionContainer(value.loc, value); + } break; } default: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.expect.md new file mode 100644 index 0000000000..4dc3cae006 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.expect.md @@ -0,0 +1,48 @@ + +## Input + +```javascript +export function Component() { + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +export function Component() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = ; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +### Eval output +(kind: ok) Some \"text\" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.js new file mode 100644 index 0000000000..8f1592217e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute-escaped.js @@ -0,0 +1,12 @@ +export function Component() { + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.expect.md new file mode 100644 index 0000000000..490c3bc8c8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.expect.md @@ -0,0 +1,48 @@ + +## Input + +```javascript +export function Component() { + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +export function Component() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = ; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +### Eval output +(kind: ok) Some "text" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.js new file mode 100644 index 0000000000..341b02e0c2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-in-jsx-attribute.js @@ -0,0 +1,12 @@ +export function Component() { + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.expect.md new file mode 100644 index 0000000000..7d8fbdb0e5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +export function Component() { + // Test what happens if a string with double-quotes is interpolated via constant propagation + const text = 'Some "text"'; + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +export function Component() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = ; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + +### Eval output +(kind: ok) Some "text" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.js new file mode 100644 index 0000000000..ceb81cd29e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/quoted-strings-jsx-attribute-escaped-constant-propagation.js @@ -0,0 +1,14 @@ +export function Component() { + // Test what happens if a string with double-quotes is interpolated via constant propagation + const text = 'Some "text"'; + return ; +} + +function Child(props) { + return props.text; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; diff --git a/compiler/yarn.lock b/compiler/yarn.lock index c196dc6d79..8453c68e50 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -3745,6 +3745,11 @@ babel-plugin-polyfill-regenerator@^0.5.0: dependencies: "@babel/helper-define-polyfill-provider" "^0.4.0" +babel-plugin-react-compiler@*: + version "0.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0.tgz#1a1f9867fad83f217f0b3fe6f1b94cca0b77b68b" + integrity sha512-Kigl0V36a/6hLVH7+CCe1CCtU3mFBqBd829V//VtuG7I/pyq+B2QZJqOefd63snQmdfCryNhO9XW1FbGPBvYDA== + babel-plugin-syntax-hermes-parser@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.15.1.tgz#d115ee9761a808af590a9b2a0b568115e25ea743"