fix(aliases): wikilink resolution for aliases (#1681)
With markdownLinkResolution: "shortest", aka "+/- how Obsidian does it" and given pages A and nested/B which has an alias Z, if you try to link from A using [[Z]] it wouldn't work and get 404. This is caused by alias slugs (nested/Z in this case, emitted by AliasRedirects) not being present in the `allSlugs` list which is used by the link transformer. The fix is to compute the alias slugs in the frontmatter transformer and add them to `allSlugs` there. Also we store them in file data to avoid recomputing them when emitting alias redirect pages. Fixes #904 Note: given how currently the markdown/html transformers are ordered this doesn't really work. Given pages A and nested/B which has an alias Z, here's the order which currently happens: md-transformers(A) => html-transformers(A) => md-transformers(B) => html-transformers(B) Since the nested/Z slug will get added when md-transformers(B) are run, but the slugs are used by html-transformers(A) when resolving it's links - the link [[Z]] in A will still 404 A fix for this is to split the parser into two stages - first apply the md-transformers to all files, and only then apply html-transformers to all files. I did just that in a different commit, which is needed for this one to work correctly.
This commit is contained in:
		
							parent
							
								
									1a02642469
								
							
						
					
					
						commit
						29c533a265
					
				| @ -1,8 +1,8 @@ | ||||
| import { FilePath, FullSlug, joinSegments, resolveRelative, simplifySlug } from "../../util/path" | ||||
| import { FilePath, joinSegments, resolveRelative, simplifySlug } from "../../util/path" | ||||
| import { QuartzEmitterPlugin } from "../types" | ||||
| import path from "path" | ||||
| import { write } from "./helpers" | ||||
| import DepGraph from "../../depgraph" | ||||
| import { getAliasSlugs } from "../transformers/frontmatter" | ||||
| 
 | ||||
| export const AliasRedirects: QuartzEmitterPlugin = () => ({ | ||||
|   name: "AliasRedirects", | ||||
| @ -14,20 +14,7 @@ export const AliasRedirects: QuartzEmitterPlugin = () => ({ | ||||
| 
 | ||||
|     const { argv } = ctx | ||||
|     for (const [_tree, file] of content) { | ||||
|       const dir = path.posix.relative(argv.directory, path.dirname(file.data.filePath!)) | ||||
|       const aliases = file.data.frontmatter?.aliases ?? [] | ||||
|       const slugs = aliases.map((alias) => path.posix.join(dir, alias) as FullSlug) | ||||
|       const permalink = file.data.frontmatter?.permalink | ||||
|       if (typeof permalink === "string") { | ||||
|         slugs.push(permalink as FullSlug) | ||||
|       } | ||||
| 
 | ||||
|       for (let slug of slugs) { | ||||
|         // fix any slugs that have trailing slash
 | ||||
|         if (slug.endsWith("/")) { | ||||
|           slug = joinSegments(slug, "index") as FullSlug | ||||
|         } | ||||
| 
 | ||||
|       for (const slug of getAliasSlugs(file.data.frontmatter?.aliases ?? [], argv, file)) { | ||||
|         graph.addEdge(file.data.filePath!, joinSegments(argv.output, slug + ".html") as FilePath) | ||||
|       } | ||||
|     } | ||||
| @ -40,20 +27,8 @@ export const AliasRedirects: QuartzEmitterPlugin = () => ({ | ||||
| 
 | ||||
|     for (const [_tree, file] of content) { | ||||
|       const ogSlug = simplifySlug(file.data.slug!) | ||||
|       const dir = path.posix.relative(argv.directory, path.dirname(file.data.filePath!)) | ||||
|       const aliases = file.data.frontmatter?.aliases ?? [] | ||||
|       const slugs: FullSlug[] = aliases.map((alias) => path.posix.join(dir, alias) as FullSlug) | ||||
|       const permalink = file.data.frontmatter?.permalink | ||||
|       if (typeof permalink === "string") { | ||||
|         slugs.push(permalink as FullSlug) | ||||
|       } | ||||
| 
 | ||||
|       for (let slug of slugs) { | ||||
|         // fix any slugs that have trailing slash
 | ||||
|         if (slug.endsWith("/")) { | ||||
|           slug = joinSegments(slug, "index") as FullSlug | ||||
|         } | ||||
| 
 | ||||
|       for (const slug of file.data.aliases ?? []) { | ||||
|         const redirUrl = resolveRelative(slug, file.data.slug!) | ||||
|         const fp = await write({ | ||||
|           ctx, | ||||
|  | ||||
| @ -3,9 +3,12 @@ import remarkFrontmatter from "remark-frontmatter" | ||||
| import { QuartzTransformerPlugin } from "../types" | ||||
| import yaml from "js-yaml" | ||||
| import toml from "toml" | ||||
| import { slugTag } from "../../util/path" | ||||
| import { FilePath, FullSlug, joinSegments, slugifyFilePath, slugTag } from "../../util/path" | ||||
| import { QuartzPluginData } from "../vfile" | ||||
| import { i18n } from "../../i18n" | ||||
| import { Argv } from "../../util/ctx" | ||||
| import { VFile } from "vfile" | ||||
| import path from "path" | ||||
| 
 | ||||
| export interface Options { | ||||
|   delimiters: string | [string, string] | ||||
| @ -40,11 +43,26 @@ function coerceToArray(input: string | string[]): string[] | undefined { | ||||
|     .map((tag: string | number) => tag.toString()) | ||||
| } | ||||
| 
 | ||||
| export function getAliasSlugs(aliases: string[], argv: Argv, file: VFile): FullSlug[] { | ||||
|   const dir = path.posix.relative(argv.directory, path.dirname(file.data.filePath!)) | ||||
|   const slugs: FullSlug[] = aliases.map( | ||||
|     (alias) => path.posix.join(dir, slugifyFilePath(alias as FilePath)) as FullSlug, | ||||
|   ) | ||||
|   const permalink = file.data.frontmatter?.permalink | ||||
|   if (typeof permalink === "string") { | ||||
|     slugs.push(permalink as FullSlug) | ||||
|   } | ||||
|   // fix any slugs that have trailing slash
 | ||||
|   return slugs.map((slug) => | ||||
|     slug.endsWith("/") ? (joinSegments(slug, "index") as FullSlug) : slug, | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts) => { | ||||
|   const opts = { ...defaultOptions, ...userOpts } | ||||
|   return { | ||||
|     name: "FrontMatter", | ||||
|     markdownPlugins({ cfg }) { | ||||
|     markdownPlugins({ cfg, allSlugs, argv }) { | ||||
|       return [ | ||||
|         [remarkFrontmatter, ["yaml", "toml"]], | ||||
|         () => { | ||||
| @ -67,7 +85,11 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts) | ||||
|             if (tags) data.tags = [...new Set(tags.map((tag: string) => slugTag(tag)))] | ||||
| 
 | ||||
|             const aliases = coerceToArray(coalesceAliases(data, ["aliases", "alias"])) | ||||
|             if (aliases) data.aliases = aliases | ||||
|             if (aliases) { | ||||
|               data.aliases = aliases // frontmatter
 | ||||
|               const slugs = (file.data.aliases = getAliasSlugs(aliases, argv, file)) | ||||
|               allSlugs.push(...slugs) | ||||
|             } | ||||
|             const cssclasses = coerceToArray(coalesceAliases(data, ["cssclasses", "cssclass"])) | ||||
|             if (cssclasses) data.cssclasses = cssclasses | ||||
| 
 | ||||
| @ -98,6 +120,7 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options>> = (userOpts) | ||||
| 
 | ||||
| declare module "vfile" { | ||||
|   interface DataMap { | ||||
|     aliases: FullSlug[] | ||||
|     frontmatter: { [key: string]: unknown } & { | ||||
|       title: string | ||||
|     } & Partial<{ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user