npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

miraat

v0.12.4

Published

Find & fix the RTL mistakes AI code tools keep making — for Arabic, Hebrew, Syriac, Thaana, N’Ko & Adlam. AST-verified logical CSS, mirrored Tailwind utilities, an MCP server, and an AI-rules file so your agent stops reintroducing them. (formerly rtlint)

Readme

Miraat (مرآة)

npm CI tests license sponsor

Find & fix the RTL mistakes AI code tools keep making — for every right-to-left script.

Formerly rtlint. Miraat (مرآة) is Arabic for "mirror" — mirroring left↔right is the whole job. The rtlint command and the rtlint_* MCP tools still work as aliases.

AI now writes most of the UI code in the world — and it is quietly, consistently bad at right-to-left. It reaches for ml-4, text-left, padding-right, hard-codes dir="ltr", and never mirrors an icon. It looks fine in English and breaks the moment a real Arabic, Hebrew, Syriac, Thaana, N'Ko or Adlam user opens it.

miraat scans your React / Next / Tailwind / CSS, auto-fixes the mechanical RTL mistakes, flags the ones that need a human eye, and writes an AI-rules file so your agent (Cursor, Claude, Copilot) stops reintroducing them. It's script-aware: physical→logical, dir and mirrored-icon guidance fire for all RTL scripts, while script-specific checks (like Western digits in a native-numeral script) fire only where they're actually wrong — Arabic/Thaana/N'Ko/Adlam carry their own numerals; Hebrew and Syriac use Western digits, so those are never falsely flagged.

▶ Try it in 10 seconds — paste your code in the playground (runs in your browser, nothing uploaded), or run npx miraat . below.

npx miraat .            # scan and report
npx miraat . --fix      # apply the safe fixes (physical → logical)
npx miraat . --check    # report only, exit non-zero if anything is found (CI)
npx miraat . --dry-run  # show what --fix would change, but write nothing
npx miraat . --init-rules   # inject RTL rules into your AI agents (Claude/Cursor/Gemini/Windsurf/Cline/Copilot/Codex)

No install needed — npx miraat fetches the published package and runs. Prefer a live demo? The hosted audit takes a URL or pasted code and returns a shareable A–F report.

One command, the whole suite

miraat is the umbrella for the RTL toolchain — one install, one command, every rule-pack:

npx miraat .            # RTL correctness            (default)
npx miraat type .       # Arabic typography & shaping (kashida)
npx miraat i18n .       # hardcoded strings / catalog (lahja)
npx miraat a11y .       # DGA Platforms-Code + WCAG   (daleel)
npx miraat all  .       # run every pack, one after another

The packs ship with miraat, so npx miraat all . runs the whole suite out of the box — no extra install. Each pack keeps its own audited engine (no monolith), so you can also install and run any of them standalone (npx kashida ., npx lahja ., npx daleel .), and npx miraat . --score gives the single RTL Score. The base RTL engine itself is dependency-light (Babel + PostCSS); the packs' heavier, feature-specific extras (e.g. a headless browser for live rendering) stay optional and load only when you use them.

Zero-corruption by design

miraat parses your code with a real AST (Babel for JS/TS/JSX/TSX, PostCSS for CSS) — it does not regex over raw text. Only high-confidence, mechanically-safe edits are auto-applied, and they're written as surgical splices into the original source, so formatting is preserved to the byte. Custom class names (left-sidebar, pl-PL), CSS selectors/comments/custom-properties, and JS identifiers/params/types that merely look physical are never touched. Everything ambiguous is reported, never rewritten. Re-running --fix is always a no-op.

Every RTL script, not just Arabic

miraat carries a Unicode scripts table (lib/scripts.js) so it reasons about each right-to-left script correctly instead of hard-coding Arabic:

| Script | dir | Own numerals? | Western digits flagged? | |--------|-----|---------------|--------------------------| | Arabic, N'Ko, Adlam, Thaana | rtl | yes | yes — use native / locale-aware numerals | | Hebrew, Syriac | rtl | no (use Western) | no — never falsely flagged |

Physical→logical, dir handling and mirrored-icon flags apply to all of them; the numeral check keys off the table so it only fires where a script has its own digits.

What it catches

