rizaldy.club/content/advanced/paths.md

46 lines
2.3 KiB
Markdown

---
title: Paths in Quartz
---
Paths are pretty complex to reason about because, especially for a static site generator, they can come from so many places.
The current browser URL? Technically a path. 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](https://en.wikipedia.org/wiki/Nominal_type_system) 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](https://www.typescriptlang.org/play#example/nominal-typing).
```typescript
// instead of
type ClientSlug = string
// we do
type ClientSlug = string & { __brand: "client" }
// that way, the following will fail typechecking
const slug: ClientSlug = "some random slug"
```
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.
```mermaid
graph LR
Browser{{Browser}} --> Window{{Window}} & LinkElement{{Link Element}}
Window --"getCanonicalSlug()"--> Canonical[Canonical Slug]
Window --"getClientSlug()"--> Client[Client Slug]
LinkElement --".href"--> Relative[Relative URL]
Client --"canonicalizeClient()"--> Canonical
Canonical --"pathToRoot()"--> Relative
Canonical --"resolveRelative()" --> Relative
MD{{Markdown File}} --> FilePath{{File Path}} & Links[Markdown links]
Links --"transformLink()"--> Relative
FilePath --"slugifyFilePath()"--> Server[Server Slug]
Server --> HTML["HTML File"]
Server --"canonicalizeServer()"--> Canonical
style Canonical stroke-width:4px
```