Skip to content

fix(oxlint-plugin): treat fbtee translation tags as transparent in rn-no-raw-text#582

Merged
aidenybai merged 4 commits into
mainfrom
ray/fbtee-transparent-50d2
May 30, 2026
Merged

fix(oxlint-plugin): treat fbtee translation tags as transparent in rn-no-raw-text#582
aidenybai merged 4 commits into
mainfrom
ray/fbtee-transparent-50d2

Conversation

@rayhanadev
Copy link
Copy Markdown
Member

@rayhanadev rayhanadev commented May 29, 2026

Why

Catches a rn-no-raw-text false 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:

import { Text } from "react-native";

// ✗ react-doctor/rn-no-raw-text: Raw "Welcome" outside a <Text> component
<Text>
  <fbt desc="Greeting">Welcome</fbt>
</Text>

After:

import { Text } from "react-native";

// ✓ no diagnostic — <fbt> is transparent inside <Text>
<Text>
  <fbt desc="Greeting">Welcome</fbt>
</Text>

// ✗ still flagged — <fbt> is NOT a <Text> substitute on its own
<fbt desc="Greeting">Welcome</fbt>

What changed

  • Added a REACT_NATIVE_TEXT_TRANSPARENT_COMPONENTS set (fbt, fbs) — the single, documented extension point for compile-time / i18n wrappers.
  • rn-no-raw-text now 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.
  • Namespaced children (<fbt:param>, <fbt:plural>, …) inherit transparency via their namespace, so one entry covers every <fbt:*> child.
  • Consolidated tag-name resolution into a single resolveTextBoundaryName helper and gave isTransparentTextWrapper the same string-name signature as isTextHandlingComponent, removing the dual name-resolution path.
  • Added regression coverage for rn-no-raw-text flags fbtee <fbt> inside React Native <Text> #581 (fbt inside <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

Note: a sandbox-only oxc-parser mismatch makes some unrelated react-builtins suites fail locally; they pass on every CI runner.

Slack Thread

Open in Web Open in Cursor 

Co-authored-by: Ray Arayilakath <me@rayhanadev.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 29, 2026

React Doctor

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 ray/fbtee-transparent-50d2 vs. main.

View workflow run

Generated by React Doctor. Questions? Contact founders@million.dev.

Co-authored-by: Ray Arayilakath <me@rayhanadev.com>
@aidenybai aidenybai marked this pull request as ready for review May 29, 2026 22:23
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

…sh regression header

Adds the missing changeset (patch for oxlint-plugin/eslint-plugin/react-doctor)
documenting the rn-no-raw-text fbtee false-positive fix, and updates the
regression file's covered-issues header to include #183, #581, and #76.
Copilot AI review requested due to automatic review settings May 29, 2026 22:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 namespaced fbt:* / fbs:*) as transparent wrappers for the rn-no-raw-text rule 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, and react-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>
@cursor cursor Bot changed the title Handle fbtee tags inside RN Text fix(oxlint-plugin): treat fbtee translation tags as transparent in rn-no-raw-text May 29, 2026
@aidenybai
Copy link
Copy Markdown
Member

RDE eval results

Validated at PR head 9aae2a82 (re-ran after the resolveTextBoundaryName refactor — confirmed behavior-preserving).

Harness note: the Vercel sandbox pool on the current evals checkout (fix/sandbox-vercel-eval) returned an empty result set, so I used the local runner against a targeted React Native subset of the corpus (fbtee only appears in RN text trees). Baseline = PR base e7a998a9.

Parity (base vs PR head)

Metric Result
Distinct RN repos scanned ~22 (18 produced diagnostics)
RootDir scans 24
Total diagnostics 5,411 across 89 rules
Net diagnostics added / removed 0 / 0 across all rules
rn-no-raw-text added / removed 0 / 0

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.

rn-no-raw-text hits manually inspected (4/4, identical on both versions)

Location Verdict
cometchat-uikit-react-native …/ThreadView.tsx:186 ✅ True positive — raw inside <TouchableOpacity>
react-native-chatgpt …/Login.tsx:16 ⚠️ Pre-existing FP — <Headline> (react-native-paper)
react-native-chatgpt …/Login.tsx:24 ⚠️ Pre-existing FP — <Button> label (react-native-paper)
react-native-firebase-social-app …/PostCard.js:82 ⚠️ Pre-existing FP — {' '} 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 #581 cases)
  • turbo typecheck --filter=oxlint-plugin-react-doctor → pass
  • vp lint / vp fmt --check on changed files → pass

Verdict: safe to merge. Suppression-only, tightly gated to fbt/fbs inside a <Text> boundary; <fbt> outside <Text> is still reported.

@aidenybai aidenybai merged commit b2934f9 into main May 30, 2026
14 checks passed
@aidenybai aidenybai deleted the ray/fbtee-transparent-50d2 branch May 30, 2026 00:48
@github-actions github-actions Bot mentioned this pull request May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants