various path fixes for links to extensions, fix relative paths in links
This commit is contained in:
		
							parent
							
								
									2dc0ae279c
								
							
						
					
					
						commit
						0c199975f2
					
				| @ -7,7 +7,7 @@ title: Making your own plugins | ||||
| 
 | ||||
| Quartz's plugins are a series of transformations over content. This is illustrated in the diagram of the processing pipeline below: | ||||
| 
 | ||||
| ![[quartz-transform-pipeline.png]] | ||||
| ![[quartz transform pipeline.png]] | ||||
| 
 | ||||
| All plugins are defined as a function that takes in a single parameter for options `type OptionType = object | undefined` and return an object that corresponds to the type of plugin it is. | ||||
| 
 | ||||
|  | ||||
| @ -50,7 +50,7 @@ This part of the configuration concerns anything that can affect the whole site. | ||||
| 
 | ||||
| You can think of Quartz plugins as a series of transformations over content. | ||||
| 
 | ||||
| ![[quartz-transform-pipeline.png]] | ||||
| ![[quartz transform pipeline.png]] | ||||
| 
 | ||||
| ```ts | ||||
| plugins: { | ||||
|  | ||||
| @ -4,6 +4,8 @@ draft: true | ||||
| 
 | ||||
| ## todo | ||||
| 
 | ||||
| - static icon path (in head) never gets updated | ||||
| 	- do we update relative links on spa? | ||||
| - back button with anchors / popovers + spa is broken | ||||
| - debounce cfg rebuild on large repos | ||||
|   - investigate content rebuild triggering multiple times even when debounced, causing an esbuild deadlock | ||||
|  | ||||
| @ -100,7 +100,7 @@ Here's how to add a custom domain to your GitHub pages deployment. | ||||
|      - `185.199.111.153` | ||||
|    - If you are using a subdomain, navigate to your DNS provider and create a `CNAME` record that points your subdomain to the default domain for your site. For example, if you want to use the subdomain `quartz.example.com` for your user site, create a `CNAME` record that points `quartz.example.com` to `<github-username>.github.io`. | ||||
| 
 | ||||
| ![[dns-records.png]]_The above shows a screenshot of Google Domains configured for both `jzhao.xyz` (an apex domain) and `quartz.jzhao.xyz` (a subdomain)._ | ||||
| ![[dns records.png]]_The above shows a screenshot of Google Domains configured for both `jzhao.xyz` (an apex domain) and `quartz.jzhao.xyz` (a subdomain)._ | ||||
| 
 | ||||
| See the [GitHub documentation](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain) for more detail about how to setup your own custom domain with GitHub Pages. | ||||
| 
 | ||||
|  | ||||
| Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB | 
| Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB | 
| Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB | 
| @ -20,7 +20,7 @@ export interface FullPageLayout { | ||||
| 
 | ||||
| These correspond to following parts of the page: | ||||
| 
 | ||||
| ![[quartz-layout.png|800]] | ||||
| ![[quartz layout.png|800]] | ||||
| 
 | ||||
| > [!note] | ||||
| > There are two additional layout fields that are _not_ shown in the above diagram. | ||||
|  | ||||
| @ -388,7 +388,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
| 
 | ||||
|       await build(clientRefresh) | ||||
|       const server = http.createServer(async (req, res) => { | ||||
|         const serve = async (fp) => { | ||||
|         const serve = async () => { | ||||
|           await serveHandler(req, res, { | ||||
|             public: argv.output, | ||||
|             directoryListing: false, | ||||
| @ -400,11 +400,11 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|         } | ||||
| 
 | ||||
|         const redirect = (newFp) => { | ||||
|           res.writeHead(301, { | ||||
|           res.writeHead(302, { | ||||
|             Location: newFp, | ||||
|           }) | ||||
|           console.log(chalk.yellow("[301]") + chalk.grey(` ${req.url} -> ${newFp}`)) | ||||
|           return res.end() | ||||
|           console.log(chalk.yellow("[302]") + chalk.grey(` ${req.url} -> ${newFp}`)) | ||||
|           res.end() | ||||
|         } | ||||
| 
 | ||||
|         let fp = req.url?.split("?")[0] ?? "/" | ||||
| @ -415,7 +415,8 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|           // does /trailing/index.html exist? if so, serve it
 | ||||
|           const indexFp = path.posix.join(fp, "index.html") | ||||
|           if (fs.existsSync(path.posix.join(argv.output, indexFp))) { | ||||
|             return serve(indexFp) | ||||
|             req.url = fp | ||||
|             return serve() | ||||
|           } | ||||
| 
 | ||||
|           // does /trailing.html exist? if so, redirect to /trailing
 | ||||
| @ -424,7 +425,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|             base += ".html" | ||||
|           } | ||||
|           if (fs.existsSync(path.posix.join(argv.output, base))) { | ||||
|             return redirect(base) | ||||
|             return redirect(fp.slice(0, -1)) | ||||
|           } | ||||
|         } else { | ||||
|           // /regular
 | ||||
| @ -434,7 +435,8 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|             base += ".html" | ||||
|           } | ||||
|           if (fs.existsSync(path.posix.join(argv.output, base))) { | ||||
|             return serve(base) | ||||
|             req.url = fp | ||||
|             return serve() | ||||
|           } | ||||
| 
 | ||||
|           // does /regular/index.html exist? if so, redirect to /regular/
 | ||||
| @ -444,7 +446,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         return serve(fp) | ||||
|         return serve() | ||||
|       }) | ||||
|       server.listen(argv.port) | ||||
|       console.log(chalk.cyan(`Started a Quartz server listening at http://localhost:${argv.port}`)) | ||||
| @ -458,7 +460,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. | ||||
|           await build(clientRefresh) | ||||
|         }) | ||||
|     } else { | ||||
|       await build(() => {}) | ||||
|       await build(() => { }) | ||||
|       ctx.dispose() | ||||
|     } | ||||
|   }) | ||||
|  | ||||
| @ -17,7 +17,7 @@ const isLocalUrl = (href: string) => { | ||||
|       } | ||||
|       return true | ||||
|     } | ||||
|   } catch (e) {} | ||||
|   } catch (e) { } | ||||
|   return false | ||||
| } | ||||
| 
 | ||||
