svem
Version:
Svelte in Markdown preprocessor
88 lines (87 loc) • 2.34 kB
JavaScript
import { visit } from "unist-util-visit";
import { getAttributes } from "./attribute.js";
const remarkDirective = () => {
return (tree) => {
visit(tree, "paragraph", (node, index = 0, parent) => {
if (!isSectionOpen(node)) {
return;
}
wrapDirective(node, index, parent);
});
};
};
const wrapDirective = (node, index = 0, parent) => {
const children = [];
const initNode = node.children?.[0];
if (!initNode?.value) {
return node;
}
const [name, ...rest] = initNode.value.replace(/:::\s?/, "").trim().split(/\s+/);
const meta = rest.join(" ");
node.type = "directive";
node.name = name.trim();
node.meta = meta.trim();
node.attributes = getAttributes(meta);
if (!node.name && node.attributes?.name) {
node.name = node.attributes.name;
}
if (parent.children?.length) {
let done = false;
while (!done) {
const child = parent.children.splice(index + 1, 1)[0];
if (!child || isSectionClose(child)) {
done = true;
break;
}
if (isSectionOpen(child)) {
wrapDirective(child, index, parent);
}
children.push(child);
}
}
node.children = children;
return node;
};
const remarkDirectiveEject = () => {
return (tree) => {
visit(tree, "directive", (node) => {
node.type = "html-node";
node.tagName = "div";
if (!node.attributes) {
node.attributes = {};
}
if (!Array.isArray(node.attributes.class)) {
node.attributes.class = [node.attributes.class].filter(Boolean);
}
node.attributes.class.push("directive", node.name);
});
};
};
const isSectionOpen = (node) => {
if (node.type === "text" && /^:::/.test(node.value ?? "")) {
return true;
}
if (node.type !== "paragraph") {
return false;
}
const firstChild = node.children?.[0];
if (firstChild?.type === "text" && /^:::/.test(firstChild?.value ?? "")) {
return true;
}
};
const isSectionClose = (node) => {
if (node.type === "text" && /^:::$/.test(node.value?.trim() ?? "")) {
return true;
}
if (node.type !== "paragraph") {
return false;
}
const firstChild = node.children?.[0];
if (firstChild?.type === "text" && /^:::$/.test(firstChild?.value?.trim() ?? "")) {
return true;
}
};
export {
remarkDirective,
remarkDirectiveEject
};