fix(oxlint-plugin): treat fbtee translation tags as transparent in rn-no-raw-text#582
Conversation
Co-authored-by: Ray Arayilakath <me@rayhanadev.com>
|
React Doctor found 4 files changed in this pull request, but none matched the files covered by its enabled checks. Scope: 4 files changed on Generated by React Doctor. Questions? Contact founders@million.dev. |
Co-authored-by: Ray Arayilakath <me@rayhanadev.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a React Native false positive in rn-no-raw-text where fbtee’s compile-time translation tags (<fbt> / <fbs> and namespaced variants like <fbt:param>) were incorrectly treated as breaking the <Text> boundary, causing “raw text outside <Text>” diagnostics.
Changes:
- Treat
fbt/fbs(including namespacedfbt:*/fbs:*) as transparent wrappers for thern-no-raw-textrule when they appear under a React Native text-handling component. - Add regression tests covering
<Text><fbt>…</fbt></Text>, namespaced tags, and the negative case where<fbt>is outside<Text>. - Add a changeset for patch releases across
oxlint-plugin-react-doctor,eslint-plugin-react-doctor, andreact-doctor.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/react-doctor/tests/regressions/rn-and-motion.test.ts | Adds end-to-end regression coverage for fbtee tags under RN <Text>. |
| packages/oxlint-plugin-react-doctor/src/plugin/rules/react-native/rn-no-raw-text.ts | Updates the rule to skip raw-text reporting inside transparent fbtee wrappers when enclosed by a text-handling ancestor. |
| packages/oxlint-plugin-react-doctor/src/plugin/constants/react-native.ts | Introduces the REACT_NATIVE_TEXT_TRANSPARENT_COMPONENTS set (fbt, fbs). |
| .changeset/rn-no-raw-text-fbtee.md | Documents the behavior change and bumps patch versions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…e resolution Resolve the JSX tag name once via resolveTextBoundaryName (namespaced fbtee children resolve to their namespace) and let isTransparentTextWrapper take that name, matching isTextHandlingComponent's signature. Removes the dual name-resolution path and documents the transparent-wrapper set as the single extension point for other compile-time/i18n wrappers. Co-authored-by: Ray Arayilakath <me@rayhanadev.com>
RDE eval resultsValidated at PR head Harness note: the Vercel sandbox pool on the current evals checkout ( Parity (base vs PR head)
The change is byte-for-byte inert on real RN code (no fbtee present in OSS), confirming the suppression-only fix introduces zero collateral over-suppression.
|
| Location | Verdict |
|---|---|
cometchat-uikit-react-native …/ThreadView.tsx:186 |
✅ True positive — raw … inside <TouchableOpacity> |
react-native-chatgpt …/Login.tsx:16 |
<Headline> (react-native-paper) |
react-native-chatgpt …/Login.tsx:24 |
<Button> label (react-native-paper) |
react-native-firebase-social-app …/PostCard.js:82 |
{' '} inside styled <UserName> |
The 3 false positives are unrelated to this PR (library/styled text components not in the keyword allowlist), are unchanged by it, and are already suppressible via the rule's textComponents config — out of scope here, worth a separate follow-up.
Local checks
vp test packages/react-doctor/tests/regressions/rn-and-motion.test.ts→ 21/21 pass (incl. 3 new#581cases)turbo typecheck --filter=oxlint-plugin-react-doctor→ passvp lint/vp fmt --checkon changed files → pass
Verdict: safe to merge. Suppression-only, tightly gated to fbt/fbs inside a <Text> boundary; <fbt> outside <Text> is still reported.
Why
Catches a
rn-no-raw-textfalse positive on fbtee translation tags (#581).fbtee's
<fbt>/<fbs>(and namespaced children like<fbt:param>) are compile-time translation constructs — a Babel/SWC transform erases them at build time, so text inside<Text><fbt>…</fbt></Text>really renders inside<Text>and is safe on React Native. The rule was treating<fbt>like a normal element, so it flagged its child text as "outside a<Text>". This pattern is used by the official fbtee Expo template (and was independently hit in production).Before:
After:
What changed
REACT_NATIVE_TEXT_TRANSPARENT_COMPONENTSset (fbt,fbs) — the single, documented extension point for compile-time / i18n wrappers.rn-no-raw-textnow treats a transparent wrapper's raw text as safe only when every ancestor up to a real text component is also transparent, so a bare<fbt>outside<Text>is still reported.<fbt:param>,<fbt:plural>, …) inherit transparency via their namespace, so one entry covers every<fbt:*>child.resolveTextBoundaryNamehelper and gaveisTransparentTextWrapperthe samestring-name signature asisTextHandlingComponent, removing the dual name-resolution path.<Text>, namespaced fbt inside<Text>, and fbt outside<Text>).Eval results
RDE not run: this is a targeted false-positive fix on an existing rule (not a new broad/heuristic rule). Behavior is pinned by end-to-end oxlint regression tests on real React Native fixtures.
Test plan
pnpm exec vp test run rn-and-motion(inpackages/react-doctor) — 21 passed, including the three rn-no-raw-text flags fbtee <fbt> inside React Native <Text> #581 casespnpm --filter oxlint-plugin-react-doctor typecheck— passpnpm lint— pass (only pre-existing fixture warnings)pnpm format— passNote: a sandbox-only oxc-parser mismatch makes some unrelated
react-builtinssuites fail locally; they pass on every CI runner.Slack Thread