| @ -50,6 +50,7 @@ async function navigate(url: URL, isBack: boolean = false) { | ||||
|     history.pushState({}, "", url) | ||||
|     window.scrollTo({ top: 0 }) | ||||
|   } | ||||
| 
 | ||||
|   const html = p.parseFromString(contents, "text/html") | ||||
|   let title = html.querySelector("title")?.textContent | ||||
|   if (title) { | ||||
|  | ||||
| @ -18,7 +18,7 @@ export const Assets: QuartzEmitterPlugin = () => { | ||||
|       for (const fp of fps) { | ||||
|         const ext = path.extname(fp) | ||||
|         const src = joinSegments(argv.directory, fp) as FilePath | ||||
|         const name = (slugifyFilePath(fp as FilePath) + ext) as FilePath | ||||
|         const name = (slugifyFilePath(fp as FilePath, true) + ext) as FilePath | ||||
| 
 | ||||
|         const dest = joinSegments(assetsPath, name) as FilePath | ||||
|         const dir = path.dirname(dest) as FilePath | ||||
|  | ||||
| @ -36,6 +36,7 @@ export const CreatedModifiedDate: QuartzTransformerPlugin<Partial<Options> | und | ||||
|               } else if (source === "frontmatter" && file.data.frontmatter) { | ||||
|                 created ||= file.data.frontmatter.date | ||||
|                 modified ||= file.data.frontmatter.lastmod | ||||
|                 modified ||= file.data.frontmatter.updated | ||||
|                 modified ||= file.data.frontmatter["last-modified"] | ||||
|                 published ||= file.data.frontmatter.publishDate | ||||
|               } else if (source === "git") { | ||||
|  | ||||
| @ -79,9 +79,8 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> = | ||||
|               ) { | ||||
|                 if (!isAbsoluteUrl(node.properties.src)) { | ||||
|                   let dest = node.properties.src as RelativeURL | ||||
|                   const ext = path.extname(node.properties.src) | ||||
|                   dest = node.properties.src = transformLink(curSlug, dest, transformOptions) | ||||
|                   node.properties.src = dest + ext | ||||
|                   node.properties.src = dest | ||||
|                 } | ||||
|               } | ||||
|             }) | ||||
|  | ||||
| @ -196,7 +196,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options> | ||||
|               // embed cases
 | ||||
