fixed markdown and shiki(untested) link transformers

This commit is contained in:
Xanazf 2024-10-10 21:06:15 +03:00
parent 6d353e0c6b
commit 4fbb038c0d
Signed by: Xanazf
GPG key ID: 4E4A5AD1FB748427
4 changed files with 103 additions and 66 deletions

View file

@ -20,6 +20,7 @@
"@types/node": "^20.14.11", "@types/node": "^20.14.11",
"astro": "^4.15.9", "astro": "^4.15.9",
"astro-breadcrumbs": "^2.3.1", "astro-breadcrumbs": "^2.3.1",
"hast": "^1.0.0",
"hast-util-from-html": "^2.0.3", "hast-util-from-html": "^2.0.3",
"node": "npm:22.7.0", "node": "npm:22.7.0",
"remark-github-blockquote-alert": "^1.2.1", "remark-github-blockquote-alert": "^1.2.1",

View file

@ -75,7 +75,9 @@ export function groupRoutes(routes: RouteData[]): GroupedRoutes {
}, defaultValue); }, defaultValue);
} }
export async function processQsMarkdown(markdown: string): Promise<string> { export async function processQsMarkdown(
markdown: string
): Promise<string> {
return await markdownUtils.processMarkdown(markdown); return await markdownUtils.processMarkdown(markdown);
} }

View file

