Skip to content

@gram-lang/analyzer

Enrichit un CompilationResult (issu de @gram-lang/kitchen) avec des propriétés physiques — masse standardisée, rendement d'achat, estimations nutritionnelles, et pourcentages boulanger — en croisant les données avec une base de données d'ingrédients. C'est la seule étape qui nécessite une base de données ; le parsing et la compilation fonctionnent sur n'importe quelle recette sans données externes.

analyze

typescript
function analyze(
  result: CompilationResult,
  database: Record<string, IngredientData>,
  options?: AnalyzerOptions,
): AnalysisResult

interface AnalysisResult {
  result: AnalyzedCompilationResult;
  missingIngredients: string[]; // ids présents dans la recette mais absents de `database`
}
typescript
import { compile } from '@gram-lang/kitchen';
import { analyze } from '@gram-lang/analyzer';

const compiled = compile(ast);
const { result: analyzed, missingIngredients } = analyze(compiled, myIngredientDatabase);

La base de données d'ingrédients est le deuxième argument positionnel, pas un champ de optionsanalyze(compiled, database, options?).

analyze() est pure et ne mute jamais result. AnalyzedCompilationResult étend CompilationResult — même forme, plus des champs normalizedMass/conversionMethod/isEstimate/purchasingMass/bakersPercentage par usage et un bloc metrics.nutrition. Voir Formats de Données pour un exemple entièrement annoté.

AnalyzerOptions

Tous les indicateurs sont activés par défaut (vérifications internes !== false) — passez false pour désactiver une passe d'enrichissement donnée.

OptionTypeDescription
enableMassStandardizationbooleanConvertit les quantités d'ingrédients en grammes standardisés.
enableYieldCalculationbooleanApplique le physical.yield (facteur de perte) de la base de données lors de la standardisation de la masse.
enableNutritionalEstimationbooleanCalcule metrics.nutrition (calories, macros, éventuellement par portion).
enableBakersMathbooleanCalcule bakersPercentage par rapport à l'ingrédient marqué * (ou bakersReference).
bakersReferencestringId d'ingrédient explicite à utiliser comme base 100% du pourcentage boulanger, au lieu du modificateur *.
portionsnumberNombre de portions utilisé pour calculer metrics.nutrition.perPortion.
langstringCode de langue optionnel (ex : 'en', 'fr') pour la normalisation d'unités et le tri des catégories par langue.

validateIngredientDatabase

typescript
function validateIngredientDatabase(rawDb: unknown): {
  data: Record<string, IngredientData>;
  rejected: { key: string; message: string }[];
}

Valide entrée par entrée plutôt que tout-ou-rien : un ingrédient malformé n'empêche pas le chargement de tous les autres. Utilisez data pour compiler/analyser ; affichez rejected à l'utilisateur (ex : gram db validate). Voir Formats de Données pour le schéma YAML IngredientData.

Utilitaires de masse

typescript
function standardizeMass(
  amount: number,
  unit: string,
  database: Record<string, IngredientData>,
  ingredientName?: string,
  overrides?: Record<string, number>, // slug -> densité (g/mL) ou poids unitaire (g), issu du frontmatter `densities:`
  lang?: string,
): { mass: number; method: "physical" | "density" | "unit_weight" | "default" | "explicit"; isEstimate: boolean } | null

function convertUnit(value: number, fromUnit: string, toUnit: string, density?: number, lang?: string): number | null

function applyYield(
  mass: number,
  method: "physical" | "density" | "unit_weight" | "default" | "explicit",
  yieldFactor?: number,
): { normalizedMass: number; purchasingMass?: number }

standardizeMass résout une quantité en grammes via, dans l'ordre : (1) une unité de masse directe (g, kg, oz...), (2) une unité de volume convertie via la densité résolue de l'ingrédient, (3) une unité non reconnue (gousse, tranche...) traitée comme un décompte via le unit_weight de l'ingrédient. Retourne null — sans jamais deviner — quand une unité de volume n'a aucune densité résolvable.

convertUnit convertit entre deux chaînes d'unité arbitraires, faisant le pont masse↔volume via density (g/mL) si fournie. Retourne null pour une conversion inter-famille non résolvable sans densité.

Table de conversion masse & volume

Les facteurs de conversion de base utilisés par standardizeMass/convertUnit pour les conversions intra-famille (masse↔masse, volume↔volume), avant toute densité :

FamilleUnitéFacteur (par rapport à la base)
mass (base: g)mg0.001
mass (base: g)g1
mass (base: g)kg1000
mass (base: g)oz28.3495
mass (base: g)lb453.592
mass (base: g)livre500
volume (base: ml)ml1
volume (base: ml)cl10
volume (base: ml)dl100
volume (base: ml)l1000
volume (base: ml)drop0.078
volume (base: ml)smidgen0.156
volume (base: ml)pinch0.3125
volume (base: ml)dash0.625
volume (base: ml)tad1.25
volume (base: ml)tsp4.9289
volume (base: ml)tbsp14.7868
volume (base: ml)cup236.588
volume (base: ml)tasse250
volume (base: ml)pt473.176
volume (base: ml)qt946.353
volume (base: ml)gal3785.41
volume (base: ml)fl oz29.5735

calculateNutrition

typescript
function calculateNutrition(
  ingredients: AnalyzedUsage[],
  database: Record<string, IngredientData>,
  portions?: number,
): NutritionMetrics

Aplatit les composites et les alternatives (en prenant la première option), ignore les ingrédients marqués optional et ceux à quantité nulle, et somme les champs nutrition (déclarés pour 100g dans la base de données — voir Formats de Données) mis à l'échelle par la masse standardisée de chaque ingrédient. Retourne isEstimate: true si l'une des masses contributrices était elle-même une estimation, et coverage (0–1 : fraction des ingrédients avec des données nutritionnelles connues).

diffRecipes

typescript
function diffRecipes(a: CompilationResult, b: CompilationResult): DiffResult

Diff structurel entre deux recettes compilées (ex : deux versions d'un même fichier, ou un résultat mis à l'échelle vs. non mis à l'échelle) — changements de quantité/unité d'ingrédients (avec percentChange quand comparable), changements de préparation, écarts de minutage, sections ajoutées/supprimées/modifiées, changements de température et de minuteur, et changements de frontmatter (meta). hasChanges vaut true si une catégorie au moins est non vide.