@scalar/code-highlight
Version:
Central methods and themes for code highlighting in Scalar projects
74 lines (73 loc) • 2.29 kB
JavaScript
import { visit } from "unist-util-visit";
function isText(element) {
return element?.type === "text";
}
function isElement(node) {
return node?.type === "element";
}
function textElement(value) {
return { type: "text", value };
}
function lineBreak() {
return { type: "text", value: "\n" };
}
function codeBlockLinesPlugin() {
return (tree) => {
visit(tree, "element", (node, _i, parent) => {
if (parent?.type === "element" && parent.tagName === "pre" && node.tagName === "code") {
let numLines = 0;
node.children = addLines(node);
node.children.forEach((child) => {
if (child.type === "element" && child.tagName === "span") {
const lastChild = child.children[child.children.length - 1];
if (lastChild && (!isText(lastChild) || isText(lastChild) && !hasLineBreak(lastChild))) {
child.children.push(lineBreak());
numLines++;
}
}
});
node.properties.style = [`--line-count: ${numLines};`, `--line-digits: ${numLines.toString().length};`];
}
});
};
}
function addLines(node, lines = [], copyParent) {
const line = () => lines[lines.length - 1] ?? (lines.push(createLine()) && lines[lines.length - 1] || void 0);
node.children.forEach((child) => {
if (isText(child) && hasLineBreak(child)) {
const split = child.value.split(/\n/);
split.forEach((content, i) => {
if (copyParent) {
line()?.children.push({ ...node, children: [textElement(content)] });
} else {
line()?.children.push(textElement(content));
}
i !== split.length - 1 && lines.push(createLine());
});
} else if (isElement(child) && child.children.some(hasLineBreak)) {
addLines(child, lines, true);
} else {
line()?.children.push(child);
}
});
return lines;
}
function createLine(...children) {
return {
type: "element",
tagName: "span",
properties: { class: ["line"] },
children
};
}
function hasLineBreak(node) {
return isText(node) && /\r?\n/.test(node.value) || isElement(node) && node.children.some(hasLineBreak);
}
export {
codeBlockLinesPlugin,
isElement,
isText,
lineBreak,
textElement
};
//# sourceMappingURL=line-numbers.js.map