Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hakyll gets confused with list fields if the YAML metadata isn't consistent #510

Open
beerendlauwers opened this issue Jan 16, 2017 · 2 comments

Comments

@beerendlauwers
Copy link
Contributor

Prelude

For HaskAnything.com, I have an authors field. Sometimes, it has data like this:

authors: Beerend Lauwers

And sometimes, it has data like this:

authors:
 - Beerend Lauwers

The context I pass to my templates can be simplified to the following:

templateCtx = metadataListField <> defaultContext

where metadataListField is a custom context I wrote myself that maps a YAML list field to a Hakyll list field, failing to yield a Hakyll field if no such YAML list field could be found:

--------------------------------------------------------------------------------
-- | Map any list field to its metadata value, if present
metadataListField :: Context a
metadataListField = Context $ \k _ i -> do
   values <- getMetadataListField (itemIdentifier i) k
   case values of
     Just vs -> do
                 listItems <- mapM makeItem vs
                 return $ ListField (field "item" (return.itemBody)) listItems
     Nothing -> empty

Problem

The problem I get is that if if have inconsistent YAML data (as explained above), referencing $authors$ in a template will result in an error:

Using YAML:

authors:
 - Beerend Lauwers
[ERROR] Hakyll.Web.Template.applyTemplateWith: expected StringField but got ListField for expr authors

Trying to reference it as a list field with $for(authors)$ $item$ $endfor$ results in the opposite problem for another file:

Using YAML:

authors: Beerend Lauwers
[ERROR] Hakyll.Web.Template.applyTemplateWith: expected ListField but got StringField for expr authors

In the second file, the authors key could be interpreted as a string field or a list field (from Hakyll's perspective), but it is interpreted as a string field.

Solution

First off, perhaps it would be a good idea to automatically expose true YAML list fields as a Hakyll ListField by modifying metadataField to not always return a StringField, but a ListField as well. Here's the current definition:

-- | Map any field to its metadata value, if present
metadataField :: Context a
metadataField = Context $ \k _ i -> do
    value <- getMetadataField (itemIdentifier i) k
    maybe empty (return . StringField) value

Second, perhaps we should document this caveat somewhere, or, even better, error out when we're parsing the YAML metadata of several files and notice an inconsistency like this.

@jaspervdj
Copy link
Owner

Yes, I think you are right. The reason for this behavior is that Hakyll hasn't supported YAML for too long -- it used to be just key: value Metadata.

In order to preserve backwards compatibility, I think we could add another primitive like metadataField, but one which understands YAML and tries to do the right thing in most cases, also supporting $for$ loops and data inside that and so on. This could be called yamlMetadataField. What do you think?

@beerendlauwers
Copy link
Contributor Author

Sounds good. I already have some code for turning YAML lists into Hakyll lists here: https://github.com/beerendlauwers/HaskAnything/blob/master/src/HaskAnything/Internal/Field.hs#L133

We could have a function that returns Maybe Either a String or a [String], pattern match on that and return a StringField or ListField accordingly.

Bonus points if we make the ListField path recursive, so we can have nested YAML lists :)

I'll see if I can whip up a PR this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants