@samitouri / QOS-React-1 / commits / 49a4887586

[compiler:codegen] Wrap non-ascii characters in JsxExpressionContainer

This PR extends the previous logic added in #29141 to also account for other kinds of non-ascii characters such as `\n`. Because these control characters are individual special characters (and not 2 characters `\` and `n`) we match based on unicode which was already being checked for non-Latin characters. This allows control characters to continue to be compiled equivalently to its original source if it was provided in a JsxExpressionContainer. However note that this PR does not convert JSX attributes that are StringLiterals to JsxExpressionContainer, to preserve the original source code as it was written. Alternatively we could always emit a JsxExpressionContainer if it was used in the source and not try to down level it to some other node kind. But since we already do this I opted to keep this behavior. Partially addresses #29648. ghstack-source-id: ecc61c9f0bece90d18623b3c570fea05fbcd811a Pull Request resolved: https://github.com/facebook/react/pull/29997

Lauren Tan committed Jun 20, 2024 at 19:09 UTC 49a48875860e652f2d7c097faf256440676f4d18
4 files changed +116 -4
compiler/.eslintrc.js
+7 -1
@@ -43,6 +43,12 @@ module.exports = {
43
44 "multiline-comment-style": ["error", "starred-block"],
45
46 + /**
47 + * We sometimes need to check for control characters in regexes for things like preserving input
48 + * strings
49 + */
50 + "no-control-regex": "off",
51 +
52 "@typescript-eslint/no-empty-function": "off",
53
54 /*
@@ -82,7 +88,7 @@ module.exports = {
88 ],
89 "@typescript-eslint/array-type": ["error", { default: "generic" }],
90 "@typescript-eslint/triple-slash-reference": "off",
85 - "@typescript-eslint/no-var-requires": "off"
91 + "@typescript-eslint/no-var-requires": "off",
92 },
93 parser: "@typescript-eslint/parser",
94 plugins: ["@typescript-eslint"],
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+11 -3
@@ -2157,10 +2157,18 @@ function codegenInstructionValue(
2157 }
2158
2159 /**
2160 - * Due to a bug in earlier Babel versions, JSX string attributes with double quotes or with unicode characters
2161 - * may be escaped unnecessarily. To avoid trigger this Babel bug, we use a JsxExpressionContainer for such strings.
2160 + * Due to a bug in earlier Babel versions, JSX string attributes with double quotes, unicode characters, or special
2161 + * control characters such as \n may be escaped unnecessarily. To avoid trigger this Babel bug, we use a
2162 + * JsxExpressionContainer for such strings.
2163 + *
2164 + * u0000 to u001F: C0 control codes
2165 + * u007F : Delete character
2166 + * u0080 to u009F: C1 control codes
2167 + * u00A0 to uFFFF: All non-basic Latin characters
2168 + * https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
2169 */
2163 -const STRING_REQUIRES_EXPR_CONTAINER_PATTERN = /[\u{0080}-\u{FFFF}]|"/u;
2170 +const STRING_REQUIRES_EXPR_CONTAINER_PATTERN =
2171 + /[\u{0000}-\u{001F}|\u{007F}|\u{0080}-\u{FFFF}]|"/u;
2172 function codegenJsxAttribute(
2173 cx: Context,
2174 attribute: JsxAttribute
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-string-attribute-expression-container.expect.md new
+77
@@ -0,0 +1,77 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component() {
6 + return (
7 + <div>
8 + <Text value={"\n"} />
9 + <Text value={"A\tE"} />
10 + <Text value={"나은"} />
11 + <Text value={"Lauren"} />
12 + <Text value={"சத்யா"} />
13 + <Text value={"Sathya"} />
14 + </div>
15 + );
16 +}
17 +
18 +function Text({ value }) {
19 + return <span>{value}</span>;
20 +}
21 +
22 +export const FIXTURE_ENTRYPOINT = {
23 + fn: Component,
24 + params: [{}],
25 +};
26 +
27 +```
28 +
29 +## Code
30 +
31 +```javascript
32 +import { c as _c } from "react/compiler-runtime";
33 +function Component() {
34 + const $ = _c(1);
35 + let t0;
36 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
37 + t0 = (
38 + <div>
39 + <Text value={"\n"} />
40 + <Text value={"A\tE"} />
41 + <Text value={"\uB098\uC740"} />
42 + <Text value="Lauren" />
43 + <Text value={"\u0B9A\u0BA4\u0BCD\u0BAF\u0BBE"} />
44 + <Text value="Sathya" />
45 + </div>
46 + );
47 + $[0] = t0;
48 + } else {
49 + t0 = $[0];
50 + }
51 + return t0;
52 +}
53 +
54 +function Text(t0) {
55 + const $ = _c(2);
56 + const { value } = t0;
57 + let t1;
58 + if ($[0] !== value) {
59 + t1 = <span>{value}</span>;
60 + $[0] = value;
61 + $[1] = t1;
62 + } else {
63 + t1 = $[1];
64 + }
65 + return t1;
66 +}
67 +
68 +export const FIXTURE_ENTRYPOINT = {
69 + fn: Component,
70 + params: [{}],
71 +};
72 +
73 +```
74 +
75 +### Eval output
76 +(kind: ok) <div><span>
77 +</span><span>A E</span><span>나은</span><span>Lauren</span><span>சத்யா</span><span>Sathya</span></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-string-attribute-expression-container.js new
+21
@@ -0,0 +1,21 @@
1 +function Component() {
2 + return (
3 + <div>
4 + <Text value={"\n"} />
5 + <Text value={"A\tE"} />
6 + <Text value={"나은"} />
7 + <Text value={"Lauren"} />
8 + <Text value={"சத்யா"} />
9 + <Text value={"Sathya"} />
10 + </div>
11 + );
12 +}
13 +
14 +function Text({ value }) {
15 + return <span>{value}</span>;
16 +}
17 +
18 +export const FIXTURE_ENTRYPOINT = {
19 + fn: Component,
20 + params: [{}],
21 +};