@ -1,78 +1,102 @@
import type { Transformer } from "unified"; import type { Parent, Node } from "unist";
import type { Node, Parent } from "unist";
import { visit, CONTINUE, SKIP } from "unist-util-visit"; import { visit, CONTINUE, SKIP } from "unist-util-visit";
import { fromHtml } from "hast-util-from-html"; import { fromHtml } from "hast-util-from-html";
import type { Root, Element } from "hast";
import type { AstroMarkdownOptions, MarkdownProcessor } from "@astrojs/markdown-remark"; import type {
AstroMarkdownOptions,
MarkdownProcessor,
RehypePlugin,
} from "@astrojs/markdown-remark";
import { createMarkdownProcessor } from "@astrojs/markdown-remark"; import { createMarkdownProcessor } from "@astrojs/markdown-remark";
import { remarkAlert } from "remark-github-blockquote-alert"; import { remarkAlert } from "remark-github-blockquote-alert";
import sectionize from "@hbsnow/rehype-sectionize"; import sectionize from "@hbsnow/rehype-sectionize";
import type { ShikiTransformer } from "shiki";
import { getQMLTypeLinkObject, getQMLTypeLink, getIconForLink } from "./helpers.ts" import {
getQMLTypeLinkObject,
getQMLTypeLink,
getIconForLink,
} from "./helpers.ts";
// couldn't find the actual type to use // couldn't find the actual type to use
type HtmlNode = Node & { interface HtmlNode extends Node {
value: string, value: string;
type: string, type: string;
tagName: string, tagName: string;
}; }
function rehypeRewriteTypelinks(): Transformer { const rehypeRewriteTypelinks: RehypePlugin<[]> = () => {
return function (root: Node): Node { return (root: Node): Root => {
// @ts-ignore: does not appear to be a way to give this a correct type, it works for the one with a test below visit(
visit(root, (node: HtmlNode, index: number, parent: Parent) => { root,
if (node.type == "element" && node.tagName == "pre") return SKIP; "text",
(node: HtmlNode, index: number, parent: Parent) => {
if (node.type == "text") {
let changed = false; let changed = false;
node.value = node.value.replace(/TYPE99(\w+.)99TYPE/g, (_full: string, match: string) => { node.value = node.value.replace(
/TYPE99(\w+.)99TYPE/g,
(_full: string, match: string) => {
changed = true; changed = true;
const linkObject = getQMLTypeLinkObject(match); const linkObject = getQMLTypeLinkObject(match);
const link = getQMLTypeLink(linkObject); const link = getQMLTypeLink(linkObject);
const icon = (linkObject.mtype && linkObject.mtype != "func") ? getIconForLink(linkObject.mtype, false) : null; const icon =
const hasParens = linkObject.mtype == "func" || linkObject.mtype == "signal"; linkObject.mtype && linkObject.mtype !== "func"
? getIconForLink(linkObject.mtype, false)
: null;
const hasParens =
linkObject.mtype === "func" ||
linkObject.mtype === "signal";
const hasDot = linkObject.name && linkObject.mname; const hasDot = linkObject.name && linkObject.mname;
return `<a class="type${linkObject.mtype}-link typedata-link" href=${link}>${icon ?? ""}${linkObject.name ?? ""}${hasDot ? "." : ""}${linkObject.mname ?? ""}${hasParens ? "()" : ""}</a>`; return `<a class="type${linkObject.mtype}-link typedata-link" href=${link}>${icon ?? ""}${linkObject.name ?? ""}${hasDot ? "." : ""}${linkObject.mname ?? ""}${hasParens ? "()" : ""}</a>`;
}); }
);
if (changed) { if (changed) {
const fragment = fromHtml(node.value, { fragment: true }); const fragment = fromHtml(node.value, {
fragment: true,
});
parent.children.splice(index, 1, ...fragment.children); parent.children.splice(index, 1, ...fragment.children);
return SKIP; return SKIP;
} }
}
return CONTINUE; return CONTINUE;
});
return root;
}
} }
);
const shikiRewriteTypelinks = { return root as Root;
code: (root: Node) => { };
visit(root, "text", (node: HtmlNode, index: number, parent: Parent) => { };
let changed = false;
node.value = node.value.replace(/TYPE99(\w+.)99TYPE/g, (_full: string, match: string) => { const shikiRewriteTypelinks = (): ShikiTransformer => {
changed = true; return {
name: "rewrite-typelinks",
preprocess(code, _options) {
const qtRegExp = /QT_(\w+)/g;
const qsRegExp = /QS_(\w+)/g;
// WARN: need to change the code link identifier to this
// const hasTypelinks = code.search(/TYPE99(\w+.)99TYPE/g) !== -1;
const hasQTLink = code.search(qtRegExp) !== -1;
const hasQSLink = code.search(qsRegExp) !== -1;
if (hasQTLink) {
code.replace(qtRegExp, (_full: string, match: string) => {
const linkObject = getQMLTypeLinkObject(match); const linkObject = getQMLTypeLinkObject(match);
const link = getQMLTypeLink(linkObject); const link = getQMLTypeLink(linkObject);
return `<a href=${link}>${linkObject.name ?? ""}</a>`; return `<a href=${link}>${linkObject.name ?? ""}</a>`;
}); });
if (changed) {
const fragment = fromHtml(node.value, { fragment: true });
parent.children.splice(index, 1, ...fragment.children);
} }
if (hasQSLink) {
code.replace(qsRegExp, (_full: string, match: string) => {
const linkObject = getQMLTypeLinkObject(match);
const link = getQMLTypeLink(linkObject);
return `<a href=${link}>${linkObject.name ?? ""}</a>`;
}); });
} }
},
};
}; };
export const markdownConfig: AstroMarkdownOptions = { export const markdownConfig: AstroMarkdownOptions = {
@ -80,16 +104,14 @@ export const markdownConfig: AstroMarkdownOptions = {
shikiConfig: { shikiConfig: {
theme: "material-theme-ocean", theme: "material-theme-ocean",
wrap: true, wrap: true,
transformers: [ shikiRewriteTypelinks ], transformers: [shikiRewriteTypelinks()],
}, },
remarkPlugins: [[ remarkPlugins: [[remarkAlert, { legacyTitle: true }]],
remarkAlert,
{ legacyTitle: true },
]],
rehypePlugins: [ rehypePlugins: [
[ sectionize, { idPropertyName: "id" } ], // FIXME: incompatible types between unified/Plugin and Astro/RehypePlugin
// @ts-ignore: can't tell what this wants // @ts-expect-error
[ rehypeRewriteTypelinks, {} ], [sectionize as RehypePlugin, { idPropertyName: "id" }],
rehypeRewriteTypelinks,
], ],
}; };
@ -97,12 +119,16 @@ let globalMarkdownProcessor: Promise<MarkdownProcessor>;
async function getMarkdownProcessor(): Promise<MarkdownProcessor> { async function getMarkdownProcessor(): Promise<MarkdownProcessor> {
if (!globalMarkdownProcessor) { if (!globalMarkdownProcessor) {
globalMarkdownProcessor = createMarkdownProcessor(markdownConfig); globalMarkdownProcessor =
createMarkdownProcessor(markdownConfig);
} }
return globalMarkdownProcessor; return globalMarkdownProcessor;
} }
export async function processMarkdown(markdown: string): Promise<string> { export async function processMarkdown(
return (await (await getMarkdownProcessor()).render(markdown)).code; markdown: string
): Promise<string> {
return (await (await getMarkdownProcessor()).render(markdown))
.code;
} }

View file

@ -4364,6 +4364,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"hast@npm:^1.0.0":
version: 1.0.0
resolution: "hast@npm:1.0.0"
checksum: 10c0/a1a4ffaa99c6a4cfe6bd31e54ee919625a8ebcfc621d2d06cc76e593d7aeee4f1f430fcdbbf17ae8e249567ee7b724e4814b5eb273455d23bad8334c9bfc667d
languageName: node
linkType: hard
"hastscript@npm:^7.0.0": "hastscript@npm:^7.0.0":
version: 7.2.0 version: 7.2.0
resolution: "hastscript@npm:7.2.0" resolution: "hastscript@npm:7.2.0"
@ -6312,6 +6319,7 @@ __metadata:
"@types/node": "npm:^20.14.11" "@types/node": "npm:^20.14.11"
astro: "npm:^4.15.9" astro: "npm:^4.15.9"
astro-breadcrumbs: "npm:^2.3.1" astro-breadcrumbs: "npm:^2.3.1"
hast: "npm:^1.0.0"
hast-util-from-html: "npm:^2.0.3" hast-util-from-html: "npm:^2.0.3"
node: "npm:22.7.0" node: "npm:22.7.0"
pagefind: "npm:^1.1.1" pagefind: "npm:^1.1.1"