Upgrade Biome to 2.4.7 and enable 54 additional lint rules
Add rules covering bug prevention (noLeakedRender, noFloatingPromises, noImportCycles, noReactForwardRef), security (noScriptUrl, noAlert), performance (noAwaitInLoops, useTopLevelRegex), and code style (noNestedTernary, useGlobalThis, useNullishCoalescing, useSortedClasses, plus ~40 more). Fix all violations: extract top-level regex constants, guard React && renders with boolean coercion, refactor nested ternaries, replace window with globalThis, sort Tailwind classes, and introduce expectDomainError test helper to eliminate conditional expects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -44,7 +44,7 @@ export function useBestiary(): BestiaryHook {
|
||||
setIsLoaded(true);
|
||||
}
|
||||
|
||||
bestiaryCache.loadAllCachedCreatures().then((map) => {
|
||||
void bestiaryCache.loadAllCachedCreatures().then((map) => {
|
||||
setCreatureMap(map);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -48,7 +48,7 @@ export function useBulkImport(): BulkImportHook {
|
||||
countersRef.current = { completed: 0, failed: 0 };
|
||||
setState({ status: "loading", total, completed: 0, failed: 0 });
|
||||
|
||||
(async () => {
|
||||
void (async () => {
|
||||
const cacheChecks = await Promise.all(
|
||||
allCodes.map(async (code) => ({
|
||||
code,
|
||||
@@ -75,6 +75,7 @@ export function useBulkImport(): BulkImportHook {
|
||||
|
||||
for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
|
||||
const batch = uncached.slice(i, i + BATCH_SIZE);
|
||||
// biome-ignore lint/performance/noAwaitInLoops: sequential batching is intentional to avoid overwhelming the server with too many concurrent requests
|
||||
await Promise.allSettled(
|
||||
batch.map(async ({ code }) => {
|
||||
const url = getDefaultFetchUrl(code, baseUrl);
|
||||
|
||||
@@ -33,6 +33,8 @@ import {
|
||||
saveEncounter,
|
||||
} from "../persistence/encounter-storage.js";
|
||||
|
||||
const COMBATANT_ID_REGEX = /^c-(\d+)$/;
|
||||
|
||||
const EMPTY_ENCOUNTER: Encounter = {
|
||||
combatants: [],
|
||||
activeIndex: 0,
|
||||
@@ -48,7 +50,7 @@ function initializeEncounter(): Encounter {
|
||||
function deriveNextId(encounter: Encounter): number {
|
||||
let max = 0;
|
||||
for (const c of encounter.combatants) {
|
||||
const match = /^c-(\d+)$/.exec(c.id);
|
||||
const match = COMBATANT_ID_REGEX.exec(c.id);
|
||||
if (match) {
|
||||
const n = Number.parseInt(match[1], 10);
|
||||
if (n > max) max = n;
|
||||
@@ -316,7 +318,7 @@ export function useEncounter() {
|
||||
|
||||
setEvents((prev) => [...prev, ...addResult]);
|
||||
},
|
||||
[makeStore, editCombatant],
|
||||
[makeStore],
|
||||
);
|
||||
|
||||
const addFromPlayerCharacter = useCallback(
|
||||
@@ -368,7 +370,7 @@ export function useEncounter() {
|
||||
|
||||
setEvents((prev) => [...prev, ...addResult]);
|
||||
},
|
||||
[makeStore, editCombatant],
|
||||
[makeStore],
|
||||
);
|
||||
|
||||
const isEmpty = encounter.combatants.length === 0;
|
||||
|
||||
@@ -34,11 +34,11 @@ export function useSidePanelState(): SidePanelState & SidePanelActions {
|
||||
null,
|
||||
);
|
||||
const [isWideDesktop, setIsWideDesktop] = useState(
|
||||
() => window.matchMedia("(min-width: 1280px)").matches,
|
||||
() => globalThis.matchMedia("(min-width: 1280px)").matches,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const mq = window.matchMedia("(min-width: 1280px)");
|
||||
const mq = globalThis.matchMedia("(min-width: 1280px)");
|
||||
const handler = (e: MediaQueryListEvent) => setIsWideDesktop(e.matches);
|
||||
mq.addEventListener("change", handler);
|
||||
return () => mq.removeEventListener("change", handler);
|
||||
|
||||
Reference in New Issue
Block a user