chore(tooling): миграция с ESLint + Prettier на Biome

Один инструмент вместо девяти dev-зависимостей. Замеры на этом репо
(483 файла, медиана из 3 прогонов, один и тот же компьютер):

- eslint .            ~20.4s  ->  biome lint .    ~2s
- prettier --check .  ~8.8s   ->  biome format .  ~0.2s
- суммарно линт+формат ~29s   ->  biome check .   ~2-3s (~10x)

Паритет с прежними правилами:
- форматирование бинарно совместимо с Prettier-конфигом (biome format
  --write тронул 9 файлов из ~480 — микроразличия);
- запрет window.confirm/alert/open/prompt и navigator.clipboard
  (Telegram WebView) перенесён GritQL-плагином
  biome-plugins/telegram-webview-guards.grit c теми же сообщениями
  и исключениями для src/platform/** и clipboard.ts; плагин сразу
  нашёл window.open в Wheel.tsx под старым eslint-disable —
  переведён на biome-ignore;
- react-hooks-правила: useExhaustiveDependencies/useHookAtTopLevel;
- новые для проекта правила (a11y и пр.) не включались или понижены
  до warning, чтобы миграция не смешивалась с чисткой кода — включать
  можно отдельными PR.

Ограничения (задокументированы): сортировка tailwind-классов
(prettier-plugin-tailwindcss) в Biome пока nursery — не включена;
CSS исключён из Biome (парсер спотыкается о Tailwind-синтаксис
globals.css) — файл один и правится редко.

CI не меняется: имена npm-скриптов lint/format:check сохранены.
lint-staged переведён на biome check --write.
This commit is contained in:
kewldan
2026-07-12 00:12:15 +03:00
parent 20565b8f59
commit cf3837163e
17 changed files with 279 additions and 1645 deletions

View File

@@ -0,0 +1,31 @@
language js
// Cross-platform guard (was eslint no-restricted-properties): these browser
// APIs misbehave inside the Telegram WebView. Route them through the platform
// abstraction instead. The platform adapters and the clipboard util (the
// canonical implementations) are exempted by the filename conditions below.
file(name=$name, body=$body) where {
$name <: not includes "platform",
$name <: not includes or {
"clipboard.ts",
"clipboard.js"
},
$body <: contains bubble or {
`window.confirm` as $use where {
register_diagnostic(span=$use, message="Use useNativeDialog().confirm — window.confirm is silently ignored in the Telegram WebView.", severity="error")
},
`window.alert` as $use where {
register_diagnostic(span=$use, message="Use useNativeDialog().alert — window.alert is silently ignored in the Telegram WebView.", severity="error")
},
`window.open` as $use where {
register_diagnostic(span=$use, message="Use usePlatform().openLink / openTelegramLink — window.open is intercepted by the Telegram WebView.", severity="error")
},
`window.prompt` as $use where {
register_diagnostic(span=$use, message="Use usePrompt() (PromptDialogHost) — window.prompt is not supported in the Telegram WebView.", severity="error")
},
`navigator.clipboard` as $use where {
register_diagnostic(span=$use, message="Use copyToClipboard from @/utils/clipboard — it falls back to execCommand when the Clipboard API is unavailable (Telegram WebView).", severity="error")
}
}
}