diff --git a/apps/api/src/lib/ingredient-matcher.ts b/apps/api/src/lib/ingredient-matcher.ts
index 0ba0c3c..2c3c71f 100644
--- a/apps/api/src/lib/ingredient-matcher.ts
+++ b/apps/api/src/lib/ingredient-matcher.ts
@@ -1,6 +1,6 @@
import {
- INGREDIENT_LABELS_EN,
INGREDIENT_LABEL_SYNONYMS_EN,
+ INGREDIENT_LABELS_EN,
UNIT_LABELS_EN,
} from "@batch-cooking/shared";
import { prisma } from "../db/prisma.js";
diff --git a/apps/api/src/lib/recipe-translation.ts b/apps/api/src/lib/recipe-translation.ts
index 257f25c..a3de19e 100644
--- a/apps/api/src/lib/recipe-translation.ts
+++ b/apps/api/src/lib/recipe-translation.ts
@@ -1,12 +1,12 @@
import type { UnitType } from "@batch-cooking/shared";
import {
- type IngredientMatchEntry,
- type UnitMatchEntry,
extractQuantity,
+ type IngredientMatchEntry,
loadIngredientCatalog,
loadUnitCatalog,
matchIngredientName,
matchUnit,
+ type UnitMatchEntry,
} from "./ingredient-matcher.js";
import type {
ParsedRecipe,
@@ -14,9 +14,9 @@ import type {
ParsedRecipeStep,
} from "./recipe-source-adapter.js";
import {
- type TechStepMappingRule,
loadTechStepMappingRules,
matchTechSteps,
+ type TechStepMappingRule,
} from "./tech-step-matcher.js";
/**
diff --git a/apps/api/src/modules/auth/auth.routes.ts b/apps/api/src/modules/auth/auth.routes.ts
index 67c2440..af7bbcb 100644
--- a/apps/api/src/modules/auth/auth.routes.ts
+++ b/apps/api/src/modules/auth/auth.routes.ts
@@ -1,7 +1,7 @@
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
import { deleteAccountSchema, loginSchema, signupSchema } from "@batch-cooking/shared";
-import { Router } from "express";
import type { CookieOptions, Response } from "express";
+import { Router } from "express";
import { env } from "../../config/env.js";
import { type AuthLocals, requireAuth } from "../../middlewares/require-auth.js";
import { deleteAccount, login, signup } from "./auth.service.js";
diff --git a/apps/api/src/modules/house/house.routes.ts b/apps/api/src/modules/house/house.routes.ts
index 1ffd8b3..04bb18a 100644
--- a/apps/api/src/modules/house/house.routes.ts
+++ b/apps/api/src/modules/house/house.routes.ts
@@ -1,8 +1,8 @@
import { HttpError } from "@batch-cooking/error-tools";
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
import {
- ErrorCode,
createHouseSchema,
+ ErrorCode,
joinHouseSchema,
renameHouseSchema,
updateHouseSourcesSchema,
diff --git a/apps/api/src/modules/planning/planning.routes.ts b/apps/api/src/modules/planning/planning.routes.ts
index a4b04f5..26ce92d 100644
--- a/apps/api/src/modules/planning/planning.routes.ts
+++ b/apps/api/src/modules/planning/planning.routes.ts
@@ -1,7 +1,7 @@
import { parseDateOnly } from "@batch-cooking/date-tools";
import { HttpError } from "@batch-cooking/error-tools";
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
-import { ErrorCode, addPlanningItemSchema, getPlanningByDateSchema } from "@batch-cooking/shared";
+import { addPlanningItemSchema, ErrorCode, getPlanningByDateSchema } from "@batch-cooking/shared";
import { Router } from "express";
import { type AuthLocals, requireAuth } from "../../middlewares/require-auth.js";
import { addPlanningItem, getPlanningForDate, removePlanningItem } from "./planning.service.js";
diff --git a/apps/api/src/modules/recipe/recipe.routes.ts b/apps/api/src/modules/recipe/recipe.routes.ts
index ece4f9e..669bdc7 100644
--- a/apps/api/src/modules/recipe/recipe.routes.ts
+++ b/apps/api/src/modules/recipe/recipe.routes.ts
@@ -1,8 +1,8 @@
import { HttpError } from "@batch-cooking/error-tools";
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
import {
- ErrorCode,
createRecipeSchema,
+ ErrorCode,
listRecipesSchema,
updateRecipeSchema,
} from "@batch-cooking/shared";
diff --git a/apps/api/src/modules/sources/sources.routes.ts b/apps/api/src/modules/sources/sources.routes.ts
index edba393..083b911 100644
--- a/apps/api/src/modules/sources/sources.routes.ts
+++ b/apps/api/src/modules/sources/sources.routes.ts
@@ -1,6 +1,6 @@
import { HttpError } from "@batch-cooking/error-tools";
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
-import { ErrorCode, browseSourceSchema, createRecipeSchema } from "@batch-cooking/shared";
+import { browseSourceSchema, createRecipeSchema, ErrorCode } from "@batch-cooking/shared";
import { Router } from "express";
import { type AuthLocals, requireAuth } from "../../middlewares/require-auth.js";
import { browseSource, importSourceItem, previewSourceItem } from "./sources.service.js";
diff --git a/apps/api/src/modules/sources/sources.service.ts b/apps/api/src/modules/sources/sources.service.ts
index 1605a46..cb14c01 100644
--- a/apps/api/src/modules/sources/sources.service.ts
+++ b/apps/api/src/modules/sources/sources.service.ts
@@ -12,11 +12,11 @@ import { prisma } from "../../db/prisma.js";
import { findImportedRecipeIds } from "../../db/recipe-source-sync.js";
import {
type IngredientMatchEntry,
- type UnitMatchEntry,
loadIngredientCatalog,
loadUnitCatalog,
+ type UnitMatchEntry,
} from "../../lib/ingredient-matcher.js";
-import { type RecipeSourceAdapter, markAlreadyImported } from "../../lib/recipe-source-adapter.js";
+import { markAlreadyImported, type RecipeSourceAdapter } from "../../lib/recipe-source-adapter.js";
import { RecipeSourceError } from "../../lib/recipe-source-errors.js";
import { getRecipeSource } from "../../lib/recipe-source-registry.js";
import {
diff --git a/apps/api/test/ingredient-matcher.test.ts b/apps/api/test/ingredient-matcher.test.ts
index 072d0fc..1114001 100644
--- a/apps/api/test/ingredient-matcher.test.ts
+++ b/apps/api/test/ingredient-matcher.test.ts
@@ -2,13 +2,13 @@ import { INGREDIENT_LABEL_SYNONYMS_EN } from "@batch-cooking/shared";
import { expect } from "chai";
import { prisma } from "../src/db/prisma.js";
import {
- type IngredientMatchEntry,
- type UnitMatchEntry,
extractQuantity,
+ type IngredientMatchEntry,
loadIngredientCatalog,
loadUnitCatalog,
matchIngredientName,
matchUnit,
+ type UnitMatchEntry,
} from "../src/lib/ingredient-matcher.js";
import { resetDatabase } from "../test-support/reset-db.js";
diff --git a/apps/api/test/recipe-translation.test.ts b/apps/api/test/recipe-translation.test.ts
index f3d3ffd..6dbebc2 100644
--- a/apps/api/test/recipe-translation.test.ts
+++ b/apps/api/test/recipe-translation.test.ts
@@ -3,12 +3,12 @@ import { prisma } from "../src/db/prisma.js";
import type { IngredientMatchEntry, UnitMatchEntry } from "../src/lib/ingredient-matcher.js";
import type { ParsedRecipe, ParsedRecipeIngredient } from "../src/lib/recipe-source-adapter.js";
import {
- type TranslatedRecipeIngredient,
- type UnitConversionEntry,
mergeDuplicateIngredients,
+ type TranslatedRecipeIngredient,
translateRecipe,
translateRecipeIngredients,
translateRecipeSteps,
+ type UnitConversionEntry,
} from "../src/lib/recipe-translation.js";
import type { TechStepMappingRule } from "../src/lib/tech-step-matcher.js";
import { resetDatabase } from "../test-support/reset-db.js";
diff --git a/apps/api/test/recipe.test.ts b/apps/api/test/recipe.test.ts
index c78c3f5..90ffd67 100644
--- a/apps/api/test/recipe.test.ts
+++ b/apps/api/test/recipe.test.ts
@@ -773,8 +773,8 @@ describe("Recipes", () => {
const tomate = await ingredientId("tomato");
const piece = await unitId("piece");
const chop = await techStepId("chop");
- const mince = await techStepId("mince");
- const melt = await techStepId("melt");
+ const _mince = await techStepId("mince");
+ const _melt = await techStepId("melt");
const simmer = await techStepId("simmer");
const bake = await techStepId("bake");
@@ -886,7 +886,7 @@ describe("Recipes", () => {
});
it("rejects an edit from anyone other than the recipe's author with 403 NOT_RECIPE_AUTHOR", async () => {
- const { agent, profileId } = await signup();
+ const { profileId } = await signup();
const { agent: otherAgent } = await signup();
const tomate = await ingredientId("tomato");
const piece = await unitId("piece");
diff --git a/apps/api/test/tech-step-matcher.test.ts b/apps/api/test/tech-step-matcher.test.ts
index 624f148..8646b2a 100644
--- a/apps/api/test/tech-step-matcher.test.ts
+++ b/apps/api/test/tech-step-matcher.test.ts
@@ -1,11 +1,11 @@
import { expect } from "chai";
import { prisma } from "../src/db/prisma.js";
import {
- type TechStepMappingRule,
loadTechStepMappingRules,
matchTechStepSpans,
matchTechSteps,
normalizeText,
+ type TechStepMappingRule,
} from "../src/lib/tech-step-matcher.js";
import { resetDatabase } from "../test-support/reset-db.js";
diff --git a/apps/web/cypress/e2e/recipes.cy.ts b/apps/web/cypress/e2e/recipes.cy.ts
index da874e1..a3190df 100644
--- a/apps/web/cypress/e2e/recipes.cy.ts
+++ b/apps/web/cypress/e2e/recipes.cy.ts
@@ -16,7 +16,7 @@ const authenticatedProfile = {
};
const vegetarien = { id: 1, key: "vegetarian" };
-const gluten = { id: 1, key: "gluten", kind: "INTOLERANCE" };
+const _gluten = { id: 1, key: "gluten", kind: "INTOLERANCE" };
const oeufs = { id: 2, key: "eggs", kind: "ALLERGY" };
const ratatouille = {
diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
index 88911dd..b5c7695 100644
--- a/apps/web/src/App.tsx
+++ b/apps/web/src/App.tsx
@@ -4,15 +4,15 @@ import { RequireAuth } from "./features/auth/RequireAuth";
import { AppLayout } from "./layouts/AppLayout";
import { ImportRecipePage } from "./pages/ImportRecipePage";
import { LoginPage } from "./pages/LoginPage";
+import { OnboardingAllergensPage } from "./pages/onboarding/OnboardingAllergensPage";
+import { OnboardingDietPage } from "./pages/onboarding/OnboardingDietPage";
+import { OnboardingHouseholdPage } from "./pages/onboarding/OnboardingHouseholdPage";
+import { OnboardingSourcesPage } from "./pages/onboarding/OnboardingSourcesPage";
import { PlanningPage } from "./pages/PlanningPage";
import { RecipeFormPage } from "./pages/RecipeFormPage";
import { RecipesPage } from "./pages/RecipesPage";
import { ShoppingListPage } from "./pages/ShoppingListPage";
import { SignupPage } from "./pages/SignupPage";
-import { OnboardingAllergensPage } from "./pages/onboarding/OnboardingAllergensPage";
-import { OnboardingDietPage } from "./pages/onboarding/OnboardingDietPage";
-import { OnboardingHouseholdPage } from "./pages/onboarding/OnboardingHouseholdPage";
-import { OnboardingSourcesPage } from "./pages/onboarding/OnboardingSourcesPage";
import { AccountSettingsPage } from "./pages/settings/AccountSettingsPage";
import { CreditsPage } from "./pages/settings/CreditsPage";
import { HouseholdSettingsPage } from "./pages/settings/HouseholdSettingsPage";
diff --git a/apps/web/src/components/ui/Tooltip.tsx b/apps/web/src/components/ui/Tooltip.tsx
index c323850..2db91c7 100644
--- a/apps/web/src/components/ui/Tooltip.tsx
+++ b/apps/web/src/components/ui/Tooltip.tsx
@@ -1,4 +1,4 @@
-import { type ReactElement, cloneElement, useId } from "react";
+import { cloneElement, type ReactElement, useId } from "react";
import "./tooltip.scss";
/**
diff --git a/apps/web/src/features/auth/AuthContext.tsx b/apps/web/src/features/auth/AuthContext.tsx
index 1a8b58a..a89c1d6 100644
--- a/apps/web/src/features/auth/AuthContext.tsx
+++ b/apps/web/src/features/auth/AuthContext.tsx
@@ -1,5 +1,5 @@
import type { LoginInput, SafeUserProfile, SignupInput } from "@batch-cooking/shared";
-import { type ReactNode, createContext, useCallback, useContext, useEffect, useState } from "react";
+import { createContext, type ReactNode, useCallback, useContext, useEffect, useState } from "react";
import { apiClient } from "../../api/client";
/** Shape of the auth state/actions exposed via {@link useAuth}. */
diff --git a/apps/web/src/features/planning/RecipePickerDialog.tsx b/apps/web/src/features/planning/RecipePickerDialog.tsx
index 1f6cb9f..7cfcb3c 100644
--- a/apps/web/src/features/planning/RecipePickerDialog.tsx
+++ b/apps/web/src/features/planning/RecipePickerDialog.tsx
@@ -22,10 +22,10 @@ import { RecipeImportForm } from "../recipes/RecipeImportForm";
import { RecipeSourcesPanel, type SourceItemSelection } from "../recipes/RecipeSourcesPanel";
import { RecipeTable } from "../recipes/RecipeTable";
import {
- RecipeTabs,
- type RecipesPageTab,
isSourceTab,
parseSourceTabValue,
+ type RecipesPageTab,
+ RecipeTabs,
} from "../recipes/RecipeTabs";
import { tryBuildCompleteImport } from "../recipes/recipe-import-draft";
import { useEnabledSources } from "../recipes/useEnabledSources";
@@ -313,7 +313,7 @@ export function RecipePickerDialog({
// for the identical failure — see this dialog's `onImported` handler
// below).
setIsConfirmingDraft(false);
- navigate(`/recettes/${saved.id}`);
+ void navigate(`/recettes/${saved.id}`);
}
}
@@ -361,7 +361,7 @@ export function RecipePickerDialog({
// to this slot failed. Same fallback as the transparent-
// import path above: land on its own page instead of
// retrying.
- navigate(`/recettes/${recipe.id}`);
+ void navigate(`/recettes/${recipe.id}`);
}
}}
/>
diff --git a/apps/web/src/features/recipes/IngredientPicker.tsx b/apps/web/src/features/recipes/IngredientPicker.tsx
index 20ac680..b12450e 100644
--- a/apps/web/src/features/recipes/IngredientPicker.tsx
+++ b/apps/web/src/features/recipes/IngredientPicker.tsx
@@ -11,8 +11,8 @@ import { CheckboxOption } from "../../components/ui/Checkbox";
import { SettingsIcon } from "../../layouts/nav-icons";
import { AllergenBadges } from "./AllergenBadges";
import { DietBadges } from "./DietBadges";
-import { ReproducibleBadge } from "./ReproducibleBadge";
import { CategoryIcon, IngredientTypeIcon, SubcategoryIcon } from "./ingredient-icons";
+import { ReproducibleBadge } from "./ReproducibleBadge";
import "./recipes.scss";
/** "No filter at this level" — a UI-only pseudo-value, never sent to/received from the API (see {@link INGREDIENT_CATEGORIES}/{@link INGREDIENT_CATEGORY_SUBCATEGORIES} for the real, closed sets). */
diff --git a/apps/web/src/features/recipes/IngredientRow.tsx b/apps/web/src/features/recipes/IngredientRow.tsx
index ea2c360..d73e752 100644
--- a/apps/web/src/features/recipes/IngredientRow.tsx
+++ b/apps/web/src/features/recipes/IngredientRow.tsx
@@ -2,8 +2,8 @@ import type { IngredientView, UnitView } from "@batch-cooking/shared";
import { useTranslation } from "react-i18next";
import { AllergenBadges } from "./AllergenBadges";
import { DietBadges } from "./DietBadges";
-import { ReproducibleBadge } from "./ReproducibleBadge";
import { IngredientTypeIcon } from "./ingredient-icons";
+import { ReproducibleBadge } from "./ReproducibleBadge";
import "./recipes.scss";
/** One selected ingredient line in the recipe form — the ingredient itself (picked via `IngredientPicker`) plus its quantity/unit for this recipe. Quantity is kept as a raw string while editing (not parsed to a number until submit) so an in-progress/invalid value doesn't fight the input; `unit` picks from `unitsCatalog` (a closed reference list, see `Unit` in schema.prisma) rather than free text. */
diff --git a/apps/web/src/features/recipes/RecipeDetailPanel.tsx b/apps/web/src/features/recipes/RecipeDetailPanel.tsx
index d5c6ceb..2f3da78 100644
--- a/apps/web/src/features/recipes/RecipeDetailPanel.tsx
+++ b/apps/web/src/features/recipes/RecipeDetailPanel.tsx
@@ -135,6 +135,7 @@ export function RecipeDetailPanel({
{t("recipes.stepsTitle")}
{draft.steps.map((step, index) => (
+ // biome-ignore lint/suspicious/noArrayIndexKey: DraftRecipeStepView (packages/shared) has no id — it's an unsaved source preview, nothing to key on yet — and this list is a static read-only render, never reordered/edited here.
-
{step.picture &&
}
@@ -218,13 +219,7 @@ export function RecipeDetailPanel({
}
/** Delete action with an inline two-step confirmation, same pattern as `HouseholdSettingsPage`'s danger zone. */
-function DeleteRecipeButton({
- recipeId,
- onDeleted,
-}: {
- recipeId: number;
- onDeleted: () => void;
-}) {
+function DeleteRecipeButton({ recipeId, onDeleted }: { recipeId: number; onDeleted: () => void }) {
const { t } = useTranslation();
const [isConfirming, setIsConfirming] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
diff --git a/apps/web/src/features/recipes/RecipeImportForm.tsx b/apps/web/src/features/recipes/RecipeImportForm.tsx
index e92252b..0202249 100644
--- a/apps/web/src/features/recipes/RecipeImportForm.tsx
+++ b/apps/web/src/features/recipes/RecipeImportForm.tsx
@@ -1,5 +1,6 @@
import {
type CreateRecipeInput,
+ createRecipeSchema,
type DietView,
ErrorCode,
type IngredientView,
@@ -9,7 +10,6 @@ import {
type RecipeVisibility,
type UnitView,
type WeekDay,
- createRecipeSchema,
} from "@batch-cooking/shared";
import { type FormEvent, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
diff --git a/apps/web/src/features/recipes/recipe-import-draft.ts b/apps/web/src/features/recipes/recipe-import-draft.ts
index ebdbff9..29a5bef 100644
--- a/apps/web/src/features/recipes/recipe-import-draft.ts
+++ b/apps/web/src/features/recipes/recipe-import-draft.ts
@@ -1,7 +1,7 @@
import {
type CreateRecipeInput,
- type RecipeImportDraftView,
createRecipeSchema,
+ type RecipeImportDraftView,
} from "@batch-cooking/shared";
/**
diff --git a/apps/web/src/features/theme/ThemeContext.tsx b/apps/web/src/features/theme/ThemeContext.tsx
index f8c1021..8a31aec 100644
--- a/apps/web/src/features/theme/ThemeContext.tsx
+++ b/apps/web/src/features/theme/ThemeContext.tsx
@@ -1,5 +1,5 @@
import type { ThemePreference } from "@batch-cooking/shared";
-import { type ReactNode, createContext, useCallback, useContext, useEffect, useState } from "react";
+import { createContext, type ReactNode, useCallback, useContext, useEffect, useState } from "react";
import { apiClient } from "../../api/client";
import { useAuth } from "../auth/AuthContext";
diff --git a/apps/web/src/layouts/AppLayout.tsx b/apps/web/src/layouts/AppLayout.tsx
index e3aef78..a02a536 100644
--- a/apps/web/src/layouts/AppLayout.tsx
+++ b/apps/web/src/layouts/AppLayout.tsx
@@ -195,7 +195,7 @@ function AccountMenu() {
async function handleLogout() {
setIsOpen(false);
await logout();
- navigate("/login");
+ void navigate("/login");
}
const initial = user?.firstName?.charAt(0).toUpperCase() ?? "";
diff --git a/apps/web/src/layouts/nav-icons.tsx b/apps/web/src/layouts/nav-icons.tsx
index a698dfa..dbfb6fb 100644
--- a/apps/web/src/layouts/nav-icons.tsx
+++ b/apps/web/src/layouts/nav-icons.tsx
@@ -13,18 +13,18 @@
// every consumer passes `aria-hidden="true"` itself (unlike the old custom
// `Icon` wrapper, lucide doesn't set this by default).
export {
- Calendar as PlanningIcon,
BookOpen as RecipesIcon,
- ShoppingCart as ShoppingListIcon,
- Settings as SettingsIcon,
- User as AccountIcon,
- Leaf as DietPreferencesIcon,
- Home as HouseholdIcon,
- Palette as UserPreferencesIcon,
- Info as CreditsIcon,
+ Calendar as PlanningIcon,
ChevronLeft as ChevronLeftIcon,
- Star as FavoriteIcon,
- Globe as PublicIcon,
- Rss as SourcesIcon,
ExternalLink as SourceLinkIcon,
+ Globe as PublicIcon,
+ Home as HouseholdIcon,
+ Info as CreditsIcon,
+ Leaf as DietPreferencesIcon,
+ Palette as UserPreferencesIcon,
+ Rss as SourcesIcon,
+ Settings as SettingsIcon,
+ ShoppingCart as ShoppingListIcon,
+ Star as FavoriteIcon,
+ User as AccountIcon,
} from "lucide-react";
diff --git a/apps/web/src/pages/ImportRecipePage.tsx b/apps/web/src/pages/ImportRecipePage.tsx
index 24234de..6314c9c 100644
--- a/apps/web/src/pages/ImportRecipePage.tsx
+++ b/apps/web/src/pages/ImportRecipePage.tsx
@@ -72,7 +72,7 @@ export function ImportRecipePage() {
externalId={externalId}
planningSlot={planningSlot ?? undefined}
onImported={({ recipe, planningItem }) => {
- navigate(planningItem ? "/" : `/recettes/${recipe.id}`);
+ void navigate(planningItem ? "/" : `/recettes/${recipe.id}`);
}}
/>
diff --git a/apps/web/src/pages/LoginPage.tsx b/apps/web/src/pages/LoginPage.tsx
index 98a931b..8961f6e 100644
--- a/apps/web/src/pages/LoginPage.tsx
+++ b/apps/web/src/pages/LoginPage.tsx
@@ -50,7 +50,7 @@ export function LoginPage() {
setIsSubmitting(true);
try {
await login(result.data);
- navigate("/");
+ void navigate("/");
} catch (err) {
// ApiError.code is looked up through ErrorMessageService so the
// label is centralized and localized — never display err.message
diff --git a/apps/web/src/pages/PlanningPage.tsx b/apps/web/src/pages/PlanningPage.tsx
index 0771e23..e9e082e 100644
--- a/apps/web/src/pages/PlanningPage.tsx
+++ b/apps/web/src/pages/PlanningPage.tsx
@@ -1,7 +1,7 @@
import {
- DateTime,
addWeeks,
buildCalendarMonth,
+ DateTime,
formatDateOnly,
getWeekStart,
toDateOnly,
diff --git a/apps/web/src/pages/RecipeFormPage.tsx b/apps/web/src/pages/RecipeFormPage.tsx
index fd0fab9..66de3cd 100644
--- a/apps/web/src/pages/RecipeFormPage.tsx
+++ b/apps/web/src/pages/RecipeFormPage.tsx
@@ -1,11 +1,11 @@
import {
type CreateRecipeInput,
+ createRecipeSchema,
type DietView,
ErrorCode,
type IngredientView,
type RecipeVisibility,
type UnitView,
- createRecipeSchema,
} from "@batch-cooking/shared";
import { type FormEvent, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -196,7 +196,7 @@ export function RecipeFormPage() {
recipeId !== null
? await apiClient.updateRecipe(recipeId, result.data)
: await apiClient.createRecipe(result.data);
- navigate(`/recettes/${saved.id}`);
+ void navigate(`/recettes/${saved.id}`);
} catch (err) {
const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
setFormError(errorMessageService.getLabel(code));
diff --git a/apps/web/src/pages/RecipesPage.tsx b/apps/web/src/pages/RecipesPage.tsx
index c7ac2fa..7d963b2 100644
--- a/apps/web/src/pages/RecipesPage.tsx
+++ b/apps/web/src/pages/RecipesPage.tsx
@@ -10,10 +10,10 @@ import {
} from "../features/recipes/RecipeSourcesPanel";
import { RecipeTable } from "../features/recipes/RecipeTable";
import {
- RecipeTabs,
- type RecipesPageTab,
isSourceTab,
parseSourceTabValue,
+ type RecipesPageTab,
+ RecipeTabs,
sourceTabValue,
} from "../features/recipes/RecipeTabs";
import { useEnabledSources } from "../features/recipes/useEnabledSources";
@@ -164,7 +164,7 @@ export function RecipesPage() {
/** After a delete, the removed recipe can no longer be selected, and the table must drop it too. */
function handleDeleted(recipeId: number) {
- navigate("/recettes");
+ void navigate("/recettes");
setListState((prev) =>
prev.status === "loaded"
? { status: "loaded", recipes: prev.recipes.filter((r) => r.id !== recipeId) }
@@ -219,7 +219,7 @@ export function RecipesPage() {
}
onSelectImportedRecipe={(recipe) => {
setActiveTab("favoris");
- navigate(`/recettes/${recipe.id}`);
+ void navigate(`/recettes/${recipe.id}`);
}}
/>
) : (
diff --git a/apps/web/src/pages/SignupPage.tsx b/apps/web/src/pages/SignupPage.tsx
index 6776e88..8c481db 100644
--- a/apps/web/src/pages/SignupPage.tsx
+++ b/apps/web/src/pages/SignupPage.tsx
@@ -52,7 +52,7 @@ export function SignupPage() {
setIsSubmitting(true);
try {
await signup(result.data);
- navigate("/onboarding/regime");
+ void navigate("/onboarding/regime");
} catch (err) {
// ApiError.code is looked up through ErrorMessageService so the
// label is centralized and localized — never display err.message
diff --git a/apps/web/src/pages/onboarding/OnboardingAllergensPage.tsx b/apps/web/src/pages/onboarding/OnboardingAllergensPage.tsx
index 7c5868b..6052d9f 100644
--- a/apps/web/src/pages/onboarding/OnboardingAllergensPage.tsx
+++ b/apps/web/src/pages/onboarding/OnboardingAllergensPage.tsx
@@ -42,6 +42,14 @@ export function OnboardingAllergensPage() {
setAllergies(allergiesResult);
setTotalSteps(house !== null ? 4 : 3);
})
+ .catch(() => {
+ // Neither piece is essential for this last step to render — the
+ // allergy list just stays empty (nothing to pick from) and the
+ // step count keeps its 3-of-3 default, same "don't strand the
+ // visitor over a transient failure" reasoning as
+ // OnboardingSourcesPage's own catch, just with nothing to
+ // navigate away to since this already is the last step.
+ })
.finally(() => {
if (!cancelled) setIsLoading(false);
});
@@ -57,7 +65,7 @@ export function OnboardingAllergensPage() {
setIsSubmitting(true);
try {
await apiClient.updateAllergyIds(allergyIds);
- navigate("/");
+ void navigate("/");
} catch (err) {
const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
setFormError(errorMessageService.getLabel(code));
diff --git a/apps/web/src/pages/onboarding/OnboardingDietPage.tsx b/apps/web/src/pages/onboarding/OnboardingDietPage.tsx
index 2e92117..e4ca7b8 100644
--- a/apps/web/src/pages/onboarding/OnboardingDietPage.tsx
+++ b/apps/web/src/pages/onboarding/OnboardingDietPage.tsx
@@ -34,6 +34,11 @@ export function OnboardingDietPage() {
.then((result) => {
if (!cancelled) setDiets(result);
})
+ // Not essential for this step to render — the diet list just stays
+ // empty (nothing to pick, "Aucun régime particulier" still works)
+ // rather than stranding the visitor over a transient failure, same
+ // reasoning as OnboardingSourcesPage's own catch.
+ .catch(() => {})
.finally(() => {
if (!cancelled) setIsLoading(false);
});
@@ -48,7 +53,7 @@ export function OnboardingDietPage() {
setIsSubmitting(true);
try {
await apiClient.updateDiet(dietId);
- navigate("/onboarding/foyer");
+ void navigate("/onboarding/foyer");
} catch (err) {
const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
setFormError(errorMessageService.getLabel(code));
diff --git a/apps/web/src/pages/onboarding/OnboardingHouseholdPage.tsx b/apps/web/src/pages/onboarding/OnboardingHouseholdPage.tsx
index 3d1a2d0..a332fdf 100644
--- a/apps/web/src/pages/onboarding/OnboardingHouseholdPage.tsx
+++ b/apps/web/src/pages/onboarding/OnboardingHouseholdPage.tsx
@@ -36,6 +36,11 @@ export function OnboardingHouseholdPage() {
.then((result) => {
if (!cancelled) setHouse(result);
})
+ // Not essential for this step to render — `house` just stays `null`
+ // (same as a genuinely household-less profile) rather than
+ // stranding the visitor over a transient failure, same reasoning as
+ // OnboardingSourcesPage's own catch.
+ .catch(() => {})
.finally(() => {
if (!cancelled) setIsLoading(false);
});
@@ -51,7 +56,7 @@ export function OnboardingHouseholdPage() {
* configure sources for without a household).
*/
function goToNextStep(hasHousehold: boolean) {
- navigate(hasHousehold ? "/onboarding/sources" : "/onboarding/allergenes");
+ void navigate(hasHousehold ? "/onboarding/sources" : "/onboarding/allergenes");
}
return (
diff --git a/apps/web/src/pages/onboarding/OnboardingSourcesPage.tsx b/apps/web/src/pages/onboarding/OnboardingSourcesPage.tsx
index 68f7cd3..973a4f8 100644
--- a/apps/web/src/pages/onboarding/OnboardingSourcesPage.tsx
+++ b/apps/web/src/pages/onboarding/OnboardingSourcesPage.tsx
@@ -40,7 +40,7 @@ export function OnboardingSourcesPage() {
.then((result) => {
if (cancelled) return;
if (result.length === 0) {
- navigate("/onboarding/allergenes", { replace: true });
+ void navigate("/onboarding/allergenes", { replace: true });
return;
}
setSources(result);
@@ -50,7 +50,7 @@ export function OnboardingSourcesPage() {
// Nothing to configure sources for if we can't even list them — the
// wizard shouldn't strand the visitor here over a transient failure
// fetching an optional step's own data.
- if (!cancelled) navigate("/onboarding/allergenes", { replace: true });
+ if (!cancelled) void navigate("/onboarding/allergenes", { replace: true });
});
return () => {
cancelled = true;
@@ -63,7 +63,7 @@ export function OnboardingSourcesPage() {
setIsSubmitting(true);
try {
await apiClient.updateHouseSourceIds(sourceIds);
- navigate("/onboarding/allergenes");
+ void navigate("/onboarding/allergenes");
} catch (err) {
const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
setFormError(errorMessageService.getLabel(code));
diff --git a/apps/web/src/pages/settings/AccountSettingsPage.tsx b/apps/web/src/pages/settings/AccountSettingsPage.tsx
index 3bd7517..b00b084 100644
--- a/apps/web/src/pages/settings/AccountSettingsPage.tsx
+++ b/apps/web/src/pages/settings/AccountSettingsPage.tsx
@@ -30,7 +30,7 @@ export function AccountSettingsPage() {
setIsSubmitting(true);
try {
await deleteAccount(password);
- navigate("/login");
+ void navigate("/login");
} catch (err) {
const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
setError(errorMessageService.getLabel(code));
diff --git a/apps/web/src/pages/settings/HouseholdSettingsPage.tsx b/apps/web/src/pages/settings/HouseholdSettingsPage.tsx
index 38b07ba..62f75df 100644
--- a/apps/web/src/pages/settings/HouseholdSettingsPage.tsx
+++ b/apps/web/src/pages/settings/HouseholdSettingsPage.tsx
@@ -1,10 +1,10 @@
import {
ErrorCode,
type HouseView,
- type SourceView,
renameHouseSchema,
+ type SourceView,
} from "@batch-cooking/shared";
-import { type FormEvent, useEffect, useRef, useState } from "react";
+import { type FormEvent, useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { ApiError, apiClient } from "../../api/client";
import { useAuth } from "../../features/auth/AuthContext";
@@ -48,11 +48,15 @@ export function HouseholdSettingsPage() {
const [loadError, setLoadError] = useState(false);
const [house, setHouse] = useState(null);
- useEffect(() => {
- loadHouse();
- }, []);
-
- function loadHouse() {
+ // Stable across renders (empty deps — only closes over setters, which
+ // React itself guarantees are stable) so the effect below only re-runs on
+ // mount, not on every render. It used to be a plain function declaration,
+ // a fresh reference every render — its `useEffect` dependency on it then
+ // re-triggered the effect (and thus the fetch, and thus a state update,
+ // and thus another render...) forever. `loadHouse` is also handed to
+ // `NoHousehold`/`HasHousehold` below as their `onChanged` callback, so it
+ // has to stay this stable regardless of the effect.
+ const loadHouse = useCallback(() => {
setIsLoading(true);
setLoadError(false);
return apiClient
@@ -60,7 +64,11 @@ export function HouseholdSettingsPage() {
.then((result) => setHouse(result))
.catch(() => setLoadError(true))
.finally(() => setIsLoading(false));
- }
+ }, []);
+
+ useEffect(() => {
+ void loadHouse();
+ }, [loadHouse]);
if (isLoading) {
return (
@@ -300,6 +308,11 @@ function SourcesSection() {
setSources(sourcesResult);
setSourceIds(sourceIdsResult);
})
+ // Not essential for the rest of the page to render — the sources
+ // list just stays empty (nothing to toggle) rather than stranding
+ // the visitor over a transient failure, same reasoning as
+ // OnboardingSourcesPage's own catch.
+ .catch(() => {})
.finally(() => {
if (!cancelled) setIsLoading(false);
});
@@ -368,13 +381,7 @@ function InviteCode({ code }: { code: string }) {
}
/** Admin-only button removing one specific member from the household. */
-function RemoveMemberButton({
- memberId,
- onChanged,
-}: {
- memberId: number;
- onChanged: () => void;
-}) {
+function RemoveMemberButton({ memberId, onChanged }: { memberId: number; onChanged: () => void }) {
const { t } = useTranslation();
const [isRemoving, setIsRemoving] = useState(false);
diff --git a/biome.json b/biome.json
index 8b9953f..5d95335 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.5.9/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
@@ -7,13 +7,14 @@
},
"files": {
"ignoreUnknown": false,
- "ignore": [
- "dist",
- "coverage",
- "**/node_modules",
- ".pnpm-store",
- "cypress/videos",
- "cypress/screenshots"
+ "includes": [
+ "**",
+ "!**/dist",
+ "!**/coverage",
+ "!**/node_modules",
+ "!**/.pnpm-store",
+ "!**/cypress/videos",
+ "!**/cypress/screenshots"
]
},
"formatter": {
@@ -22,13 +23,21 @@
"indentWidth": 2,
"lineWidth": 100
},
- "organizeImports": {
- "enabled": true
- },
+ "assist": { "actions": { "source": { "organizeImports": "on" } } },
"linter": {
"enabled": true,
"rules": {
- "recommended": true
+ "preset": "recommended",
+ "nursery": {
+ "noFloatingPromises": "error"
+ },
+ "suspicious": {
+ "noConsole": {
+ "level": "error",
+ "options": { "allow": ["error", "warn", "info", "debug", "table", "assert"] }
+ },
+ "noExplicitAny": "error"
+ }
}
},
"javascript": {
diff --git a/package.json b/package.json
index b8a073d..c3bca94 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"dev:web": "pnpm --filter web dev"
},
"devDependencies": {
- "@biomejs/biome": "^1.9.4",
+ "@biomejs/biome": "^2.5.9",
"typescript": "^5.7.2"
},
"pnpm": {
diff --git a/packages/date-tools/src/index.ts b/packages/date-tools/src/index.ts
index be425aa..f0b064a 100644
--- a/packages/date-tools/src/index.ts
+++ b/packages/date-tools/src/index.ts
@@ -4,9 +4,8 @@
// this package rather than hand-rolled `Date` arithmetic or a second,
// differently-behaved date library creeping into one side only.
-export * from "./date-only.js";
-export * from "./week.js";
-
// Re-exported so a consumer never needs its own direct `luxon` dependency
// just to type a `DateTime` value passed to/from this package's functions.
export { DateTime } from "luxon";
+export * from "./date-only.js";
+export * from "./week.js";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7560769..c06548d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
devDependencies:
'@biomejs/biome':
- specifier: ^1.9.4
- version: 1.9.4
+ specifier: ^2.5.9
+ version: 2.5.9
typescript:
specifier: ^5.7.2
version: 5.9.3
@@ -347,55 +347,55 @@ packages:
peerDependencies:
esbuild: '>=0.17.0'
- '@biomejs/biome@1.9.4':
- resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==, tarball: https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.4.tgz}
+ '@biomejs/biome@2.5.9':
+ resolution: {integrity: sha512-KkgCvdHB4IhtpHpF564plA9jo6fDOwWGQ/3jvreLzgOtRLEDoPqr7QO9qejNA8jKwDsSkAKr77hqBHnyUbIw4g==, tarball: https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.9.tgz}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@1.9.4':
- resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.4.tgz}
+ '@biomejs/cli-darwin-arm64@2.5.9':
+ resolution: {integrity: sha512-am22pX2aBqznqq1eMyIj/bZ++riF3Lk6ct7cbv+gQK0csFhr+d8O0RkOi2FF2qSgFgANbqNkIZ0/PxlnW2pLFg==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@1.9.4':
- resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.4.tgz}
+ '@biomejs/cli-darwin-x64@2.5.9':
+ resolution: {integrity: sha512-l44KWDHLDvEnD0N/XcrVs7VXb3A18xL7QS3WB0eL93wbmk529ffIG55vleGCqaunpRUjLrdnjK05Qki1dsjylg==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@1.9.4':
- resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.4.tgz}
+ '@biomejs/cli-linux-arm64-musl@2.5.9':
+ resolution: {integrity: sha512-7ImVPwBLCtkmpR5esd8RHhTqW94f0JLJQum6AneYcy94jRm18TaPPm7slaigGzFhfgt3QiD1Vj52LKmBAnKizA==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@1.9.4':
- resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.4.tgz}
+ '@biomejs/cli-linux-arm64@2.5.9':
+ resolution: {integrity: sha512-ICaK+IYaVZvKbBxX2rwrPT0DdUDMnE9Vm3nQGe+mltQPmUg19pONzkPWGdY4FCsoreDETWDynvdt4ysCbF5gNQ==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@1.9.4':
- resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.4.tgz}
+ '@biomejs/cli-linux-x64-musl@2.5.9':
+ resolution: {integrity: sha512-RXGaD0o1/pTTguYw1aeDJh9ad6Lfrui0fI7mBderTyGr7WuUJkBIttgLkR3XJyoxOkkgfBDspaUT8wXArTqLZw==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@1.9.4':
- resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.4.tgz}
+ '@biomejs/cli-linux-x64@2.5.9':
+ resolution: {integrity: sha512-z22Q/zFYSvbIJfW1CbfZPu4X8PddS6Qd2ORbc6h+aT6EcwAxUF3m6fA4HjNvA3TU4X0dTJRwNPB165ES3PJXzg==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@1.9.4':
- resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.4.tgz}
+ '@biomejs/cli-win32-arm64@2.5.9':
+ resolution: {integrity: sha512-nHK+/HHC+D0ogAHUxomgoSTdjImb6fmNNVTKmf0tyu4eDL1DqPKIHc+i+UL8+b0RnAu8224qo8F2tCVnaT0A3w==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@1.9.4':
- resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.4.tgz}
+ '@biomejs/cli-win32-x64@2.5.9':
+ resolution: {integrity: sha512-Yiq0H56LjXSSw/hd9YkXgSLQfzyDJzbzU2TezozxyNw+uKWAqOtqGVvBfzKRRDiaFF5avGAhHdWKx7LtDOShUw==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.9.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -3963,39 +3963,39 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@biomejs/biome@1.9.4':
+ '@biomejs/biome@2.5.9':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 1.9.4
- '@biomejs/cli-darwin-x64': 1.9.4
- '@biomejs/cli-linux-arm64': 1.9.4
- '@biomejs/cli-linux-arm64-musl': 1.9.4
- '@biomejs/cli-linux-x64': 1.9.4
- '@biomejs/cli-linux-x64-musl': 1.9.4
- '@biomejs/cli-win32-arm64': 1.9.4
- '@biomejs/cli-win32-x64': 1.9.4
+ '@biomejs/cli-darwin-arm64': 2.5.9
+ '@biomejs/cli-darwin-x64': 2.5.9
+ '@biomejs/cli-linux-arm64': 2.5.9
+ '@biomejs/cli-linux-arm64-musl': 2.5.9
+ '@biomejs/cli-linux-x64': 2.5.9
+ '@biomejs/cli-linux-x64-musl': 2.5.9
+ '@biomejs/cli-win32-arm64': 2.5.9
+ '@biomejs/cli-win32-x64': 2.5.9
- '@biomejs/cli-darwin-arm64@1.9.4':
+ '@biomejs/cli-darwin-arm64@2.5.9':
optional: true
- '@biomejs/cli-darwin-x64@1.9.4':
+ '@biomejs/cli-darwin-x64@2.5.9':
optional: true
- '@biomejs/cli-linux-arm64-musl@1.9.4':
+ '@biomejs/cli-linux-arm64-musl@2.5.9':
optional: true
- '@biomejs/cli-linux-arm64@1.9.4':
+ '@biomejs/cli-linux-arm64@2.5.9':
optional: true
- '@biomejs/cli-linux-x64-musl@1.9.4':
+ '@biomejs/cli-linux-x64-musl@2.5.9':
optional: true
- '@biomejs/cli-linux-x64@1.9.4':
+ '@biomejs/cli-linux-x64@2.5.9':
optional: true
- '@biomejs/cli-win32-arm64@1.9.4':
+ '@biomejs/cli-win32-arm64@2.5.9':
optional: true
- '@biomejs/cli-win32-x64@1.9.4':
+ '@biomejs/cli-win32-x64@2.5.9':
optional: true
'@colors/colors@1.5.0':