feat: add RecipeSearchEntry JSON encoding for search payload

This commit is contained in:
2026-05-19 21:29:41 -04:00
parent 61484cecc5
commit 632f61820b
+37 -2
View File
@@ -1,11 +1,17 @@
{-# LANGUAGE DeriveGeneric #-}
-- | Scanning and indexing of Cooklang recipe files on disk.
module Roux.RecipeIndex (
RecipeInfo (..),
RecipeSearchEntry (..),
scanRecipes,
toSearchEntry,
) where
import Data.Aeson (ToJSON (..), camelTo2, defaultOptions, fieldLabelModifier, genericToJSON)
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic)
import System.Directory (listDirectory)
import System.FilePath (takeBaseName, takeExtension, (</>))
@@ -45,9 +51,38 @@ loadRecipe dir filename = do
, riRecipe = parsed
}
{- | Extract a display title from the recipe's metadata or fall back to the
filename.
-- | Search payload for type-ahead / recipe search.
data RecipeSearchEntry = RecipeSearchEntry
{ rseTitle :: !Text
, rseFilename :: !Text
, rseCourse :: !(Maybe Text)
, rseTags :: ![Text]
}
deriving stock (Generic)
instance ToJSON RecipeSearchEntry where
toJSON = genericToJSON defaultOptions{fieldLabelModifier = camelTo2 '_' . drop 3}
{- | Convert a 'RecipeInfo' into a 'RecipeSearchEntry', extracting course and
tags from the parsed recipe metadata when available.
-}
toSearchEntry :: RecipeInfo -> RecipeSearchEntry
toSearchEntry info =
let (course, tags) = case riRecipe info of
Right r ->
( metaCourse (recipeMetadata r)
, metaTags (recipeMetadata r)
)
Left _ -> (Nothing, [])
in RecipeSearchEntry
{ rseTitle = riTitle info
, rseFilename = T.pack (riFilename info)
, rseCourse = course
, rseTags = tags
}
-- | Extract a display title from the recipe's metadata or fall back to the
-- filename.
extractTitle :: Recipe -> FilePath -> Text
extractTitle recipe filename =
case metaTitle (recipeMetadata recipe) of