| # | Pattern | miraat | |---|---------|--------| | 1 | Physical CSS (margin-left, padding-right, border-left, text-align: left) | auto-fix → logical (margin-inline-start, …) | | 2 | Physical Tailwind (ml-, pr-, left-, text-right, rounded-l, border-r) — incl. inside cn()/clsx()/cva() | auto-fix → logical (ms-, pe-, start-, text-end, rounded-s, border-e) | | 3 | Hard-coded dir="ltr" / dir={"ltr"} / direction: "ltr" / setAttribute('dir','ltr') (and "rtl") | flag — make it dynamic | | 4 | Un-mirrored directional icons (ChevronLeft, BsChevronLeft, ArrowLeftIcon, MdKeyboardArrowRight, …) | flag — mirror for RTL | | 5 | Inline JS physical styles (marginLeft, textAlign: 'left', el.style.marginLeft = …) | auto-fix → logical | | 6 | Script-blind font stacks (no RTL-capable fallback) | flag — add a script-capable font | | 7 | Western numerals inside a native-numeral RTL script (السعر 1234 درهم) | flag — use native / locale-aware numerals | | 8 | LTR-native <input type="tel\|email\|url\|number"> with no dir | flag — add dir="ltr" so the value & caret don't jump | | 9 | React Native physical style in StyleSheet.create (marginLeft, left, textAlign:'left') | flag — use RN logical (marginStart, start, textAlign:'auto') |

Before → after

- <div dir="ltr" className="ml-4 pr-2 text-left border-l rounded-l-lg">
+ <div dir="ltr" className="ms-4 pe-2 text-start border-s rounded-s-lg">
- margin-left: 16px; padding-right: 8px; text-align: left;
+ margin-inline-start: 16px; padding-inline-end: 8px; text-align: start;

Why the flags aren't auto-fixed

The mechanical half of RTL — logical properties, mirrored utilities — is now commodity (shadcn and Tailwind ship it). miraat gives you that for free. But the half that actually makes an RTL script feel right — mirroring the correct icons, typographic scale and font pairing per script, bidi edge-cases, native numerals, cultural correctness — takes native judgment. miraat flags those; it doesn't guess. That judgment is a service, not a regex — see the roadmap.

Use it in your AI agent (MCP)

miraat ships an MCP server, so Cursor / Claude / Windsurf can call it while they write code — the bug never ships:

{
  "mcpServers": {
    "miraat": { "command": "npx", "args": ["-y", "-p", "github:Otto-OttoSpace/miraat", "miraat-mcp"] }
  }
}

RTL tools: miraat_scan (scan a path), miraat_check_code (snippet → findings + fixed code), and miraat_fix_code — send a snippet, get the corrected code back up front with the judgment calls (icons/dir/fonts/bidi/numerals) listed separately to decide. Call miraat_fix_code before proposing any UI code and the RTL bug never ships. The rtlint_* and legacy rtl_* names resolve to the same handlers.

The whole suite, one server. The same MCP also exposes the rest of the Arabic toolchain, so your agent gets every check over one connection:

  • miraat_type_check — Arabic typography & shaping (kashida): broken cursive joins, letter-spacing on Arabic, tofu, script-blind fonts.
  • miraat_i18n_check — internationalization (lahja): hard-coded strings, missing/empty keys, placeholder drift, CLDR plural completeness.
  • miraat_a11y_check — accessibility (daleel): WCAG 2.2 AA + the Saudi DGA Platforms-Code.

Each takes a path. The packs ship with miraat; in the rare case one is unavailable, the tool returns a one-line install hint instead of failing.

Use it in your editor (LSP)

miraat ships a Language Server — one binary that gives you live RTL squiggles as you type and quick-fixes, in every LSP editor (VS Code, Cursor, Windsurf, Neovim, JetBrains). It runs the same engine as the CLI, so your miraat.config.json severities and miraat-disable comments are honoured in the editor too. There is no other RTL language server.

npx -p miraat miraat-lsp        # stdio LSP server

Neovim (built-in LSP) example:

vim.lsp.start({ name = 'miraat', cmd = { 'npx', '-p', 'miraat', 'miraat-lsp' },
  root_dir = vim.fn.getcwd(), filetypes = { 'javascriptreact','typescriptreact','css','scss' } })

It publishes diagnostics on open/change/save and offers a per-finding fix plus "fix all safe RTL issues in this file" as code actions.

VS Code: install the one-click Miraat — RTL / Arabic linter extension — it boots this server for you, adds a status-bar fix-all button, and supports "editor.codeActionsOnSave": { "source.fixAll.miraat": "explicit" }.

Use it in CI (GitHub Action)

- uses: Otto-OttoSpace/miraat@main
  with:
    path: .
    # fix: true   # optionally apply fixes

Get inline PR annotations via GitHub code scanning — emit SARIF and upload it:

