refactor(api): regroupe lib/ par sous-domaine au lieu d'un dossier à plat
9 fichiers à plat -> recipe-sources/ (recipe-source-adapter, recipe-source- errors, recipe-source-registry) et recipe-matching/ (recipe-translation, ingredient-matcher, tech-step-matcher). jwt.ts, safe-profile.ts et logger.service.ts restent à la racine de lib/ (pas de sous-domaine partagé avec les autres). Chemins relatifs corrigés dans les fichiers déplacés (profondeur +1 vers db/) et chez tous leurs importeurs (modules/sources, modules/recipe, sources/*, db/recipe-source-sync.ts, 12 fichiers de test), doc mise à jour (specs/backend-architecture.md, specs/batch-cooking-architecture.md). Vérifié : tsc --noEmit, biome check, build complet, 303 tests API. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
ae80537b7c
commit
4db8e1369f
26 changed files with 89 additions and 47 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import type { PrismaClient } from "@prisma/client";
|
import type { PrismaClient } from "@prisma/client";
|
||||||
import { listRecipeSources } from "../lib/recipe-source-registry.js";
|
import { listRecipeSources } from "../lib/recipe-sources/recipe-source-registry.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upserts one `Source` row (schema.prisma) per adapter currently in
|
* Upserts one `Source` row (schema.prisma) per adapter currently in
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {
|
||||||
INGREDIENT_LABELS_EN,
|
INGREDIENT_LABELS_EN,
|
||||||
UNIT_LABELS_EN,
|
UNIT_LABELS_EN,
|
||||||
} from "@batch-cooking/shared";
|
} from "@batch-cooking/shared";
|
||||||
import { prisma } from "../db/prisma.js";
|
import { prisma } from "../../db/prisma.js";
|
||||||
import { normalizeText } from "./tech-step-matcher.js";
|
import { normalizeText } from "./tech-step-matcher.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import type { UnitType } from "@batch-cooking/shared";
|
import type { UnitType } from "@batch-cooking/shared";
|
||||||
|
import type {
|
||||||
|
ParsedRecipe,
|
||||||
|
ParsedRecipeIngredient,
|
||||||
|
ParsedRecipeStep,
|
||||||
|
} from "../recipe-sources/recipe-source-adapter.js";
|
||||||
import {
|
import {
|
||||||
extractQuantity,
|
extractQuantity,
|
||||||
type IngredientMatchEntry,
|
type IngredientMatchEntry,
|
||||||
|
|
@ -8,11 +13,6 @@ import {
|
||||||
matchUnit,
|
matchUnit,
|
||||||
type UnitMatchEntry,
|
type UnitMatchEntry,
|
||||||
} from "./ingredient-matcher.js";
|
} from "./ingredient-matcher.js";
|
||||||
import type {
|
|
||||||
ParsedRecipe,
|
|
||||||
ParsedRecipeIngredient,
|
|
||||||
ParsedRecipeStep,
|
|
||||||
} from "./recipe-source-adapter.js";
|
|
||||||
import {
|
import {
|
||||||
loadTechStepMappingRules,
|
loadTechStepMappingRules,
|
||||||
matchTechSteps,
|
matchTechSteps,
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { prisma } from "../db/prisma.js";
|
import { prisma } from "../../db/prisma.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-detects which cooking techniques (`TechStep`) a free-text recipe
|
* Auto-detects which cooking techniques (`TechStep`) a free-text recipe
|
||||||
|
|
@ -14,7 +14,10 @@ import {
|
||||||
} from "@batch-cooking/shared";
|
} from "@batch-cooking/shared";
|
||||||
import type { Prisma } from "@prisma/client";
|
import type { Prisma } from "@prisma/client";
|
||||||
import { prisma } from "../../db/prisma.js";
|
import { prisma } from "../../db/prisma.js";
|
||||||
import { loadTechStepMappingRules, matchTechStepSpans } from "../../lib/tech-step-matcher.js";
|
import {
|
||||||
|
loadTechStepMappingRules,
|
||||||
|
matchTechStepSpans,
|
||||||
|
} from "../../lib/recipe-matching/tech-step-matcher.js";
|
||||||
|
|
||||||
// No user-language preference exists anywhere in the app yet (a single
|
// No user-language preference exists anywhere in the app yet (a single
|
||||||
// "fr" translation file, no locale field on User/UserProfile) — steps are
|
// "fr" translation file, no locale field on User/UserProfile) — steps are
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,21 @@ import {
|
||||||
loadIngredientCatalog,
|
loadIngredientCatalog,
|
||||||
loadUnitCatalog,
|
loadUnitCatalog,
|
||||||
type UnitMatchEntry,
|
type UnitMatchEntry,
|
||||||
} from "../../lib/ingredient-matcher.js";
|
} from "../../lib/recipe-matching/ingredient-matcher.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 {
|
import {
|
||||||
mergeDuplicateIngredients,
|
mergeDuplicateIngredients,
|
||||||
translateRecipeIngredients,
|
translateRecipeIngredients,
|
||||||
} from "../../lib/recipe-translation.js";
|
} from "../../lib/recipe-matching/recipe-translation.js";
|
||||||
import { loadTechStepMappingRules, matchTechStepSpans } from "../../lib/tech-step-matcher.js";
|
import {
|
||||||
|
loadTechStepMappingRules,
|
||||||
|
matchTechStepSpans,
|
||||||
|
} from "../../lib/recipe-matching/tech-step-matcher.js";
|
||||||
|
import {
|
||||||
|
markAlreadyImported,
|
||||||
|
type RecipeSourceAdapter,
|
||||||
|
} from "../../lib/recipe-sources/recipe-source-adapter.js";
|
||||||
|
import { RecipeSourceError } from "../../lib/recipe-sources/recipe-source-errors.js";
|
||||||
|
import { getRecipeSource } from "../../lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { getHouseSourceIds } from "../house/house.service.js";
|
import { getHouseSourceIds } from "../house/house.service.js";
|
||||||
import { createImportedRecipe } from "../recipe/recipe.service.js";
|
import { createImportedRecipe } from "../recipe/recipe.service.js";
|
||||||
import { getIngredients, getUnits } from "../reference/reference.service.js";
|
import { getIngredients, getUnits } from "../reference/reference.service.js";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { registerRecipeSource } from "../lib/recipe-source-registry.js";
|
import { registerRecipeSource } from "../lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { theMealDbAdapter } from "./the-meal-db.js";
|
import { theMealDbAdapter } from "./the-meal-db.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ import type {
|
||||||
ParsedRecipe,
|
ParsedRecipe,
|
||||||
ParsedRecipeIngredient,
|
ParsedRecipeIngredient,
|
||||||
RecipeSourceAdapter,
|
RecipeSourceAdapter,
|
||||||
} from "../lib/recipe-source-adapter.js";
|
} from "../lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { RecipeSourceFetchError, RecipeSourceParseError } from "../lib/recipe-source-errors.js";
|
import {
|
||||||
|
RecipeSourceFetchError,
|
||||||
|
RecipeSourceParseError,
|
||||||
|
} from "../lib/recipe-sources/recipe-source-errors.js";
|
||||||
|
|
||||||
const SOURCE_KEY = "jsonLdRecipe";
|
const SOURCE_KEY = "jsonLdRecipe";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@ import type {
|
||||||
RecipeSourceAdapter,
|
RecipeSourceAdapter,
|
||||||
RecipeSourceListParams,
|
RecipeSourceListParams,
|
||||||
RecipeSourceListResult,
|
RecipeSourceListResult,
|
||||||
} from "../lib/recipe-source-adapter.js";
|
} from "../lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { RecipeSourceFetchError, RecipeSourceParseError } from "../lib/recipe-source-errors.js";
|
import {
|
||||||
|
RecipeSourceFetchError,
|
||||||
|
RecipeSourceParseError,
|
||||||
|
} from "../lib/recipe-sources/recipe-source-errors.js";
|
||||||
|
|
||||||
const SOURCE_KEY = "theMealDb";
|
const SOURCE_KEY = "theMealDb";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
||||||
import type { RecipeSourceAdapter } from "../src/lib/recipe-source-adapter.js";
|
import type { RecipeSourceAdapter } from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { clearRecipeSources, registerRecipeSource } from "../src/lib/recipe-source-registry.js";
|
import {
|
||||||
|
clearRecipeSources,
|
||||||
|
registerRecipeSource,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
function buildSignupPayload(): SignupInput {
|
function buildSignupPayload(): SignupInput {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
matchIngredientName,
|
matchIngredientName,
|
||||||
matchUnit,
|
matchUnit,
|
||||||
type UnitMatchEntry,
|
type UnitMatchEntry,
|
||||||
} from "../src/lib/ingredient-matcher.js";
|
} from "../src/lib/recipe-matching/ingredient-matcher.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
describe("ingredient-matcher", () => {
|
describe("ingredient-matcher", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { RecipeSourceFetchError, RecipeSourceParseError } from "../src/lib/recipe-source-errors.js";
|
import {
|
||||||
|
RecipeSourceFetchError,
|
||||||
|
RecipeSourceParseError,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-errors.js";
|
||||||
import { jsonLdRecipeAdapter } from "../src/sources/json-ld-recipe.js";
|
import { jsonLdRecipeAdapter } from "../src/sources/json-ld-recipe.js";
|
||||||
|
|
||||||
/** Stubs `globalThis.fetch` to return `html` as the response body — same reasoning/pattern as `the-meal-db.test.ts`'s `stubFetch`, just returning text instead of JSON. */
|
/** Stubs `globalThis.fetch` to return `html` as the response body — same reasoning/pattern as `the-meal-db.test.ts`'s `stubFetch`, just returning text instead of JSON. */
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { findImportedRecipeIds, syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
import { findImportedRecipeIds, syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
||||||
import type { RecipeSourceAdapter } from "../src/lib/recipe-source-adapter.js";
|
import type { RecipeSourceAdapter } from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { clearRecipeSources, registerRecipeSource } from "../src/lib/recipe-source-registry.js";
|
import {
|
||||||
|
clearRecipeSources,
|
||||||
|
registerRecipeSource,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** See `recipe.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
/** See `recipe.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,19 @@ import type {
|
||||||
RecipeSourceListItem,
|
RecipeSourceListItem,
|
||||||
RecipeSourceListParams,
|
RecipeSourceListParams,
|
||||||
RecipeSourceListResult,
|
RecipeSourceListResult,
|
||||||
} from "../src/lib/recipe-source-adapter.js";
|
} from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { markAlreadyImported } from "../src/lib/recipe-source-adapter.js";
|
import { markAlreadyImported } from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import {
|
import {
|
||||||
RecipeSourceError,
|
RecipeSourceError,
|
||||||
RecipeSourceFetchError,
|
RecipeSourceFetchError,
|
||||||
RecipeSourceParseError,
|
RecipeSourceParseError,
|
||||||
} from "../src/lib/recipe-source-errors.js";
|
} from "../src/lib/recipe-sources/recipe-source-errors.js";
|
||||||
import {
|
import {
|
||||||
clearRecipeSources,
|
clearRecipeSources,
|
||||||
getRecipeSource,
|
getRecipeSource,
|
||||||
listRecipeSources,
|
listRecipeSources,
|
||||||
registerRecipeSource,
|
registerRecipeSource,
|
||||||
} from "../src/lib/recipe-source-registry.js";
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
|
|
||||||
interface FakeRawRecipe {
|
interface FakeRawRecipe {
|
||||||
externalId: string;
|
externalId: string;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import type { IngredientMatchEntry, UnitMatchEntry } from "../src/lib/ingredient-matcher.js";
|
import type {
|
||||||
import type { ParsedRecipe, ParsedRecipeIngredient } from "../src/lib/recipe-source-adapter.js";
|
IngredientMatchEntry,
|
||||||
|
UnitMatchEntry,
|
||||||
|
} from "../src/lib/recipe-matching/ingredient-matcher.js";
|
||||||
import {
|
import {
|
||||||
mergeDuplicateIngredients,
|
mergeDuplicateIngredients,
|
||||||
type TranslatedRecipeIngredient,
|
type TranslatedRecipeIngredient,
|
||||||
|
|
@ -9,8 +11,12 @@ import {
|
||||||
translateRecipeIngredients,
|
translateRecipeIngredients,
|
||||||
translateRecipeSteps,
|
translateRecipeSteps,
|
||||||
type UnitConversionEntry,
|
type UnitConversionEntry,
|
||||||
} from "../src/lib/recipe-translation.js";
|
} from "../src/lib/recipe-matching/recipe-translation.js";
|
||||||
import type { TechStepMappingRule } from "../src/lib/tech-step-matcher.js";
|
import type { TechStepMappingRule } from "../src/lib/recipe-matching/tech-step-matcher.js";
|
||||||
|
import type {
|
||||||
|
ParsedRecipe,
|
||||||
|
ParsedRecipeIngredient,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** A minimal fixture `ParsedRecipe` — only `steps` (built from `descriptions`) matters for most tests here, the rest is filler to prove it survives translation untouched. */
|
/** A minimal fixture `ParsedRecipe` — only `steps` (built from `descriptions`) matters for most tests here, the rest is filler to prove it survives translation untouched. */
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,11 @@ import request from "supertest";
|
||||||
import { createApp } from "../src/app.js";
|
import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
||||||
import type { RecipeSourceAdapter } from "../src/lib/recipe-source-adapter.js";
|
import type { RecipeSourceAdapter } from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { clearRecipeSources, registerRecipeSource } from "../src/lib/recipe-source-registry.js";
|
import {
|
||||||
|
clearRecipeSources,
|
||||||
|
registerRecipeSource,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** A minimal `RecipeSourceAdapter` — only `key`/`name`/`official`/`iconUrl` matter for `syncRecipeSources` fixtures here. */
|
/** A minimal `RecipeSourceAdapter` — only `key`/`name`/`official`/`iconUrl` matter for `syncRecipeSources` fixtures here. */
|
||||||
|
|
@ -60,7 +63,7 @@ async function techStepId(key: string): Promise<number> {
|
||||||
return techStep.id;
|
return techStep.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A step's detected technique sequence, in order — mirrors `matchTechSteps`' return shape (`../src/lib/tech-step-matcher.js`) so tests can assert on it directly. */
|
/** A step's detected technique sequence, in order — mirrors `matchTechSteps`' return shape (`../src/lib/recipe-matching/tech-step-matcher.js`) so tests can assert on it directly. */
|
||||||
async function stepTechStepIds(stepId: number): Promise<number[]> {
|
async function stepTechStepIds(stepId: number): Promise<number[]> {
|
||||||
const links = await prisma.stepTechStep.findMany({
|
const links = await prisma.stepTechStep.findMany({
|
||||||
where: { stepId },
|
where: { stepId },
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ import { createApp } from "../src/app.js";
|
||||||
import { prisma } from "../src/db/prisma.js";
|
import { prisma } from "../src/db/prisma.js";
|
||||||
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
import { syncRecipeSources } from "../src/db/recipe-source-sync.js";
|
||||||
import { seedReferenceData } from "../src/db/reference-seed-data.js";
|
import { seedReferenceData } from "../src/db/reference-seed-data.js";
|
||||||
import type { RecipeSourceAdapter } from "../src/lib/recipe-source-adapter.js";
|
import type { RecipeSourceAdapter } from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { clearRecipeSources, registerRecipeSource } from "../src/lib/recipe-source-registry.js";
|
import {
|
||||||
|
clearRecipeSources,
|
||||||
|
registerRecipeSource,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** A minimal `RecipeSourceAdapter` — only `key`/`name`/`official`/`iconUrl` matter for `syncRecipeSources` fixtures here. */
|
/** A minimal `RecipeSourceAdapter` — only `key`/`name`/`official`/`iconUrl` matter for `syncRecipeSources` fixtures here. */
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {
|
||||||
clearRecipeSources,
|
clearRecipeSources,
|
||||||
getRecipeSource,
|
getRecipeSource,
|
||||||
listRecipeSources,
|
listRecipeSources,
|
||||||
} from "../src/lib/recipe-source-registry.js";
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { registerAllRecipeSources } from "../src/sources/index.js";
|
import { registerAllRecipeSources } from "../src/sources/index.js";
|
||||||
|
|
||||||
// Not exercised by any other test file — `registerAllRecipeSources` is
|
// Not exercised by any other test file — `registerAllRecipeSources` is
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,12 @@ import type {
|
||||||
RecipeSourceAdapter,
|
RecipeSourceAdapter,
|
||||||
RecipeSourceListParams,
|
RecipeSourceListParams,
|
||||||
RecipeSourceListResult,
|
RecipeSourceListResult,
|
||||||
} from "../src/lib/recipe-source-adapter.js";
|
} from "../src/lib/recipe-sources/recipe-source-adapter.js";
|
||||||
import { RecipeSourceFetchError } from "../src/lib/recipe-source-errors.js";
|
import { RecipeSourceFetchError } from "../src/lib/recipe-sources/recipe-source-errors.js";
|
||||||
import { clearRecipeSources, registerRecipeSource } from "../src/lib/recipe-source-registry.js";
|
import {
|
||||||
|
clearRecipeSources,
|
||||||
|
registerRecipeSource,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-registry.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
/** See `recipe.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
/** See `recipe.test.ts` — generated rather than hardcoded, no test fixture looks like a real person's data. */
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
matchTechSteps,
|
matchTechSteps,
|
||||||
normalizeText,
|
normalizeText,
|
||||||
type TechStepMappingRule,
|
type TechStepMappingRule,
|
||||||
} from "../src/lib/tech-step-matcher.js";
|
} from "../src/lib/recipe-matching/tech-step-matcher.js";
|
||||||
import { resetDatabase } from "../test-support/reset-db.js";
|
import { resetDatabase } from "../test-support/reset-db.js";
|
||||||
|
|
||||||
describe("tech-step-matcher", () => {
|
describe("tech-step-matcher", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { RecipeSourceFetchError, RecipeSourceParseError } from "../src/lib/recipe-source-errors.js";
|
import {
|
||||||
|
RecipeSourceFetchError,
|
||||||
|
RecipeSourceParseError,
|
||||||
|
} from "../src/lib/recipe-sources/recipe-source-errors.js";
|
||||||
import { type TheMealDbMeal, theMealDbAdapter } from "../src/sources/the-meal-db.js";
|
import { type TheMealDbMeal, theMealDbAdapter } from "../src/sources/the-meal-db.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ Le module « Import d'une recette » du plan initial (voir
|
||||||
[batch-cooking-architecture.md](./batch-cooking-architecture.md)) est
|
[batch-cooking-architecture.md](./batch-cooking-architecture.md)) est
|
||||||
implémenté. Pièces principales :
|
implémenté. Pièces principales :
|
||||||
|
|
||||||
### `RecipeSourceAdapter` (`apps/api/src/lib/recipe-source-adapter.ts`)
|
### `RecipeSourceAdapter` (`apps/api/src/lib/recipe-sources/recipe-source-adapter.ts`)
|
||||||
|
|
||||||
Contrat générique que chaque source concrète implémente : `list(params)`
|
Contrat générique que chaque source concrète implémente : `list(params)`
|
||||||
(parcours paginé, `query`/`cursor` optionnels), `fetchDetail(externalId)`
|
(parcours paginé, `query`/`cursor` optionnels), `fetchDetail(externalId)`
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ Logique de calcul du batch-cooking (optimisation du planning/des recettes selon
|
||||||
|
|
||||||
1. **Import depuis source** — chaque source concrète (aujourd'hui : TheMealDB,
|
1. **Import depuis source** — chaque source concrète (aujourd'hui : TheMealDB,
|
||||||
API officielle) implémente le contrat `RecipeSourceAdapter`
|
API officielle) implémente le contrat `RecipeSourceAdapter`
|
||||||
(`apps/api/src/lib/recipe-source-adapter.ts` — `list`/`fetchDetail`/`parse`),
|
(`apps/api/src/lib/recipe-sources/recipe-source-adapter.ts` — `list`/`fetchDetail`/`parse`),
|
||||||
enregistré dans un registre en mémoire et synchronisé vers la table
|
enregistré dans un registre en mémoire et synchronisé vers la table
|
||||||
`sources`. Un scraper générique JSON-LD/schema.org (`json-ld-recipe.ts`)
|
`sources`. Un scraper générique JSON-LD/schema.org (`json-ld-recipe.ts`)
|
||||||
existe aussi, en briques réutilisables par un futur adaptateur dédié à un
|
existe aussi, en briques réutilisables par un futur adaptateur dédié à un
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue