Skip to content

Commit 98a03a0

Browse files
committed
[compiler] Fix FBT whitespace handling again (again (again))
ghstack-source-id: ca54bce Pull Request resolved: #30451
1 parent 36ea60a commit 98a03a0

File tree

6 files changed

+77
-90
lines changed

6 files changed

+77
-90
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,10 +2113,10 @@ function lowerExpression(
21132113
}
21142114
props.push({kind: 'JsxAttribute', name: propName, place: value});
21152115
}
2116-
if (
2117-
tag.kind === 'BuiltinTag' &&
2118-
(tag.name === 'fbt' || tag.name === 'fbs')
2119-
) {
2116+
2117+
const isFbt =
2118+
tag.kind === 'BuiltinTag' && (tag.name === 'fbt' || tag.name === 'fbs');
2119+
if (isFbt) {
21202120
const tagName = tag.name;
21212121
const openingIdentifier = opening.get('name');
21222122
const tagIdentifier = openingIdentifier.isJSXIdentifier()
@@ -2168,35 +2168,17 @@ function lowerExpression(
21682168
}
21692169
}
21702170

2171-
let children: Array<Place>;
2172-
if (
2173-
tag.kind === 'BuiltinTag' &&
2174-
(tag.name === 'fbt' || tag.name === 'fbs')
2175-
) {
2176-
children = expr
2177-
.get('children')
2178-
.map(child => {
2179-
if (child.isJSXText()) {
2180-
/*
2181-
* FBT whitespace normalization differs from standard JSX:
2182-
* https://github.com/facebook/fbt/blob/0b4e0d13c30bffd0daa2a75715d606e3587b4e40/packages/babel-plugin-fbt/src/FbtUtil.js#L76-L87
2183-
*/
2184-
const text = child.node.value.replace(/[^\S\u00A0]+/g, ' ');
2185-
return lowerValueToTemporary(builder, {
2186-
kind: 'JSXText',
2187-
value: text,
2188-
loc: child.node.loc ?? GeneratedSource,
2189-
});
2190-
}
2191-
return lowerJsxElement(builder, child);
2192-
})
2193-
.filter(notNull);
2194-
} else {
2195-
children = expr
2196-
.get('children')
2197-
.map(child => lowerJsxElement(builder, child))
2198-
.filter(notNull);
2199-
}
2171+
/**
2172+
* Increment fbt counter before traversing into children, as whitespace
2173+
* in jsx text is handled differently for fbt subtrees.
2174+
*/
2175+
isFbt && builder.fbtDepth++;
2176+
const children: Array<Place> = expr
2177+
.get('children')
2178+
.map(child => lowerJsxElement(builder, child))
2179+
.filter(notNull);
2180+
isFbt && builder.fbtDepth--;
2181+
22002182
return {
22012183
kind: 'JsxExpression',
22022184
tag,
@@ -3158,7 +3140,17 @@ function lowerJsxElement(
31583140
return lowerExpressionToTemporary(builder, expression);
31593141
}
31603142
} else if (exprPath.isJSXText()) {
3161-
const text = trimJsxText(exprPath.node.value);
3143+
let text: string | null;
3144+
if (builder.fbtDepth > 0) {
3145+
/*
3146+
* FBT whitespace normalization differs from standard JSX:
3147+
* https://github.com/facebook/fbt/blob/0b4e0d13c30bffd0daa2a75715d606e3587b4e40/packages/babel-plugin-fbt/src/FbtUtil.js#L76-L87
3148+
*/
3149+
text = exprPath.node.value.replace(/[^\S\u00A0]+/g, ' ');
3150+
} else {
3151+
text = trimJsxText(exprPath.node.value);
3152+
}
3153+
31623154
if (text === null) {
31633155
return null;
31643156
}

compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ export default class HIRBuilder {
110110
#exceptionHandlerStack: Array<BlockId> = [];
111111
parentFunction: NodePath<t.Function>;
112112
errors: CompilerError = new CompilerError();
113+
/**
114+
* Traversal context: counts the number of `fbt` tag parents
115+
* of the current babel node.
116+
*/
117+
fbtDepth: number = 0;
113118

114119
get nextIdentifierId(): IdentifierId {
115120
return this.#env.nextIdentifierId;

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/bug-fbt-preserve-whitespace-param.tsx

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,21 @@
55
import fbt from 'fbt';
66

77
/**
8-
* Currently fails with the following:
9-
* Found differences in evaluator results
10-
* Non-forget (expected):
11-
* (kind: ok) <div><span>Jason !</span></div>
12-
* Forget:
13-
* (kind: ok) <div><span>Jason!</span></div>
14-
8+
* Note that fbt whitespace rules apply to the entire fbt subtree,
9+
* not just direct children of fbt elements.
10+
* (e.g. here, the JSXText children of the span element also use
11+
* fbt whitespace rules)
1512
*/
1613

1714
function Foo(props) {
1815
return (
19-
// prettier-ignore
2016
<div>
21-
<fbt desc={"Dialog to show to user"}>
17+
<fbt desc={'Dialog to show to user'}>
2218
<span>
23-
<fbt:param name="user name">
19+
<fbt:param name="user name really long description for prettier">
2420
{props.name}
2521
</fbt:param>
26-
!
22+
!
2723
</span>
2824
</fbt>
2925
</div>
@@ -44,13 +40,10 @@ import { c as _c } from "react/compiler-runtime";
4440
import fbt from "fbt";
4541

4642
/**
47-
* Currently fails with the following:
48-
* Found differences in evaluator results
49-
* Non-forget (expected):
50-
* (kind: ok) <div><span>Jason !</span></div>
51-
* Forget:
52-
* (kind: ok) <div><span>Jason!</span></div>
53-
43+
* Note that fbt whitespace rules apply to the entire fbt subtree,
44+
* not just direct children of fbt elements.
45+
* (e.g. here, the JSXText children of the span element also use
46+
* fbt whitespace rules)
5447
*/
5548

5649
function Foo(props) {
@@ -66,20 +59,20 @@ function Foo(props) {
6659
"=m0",
6760
<span>
6861
{fbt._(
69-
"{user name}!",
62+
"{user name really long description for prettier} !",
7063
[
7164
fbt._param(
72-
"user name",
65+
"user name really long description for prettier",
7366

7467
props.name,
7568
),
7669
],
77-
{ hk: "mBBZ9" },
70+
{ hk: "rdgIJ" },
7871
)}
7972
</span>,
8073
),
8174
],
82-
{ hk: "3RVfuk" },
75+
{ hk: "32Ufy5" },
8376
)}
8477
</div>
8578
);
@@ -97,4 +90,6 @@ export const FIXTURE_ENTRYPOINT = {
9790
};
9891

9992
```
100-
93+
94+
### Eval output
95+
(kind: ok) <div><span>Jason !</span></div>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import fbt from 'fbt';
2+
3+
/**
4+
* Note that fbt whitespace rules apply to the entire fbt subtree,
5+
* not just direct children of fbt elements.
6+
* (e.g. here, the JSXText children of the span element also use
7+
* fbt whitespace rules)
8+
*/
9+
10+
function Foo(props) {
11+
return (
12+
<div>
13+
<fbt desc={'Dialog to show to user'}>
14+
<span>
15+
<fbt:param name="user name really long description for prettier">
16+
{props.name}
17+
</fbt:param>
18+
!
19+
</span>
20+
</fbt>
21+
</div>
22+
);
23+
}
24+
25+
export const FIXTURE_ENTRYPOINT = {
26+
fn: Foo,
27+
params: [{name: 'Jason'}],
28+
};

compiler/packages/snap/src/SproutTodoFilter.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,6 @@ const skipFilter = new Set([
484484
'rules-of-hooks/rules-of-hooks-69521d94fa03',
485485

486486
// bugs
487-
'fbt/bug-fbt-preserve-whitespace-param',
488487
'bug-invalid-hoisting-functionexpr',
489488
'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block',
490489
'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope',

0 commit comments

Comments
 (0)