Skip to content

Comments

chore: add RTL CSS Checker to autofix#1077

Merged
danielroe merged 7 commits intonpmx-dev:mainfrom
userquin:add-rtl-css-script
Feb 6, 2026
Merged

chore: add RTL CSS Checker to autofix#1077
danielroe merged 7 commits intonpmx-dev:mainfrom
userquin:add-rtl-css-script

Conversation

@userquin
Copy link
Member

@userquin userquin commented Feb 6, 2026

The file paths with errors using absolute path, clicking using relative paths in WebStorm terminal doesn't work (VSCode click works with absolute and relative paths).

This PR includes a fix at DownloadAnalitics.vue for a text-right style, preset-wind4 adding some rules with higher priority and the RTL preset dind't detect those cases, solved using shorcuts and a hack.

This afternoon I'll try to add the fix: https://streamable.com/fr498h

@vercel
Copy link

vercel bot commented Feb 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs.npmx.dev Error Error Feb 6, 2026 8:07pm
npmx.dev Ready Ready Preview, Comment Feb 6, 2026 8:07pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Feb 6, 2026 8:07pm

Request Review

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

Adds an RTL consistency check and threads a checker through RTL rule generation: a new script scripts/rtl-checker.ts scans .vue files using UnoCSS with Wind4 and the RTL preset and exits non‑zero when RTL-related warnings are found; package.json gains an rtl:check script and .github/workflows/autofix.yml adds a workflow step to run it. scripts/utils.ts exports ANSI COLORS. uno-preset-rtl.ts introduces a CollectorChecker type and an optional checker parameter propagated to RTL handlers (including directionSizeRTL and presetRtl) to collect/report warnings. Tests and snapshots updated to reflect the preset and warning output changes.

Possibly related PRs

  • feat: add charts to compare page #846 — Modifies app/components/Package/DownloadAnalytics.vue (class change text-righttext-end), overlapping at file level and relevant to RTL class adjustments.
🚥 Pre-merge checks | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The pull request description partially relates to the changeset but contains misleading and vague information that does not clearly map to the actual changes. Clarify the description to explain that the PR adds an RTL CSS checker to detect and report non-RTL CSS classes. Explain how the checker works and why the changes to uno-preset-rtl.ts, scripts/rtl-checker.ts, and the workflow are necessary.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
uno-preset-rtl.ts (1)

52-61: match.replace is fragile — but safe in the p/m rules only by coincidence.

In directionSizeRTL, match.replace(direction, replacement) replaces the first occurrence of the single character. For pr-4 the first r is the direction, so this works. However, the same pattern used in the rounded and border handlers below (lines 161, 181) is broken — see comments there.

Consider extracting the "compute suggestion + emit warning" block into a shared helper to reduce the six-fold duplication across handlers and to fix the replacement logic in one place.

♻️ Proposed helper to centralise warning emission and fix replacements
+function emitRtlWarning(
+  match: string,
+  direction: string,
+  replacement: string,
+  context: RuleContext<any>,
+  checker?: CollectorChecker,
+) {
+  const fullClass = context.rawSelector || match
+  const suggestedBase = match.replace(`-${direction}`, `-${replacement}`)
+  const suggestedClass = fullClass.replace(match, suggestedBase)
+  const message = `avoid using '${fullClass}', use '${suggestedClass}' instead.`
+  if (checker) {
+    checker(message, fullClass)
+  } else {
+    warnOnce(`[RTL] ${message}`, fullClass)
+  }
+}

Then each handler call site becomes a single line, e.g.:

emitRtlWarning(match, direction!, replacement, context, checker)
scripts/rtl-checker.ts (2)

12-46: Mutable closure variables (idx, line) are safe here, but fragile.

The checker callback (lines 25-35) captures idx and line by reference. This works correctly because uno.generate(line) is awaited and the preset rules invoke the checker synchronously within that call. However, if UnoCSS ever deferred the callback (e.g. microtask), the captured values would be stale.

A slightly more robust approach is to scope these per iteration:

♻️ Optional: scope variables per iteration
   const lines = file.split('\n')
   for (let i = 0; i < lines.length; i++) {
-    idx = i + 1
-    line = lines[i]
-    await uno.generate(line)
+    const currentIdx = i + 1
+    const currentLine = lines[i]!
+    idx = currentIdx
+    line = currentLine
+    await uno.generate(currentLine)
   }

Better still, move the idx/line into a small object passed to the checker, but this would require a signature change in CollectorChecker.


22-37: A new createGenerator is instantiated for every .vue file.

Each call to checkFile creates a fresh UnoCSS generator (including preset initialisation). For repositories with many Vue files this could be noticeably slow. Consider creating the generator once and passing it in, resetting only the warnings map between files.

}
}

check()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unhandled promise rejection — add a .catch() handler.

check() returns Promise<void>. If any file read, glob, or generation throws, the rejection is unhandled. Node will exit with a non-zero code on unhandled rejections, but the error message will be a raw stack trace rather than a clear diagnostic.

🛡️ Proposed fix
-check()
+check().catch((error) => {
+  console.error(`${COLORS.red}RTL check failed: ${error}${COLORS.reset}`)
+  process.exit(1)
+})

Based on learnings: "Use error handling patterns consistently".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
check()
check().catch((error) => {
console.error(`${COLORS.red}RTL check failed: ${error}${COLORS.reset}`)
process.exit(1)
})

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
uno-preset-rtl.ts (1)

46-63: Extract a helper to eliminate the repeated checker/warnOnce pattern.

The checker-vs-warnOnce dispatch block is duplicated six times across the file with near-identical structure. Extracting a small helper would reduce duplication and guarantee consistent message formatting (currently the checker message at line 117 uses '. Use ' while the other five use ', use ').

♻️ Proposed helper and usage

Add a helper near the top of the file:

function emitWarning(
  fullClass: string,
  suggestedClass: string,
  checker?: CollectorChecker,
) {
  const message = `avoid using '${fullClass}', use '${suggestedClass}' instead.`
  if (checker) {
    checker(message, fullClass)
  } else {
    warnOnce(`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`, fullClass)
  }
}

Then replace every inline block, e.g.:

-    if (checker) {
-      checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
-    } else {
-      warnOnce(`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`, fullClass)
-    }
+    emitWarning(fullClass, suggestedClass, checker)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

@userquin
Copy link
Member Author

userquin commented Feb 6, 2026

DONT MERGE YET: I have a regresion with text-(left|right), the test snapshot not replacing them with text-(start|end) 🤔

fixed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

@userquin
Copy link
Member Author

userquin commented Feb 6, 2026

PR ready to review.

# Conflicts:
#	package.json
@danielroe danielroe added this pull request to the merge queue Feb 6, 2026
Merged via the queue into npmx-dev:main with commit e076462 Feb 6, 2026
16 of 17 checks passed
@userquin userquin deleted the add-rtl-css-script branch February 7, 2026 01:22
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.

2 participants