chore: migrate oxlint config to e18e plugin and fix lint violations

- Replace root `eslint-plugin-lingui` jsPlugin with `@e18e/eslint-plugin`; move lingui rules into per-app `.oxlintrc.json` overrides for native and web
- Add `jsx-a11y`, `react-hooks-js` (native), and expanded lingui rule sets to per-app configs
- Add `oxc/no-barrel-file` warning at threshold 0 to root config
- Fix `e18e/prefer-url-canparse`: replace `try { new URL() } catch` with `URL.canParse()` in server-url screen and server lib
- Fix `e18e/prefer-timer-args`: pass callback args directly to `setTimeout` instead of wrapping in arrow functions (use-debounce, integration-card)
- Fix `e18e/prefer-static-regex`: hoist `/\/+$/` to module-level constant in server-url screen
- Fix `react-hooks-js/refs` and `react-hooks-js/set-state-in-effect`: convert `useRef` tracking patterns to `useState` + render-time derived updates in `use-server-connection`, `expandable-text`, and settings screen
- Fix `react-hooks-js/immutability`: extract stable palette sub-values before `useMemo` deps in title detail screen
- Apply `e18e` and other rule fixes across core, tmdb, web components, and i18n packages
This commit is contained in:
jake committed 2026-03-22 13:50:24 -04:00
1 parent 373a5d3caf
commit 2c7068ced3
52 files changed
+458 -205

No files matched your search

