mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
fbt:param does not allow jsxtext children
Per the title, `<fbt:param>0</fbt:param>` is invalid FBT, you must wrap the text in an expression container. But that's not all, `fbt:param` can only have a single child, which means we have to strip out the text elements that occur from the whitespace in the source.
This commit is contained in:
+53
-4
@@ -34,6 +34,7 @@ import { eachPatternOperand } from "../HIR/visitors";
|
||||
import { Err, Ok, Result } from "../Utils/Result";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
import { buildReactiveFunction } from "./BuildReactiveFunction";
|
||||
import { SINGLE_CHILD_FBT_TAGS } from "./MemoizeFbtOperandsInSameScope";
|
||||
|
||||
export type CodegenFunction = {
|
||||
type: "CodegenFunction";
|
||||
@@ -990,10 +991,34 @@ function codegenInstructionValue(
|
||||
tag = createJsxIdentifier(instrValue.loc, tagValue.value);
|
||||
}
|
||||
}
|
||||
const children =
|
||||
instrValue.children !== null
|
||||
? instrValue.children.map((child) => codegenJsxElement(cx, child))
|
||||
: [];
|
||||
let children;
|
||||
if (
|
||||
tagValue.type === "StringLiteral" &&
|
||||
SINGLE_CHILD_FBT_TAGS.has(tagValue.value)
|
||||
) {
|
||||
CompilerError.invariant(
|
||||
instrValue.children != null &&
|
||||
(instrValue.children.length === 3 ||
|
||||
instrValue.children.length === 1),
|
||||
{
|
||||
loc: instrValue.loc,
|
||||
reason:
|
||||
"Expected fbt element to have 3 children (whitespace, content, whitespace) or 1 (content)",
|
||||
suggestions: null,
|
||||
description: null,
|
||||
}
|
||||
);
|
||||
if (instrValue.children.length === 3) {
|
||||
children = [codegenJsxFbtChildElement(cx, instrValue.children[1]!)];
|
||||
} else {
|
||||
children = [codegenJsxFbtChildElement(cx, instrValue.children[0]!)];
|
||||
}
|
||||
} else {
|
||||
children =
|
||||
instrValue.children !== null
|
||||
? instrValue.children.map((child) => codegenJsxElement(cx, child))
|
||||
: [];
|
||||
}
|
||||
value = createJsxElement(
|
||||
instrValue.loc,
|
||||
t.jsxOpeningElement(tag, attributes, instrValue.children === null),
|
||||
@@ -1330,6 +1355,30 @@ function codegenJsxElement(
|
||||
}
|
||||
}
|
||||
|
||||
function codegenJsxFbtChildElement(
|
||||
cx: Context,
|
||||
place: Place
|
||||
):
|
||||
| t.JSXText
|
||||
| t.JSXExpressionContainer
|
||||
| t.JSXSpreadChild
|
||||
| t.JSXElement
|
||||
| t.JSXFragment {
|
||||
const value = codegenPlace(cx, place);
|
||||
switch (value.type) {
|
||||
case "StringLiteral": {
|
||||
return createJsxExpressionContainer(place.loc, value);
|
||||
}
|
||||
case "JSXElement":
|
||||
case "JSXFragment": {
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
return createJsxExpressionContainer(place.loc, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertMemberExpressionToJsx(
|
||||
expr: t.MemberExpression
|
||||
): t.JSXMemberExpression {
|
||||
|
||||
+2
-1
@@ -44,7 +44,8 @@ export function memoizeFbtOperandsInSameScope(fn: ReactiveFunction): void {
|
||||
}
|
||||
}
|
||||
|
||||
const FBT_TAGS: Set<string> = new Set(["fbt", "fbt:param"]);
|
||||
export const FBT_TAGS: Set<string> = new Set(["fbt", "fbt:param"]);
|
||||
export const SINGLE_CHILD_FBT_TAGS: Set<string> = new Set(["fbt:param"]);
|
||||
|
||||
class Transform extends ReactiveFunctionVisitor<void> {
|
||||
// Values that represent *potential* references of `fbt` as a JSX tag name
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
return (
|
||||
<Foo
|
||||
value={
|
||||
<fbt desc="Description of the parameter">
|
||||
<fbt:param name="value">{"0"}</fbt:param>%
|
||||
</fbt>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
const $ = useMemoCache(2);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = fbt._("{value}%", [fbt._param("value", "0")], { hk: "10F5Cc" });
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <Foo value={t0} />;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(props) {
|
||||
return (
|
||||
<Foo
|
||||
value={
|
||||
<fbt desc="Description of the parameter">
|
||||
<fbt:param name="value">{"0"}</fbt:param>%
|
||||
</fbt>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
+1
-2
@@ -2,7 +2,6 @@
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @debug
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component({ name, data, icon }) {
|
||||
@@ -26,7 +25,7 @@ function Component({ name, data, icon }) {
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { unstable_useMemoCache as useMemoCache } from "react"; // @debug
|
||||
import { unstable_useMemoCache as useMemoCache } from "react";
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component(t39) {
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// @debug
|
||||
import fbt from "fbt";
|
||||
|
||||
function Component({ name, data, icon }) {
|
||||
|
||||
@@ -455,6 +455,7 @@ const skipFilter = new Set([
|
||||
"infer-skip-components-without-hooks-or-jsx",
|
||||
"class-component-with-render-helper",
|
||||
"fbtparam-with-jsx-element-content",
|
||||
"fbtparam-text-must-use-expression-container",
|
||||
]);
|
||||
|
||||
export default skipFilter;
|
||||
|
||||
Reference in New Issue
Block a user