jackyzha0 / quartz

🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites
https://quartz.jzhao.xyz
MIT License
5.92k stars 2.37k forks source link

`AliasRedirects` fails for the aliases that can't be a file name #708

Open mnaoumov opened 5 months ago

mnaoumov commented 5 months ago

Describe the bug

If you have an alias that cannot represent a file name, emit fails

To Reproduce

  1. Create a note

Note.md

---
aliases:
  - Proper Alias
  - "Alias with invalid file system characters <>?|:"
  - "Very long name, on Windows the limit is 260 characters 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
---

My note will break the `AliasRedirects` emit
  1. Try to build Quartz
  2. Get the error Failed to emit from plugin `AliasRedirects`: ENOENT: no such file or directory

Expected behavior

The site builds without error

Screenshots and Source

N/A

Desktop (please complete the following information):

Additional context

N/A

Sylicium commented 4 months ago

That comes from quartz parsing Aliases with path functions. (such as path.posix.join()) I don't think Quartz should parse Aliases as filenames (L19 below). But also they should respect the filename formats as they could be actual filenames (aliases means other name for the file after all ?) But damn, i don't know- If still parsed as filenames, im not sure but that could also lead to a potential other issue when putting slashes and paths like:

---
  - "../someAlias"
  - "C:\SomeOtherAlias"
---

This is due to the path.posix.join() joining path with alias without any kind of input validation. Therefore the resulting path could change directory in the above case. (Not tested.)

https://github.com/jackyzha0/quartz/blob/83ab39c7bd00c7bdfddc303b765b73ae774e3aab/quartz/plugins/emitters/aliases.ts#L16-L23

We can think about something more like that:

const aliases = file.data.frontmatter?.aliases || [] // replaced ?? by || covering more error cases falling back on []
const slugs = aliases.map((alias) => (
  dir.endsWith("/")
  ? String(dir)+String(alias)
  : String(dir)+"/"+String(alias)
) as FullSlug)
ooker777 commented 2 weeks ago

that doesn't work. The code should be:

const slugs: FullSlug[] = aliases.map((alias) => {
    console.log(alias)
    const aliasWithNoInvalidFileSystemCharacters = alias.replace(/[\<\>\?\|\:]/g, '-');
    return path.posix.join(dir, aliasWithNoInvalidFileSystemCharacters) as FullSlug
});

Note that this also converts Linux path, which is unnecessary.