From 0c199975f2d469ecdfd7efcf2ddd16ffa1dc492b Mon Sep 17 00:00:00 2001
From: Jacky Zhao <j.zhao2k19@gmail.com>
Date: Thu, 17 Aug 2023 07:55:28 +0000
Subject: [PATCH] various path fixes for links to extensions, fix relative paths in links

---
 quartz/util/path.ts |   33 ++++++++++++++++++---------------
 1 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/quartz/util/path.ts b/quartz/util/path.ts
index c1016af..c949474 100644
--- a/quartz/util/path.ts
+++ b/quartz/util/path.ts
@@ -72,7 +72,7 @@
 export function isRelativeURL(s: string): s is RelativeURL {
   const validStart = /^\.{1,2}/.test(s)
   const validEnding = !(s.endsWith("/index") || s === "index")
-  return validStart && validEnding && !_hasFileExtension(s)
+  return validStart && validEnding && ![".md", ".html"].includes(_getFileExtension(s) ?? "") 
 }
 
 /** A server side slug. This is what Quartz uses to emit files so uses index suffixes */
@@ -80,7 +80,7 @@
 export function isServerSlug(s: string): s is ServerSlug {
   const validStart = !(s.startsWith(".") || s.startsWith("/"))
   const validEnding = !s.endsWith("/")
-  return validStart && validEnding && !_containsForbiddenCharacters(s) && !_hasFileExtension(s)
+  return validStart && validEnding && !_containsForbiddenCharacters(s)
 }
 
 /** The real file path to a file on disk */
@@ -114,9 +114,14 @@
   return res
 }
 
-export function slugifyFilePath(fp: FilePath): ServerSlug {
+export function slugifyFilePath(fp: FilePath, excludeExt?: boolean): ServerSlug {
   fp = _stripSlashes(fp) as FilePath
-  const withoutFileExt = fp.replace(new RegExp(_getFileExtension(fp) + "$"), "")
+  let ext = _getFileExtension(fp)
+  const withoutFileExt = fp.replace(new RegExp(ext + "$"), "")
+  if (excludeExt || [".md", ".html", undefined].includes(ext)) {
+    ext = ""
+  }
+
   let slug = withoutFileExt
     .split("/")
     .map((segment) => segment.replace(/\s/g, "-")) // slugify all segments
@@ -128,7 +133,7 @@
     slug = slug.replace(/_index$/, "index")
   }
 
-  return slug as ServerSlug
+  return slug + ext as ServerSlug
 }
 
 export function transformInternalLink(link: string): RelativeURL {
@@ -139,19 +144,16 @@
     fplike.endsWith("index.md") ||
     fplike.endsWith("index.html") ||
     fplike.endsWith("/")
+
   let segments = fplike.split("/").filter((x) => x.length > 0)
   let prefix = segments.filter(_isRelativeSegment).join("/")
   let fp = segments.filter((seg) => !_isRelativeSegment(seg)).join("/")
 
-  // implicit markdown
-  if (!_hasFileExtension(fp)) {
-    fp += ".md"
-  }
-
-  fp = canonicalizeServer(slugifyFilePath(fp as FilePath))
+  // manually add ext here as we want to not strip 'index' if it has an extension
+  fp = canonicalizeServer(slugifyFilePath(fp as FilePath) as ServerSlug)
   const joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp))
   const trail = folderPath ? "/" : ""
-  const res = (_addRelativeToStart(joined) + anchor + trail) as RelativeURL
+  const res = (_addRelativeToStart(joined) + trail + anchor) as RelativeURL
   return res
 }
 
@@ -217,8 +219,9 @@
   if (opts.strategy === "relative") {
     return _addRelativeToStart(targetSlug) as RelativeURL
   } else {
-    targetSlug = _stripSlashes(targetSlug.slice(".".length))
-    let [targetCanonical, targetAnchor] = splitAnchor(targetSlug)
+    const folderTail = targetSlug.endsWith("/") ? "/" : ""
+    const canonicalSlug = _stripSlashes(targetSlug.slice(".".length))
+    let [targetCanonical, targetAnchor] = splitAnchor(canonicalSlug)
 
     if (opts.strategy === "shortest") {
       // if the file name is unique, then it's just the filename
@@ -236,7 +239,7 @@
     }
 
     // if it's not unique, then it's the absolute path from the vault root
-    return joinSegments(pathToRoot(src), targetSlug) as RelativeURL
+    return joinSegments(pathToRoot(src), canonicalSlug) + folderTail as RelativeURL
   }
 }
 

--
Gitblit v1.10.0