89 lines
3.0 KiB
JavaScript
89 lines
3.0 KiB
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)
|
|
};
|
|
}
|
|
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);
|
|
return {
|
|
type: "element",
|
|
tag: node.tagName,
|
|
props: validateProps(node.tagName, node.properties),
|
|
children
|
|
};
|
|
}
|
|
if (node.type === "text") {
|
|
if (!/^\n+$/.test(node.value || "") || parent?.properties?.emptyLinePlaceholder) {
|
|
return {
|
|
type: "text",
|
|
value: node.value
|
|
};
|
|
}
|
|
}
|
|
if (options.keepComments && node.type === "comment") {
|
|
return {
|
|
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
|
|
};
|
|
};
|
|
}
|