52 lines
1.9 KiB
JavaScript
52 lines
1.9 KiB
JavaScript
import { visit } from "unist-util-visit";
|
|
import { toString } from "hast-util-to-string";
|
|
export default rehypeHighlight;
|
|
export function rehypeHighlight(opts) {
|
|
const options = opts;
|
|
return async (tree) => {
|
|
const tasks = [];
|
|
const styles = [];
|
|
visit(
|
|
tree,
|
|
(node) => ["pre", "code"].includes(node.tagName) && !!(node.properties?.language || node.properties?.highlights),
|
|
(node) => {
|
|
const _node = node;
|
|
const highlights = typeof _node.properties.highlights === "string" ? _node.properties.highlights.split(/[,\s]+/).map(Number) : Array.isArray(_node.properties.highlights) ? _node.properties.highlights.map(Number) : [];
|
|
const task = options.highlighter(
|
|
toString(node),
|
|
_node.properties.language,
|
|
options.theme,
|
|
{
|
|
highlights: highlights.filter(Boolean),
|
|
meta: _node.properties.meta
|
|
}
|
|
).then(({ tree: tree2, className, style, inlineStyle }) => {
|
|
_node.properties.className = ((_node.properties.className || "") + " " + className).trim();
|
|
_node.properties.style = ((_node.properties.style || "") + " " + inlineStyle).trim();
|
|
if (_node.children[0]?.tagName === "code") {
|
|
_node.children[0].children = tree2;
|
|
} else {
|
|
_node.children = tree2[0].children || tree2;
|
|
}
|
|
if (style)
|
|
styles.push(style);
|
|
});
|
|
tasks.push(task);
|
|
}
|
|
);
|
|
if (tasks.length) {
|
|
await Promise.all(tasks);
|
|
tree.children.push({
|
|
type: "element",
|
|
tagName: "style",
|
|
children: [{ type: "text", value: cleanCSS(styles.join("")) }],
|
|
properties: {}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
const cleanCSS = (css) => {
|
|
const styles = css.split("}").filter((s) => Boolean(s.trim())).map((s) => s.trim() + "}");
|
|
return Array.from(new Set(styles)).join("");
|
|
};
|