- uses: Otto-OttoSpace/miraat@main
  with:
    path: .
    sarif: true            # writes miraat.sarif (does not fail the job)
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: miraat.sarif

Or straight from the CLI: npx miraat . --sarif > miraat.sarif.

Other CI reporters: --format github prints annotations that render inline on the PR diff; --format gitlab-codequality and --format junit emit the report artifacts GitLab / most CI dashboards ingest.

- run: npx miraat . --format github        # inline PR annotations (step fails on errors)

Turn it on in a real repo (governance)

A large existing app has RTL debt already. miraat is built to be adoptable on day one — snapshot the debt, then gate CI on new debt only:

npx miraat . --suppress-all          # writes miraat-baseline.json (file → rule → count)
npx miraat . --check                 # from now on, fails only on NEW RTL debt
npx miraat . --prune-suppressions    # after you fix some, shrink the baseline

Tune per rule with an auto-discovered miraat.config.json (ESLint-shaped — nothing new to learn):

{
  "extends": "miraat:recommended",          // or "miraat:strict" (fixes become errors)
  "rules": {
    "hardcoded-dir": "error",
    "arabic-western-digits": "off"          // off | warn | error
  }
}

Keep a legitimately LTR block quiet with an inline escape hatch (works in any comment syntax):

/* miraat-disable-next-line css-logical -- phone-number field is intentionally LTR */
.phone { text-align: left; }

miraat-disable-line, block miraat-disable / miraat-enable, .miraatignore (+ your .gitignore), and --report-unused-disable-directives all work as you'd expect. Exit codes: a plain scan fails on unaddressed error-level findings; --check fails on any finding beyond the baseline (the CI gate).

Get one number: the RTL Score

npx miraat . --score          # → Miraat RTL Score  100/100  (A)
npx miraat . --score --json    # { "score": 100, "grade": "A", ... }

100 = clean. Judgment-call flags weigh double the mechanical fixes, and penalties are normalized by how much code was scanned — so one bad file doesn't tank a large, mostly-correct repo. Grades: A ≥ 90 · B ≥ 75 · C ≥ 60 · D ≥ 40 · F.

Show it off — the RTL Score badge:

npx miraat . --badge > rtl-score.svg    # shields-style SVG (score + grade, colored A→F)
![RTL Score](rtl-score.svg)             <!-- in your README -->

Shareable proof — the HTML Correctness Report:

npx miraat . --report                   # → miraat-report.html (self-contained; opens & prints anywhere)
npx miraat . --report audit.html        # custom filename

One page: the RTL Score, a by-rule breakdown, and every finding with its file/line and fix. No external assets. It's the artifact you hand a client or ship with a design system to prove the RTL is correct — checked against the ruleset, not a claim.

Use it as an ESLint / stylelint rule

RTL issues in the lint run you already have: eslint-plugin-miraat (JS/TS/JSX) and stylelint-plugin-miraat (CSS/SCSS/LESS):

// eslint.config.js (flat, ESLint 9+)
import miraat from "eslint-plugin-miraat";
export default [ miraat.configs["flat/recommended"] ];
// .stylelintrc.json
{ "plugins": ["stylelint-plugin-miraat"], "rules": { "miraat/rtl": true } }

Use it as a git hook (pre-commit)

# .pre-commit-config.yaml
- repo: https://github.com/Otto-OttoSpace/miraat
  rev: v0.11.0
  hooks:
    - id: miraat

Or with husky + lint-staged:

// package.json
"lint-staged": { "*.{js,jsx,ts,tsx,css,scss,vue,svelte,html}": "miraat --check" }

Roadmap → Miraat Pro

  • Hosted audit — paste a repo or URL, get a full Arabic-RTL report + fixes (a designer-in-the-loop pass, not just the mechanical ones).
  • CI GitHub Action — fail the PR when new physical RTL bugs land.
  • Arabic design layer — drop-in typography / font-pairing / numeral / bidi tokens that are actually correct.

Author

Built by an Arabic-RTL Design Engineer — Western-quality product design + RTL-correct code, in Arabic, French & English. The free handbook "Arabic-RTL for the AI era" is the companion to this tool.

MIT © 2026

💛 Support & commercial use

The Miraat suite is free and open-source (MIT). If it helps you ship correct Arabic/RTL, please consider sponsoring on GitHub — it funds maintenance and new rules.

Using it in a commercial product, in CI, or need the private DGA Platforms-Code rule pack? A Miraat Pro commercial licence — commercial use, a hosted CI audit that gates PRs (miraat-action), and priority support — is available. Email [email protected] and we'll set you up.