diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts index 92169a9599..4ab36cf6f8 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/BuildHIR.ts @@ -2829,9 +2829,13 @@ function lowerJsxElement( return lowerExpressionToTemporary(builder, expression); } } else if (exprPath.isJSXText()) { + const text = trimJsxText(exprPath.node.value); + if (text === null) { + return null; + } const place = lowerValueToTemporary(builder, { kind: "JSXText", - value: exprPath.node.value, + value: text, loc: exprLoc, }); return place; @@ -2851,6 +2855,67 @@ function lowerJsxElement( } } +/** + * Trims whitespace according to the JSX spec: + * > JSX removes whitespace at the beginning and ending of a line. + * > It also removes blank lines. New lines adjacent to tags are removed; + * > new lines that occur in the middle of string literals are condensed + * > into a single space. + * + * From https://legacy.reactjs.org/docs/jsx-in-depth.html#string-literals-1 + * + * Implementation adapted from Babel: + * https://github.com/babel/babel/blob/54d30f206057be64b496d2da1ec8c49d244ba4e4/packages/babel-types/src/utils/react/cleanJSXElementLiteralChild.ts#L5 + */ +function trimJsxText(original: string): string | null { + const lines = original.split(/\r\n|\n|\r/); + + let lastNonEmptyLine = 0; + + for (let i = 0; i < lines.length; i++) { + if (lines[i].match(/[^ \t]/)) { + lastNonEmptyLine = i; + } + } + + let str = ""; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + const isFirstLine = i === 0; + const isLastLine = i === lines.length - 1; + const isLastNonEmptyLine = i === lastNonEmptyLine; + + // replace rendered whitespace tabs with spaces + let trimmedLine = line.replace(/\t/g, " "); + + // trim whitespace touching a newline + if (!isFirstLine) { + trimmedLine = trimmedLine.replace(/^[ ]+/, ""); + } + + // trim whitespace touching an endline + if (!isLastLine) { + trimmedLine = trimmedLine.replace(/[ ]+$/, ""); + } + + if (trimmedLine) { + if (!isLastNonEmptyLine) { + trimmedLine += " "; + } + + str += trimmedLine; + } + } + + if (str.length !== 0) { + return str; + } else { + return null; + } +} + function lowerFunctionExpression( builder: HIRBuilder, expr: NodePath diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/fbtparam-with-jsx-element-content.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/fbtparam-with-jsx-element-content.expect.md index 67fd35327e..64db38edaf 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/fbtparam-with-jsx-element-content.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/fbtparam-with-jsx-element-content.expect.md @@ -28,9 +28,9 @@ function Component({ name, data, icon }) { import { unstable_useMemoCache as useMemoCache } from "react"; import fbt from "fbt"; -function Component(t39) { +function Component(t29) { const $ = useMemoCache(4); - const { name, data, icon } = t39; + const { name, data, icon } = t29; const c_0 = $[0] !== name; const c_1 = $[1] !== icon; const c_2 = $[2] !== data; diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md index 32ac199577..c189210d5b 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md @@ -24,101 +24,76 @@ function Component(props) { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; function Component(props) { - const $ = useMemoCache(21); + const $ = useMemoCache(15); const item = useFragment(FRAGMENT, props.item); useFreeze(item); const c_0 = $[0] !== item; let t1; let T2; - let t3; let t0; - let t4; - let T5; - let t6; + let T3; if (c_0) { const count = new MaybeMutable(item); - T5 = View; - t6 = "\n "; + T3 = View; T2 = View; - t3 = "\n "; - if ($[8] === Symbol.for("react.memo_cache_sentinel")) { + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { t0 = Text; - $[8] = t0; + $[5] = t0; } else { - t0 = $[8]; + t0 = $[5]; } - t4 = "\n "; t1 = maybeMutate(count); $[0] = item; $[1] = t1; $[2] = T2; - $[3] = t3; - $[4] = t0; - $[5] = t4; - $[6] = T5; - $[7] = t6; + $[3] = t0; + $[4] = T3; } else { t1 = $[1]; T2 = $[2]; - t3 = $[3]; - t0 = $[4]; - t4 = $[5]; - T5 = $[6]; - t6 = $[7]; + t0 = $[3]; + T3 = $[4]; } - const c_9 = $[9] !== t1; - let t7; - if (c_9) { - t7 = {t1}; - $[9] = t1; - $[10] = t7; + const c_6 = $[6] !== t1; + let t4; + if (c_6) { + t4 = {t1}; + $[6] = t1; + $[7] = t4; } else { - t7 = $[10]; + t4 = $[7]; } - const c_11 = $[11] !== T2; - const c_12 = $[12] !== t3; - const c_13 = $[13] !== t0; - const c_14 = $[14] !== t4; - const c_15 = $[15] !== t7; - let t8; - if (c_11 || c_12 || c_13 || c_14 || c_15) { - t8 = ( + const c_8 = $[8] !== T2; + const c_9 = $[9] !== t0; + const c_10 = $[10] !== t4; + let t5; + if (c_8 || c_9 || c_10) { + t5 = ( - {t3} {t0} {t4} - {t7} ); - $[11] = T2; - $[12] = t3; - $[13] = t0; - $[14] = t4; - $[15] = t7; - $[16] = t8; + $[8] = T2; + $[9] = t0; + $[10] = t4; + $[11] = t5; } else { - t8 = $[16]; + t5 = $[11]; } - const c_17 = $[17] !== T5; - const c_18 = $[18] !== t6; - const c_19 = $[19] !== t8; - let t9; - if (c_17 || c_18 || c_19) { - t9 = ( - - {t6} - {t8} - - ); - $[17] = T5; - $[18] = t6; - $[19] = t8; - $[20] = t9; + const c_12 = $[12] !== T3; + const c_13 = $[13] !== t5; + let t6; + if (c_12 || c_13) { + t6 = {t5}; + $[12] = T3; + $[13] = t5; + $[14] = t6; } else { - t9 = $[20]; + t6 = $[14]; } - return t9; + return t6; } ``` diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-static.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-static.expect.md index cf254f62a9..e41c12b880 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-static.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-static.expect.md @@ -21,63 +21,48 @@ function Component(props) { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; function Component(props) { - const $ = useMemoCache(9); + const $ = useMemoCache(6); let t1; let T2; - let t3; let t0; - let t4; - let T5; - let t6; + let T3; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { const count = new MaybeMutable(); - T5 = View; - t6 = "\n "; + T3 = View; T2 = View; - t3 = "\n "; - if ($[7] === Symbol.for("react.memo_cache_sentinel")) { + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { t0 = Text; - $[7] = t0; + $[4] = t0; } else { - t0 = $[7]; + t0 = $[4]; } - t4 = "\n "; t1 = maybeMutate(count); $[0] = t1; $[1] = T2; - $[2] = t3; - $[3] = t0; - $[4] = t4; - $[5] = T5; - $[6] = t6; + $[2] = t0; + $[3] = T3; } else { t1 = $[0]; T2 = $[1]; - t3 = $[2]; - t0 = $[3]; - t4 = $[4]; - T5 = $[5]; - t6 = $[6]; + t0 = $[2]; + T3 = $[3]; } - let t7; - if ($[8] === Symbol.for("react.memo_cache_sentinel")) { - t7 = ( - - {t6} + let t4; + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { + t4 = ( + - {t3} {t0} - {t4} {t1} - + ); - $[8] = t7; + $[5] = t4; } else { - t7 = $[8]; + t4 = $[5]; } - return t7; + return t4; } ``` diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-attribute-with-jsx-element-value.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-attribute-with-jsx-element-value.expect.md index ffda50685d..53166f4c9d 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-attribute-with-jsx-element-value.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/jsx-attribute-with-jsx-element-value.expect.md @@ -43,9 +43,9 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { unstable_useMemoCache as useMemoCache } from "react"; -function Component(t29) { +function Component(t27) { const $ = useMemoCache(2); - const { items } = t29; + const { items } = t27; const c_0 = $[0] !== items; let t0; if (c_0) { diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes.expect.md index 570871078e..a767519e03 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/merge-consecutive-scopes.expect.md @@ -78,6 +78,7 @@ function Component() { } return t3; } + export const FIXTURE_ENTRYPOINT = { fn: Component, params: [{ value: 42 }], diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md index 0ac4f37a7e..69e3c3a64c 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-duplicate-instruction-from-merge-consecutive-scopes.expect.md @@ -27,9 +27,9 @@ export const FIXTURE_ENTRYPOINT = { import { unstable_useMemoCache as useMemoCache } from "react"; // @enableMergeConsecutiveScopes function Component(id) { const $ = useMemoCache(3); - let t25; - t25 = undefined; - const bar = t25; + let t22; + t22 = undefined; + const bar = t22; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = ; diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/timers.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/timers.expect.md index 70681ffb49..c2fce33a28 100644 --- a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/timers.expect.md +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/timers.expect.md @@ -35,7 +35,8 @@ function Component(props) { if ($[1] === Symbol.for("react.memo_cache_sentinel")) { t1 = (
- rendering took {time} at {now} + rendering took + {time} at {now}
); $[1] = t1;