Skip to content

Commit

Permalink
compiler: Workaround Babel bug with unicode in jsx string attrs
Browse files Browse the repository at this point in the history
Workaround for a bug in older versions of Babel, where strings with unicode are incorrectly escaped when emitted as JSX attributes, causing double-escaping by later processing.

Closes #29120
Closes #29124

ghstack-source-id: 065440d4fb97e164beb8a8f15f252f372a59c5a0
Pull Request resolved: #29141
  • Loading branch information
josephsavona committed May 17, 2024
1 parent af3a55e commit be6712f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import * as t from "@babel/types";
import { createHmac } from "crypto";
import { pruneHoistedContexts, pruneUnusedLValues, pruneUnusedLabels } from ".";
import { CompilerError, ErrorSeverity } from "../CompilerError";
import { Environment, EnvironmentConfig, ExternalFunction } from "../HIR";
Expand Down Expand Up @@ -43,7 +44,6 @@ import { assertExhaustive } from "../Utils/utils";
import { buildReactiveFunction } from "./BuildReactiveFunction";
import { SINGLE_CHILD_FBT_TAGS } from "./MemoizeFbtOperandsInSameScope";
import { ReactiveFunctionVisitor, visitReactiveFunction } from "./visitors";
import { createHmac } from "crypto";

export const MEMO_CACHE_SENTINEL = "react.memo_cache_sentinel";
export const EARLY_RETURN_SENTINEL = "react.early_return_sentinel";
Expand Down Expand Up @@ -2018,6 +2018,11 @@ function codegenInstructionValue(
return value;
}

/**
* Due to a bug in earlier Babel versions, JSX string attributes with double quotes or with unicode characters
* may be escaped unnecessarily. To avoid trigger this Babel bug, we use a JsxExpressionContainer for such strings.
*/
const STRING_REQUIRES_EXPR_CONTAINER_PATTERN = /[\u{0080}-\u{FFFF}]|"/u;
function codegenJsxAttribute(
cx: Context,
attribute: JsxAttribute
Expand All @@ -2040,7 +2045,7 @@ function codegenJsxAttribute(
switch (innerValue.type) {
case "StringLiteral": {
value = innerValue;
if (value.value.indexOf('"') !== -1) {
if (STRING_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value)) {
value = createJsxExpressionContainer(value.loc, value);
}
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

## Input

```javascript
function Component() {
return (
<Post
author="potetotes"
text="in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands தமிழ், 中文, 日本語, 한국어 and i think that’s pretty cool"
/>
);
}

function Post({ author, text }) {
return (
<div>
<h1>{author}</h1>
<span>{text}</span>
</div>
);
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
};

```

## Code

```javascript
import { c as _c } from "react/compiler-runtime";
function Component() {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Post
author="potetotes"
text={
"in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands \u0BA4\u0BAE\u0BBF\u0BB4\u0BCD, \u4E2D\u6587, \u65E5\u672C\u8A9E, \uD55C\uAD6D\uC5B4 and i think that\u2019s pretty cool"
}
/>
);
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}

function Post(t0) {
const $ = _c(7);
const { author, text } = t0;
let t1;
if ($[0] !== author) {
t1 = <h1>{author}</h1>;
$[0] = author;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== text) {
t2 = <span>{text}</span>;
$[2] = text;
$[3] = t2;
} else {
t2 = $[3];
}
let t3;
if ($[4] !== t1 || $[5] !== t2) {
t3 = (
<div>
{t1}
{t2}
</div>
);
$[4] = t1;
$[5] = t2;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
};

```
### Eval output
(kind: ok) <div><h1>potetotes</h1><span>in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands தமிழ், 中文, 日本語, 한국어 and i think that’s pretty cool</span></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function Component() {
return (
<Post
author="potetotes"
text="in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands தமிழ், 中文, 日本語, 한국어 and i think that’s pretty cool"
/>
);
}

function Post({ author, text }) {
return (
<div>
<h1>{author}</h1>
<span>{text}</span>
</div>
);
}

export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{}],
};

0 comments on commit be6712f

Please sign in to comment.