@nuxtjs/mdc
Version:
Nuxt MDC module
91 lines (90 loc) • 3.43 kB
JavaScript
import { toString } from "hast-util-to-string";
import Slugger from "github-slugger";
import { validateProps } from "./utils/props.js";
export function compileHast(options = {}) {
const slugs = new Slugger();
function compileToJSON(node, parent) {
if (node.type === "root") {
return {
type: "root",
children: node.children.map((child) => compileToJSON(child, node)).filter(Boolean)
};
}
const position = node.position?.start?.offset && node.position?.end?.offset ? {
start: node.position.start.offset,
end: node.position.end.offset
} : void 0;
if (node.type === "element") {
if (node.tagName === "p" && node.children.every((child) => child.type === "text" && /^\s*$/.test(child.value))) {
return null;
}
if (node.tagName === "li") {
let hasPreviousParagraph = false;
node.children = node.children?.flatMap((child) => {
if (child.type === "element" && child.tagName === "p") {
if (hasPreviousParagraph) {
child.children.unshift({
type: "element",
tagName: "br",
properties: {},
children: []
});
}
hasPreviousParagraph = true;
return child.children;
}
return child;
});
}
if (node.tagName?.match(/^h\d$/)) {
node.properties = node.properties || {};
node.properties.id = String(node.properties?.id || slugs.slug(toString(node))).replace(/-+/g, "-").replace(/^-|-$/g, "").replace(/^(\d)/, "_$1");
}
if (node.tagName === "component-slot") {
node.tagName = "template";
}
const children = (node.tagName === "template" && node.content?.children.length ? node.content.children : node.children).map((child) => compileToJSON(child, node)).filter(Boolean);
const result = {
type: "element",
tag: node.tagName,
props: validateProps(node.tagName, node.properties),
children
};
if (options.keepPosition) {
result.position = position;
}
return result;
}
if (node.type === "text") {
if (!/^\n+$/.test(node.value || "") || parent?.properties?.emptyLinePlaceholder) {
return options.keepPosition ? { type: "text", value: node.value, position } : { type: "text", value: node.value };
}
}
if (options.keepComments && node.type === "comment") {
return options.keepPosition ? { type: "comment", value: node.value, position } : { type: "comment", value: node.value };
}
return null;
}
this.Compiler = (tree) => {
const body = compileToJSON(tree);
let excerpt = void 0;
const excerptIndex = tree.children.findIndex((node) => node.type === "comment" && node.value?.trim() === "more");
if (excerptIndex !== -1) {
excerpt = compileToJSON({
type: "root",
children: tree.children.slice(0, excerptIndex)
});
if (excerpt.children.find((node) => node.type === "element" && node.tag === "pre")) {
const lastChild = body.children[body.children.length - 1];
if (lastChild.type === "element" && lastChild.tag === "style") {
excerpt.children.push(lastChild);
}
}
}
body.children = (body.children || []).filter((child) => child.type !== "text");
return {
body,
excerpt
};
};
}