feat: add schemaOrgToCooklang conversion function
This commit is contained in:
+64
-4
@@ -17,7 +17,8 @@ import Data.Aeson (FromJSON (..), (.!=), (.:), (.:?))
|
||||
import qualified Data.Aeson as A
|
||||
import qualified Data.Aeson.KeyMap as KM
|
||||
import Data.Aeson.Types (parseMaybe)
|
||||
import Data.Maybe (fromMaybe, mapMaybe)
|
||||
import Data.List.NonEmpty (NonEmpty ((:|)), fromList)
|
||||
import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
|
||||
@@ -213,12 +214,71 @@ parseSchemaOrgRecipe val = do
|
||||
_ -> Nothing
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Stubs for future tasks
|
||||
-- Conversion to Cooklang Recipe
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- | Convert a SchemaOrgRecipe to a Cooklang Recipe. (Stub — will be implemented in Task 3)
|
||||
-- | Convert a SchemaOrgRecipe to a Cooklang Recipe.
|
||||
schemaOrgToCooklang :: SchemaOrgRecipe -> Either String Recipe
|
||||
schemaOrgToCooklang _ = Left "Not yet implemented"
|
||||
schemaOrgToCooklang r =
|
||||
Right
|
||||
Recipe
|
||||
{ recipeMetadata = buildMetadata r
|
||||
, recipeSections = buildSections r
|
||||
}
|
||||
|
||||
buildMetadata :: SchemaOrgRecipe -> Metadata
|
||||
buildMetadata r =
|
||||
emptyMetadata
|
||||
{ metaTitle = Just (soName r)
|
||||
, metaDescription = soDescription r
|
||||
, metaSource = soUrl r
|
||||
, metaTotalTime = soTotalTime r >>= parseISODuration
|
||||
, metaPrepTime = soPrepTime r >>= parseISODuration
|
||||
, metaCookTime = soCookTime r >>= parseISODuration
|
||||
, metaServings = parseServings =<< soRecipeYield r
|
||||
, metaAuthor = soPersonName <$> soAuthor r
|
||||
, metaCourse = soRecipeCategory r
|
||||
, metaCuisine = soRecipeCuisine r
|
||||
, metaTags = soKeywords r
|
||||
, metaImage = case soImage r of
|
||||
(img : _) -> Just (soImageObjectUrl img)
|
||||
[] -> Nothing
|
||||
}
|
||||
|
||||
buildSections :: SchemaOrgRecipe -> NonEmpty Section
|
||||
buildSections r =
|
||||
let ingSection = buildIngredientSection (soRecipeIngredient r)
|
||||
methodSection = buildMethodSection (soRecipeInstructions r)
|
||||
sections = catMaybes [Just ingSection, methodSection]
|
||||
in case sections of
|
||||
(s : ss) -> s :| ss
|
||||
[] -> Section Nothing (SecStep (Step []) :| []) :| []
|
||||
|
||||
buildIngredientSection :: [Text] -> Section
|
||||
buildIngredientSection ings
|
||||
| null ings = Section Nothing (SecStep (Step []) :| [])
|
||||
| otherwise =
|
||||
let items = concatMap (\t -> [StepText (", "), StepText t]) ings
|
||||
step = Step items
|
||||
in Section (Just "Ingredients") (SecStep step :| [])
|
||||
|
||||
buildMethodSection :: [SchemaOrgHowToStep] -> Maybe Section
|
||||
buildMethodSection [] = Nothing
|
||||
buildMethodSection steps =
|
||||
let stepItems = map (\s -> SecStep (Step [StepText (sohsText s)])) steps
|
||||
in Just (Section (Just "Method") (fromList stepItems))
|
||||
|
||||
-- | Parse a servings string like "4 to 6 servings".
|
||||
parseServings :: Text -> Maybe (Int, Maybe Text)
|
||||
parseServings t =
|
||||
case T.words t of
|
||||
(numStr : rest) -> do
|
||||
n <- readMaybe (T.unpack numStr)
|
||||
let unit = case rest of
|
||||
(_ : _) -> Just (T.intercalate " " rest)
|
||||
[] -> Nothing
|
||||
Just (n, unit)
|
||||
_ -> Nothing
|
||||
|
||||
{- | Parse an ISO 8601 duration string into a Cooklang Duration.
|
||||
Supports formats like PT20M, PT1H30M, P1DT2H, P1D.
|
||||
|
||||
Reference in New Issue
Block a user