feat(contentPage): add dead link detection for missing pages

This update introduces functionality to identify and mark links to non-existent pages as "dead links" within the content page emitter. The implementation utilizes the `unist-util-visit` library to traverse the document tree and modify link elements accordingly. Links that do not correspond to existing slugs are converted to spans with a "dead-link" class for better user feedback.
This commit is contained in:
Amir Pourmand 2025-09-10 00:30:57 +03:30
parent e77a051144
commit 198f9e79a7

View File

@ -5,15 +5,18 @@ import HeaderConstructor from "../../components/Header"
import BodyConstructor from "../../components/Body" import BodyConstructor from "../../components/Body"
import { pageResources, renderPage } from "../../components/renderPage" import { pageResources, renderPage } from "../../components/renderPage"
import { FullPageLayout } from "../../cfg" import { FullPageLayout } from "../../cfg"
import { pathToRoot } from "../../util/path" import { pathToRoot, resolveRelative } from "../../util/path"
import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout" import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout"
import { Content } from "../../components" import { Content } from "../../components"
import { styleText } from "util" import { styleText } from "util"
import { write } from "./helpers" import { write } from "./helpers"
import { BuildCtx } from "../../util/ctx" import { BuildCtx } from "../../util/ctx"
import { Node } from "unist" import { Node } from "unist"
import { Root } from "hast"
import { StaticResources } from "../../util/resources" import { StaticResources } from "../../util/resources"
import { QuartzPluginData } from "../vfile" import { QuartzPluginData } from "../vfile"
import { visit } from "unist-util-visit"
import { RelativeURL } from "../../util/path"
async function processContent( async function processContent(
ctx: BuildCtx, ctx: BuildCtx,
@ -25,6 +28,46 @@ async function processContent(
) { ) {
const slug = fileData.slug! const slug = fileData.slug!
const cfg = ctx.cfg.configuration const cfg = ctx.cfg.configuration
/** Until the end of visit(), this code snippet is from
* https://github.com/jackyzha0/quartz/issues/454#issuecomment-2408792538
* by auctumnus
*
* It removes all the links that would lead to missing pages, ie.
*
* [[Missing link]] when Missing link.md does not exist.
*/
const allSlugs = allFiles.map((f) => (f.slug ? resolveRelative(slug, f.slug) : ""))
visit(tree as Root, "element", (elem) => {
if (elem.tagName === "a" && elem.properties.href) {
const href = elem.properties.href.toString()
if (href.startsWith("#")) {
return
}
if (!allSlugs.includes(href as RelativeURL)) {
if (elem.properties.className === undefined) {
elem.properties.className = "dead-link"
} else if (Array.isArray(elem.properties.className)) {
if (elem.properties.className.includes("external")) {
return
}
elem.properties.className.push("dead-link")
} else if (typeof elem.properties.className === "string") {
if (elem.properties.className.includes("external")) {
return
}
elem.properties.className += " dead-link"
} else {
return
}
elem.tagName = "span"
}
}
})
const externalResources = pageResources(pathToRoot(slug), resources) const externalResources = pageResources(pathToRoot(slug), resources)
const componentData: QuartzComponentProps = { const componentData: QuartzComponentProps = {
ctx, ctx,