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

Potential issue with addDateParsing() and dates in filenames #3649

Closed
cmegown opened this issue Feb 4, 2025 · 5 comments
Closed

Potential issue with addDateParsing() and dates in filenames #3649

cmegown opened this issue Feb 4, 2025 · 5 comments
Labels
education feature: dates Related to content dates

Comments

@cmegown
Copy link

cmegown commented Feb 4, 2025

Operating system

Windows 11

Eleventy

3.0.0

Describe the bug

Greetings,

I'm resurrecting an old Jekyll blog that has a bunch of markdown files with the date in the filename instead of in the front matter. While spinning up a new Eleventy site I was toying around with the new addDateParsing() method and noticed that it potentially wasn't working as it should. Or maybe I just don't understand the internal mechanics of how date is handled in Eleventy.

Here's a basic reduced case:

// eleventy.config.js

import { DateTime } from 'luxon';

export default async function (eleventyConfig) {
  eleventyConfig.addDateParsing(function (dateValue) {
    return DateTime.fromFormat(dateValue, 'LLLL dd, yyyy');
  });
};
// 2024-21-31-hello-world.md

---
title: "Hello, world!"
---

Content goes here.

After running npx @11ty/eleventy the following error appears in the console:

...
[11ty] Problem writing Eleventy templates:
[11ty] fromFormat requires an input string and a format
...

Even though the config is copied almost verbatim from the documentation that error immediately made me feel like there was an issue with the date being passed in. So I swapped out the return with console.log(dateValue); just to see how the date itself was being returned. From the console:

...
[11ty] File changed: eleventy.config.js
undefined
undefined
[11ty] Writing ./dist/blog/hello-world/index.html from ./src/posts/2024-12-31-hello-world.md (njk)
...

So at this point we know that the date simply isn't coming through, even though I'm rendering the date in a template file with {{ page.date }}. I then tried adding the date in the front matter as date: 2024-12-31:

...
[11ty] File changed: eleventy.config.js
undefined
2024-12-31T00:00:00.000Z
[11ty] Writing ./dist/blog/hello-world/index.html from ./src/posts/2024-12-31-hello-world.md (njk)
...

That's more like it. Smarter people than I could explain how the extra stuff got appended there, but I'll let them explain that. Then once more I tried changing the front matter to date: "2024-12-31" (with double quotes):

...
[11ty] File changed: eleventy.config.js
undefined
2024-12-31
[11ty] Writing ./dist/blog/hello-world/index.html from ./src/posts/2024-12-31-hello-world.md (njk)
...

This is the end result I expected in the first place.

Reproduction steps

No response

Expected behavior

I expected the date-in-filename format to work without issue as it is stated in the documentation as a perfectly acceptable way to attach a date to a blog post. The date produced in this manner should be able to be manipulated via addDateParsing().

Reproduction URL

https://github.com/cmegown/eleventy-adddateparsing-reduced-case

Screenshots

No response

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Feb 4, 2025

That's more like it. Smarter people than I could explain how the extra stuff got appended there, but I'll let them explain that. Then once more I tried changing the front matter to date: "2024-12-31" (with double quotes):

Because Yaml (via js-yaml lib as used by gray-matter) is doing its own date parsing:

// YAML does its own date parsing

You'll get real strings with 11tydata.js files for example.

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Feb 4, 2025

When I look at the invocation in

eleventy/src/Template.js

Lines 1022 to 1028 in aa713c5

for (let fn of this.config.customDateParsing) {
let ret = fn.call(
{
page: data.page,
},
dateValue,
);

I can see two arguments. The first one is being assigned to this the other is an argument to the callback you have provided.

Can you inspect the value of this? In particular this.page.inputPath looks like it contains what you are asking for.
You could then run something like this within the callback:

import { basename } from "node:path";

/* … */
eleventyConfig.dateParsing(() => {
  return DateTime.fromFormat(
    basename(this.page.inputPath).slice(0, "2025-02-04".length)
  )
});
/* … */

Modulo some error handling as not every post / page contains the date. (You have the fileSlug and outputFileExtension to work with as well as a second argument to basename to work with)

@uncenter uncenter added education feature: dates Related to content dates and removed needs-triage labels Feb 5, 2025
@cmegown
Copy link
Author

cmegown commented Feb 6, 2025

@Ryuno-Ki apologies if you saw an utterly useless response here earlier today. I was trying to test some of the things you mentioned while doing about a dozen other things, and the end result was anything but helpful. Anyway, here's a more thoughtful response.

This config...

// eleventy.config.js

import { basename } from 'node:path';
import { DateTime } from 'luxon';

export default function (eleventyConfig) {
  eleventyConfig.addDateParsing(function () {
    console.log(this);
  });
}

...produces this console log:

{
  page: {
    inputPath: './src/pages/home.html',
    fileSlug: 'home',
    filePathStem: '/pages/home',
    outputFileExtension: 'html',
    templateSyntax: 'njk'
  }
}
{
  page: {
    inputPath: './src/posts/2024-12-31-hello-world.md',
    fileSlug: 'hello-world',
    filePathStem: '/posts/hello-world',
    outputFileExtension: 'html',
    templateSyntax: 'njk,md'
  }
}

If I add a condition to ensure it's a post file...

// eleventy.config.js

import { basename } from 'node:path';
import { DateTime } from 'luxon';

export default function (eleventyConfig) {
  eleventyConfig.addDateParsing(function () {
    const inputPath = this.page.inputPath;
    
    if (inputPath.startsWith('./src/posts/')) {
      console.log(inputPath);
      console.log(basename(inputPath));
      console.log(basename(inputPath).slice(0, 10));
    }
  });
}

...we now get this console log:

./src/posts/2024-12-31-hello-world.md
2024-12-31-hello-world.md
2024-12-31

So far so good-ish. If we update the config once more...

// eleventy.config.js

import { basename } from 'node:path';
import { DateTime } from 'luxon';

export default function (eleventyConfig) {
  eleventyConfig.addDateParsing(function () {
    const inputPath = this.page.inputPath;
    
    if (inputPath.startsWith('./src/posts/')) {
      const postDate = basename(inputPath).slice(0, 10);
      const newFormat = DateTime.fromFormat(postDate, 'MMMM dd, yyyy');
      
      console.log(newFormat);
    }
  });
}

...we get this message:

DateTime { Invalid, reason: unparsable }

I'm not very familiar with the luxon yet but I'll keep digging into this.

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Feb 7, 2025

I can confirm the behaviour.

Looking up the documentation a slight update should yield the expected result:

// eleventy.config.js

import { basename } from 'node:path';
import { DateTime } from 'luxon';

export default function (eleventyConfig) {
  eleventyConfig.addDateParsing(function () {
    const { inputPath } = this.page;
    
    if (inputPath.startsWith('./src/posts/')) {
      const postDate = basename(inputPath).slice(0, 10);
      const newFormat = DateTime.fromISO(postDate);
      
      console.log(newFormat);
      console.log(newFormat.toFormat("MMMM dd, yyyy"));
    }
  });
}

Resulting in

DateTime { ts: 2024-12-31T00:00:00.000+01:00, zone: Europe/Berlin, locale: de-DE }
'December 31, 2024'

here

@cmegown
Copy link
Author

cmegown commented Feb 9, 2025

Ok, so I was simply misunderstanding how this method was intended to be used! My apologies and thank you for taking the time to respond @Ryuno-Ki .

@cmegown cmegown closed this as completed Feb 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
education feature: dates Related to content dates
Projects
None yet
Development

No branches or pull requests

3 participants