Paths are pretty complex to reason about because, especially for a static site generator, they can come from so many places.
A full file path to a piece of content? Also a path. What about a slug for a piece of content? Yet another path.
It would be silly to type these all as string
and call it a day as itâs pretty common to accidentally mistake one type of path for another. Unfortunately, TypeScript does not have nominal types for type aliases meaning even if you made custom types of a server-side slug or a client-slug slug, you can still accidentally assign one to another and TypeScript wouldnât catch it.
Luckily, we can mimic nominal typing using brands.
While this prevents most typing mistakes within our nominal typing system (e.g. mistaking a server slug for a client slug), it doesnât prevent us from accidentally mistaking a string for a client slug when we forcibly cast it.
Thus, we still need to be careful when casting from a string to one of these nominal types in the âentrypointsâ, illustrated with hexagon shapes in the diagram below.
The following diagram draws the relationships between all the path sources, nominal path types, and what functions in quartz/path.ts
convert between them.
graph LR Browser{{Browser}} --> Window{{Body}} & LinkElement{{Link Element}} Window --"getFullSlug()"--> FullSlug[Full Slug] LinkElement --".href"--> Relative[Relative URL] FullSlug --"simplifySlug()" --> SimpleSlug[Simple Slug] SimpleSlug --"pathToRoot()"--> Relative SimpleSlug --"resolveRelative()" --> Relative MD{{Markdown File}} --> FilePath{{File Path}} & Links[Markdown links] Links --"transformLink()"--> Relative FilePath --"slugifyFilePath()"--> FullSlug[Full Slug] style FullSlug stroke-width:4px
Here are the main types of slugs with a rough description of each type of path:
FilePath
: a real file path to a file on disk. Cannot be relative and must have a file extension.FullSlug
: cannot be relative and may not have leading or trailing slashes. It can haveindex
as itâs last segment. Use this wherever possible is itâs the most âgeneralâ interpretation of a slug.SimpleSlug
: cannot be relative and shouldnât have/index
as an ending or a file extension. It can however have a trailing slash to indicate a folder path.RelativeURL
: must start with.
or..
to indicate itâs a relative URL. Shouldnât have/index
as an ending or a file extension but can contain a trailing slash.
To get a clearer picture of how these relate to each other, take a look at the path tests in quartz/util/path.test.ts
.