11ty / eleventy-plugin-rss

A pack of Eleventy plugins for generating an RSS feed.
https://www.11ty.dev/docs/plugins/rss/
MIT License
92 stars 22 forks source link

Error parsing JSON Feed #32

Closed xplosionmind closed 2 years ago

xplosionmind commented 2 years ago

Apparently, dump and safe Nunjucks filters are not enough to escape templateContent, as it is instead written in the sample/feed-json.njk.

Here is my JSON Feed Nunjucks file:

---
title: All of Tommi’s craziness
description: EVERYTHING from tommi.space
altUrl: https://tommi.space/
permalink: /all.json
lang: en
---
{
    "version": "https://jsonfeed.org/version/1.1",
    "title": "{{ title }}",
    "home_page_url": "{{ altUrl }}",
    "feed_url": "{{ site.url }}{{ page.url }}",
    "description": "{{ description }}",
    "favicon": "{{ site.favicon }}",
    "authors": [{
      "name": "{{ site.author.name }}",
      "url": "{{ site.author.url }}",
      "avatar": "{{ site.author.avatar }}"
    }],
    "language": "en",
    "items": [{% for entry in collections.all | reverse %}
    {
        {%- set absolutePostUrl %}{{ post.url | url | absoluteUrl(metadata.url) }}{% endset -%}
        "id": "{{ absolutePostUrl }}",
        "url": "{{ absolutePostUrl }}",
        "title": "{{ entry.data.title }}",
        "content_html": "{{ entry.templateContent | dump | safe | replace('"', '\'') }}",
        "content_text": "{{ entry.templateContent | striptags(true) | dump | safe }}",
        {%- if entry.data.description %}"summary": "{{ entry.data.description | dump | safe }}",{% endif -%}
        "image": {%- if entry.data.image %}"{{ entry.data.image }}"{% else %}"{{ image }}"{% endif -%},
        "date_published": "{{ page.date | dateToRfc3339 }}",
        {%- if page.data.updated %}"date_modified": "{{ page.data.updated | dateToRfc3339 }}",{% endif -%}
        {%- if page.data.tags %}"tags": [{% for tag in entry.data.tags -%}
        "{{ tag.title }}"{%- if forloop.last %}{% else %},{% endif -%}
        {% endfor -%}
        ],{% endif -%}
        "language": "{{ entry.data.lang }}"
    }{%- if forloop.last %}{% else %},{% endif -%}
    {%- endfor -%}]
}

What can I do to fix this?

pdehaan commented 2 years ago

I think the dump is doing some JSON converstion which will wrap extra quotes around the strings in question, which then the replace filter will convert to single quotes, leaving you with something like "content_html": "'some text'" which might be causing issues.

I had to write a stripquotes filter that just removes the first and last character in a string and returns the unquoted content (since you're already wrapping the template variable in double quotes; and even if we weren't wrapping the content in double quotes, the replace()d value would convert to single quotes, and "content_html": 'some text' isn't valid JSON).

eleventyConfig.addFilter("stripquotes", function (string) {
    return string.toString().substr(1, string.length - 1);
})

Then, you might be able to do:

"content_text": "{{ entry.templateContent | striptags(true) | dump | safe | stripquotes | replace('"', '\'') }}",

Not sure if that will solve everything, but at least running prettier against the generated /all.json file didn't tell me it was invalid HTML. Of course, a single stray quote in some content may break everything because JSON and quoted attributes, etc.

I haven't tried it yet, but you may be able to see if something like eleventy-plugin-json-feed works for you, or how they're handling escaping values.

zachleat commented 2 years ago

What entry.templateContent isn’t being escaped properly here?

dump is just an alias for JSON.stringify, so values should be JSON-compatible and quotes should be escaped properly.

As one more small note I would not expect | replace('"', '\'') to work in this context, especially for strings that have already been escaped by JSON.stringify.

"content_html": "One double quote \"",
"content_html": "One single quote '",

where the replace filter you have listed would output invalid JSON (throws an error when you try to validate it on https://jsonlint.com/)

"content_html": "One double quote \'",
zachleat commented 2 years ago

This is an automated message to let you know that a helpful response was posted to your issue and for the health of the repository issue tracker the issue will be closed. This is to help alleviate issues hanging open waiting for a response from the original poster.

If the response works to solve your problem—great! But if you’re still having problems, do not let the issue’s closing deter you if you have additional questions! Post another comment and we will reopen the issue. Thanks!

xplosionmind commented 2 years ago

My bad! The problem lied in placing {{ entry.templateContent | safe | dump }} within ". One of the two filters already encloses the output string in double quotes!

zachleat commented 2 years ago

Ah, great! Thanks for checking back in!