+13 -6
View File
@@ -13,6 +13,13 @@
import { resolve } from "node:path";
const SIMPLE_PLACEHOLDER_RE = /^[a-zA-Z0-9_]+$/;
const ICU_ARG_NAME_RE = /^([a-zA-Z0-9_]+)\s*,/;
const NUMBERED_TAG_RE = /<\/?\d+\/?>/g;
const LEADING_WS_RE = /^\s*/;
const TRAILING_WS_RE = /\s*$/;
const EDGE_WS_RE = /^\s|\s$/;
import type { CatalogType } from "@lingui/conf";
import { formatter } from "@lingui/format-po";
@@ -198,11 +205,11 @@ function extractSimplePlaceholders(text: string): string[] {
if (depth === 0 && argStart >= 0) {
const inner = text.slice(argStart + 1, i);
// Top-level simple placeholder: just an identifier, no comma (not plural/select)
if (/^[a-zA-Z0-9_]+$/.test(inner)) {
if (SIMPLE_PLACEHOLDER_RE.test(inner)) {
results.push(`{${inner}}`);
} else {
// Complex ICU argument — extract just the argument name before the comma
const argName = inner.match(/^([a-zA-Z0-9_]+)\s*,/)?.[1];
const argName = inner.match(ICU_ARG_NAME_RE)?.[1];
if (argName) results.push(`{${argName}}`);
}
argStart = -1;
@@ -215,15 +222,15 @@ function extractSimplePlaceholders(text: string): string[] {
function extractNumberedTags(text: string): string[] {
// Matches <0>, </0>, <0/>, <12>, </12>, <12/>
return [...text.matchAll(/<\/?\d+\/?>/g)].map((m) => m[0]).sort();
return Array.from(text.matchAll(NUMBERED_TAG_RE), (m) => m[0]).sort();
}
function leadingWhitespace(text: string): string {
return text.match(/^\s*/)?.[0] ?? "";
return text.match(LEADING_WS_RE)?.[0] ?? "";
}
function trailingWhitespace(text: string): string {
return text.match(/\s*$/)?.[0] ?? "";
return text.match(TRAILING_WS_RE)?.[0] ?? "";
}
function validateTranslation(source: string, translated: string): string[] {
@@ -246,7 +253,7 @@ function validateTranslation(source: string, translated: string): string[] {
}
// Only enforce whitespace when the source has meaningful edge whitespace
if (/^\s|\s$/.test(source)) {
if (EDGE_WS_RE.test(source)) {
if (leadingWhitespace(source) !== leadingWhitespace(translated)) {
issues.push("leading whitespace mismatch");
}
+3 -1
View File
@@ -1,8 +1,10 @@
import { i18n } from "./index";
const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
/** Whether a string looks like a date-only value (no time component). */
function isDateOnly(value: string): boolean {
return /^\d{4}-\d{2}-\d{2}$/.test(value);
return DATE_ONLY_RE.test(value);
}
function toDate(date: Date | string): Date {
+77
View File
@@ -22,6 +22,7 @@ msgstr ""
#~ msgid "...and {0} more"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "...and {remainingErrors} more"
msgstr "...and {remainingErrors} more"
@@ -145,10 +146,12 @@ msgstr ""
msgid "{label} URL regenerated"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "{movieCount} movies, {episodeCount} episodes"
msgstr "{movieCount} movies, {episodeCount} episodes"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "{ratingCount} ratings"
msgstr "{ratingCount} ratings"
@@ -185,6 +188,7 @@ msgstr "{watchedCount}/{episodeCount, plural, one {# episode} other {# episodes}
msgid "{watchedEpisodes}/{totalEpisodes, plural, one {# episode} other {# episodes}}"
msgstr "{watchedEpisodes}/{totalEpisodes, plural, one {# episode} other {# episodes}}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "{watchlistCount} items"
msgstr "{watchlistCount} items"
@@ -385,6 +389,7 @@ msgstr ""
#: apps/native/src/components/settings/integration-card.tsx
#: apps/native/src/components/titles/status-action-button.tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/backup-restore-section.tsx
#: apps/web/src/components/settings/backup-section.tsx
#: apps/web/src/components/settings/danger-section.tsx
@@ -611,6 +616,10 @@ msgstr ""
msgid "Could not load person details"
msgstr ""
#: apps/native/src/app/title/[id].tsx
msgid "Could not load title details"
msgstr "Could not load title details"
#: apps/web/src/components/auth-form.tsx
msgid "Create account"
msgstr ""
@@ -726,6 +735,7 @@ msgstr ""
msgid "Don't have an account?"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Done"
msgstr ""
@@ -747,6 +757,10 @@ msgstr ""
msgid "Download backup"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Download your library, watch history, and ratings as JSON"
msgstr "Download your library, watch history, and ratings as JSON"
#: apps/native/src/app/person/[id].tsx
#: apps/native/src/components/search/recently-viewed-row-content.tsx
#: apps/web/src/components/people/person-hero.tsx
@@ -819,6 +833,7 @@ msgstr ""
msgid "Episode watched"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/titles/title-seasons.tsx
msgid "Episodes"
@@ -857,6 +872,7 @@ msgstr ""
#~ msgid "Errors ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Errors ({errorCount})"
msgstr "Errors ({errorCount})"
@@ -874,6 +890,11 @@ msgstr ""
msgid "Explore titles"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Export"
msgstr "Export"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Failed"
msgstr ""
@@ -949,6 +970,7 @@ msgstr ""
msgid "Failed to mark some episodes"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Failed to parse file"
msgstr ""
@@ -1063,6 +1085,10 @@ msgstr ""
msgid "Finished importing from {source}."
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Finished importing your Sofa export."
msgstr "Finished importing your Sofa export."
#: apps/web/src/components/titles/title-availability.tsx
msgid "Free"
msgstr ""
@@ -1086,6 +1112,7 @@ msgstr ""
#: apps/native/src/app/person/[id].tsx
#: apps/native/src/app/person/[id].tsx
#: apps/native/src/app/title/[id].tsx
#: apps/native/src/app/title/[id].tsx
msgid "Go back"
msgstr ""
@@ -1137,18 +1164,22 @@ msgstr ""
msgid "Image cache and backup disk usage"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import {totalItems} items"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import complete"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import failed"
msgstr ""
@@ -1165,15 +1196,23 @@ msgstr ""
msgid "Import from {sourceLabel}"
msgstr "Import from {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import is still running in the background. Check back later."
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Import options"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Import Sofa data"
msgstr "Import Sofa data"
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Imported"
msgstr ""
@@ -1186,6 +1225,14 @@ msgstr ""
msgid "Imported {importedCount} items from {sourceLabel}"
msgstr "Imported {importedCount} items from {sourceLabel}"
#: apps/web/src/components/settings/account-section.tsx
msgid "Imported {importedCount} items from Sofa export"
msgstr "Imported {importedCount} items from Sofa export"
#: apps/web/src/components/settings/account-section.tsx
msgid "Importing data"
msgstr "Importing data"
#: apps/web/src/components/settings/imports-section.tsx
msgid "Importing from {source}"
msgstr ""
@@ -1292,14 +1339,23 @@ msgstr ""
msgid "Last run succeeded"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Library"
msgstr "Library"
#: apps/web/src/components/settings/system-health-section.tsx
msgid "Library refresh"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Library statuses"
msgstr "Library statuses"
#: apps/web/src/components/auth-form.tsx
msgid "Loading…"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Lost connection to import. Check status in settings."
msgstr ""
@@ -1404,6 +1460,7 @@ msgid "Movie"
msgstr ""
#: apps/web/src/components/people/filmography-grid.tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Movies"
msgstr ""
@@ -1602,6 +1659,10 @@ msgstr ""
msgid "Page Not Found"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Parsing file..."
msgstr "Parsing file..."
#: apps/web/src/components/settings/imports-section.tsx
msgid "Parsing..."
msgstr ""
@@ -1770,6 +1831,8 @@ msgstr ""
msgid "Rating removed"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Ratings"
@@ -1938,6 +2001,10 @@ msgstr ""
msgid "Restore failed"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
msgid "Restore from a Sofa export file"
msgstr "Restore from a Sofa export file"
#: apps/web/src/components/settings/backup-restore-section.tsx
msgid "Restoring…"
msgstr ""
@@ -1961,6 +2028,7 @@ msgstr ""
msgid "Return home"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Review what was found and choose what to import."
msgstr ""
@@ -2190,6 +2258,7 @@ msgstr ""
msgid "Sign out of other sessions"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Skipped"
msgstr ""
@@ -2217,6 +2286,7 @@ msgstr ""
#: apps/native/src/app/change-password.tsx
#: apps/native/src/app/person/[id].tsx
#: apps/native/src/app/title/[id].tsx
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/routes/__root.tsx
msgid "Something went wrong"
@@ -2251,6 +2321,7 @@ msgstr ""
msgid "Starting at"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Starting import..."
msgstr ""
@@ -2291,6 +2362,7 @@ msgstr ""
msgid "The title you're looking for doesn't exist or may have been removed from the database."
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "This may take a few minutes for large libraries. Please don't close this tab."
msgstr ""
@@ -2440,6 +2512,7 @@ msgstr ""
msgid "Trigger job"
msgstr ""
#: apps/native/src/app/title/[id].tsx
#: apps/web/src/routes/__root.tsx
msgid "Try again"
msgstr ""
@@ -2591,6 +2664,7 @@ msgstr ""
msgid "Waiting for authorization..."
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Warnings"
msgstr ""
@@ -2599,6 +2673,7 @@ msgstr ""
#~ msgid "Warnings ({0})"
#~ msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Warnings ({warningCount})"
msgstr "Warnings ({warningCount})"
@@ -2607,10 +2682,12 @@ msgstr "Warnings ({warningCount})"
msgid "Watch all"
msgstr ""
#: apps/web/src/components/settings/account-section.tsx
#: apps/web/src/components/settings/imports-section.tsx
msgid "Watch history"
msgstr ""
#: apps/web/src/components/titles/title-availability.tsx
#: apps/web/src/components/titles/title-availability.tsx
msgid "Watch on {name}"
msgstr ""