From ec00a40aefca73596ab76e3ebe3a8e1129b43688 Mon Sep 17 00:00:00 2001
From: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 27 Jan 2026 18:27:17 +0000
Subject: [PATCH] chore(deps): bump the production-dependencies group with 4 updates (#2289)

---
 quartz/util/fileTrie.ts |  142 ++++++++++++++++++++++++++++++----------------
 1 files changed, 92 insertions(+), 50 deletions(-)

diff --git a/quartz/util/fileTrie.ts b/quartz/util/fileTrie.ts
index ed87b4f..9e6706f 100644
--- a/quartz/util/fileTrie.ts
+++ b/quartz/util/fileTrie.ts
@@ -4,58 +4,84 @@
 interface FileTrieData {
   slug: string
   title: string
+  filePath: string
 }
 
 export class FileTrieNode<T extends FileTrieData = ContentDetails> {
-  children: Array<FileTrieNode<T>>
-  slugSegment: string
-  displayName: string
-  data: T | null
-  depth: number
   isFolder: boolean
+  children: Array<FileTrieNode<T>>
 
-  constructor(segment: string, data?: T, depth: number = 0) {
+  private slugSegments: string[]
+  // prefer showing the file path segment over the slug segment
+  // so that folders that dont have index files can be shown as is
+  // without dashes in the slug
+  private fileSegmentHint?: string
+  private displayNameOverride?: string
+  data: T | null
+
+  constructor(segments: string[], data?: T) {
     this.children = []
-    this.slugSegment = segment
-    this.displayName = data?.title ?? segment
+    this.slugSegments = segments
     this.data = data ?? null
-    this.depth = depth
-    this.isFolder = segment === "index"
+    this.isFolder = false
+    this.displayNameOverride = undefined
+  }
+
+  get displayName(): string {
+    const nonIndexTitle = this.data?.title === "index" ? undefined : this.data?.title
+    return (
+      this.displayNameOverride ?? nonIndexTitle ?? this.fileSegmentHint ?? this.slugSegment ?? ""
+    )
+  }
+
+  set displayName(name: string) {
+    this.displayNameOverride = name
+  }
+
+  get slug(): FullSlug {
+    const path = joinSegments(...this.slugSegments) as FullSlug
+    if (this.isFolder) {
+      return joinSegments(path, "index") as FullSlug
+    }
+
+    return path
+  }
+
+  get slugSegment(): string {
+    return this.slugSegments[this.slugSegments.length - 1]
+  }
+
+  private makeChild(path: string[], file?: T) {
+    const fullPath = [...this.slugSegments, path[0]]
+    const child = new FileTrieNode<T>(fullPath, file)
+    this.children.push(child)
+    return child
   }
 
   private insert(path: string[], file: T) {
-    if (path.length === 0) return
+    if (path.length === 0) {
+      throw new Error("path is empty")
+    }
 
-    const nextSegment = path[0]
-
-    // base case, insert here
+    // if we are inserting, we are a folder
+    this.isFolder = true
+    const segment = path[0]
     if (path.length === 1) {
-      if (nextSegment === "index") {
-        // index case (we are the root and we just found index.md)
+      // base case, we are at the end of the path
+      if (segment === "index") {
         this.data ??= file
-        const title = file.title
-        if (title !== "index") {
-          this.displayName = title
-        }
       } else {
-        // direct child
-        this.children.push(new FileTrieNode(nextSegment, file, this.depth + 1))
-        this.isFolder = true
+        this.makeChild(path, file)
       }
+    } else if (path.length > 1) {
+      // recursive case, we are not at the end of the path
+      const child =
+        this.children.find((c) => c.slugSegment === segment) ?? this.makeChild(path, undefined)
 
-      return
+      const fileParts = file.filePath.split("/")
+      child.fileSegmentHint = fileParts.at(-path.length)
+      child.insert(path.slice(1), file)
     }
-
-    // find the right child to insert into, creating it if it doesn't exist
-    path = path.splice(1)
-    let child = this.children.find((c) => c.slugSegment === nextSegment)
-    if (!child) {
-      child = new FileTrieNode<T>(nextSegment, undefined, this.depth + 1)
-      this.children.push(child)
-      child.isFolder = true
-    }
-
-    child.insert(path, file)
   }
 
   // Add new file to trie
@@ -63,6 +89,32 @@
     this.insert(file.slug.split("/"), file)
   }
 
+  findNode(path: string[]): FileTrieNode<T> | undefined {
+    if (path.length === 0 || (path.length === 1 && path[0] === "index")) {
+      return this
+    }
+
+    return this.children.find((c) => c.slugSegment === path[0])?.findNode(path.slice(1))
+  }
+
+  ancestryChain(path: string[]): Array<FileTrieNode<T>> | undefined {
+    if (path.length === 0 || (path.length === 1 && path[0] === "index")) {
+      return [this]
+    }
+
+    const child = this.children.find((c) => c.slugSegment === path[0])
+    if (!child) {
+      return undefined
+    }
+
+    const childPath = child.ancestryChain(path.slice(1))
+    if (!childPath) {
+      return undefined
+    }
+
+    return [this, ...childPath]
+  }
+
   /**
    * Filter trie nodes. Behaves similar to `Array.prototype.filter()`, but modifies tree in place
    */
@@ -88,7 +140,7 @@
   }
 
   static fromEntries<T extends FileTrieData>(entries: [FullSlug, T][]) {
-    const trie = new FileTrieNode<T>("")
+    const trie = new FileTrieNode<T>([])
     entries.forEach(([, entry]) => trie.add(entry))
     return trie
   }
@@ -98,22 +150,12 @@
    * in the a flat array including the full path and the node
    */
   entries(): [FullSlug, FileTrieNode<T>][] {
-    const traverse = (
-      node: FileTrieNode<T>,
-      currentPath: string,
-    ): [FullSlug, FileTrieNode<T>][] => {
-      const segments = [currentPath, node.slugSegment]
-      const fullPath = joinSegments(...segments) as FullSlug
-
-      const indexQualifiedPath =
-        node.isFolder && node.depth > 0 ? (joinSegments(fullPath, "index") as FullSlug) : fullPath
-
-      const result: [FullSlug, FileTrieNode<T>][] = [[indexQualifiedPath, node]]
-
-      return result.concat(...node.children.map((child) => traverse(child, fullPath)))
+    const traverse = (node: FileTrieNode<T>): [FullSlug, FileTrieNode<T>][] => {
+      const result: [FullSlug, FileTrieNode<T>][] = [[node.slug, node]]
+      return result.concat(...node.children.map(traverse))
     }
 
-    return traverse(this, "")
+    return traverse(this)
   }
 
   /**

--
Gitblit v1.10.0