fixed markdown and shiki(untested) link transformers
This commit is contained in:
parent
6d353e0c6b
commit
4fbb038c0d
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
changed = true;
|
/TYPE99(\w+.)99TYPE/g,
|
||||||
|
(_full: string, match: string) => {
|
||||||
|
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"
|
||||||
const hasDot = linkObject.name && linkObject.mname;
|
? getIconForLink(linkObject.mtype, false)
|
||||||
|
: null;
|
||||||
|
const hasParens =
|
||||||
|
linkObject.mtype === "func" ||
|
||||||
|
linkObject.mtype === "signal";
|
||||||
|
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 root as Root;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const shikiRewriteTypelinks = (): ShikiTransformer => {
|
||||||
|
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 link = getQMLTypeLink(linkObject);
|
||||||
|
return `<a href=${link}>${linkObject.name ?? ""}</a>`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return CONTINUE;
|
if (hasQSLink) {
|
||||||
});
|
code.replace(qsRegExp, (_full: string, match: string) => {
|
||||||
|
const linkObject = getQMLTypeLinkObject(match);
|
||||||
return root;
|
const link = getQMLTypeLink(linkObject);
|
||||||
}
|
return `<a href=${link}>${linkObject.name ?? ""}</a>`;
|
||||||
}
|
});
|
||||||
|
|
||||||
const shikiRewriteTypelinks = {
|
|
||||||
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) => {
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
const linkObject = getQMLTypeLinkObject(match);
|
|
||||||
const link = getQMLTypeLink(linkObject);
|
|
||||||
|
|
||||||
return `<a href=${link}>${linkObject.name ?? ""}</a>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
const fragment = fromHtml(node.value, { fragment: true });
|
|
||||||
parent.children.splice(index, 1, ...fragment.children);
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue