From 4588665bcadf380558c92436191adba9ada3a316 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Jul 2026 07:15:43 +0000 Subject: [PATCH 1/2] fix(no-all-caps-body-text): don't flag caseless scripts (CJK) as all-caps The rule was treating any text without lowercase letters as 'all caps', which incorrectly flagged Japanese, Chinese, Korean, and Arabic text. Now only text that contains uppercase letters AND lacks lowercase letters is considered literal uppercase. Caseless scripts are skipped entirely. Fixes #1429 Co-authored-by: Skosh --- .../design/no-all-caps-body-text.test.ts | 48 +++++++++++++++++++ .../rules/design/no-all-caps-body-text.ts | 5 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.test.ts b/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.test.ts index fbbdd0f0b8..bc87344df9 100644 --- a/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.test.ts +++ b/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.test.ts @@ -50,4 +50,52 @@ describe("no-all-caps-body-text", () => { ); expect(result.diagnostics).toHaveLength(0); }); + + it("does not flag long Japanese text (caseless script)", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

一部のフォルダにアクセスできないため、移動対象を検出できていない可能性があります。フォルダのアクセス権を確認してから更新してください。

;`, + ); + expect(result.diagnostics).toHaveLength(0); + }); + + it("does not flag long Chinese text (caseless script)", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

由于无法访问某些文件夹,可能无法检测到移动目标。请检查文件夹的访问权限,然后更新。

;`, + ); + expect(result.diagnostics).toHaveLength(0); + }); + + it("does not flag long Korean text (caseless script)", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

일부 폴더에 액세스할 수 없으므로 이동 대상을 감지할 수 없습니다. 폴더 액세스 권한을 확인한 후 업데이트하십시오.

;`, + ); + expect(result.diagnostics).toHaveLength(0); + }); + + it("does not flag long Arabic text (caseless script)", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

لا يمكن الوصول إلى بعض المجلدات، لذا قد لا يتم اكتشاف أهداف النقل. يرجى التحقق من أذونات الوصول إلى المجلد، ثم التحديث.

;`, + ); + expect(result.diagnostics).toHaveLength(0); + }); + + it("does not flag mixed script text (English + Japanese) without uppercase", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

Please check フォルダのアクセス権を確認してから更新してください your folder permissions before continuing.

;`, + ); + expect(result.diagnostics).toHaveLength(0); + }); + + it("flags mixed script text when English portion is all caps", () => { + const result = runRule( + noAllCapsBodyText, + `const Example = () =>

PLEASE CHECK フォルダのアクセス権を確認してから更新してください YOUR FOLDER PERMISSIONS.

;`, + ); + expect(result.diagnostics).toHaveLength(1); + }); }); diff --git a/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.ts b/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.ts index 39384adb44..5e6764b12f 100644 --- a/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.ts +++ b/packages/oxlint-plugin-react-doctor/src/plugin/rules/design/no-all-caps-body-text.ts @@ -12,6 +12,7 @@ import { getStylePropertyStringValue } from "./utils/get-style-property-string-v const BODY_TEXT_ELEMENT_NAMES = new Set(["blockquote", "dd", "figcaption", "li", "p", "td"]); const LETTER_PATTERN = /\p{L}/u; +const UPPERCASE_LETTER_PATTERN = /\p{Lu}/u; const LOWERCASE_LETTER_PATTERN = /\p{Ll}/u; const hasUppercaseStyle = (node: EsTreeNodeOfType<"JSXOpeningElement">): boolean => { @@ -47,7 +48,9 @@ export const noAllCapsBodyText = defineRule({ if (staticText.length < LONG_BODY_TEXT_MIN_CHARACTERS || !LETTER_PATTERN.test(staticText)) { return; } - const isLiteralUppercase = !LOWERCASE_LETTER_PATTERN.test(staticText); + const hasUppercase = UPPERCASE_LETTER_PATTERN.test(staticText); + const hasLowercase = LOWERCASE_LETTER_PATTERN.test(staticText); + const isLiteralUppercase = hasUppercase && !hasLowercase; if (!isLiteralUppercase && !hasUppercaseStyle(openingElement)) return; context.report({ node: openingElement, From abfe13997a27e3b6d07e5410b8be5f5f914775ef Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 23 Jul 2026 07:16:24 +0000 Subject: [PATCH 2/2] chore: add changeset for no-all-caps-body-text fix Co-authored-by: Skosh --- .changeset/fix-cjk-false-positive.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/fix-cjk-false-positive.md diff --git a/.changeset/fix-cjk-false-positive.md b/.changeset/fix-cjk-false-positive.md new file mode 100644 index 0000000000..98e69e14a6 --- /dev/null +++ b/.changeset/fix-cjk-false-positive.md @@ -0,0 +1,9 @@ +--- +"oxlint-plugin-react-doctor": patch +--- + +Fix `no-all-caps-body-text` false positive on CJK text (caseless scripts) + +The rule was incorrectly flagging Japanese, Chinese, Korean, and Arabic text as "all caps" because it treated any text without lowercase letters as uppercase. Caseless scripts have no letter case, so they were always flagged. + +Now the rule only flags text that actually contains uppercase letters AND lacks lowercase letters. Caseless scripts are skipped entirely.