|               if (value.startsWith("!")) { | ||||
|                 const ext: string = path.extname(fp).toLowerCase() | ||||
|                 const url = slugifyFilePath(fp as FilePath) + ext | ||||
|                 const url = slugifyFilePath(fp as FilePath) | ||||
|                 if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg"].includes(ext)) { | ||||
|                   const dims = alias ?? "" | ||||
|                   let [width, height] = dims.split("x", 2) | ||||
|  | ||||
| @ -49,6 +49,7 @@ describe("typeguards", () => { | ||||
|     assert(path.isRelativeURL("./abc/def#an-anchor")) | ||||
|     assert(path.isRelativeURL("./abc/def?query=1#an-anchor")) | ||||
|     assert(path.isRelativeURL("../abc/def")) | ||||
|     assert(path.isRelativeURL("./abc/def.pdf")) | ||||
| 
 | ||||
|     assert(!path.isRelativeURL("abc")) | ||||
|     assert(!path.isRelativeURL("/abc/def")) | ||||
| @ -60,12 +61,12 @@ describe("typeguards", () => { | ||||
|   test("isServerSlug", () => { | ||||
|     assert(path.isServerSlug("index")) | ||||
|     assert(path.isServerSlug("abc/def")) | ||||
|     assert(path.isServerSlug("html.energy")) | ||||
|     assert(path.isServerSlug("test.pdf")) | ||||
| 
 | ||||
|     assert(!path.isServerSlug(".")) | ||||
|     assert(!path.isServerSlug("./abc/def")) | ||||
|     assert(!path.isServerSlug("../abc/def")) | ||||
|     assert(!path.isServerSlug("index.html")) | ||||
|     assert(!path.isServerSlug("abc/def.html")) | ||||
|     assert(!path.isServerSlug("abc/def#anchor")) | ||||
|     assert(!path.isServerSlug("abc/def?query=1")) | ||||
|     assert(!path.isServerSlug("note with spaces")) | ||||
| @ -140,11 +141,12 @@ describe("transforms", () => { | ||||
|     asserts( | ||||
|       [ | ||||
|         ["content/index.md", "content/index"], | ||||
|         ["content/index.html", "content/index"], | ||||
|         ["content/_index.md", "content/index"], | ||||
|         ["/content/index.md", "content/index"], | ||||
|         ["content/cool.png", "content/cool"], | ||||
|         ["content/cool.png", "content/cool.png"], | ||||
|         ["index.md", "index"], | ||||
|         ["test.mp4", "test"], | ||||
|         ["test.mp4", "test.mp4"], | ||||
|         ["note with spaces.md", "note-with-spaces"], | ||||
|       ], | ||||
|       path.slugifyFilePath, | ||||
| @ -160,10 +162,13 @@ describe("transforms", () => { | ||||
|         [".", "."], | ||||
|         ["./", "./"], | ||||
|         ["./index", "./"], | ||||
|         ["./index#abc", "./#abc"], | ||||
|         ["./index.html", "./"], | ||||
|         ["./index.md", "./"], | ||||
|         ["./index.css", "./index.css"], | ||||
|         ["content", "./content"], | ||||
|         ["content/test.md", "./content/test"], | ||||
|         ["content/test.pdf", "./content/test.pdf"], | ||||
|         ["./content/test.md", "./content/test"], | ||||
|         ["../content/test.md", "../content/test"], | ||||
|         ["tags/", "./tags/"], | ||||
| @ -193,7 +198,7 @@ describe("transforms", () => { | ||||
| }) | ||||
| 
 | ||||
| describe("link strategies", () => { | ||||
|   const allSlugs = ["a/b/c", "a/b/d", "a/b/index", "e/f", "e/g/h", "index"] as ServerSlug[] | ||||
|   const allSlugs = ["a/b/c", "a/b/d", "a/b/index", "e/f", "e/g/h", "index", "a/test.png"] as ServerSlug[] | ||||
| 
 | ||||
|   describe("absolute", () => { | ||||
|     const opts: TransformOptions = { | ||||
| @ -204,27 +209,29 @@ describe("link strategies", () => { | ||||
|     test("from a/b/c", () => { | ||||
|       const cur = "a/b/c" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/d", opts), "../../../a/b/d") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../../a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../../a/b/") | ||||
|       assert.strictEqual(path.transformLink(cur, "e/f", opts), "../../../e/f") | ||||
|       assert.strictEqual(path.transformLink(cur, "e/g/h", opts), "../../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../..") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "index.png", opts), "../../../index.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "index#abc", opts), "../../../#abc") | ||||
|       assert.strictEqual(path.transformLink(cur, "tag/test", opts), "../../../tag/test") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/c#test", opts), "../../../a/b/c#test") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/test.png", opts), "../../../a/test.png") | ||||
|     }) | ||||
| 
 | ||||
|     test("from a/b/index", () => { | ||||
|       const cur = "a/b" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/d", opts), "../../a/b/d") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b", opts), "../../a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../..") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../") | ||||
|     }) | ||||
| 
 | ||||
|     test("from index", () => { | ||||
|       const cur = "" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), ".") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "./") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/c", opts), "./a/b/c") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b/") | ||||
|     }) | ||||
|   }) | ||||
| 
 | ||||
| @ -238,24 +245,29 @@ describe("link strategies", () => { | ||||
|       const cur = "a/b/c" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "d", opts), "../../../a/b/d") | ||||
|       assert.strictEqual(path.transformLink(cur, "h", opts), "../../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../../a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../..") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../../a/b/") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index.png", opts), "../../../a/b/index.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index#abc", opts), "../../../a/b/#abc") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "index.png", opts), "../../../index.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "test.png", opts), "../../../a/test.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "index#abc", opts), "../../../#abc") | ||||
|     }) | ||||
| 
 | ||||
|     test("from a/b/index", () => { | ||||
|       const cur = "a/b" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "d", opts), "../../a/b/d") | ||||
|       assert.strictEqual(path.transformLink(cur, "h", opts), "../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../..") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "../../a/b/") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "../../") | ||||
|     }) | ||||
| 
 | ||||
