@samitouri / QOS-React-1 / commits / be6712f72c

compiler: Workaround Babel bug with unicode in jsx string attrs

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: https://github.com/facebook/react/pull/29141

Joe Savona committed May 17, 2024 at 10:38 UTC be6712f72ccfe3e3b9388e169f6f9e261d78637b
3 files changed +126 -2
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+7 -2
@@ -6,6 +6,7 @@
6 */
7
8 import * as t from "@babel/types";
9 +import { createHmac } from "crypto";
10 import { pruneHoistedContexts, pruneUnusedLValues, pruneUnusedLabels } from ".";
11 import { CompilerError, ErrorSeverity } from "../CompilerError";
12 import { Environment, EnvironmentConfig, ExternalFunction } from "../HIR";
@@ -43,7 +44,6 @@ import { assertExhaustive } from "../Utils/utils";
44 import { buildReactiveFunction } from "./BuildReactiveFunction";
45 import { SINGLE_CHILD_FBT_TAGS } from "./MemoizeFbtOperandsInSameScope";
46 import { ReactiveFunctionVisitor, visitReactiveFunction } from "./visitors";
46 -import { createHmac } from "crypto";
47
48 export const MEMO_CACHE_SENTINEL = "react.memo_cache_sentinel";
49 export const EARLY_RETURN_SENTINEL = "react.early_return_sentinel";
@@ -2018,6 +2018,11 @@ function codegenInstructionValue(
2018 return value;
2019 }
2020
2021 +/**
2022 + * Due to a bug in earlier Babel versions, JSX string attributes with double quotes or with unicode characters
2023 + * may be escaped unnecessarily. To avoid trigger this Babel bug, we use a JsxExpressionContainer for such strings.
2024 + */
2025 +const STRING_REQUIRES_EXPR_CONTAINER_PATTERN = /[\u{0080}-\u{FFFF}]|"/u;
2026 function codegenJsxAttribute(
2027 cx: Context,
2028 attribute: JsxAttribute
@@ -2040,7 +2045,7 @@ function codegenJsxAttribute(
2045 switch (innerValue.type) {
2046 case "StringLiteral": {
2047 value = innerValue;
2043 - if (value.value.indexOf('"') !== -1) {
2048 + if (STRING_REQUIRES_EXPR_CONTAINER_PATTERN.test(value.value)) {
2049 value = createJsxExpressionContainer(value.loc, value);
2050 }
2051 break;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-string-attribute-non-ascii.expect.md new
+97
@@ -0,0 +1,97 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component() {
6 + return (
7 + <Post
8 + author="potetotes"
9 + text="in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands தமிழ், 中文, 日本語, 한국어 and i think that’s pretty cool"
10 + />
11 + );
12 +}
13 +
14 +function Post({ author, text }) {
15 + return (
16 + <div>
17 + <h1>{author}</h1>
18 + <span>{text}</span>
19 + </div>
20 + );
21 +}
22 +
23 +export const FIXTURE_ENTRYPOINT = {
24 + fn: Component,
25 + params: [{}],
26 +};
27 +
28 +```
29 +
30 +## Code
31 +
32 +```javascript
33 +import { c as _c } from "react/compiler-runtime";
34 +function Component() {
35 + const $ = _c(1);
36 + let t0;
37 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
38 + t0 = (
39 + <Post
40 + author="potetotes"
41 + text={
42 + "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"
43 + }
44 + />
45 + );
46 + $[0] = t0;
47 + } else {
48 + t0 = $[0];
49 + }
50 + return t0;
51 +}
52 +
53 +function Post(t0) {
54 + const $ = _c(7);
55 + const { author, text } = t0;
56 + let t1;
57 + if ($[0] !== author) {
58 + t1 = <h1>{author}</h1>;
59 + $[0] = author;
60 + $[1] = t1;
61 + } else {
62 + t1 = $[1];
63 + }
64 + let t2;
65 + if ($[2] !== text) {
66 + t2 = <span>{text}</span>;
67 + $[2] = text;
68 + $[3] = t2;
69 + } else {
70 + t2 = $[3];
71 + }
72 + let t3;
73 + if ($[4] !== t1 || $[5] !== t2) {
74 + t3 = (
75 + <div>
76 + {t1}
77 + {t2}
78 + </div>
79 + );
80 + $[4] = t1;
81 + $[5] = t2;
82 + $[6] = t3;
83 + } else {
84 + t3 = $[6];
85 + }
86 + return t3;
87 +}
88 +
89 +export const FIXTURE_ENTRYPOINT = {
90 + fn: Component,
91 + params: [{}],
92 +};
93 +
94 +```
95 +
96 +### Eval output
97 +(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>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-string-attribute-non-ascii.js new
+22
@@ -0,0 +1,22 @@
1 +function Component() {
2 + return (
3 + <Post
4 + author="potetotes"
5 + text="in addition to understanding JavaScript semantics and the rules of React, the compiler team also understands தமிழ், 中文, 日本語, 한국어 and i think that’s pretty cool"
6 + />
7 + );
8 +}
9 +
10 +function Post({ author, text }) {
11 + return (
12 + <div>
13 + <h1>{author}</h1>
14 + <span>{text}</span>
15 + </div>
16 + );
17 +}
18 +
19 +export const FIXTURE_ENTRYPOINT = {
20 + fn: Component,
21 + params: [{}],
22 +};