|     test("from index", () => { | ||||
|       const cur = "" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "d", opts), "./a/b/d") | ||||
|       assert.strictEqual(path.transformLink(cur, "h", opts), "./e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), ".") | ||||
|       assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b/") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "./") | ||||
|     }) | ||||
|   }) | ||||
| 
 | ||||
| @ -269,9 +281,14 @@ describe("link strategies", () => { | ||||
|       const cur = "a/b/c" as CanonicalSlug | ||||
|       assert.strictEqual(path.transformLink(cur, "d", opts), "./d") | ||||
|       assert.strictEqual(path.transformLink(cur, "index", opts), "./") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../index", opts), "../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../", opts), "../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../e/g/h", opts), "../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../index", opts), "../../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../index.png", opts), "../../../index.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../index#abc", opts), "../../../#abc") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../", opts), "../../../") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../a/test.png", opts), "../../../a/test.png") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../e/g/h", opts), "../../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../e/g/h", opts), "../../../e/g/h") | ||||
|       assert.strictEqual(path.transformLink(cur, "../../../e/g/h#abc", opts), "../../../e/g/h#abc") | ||||
|     }) | ||||
| 
 | ||||
|     test("from a/b/index", () => { | ||||
|  | ||||
| @ -72,7 +72,7 @@ export type RelativeURL = SlugLike<"relative"> | ||||
| 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 type ServerSlug = SlugLike<"server"> | ||||
| 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 @@ export function canonicalizeServer(slug: ServerSlug): CanonicalSlug { | ||||
|   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 @@ export function slugifyFilePath(fp: FilePath): ServerSlug { | ||||
|     slug = slug.replace(/_index$/, "index") | ||||
|   } | ||||
| 
 | ||||
|   return slug as ServerSlug | ||||
|   return slug + ext as ServerSlug | ||||
| } | ||||
| 
 | ||||
| export function transformInternalLink(link: string): RelativeURL { | ||||
| @ -139,19 +144,16 @@ export function transformInternalLink(link: string): RelativeURL { | ||||
|     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 @@ export function transformLink( | ||||
|   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 @@ export function transformLink( | ||||
|     } | ||||
| 
 | ||||
|     // 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 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user