astro-ghostcms/.pnpm-store/v3/files/67/c6940827f3fe6cea71d5f4ce48e...

106 lines
4.0 KiB
Plaintext

import { bundledLanguages, createCssVariablesTheme, getHighlighter } from "shikiji";
import { visit } from "unist-util-visit";
const ASTRO_COLOR_REPLACEMENTS = {
"--astro-code-foreground": "--astro-code-color-text",
"--astro-code-background": "--astro-code-color-background"
};
const COLOR_REPLACEMENT_REGEX = new RegExp(
`(${Object.keys(ASTRO_COLOR_REPLACEMENTS).join("|")})`,
"g"
);
let _cssVariablesTheme;
const cssVariablesTheme = () => _cssVariablesTheme ?? (_cssVariablesTheme = createCssVariablesTheme({ variablePrefix: "--astro-code-" }));
async function createShikiHighlighter({
langs = [],
theme = "github-dark",
experimentalThemes = {},
wrap = false,
transformers = []
} = {}) {
const themes = experimentalThemes;
theme = theme === "css-variables" ? cssVariablesTheme() : theme;
const highlighter = await getHighlighter({
langs: langs.length ? langs : Object.keys(bundledLanguages),
themes: Object.values(themes).length ? Object.values(themes) : [theme]
});
const loadedLanguages = highlighter.getLoadedLanguages();
return {
highlight(code, lang = "plaintext", options) {
if (lang !== "plaintext" && !loadedLanguages.includes(lang)) {
console.warn(`[Shiki] The language "${lang}" doesn't exist, falling back to "plaintext".`);
lang = "plaintext";
}
const themeOptions = Object.values(themes).length ? { themes } : { theme };
const inline = options?.inline ?? false;
return highlighter.codeToHtml(code, {
...themeOptions,
lang,
transformers: [
{
pre(node) {
if (inline) {
node.tagName = "code";
}
const classValue = normalizePropAsString(node.properties.class) ?? "";
const styleValue = normalizePropAsString(node.properties.style) ?? "";
node.properties.class = classValue.replace(/shiki/g, "astro-code");
if (wrap === false) {
node.properties.style = styleValue + "; overflow-x: auto;";
} else if (wrap === true) {
node.properties.style = styleValue + "; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;";
}
},
line(node) {
if (lang === "diff") {
const innerSpanNode = node.children[0];
const innerSpanTextNode = innerSpanNode?.type === "element" && innerSpanNode.children?.[0];
if (innerSpanTextNode && innerSpanTextNode.type === "text") {
const start = innerSpanTextNode.value[0];
if (start === "+" || start === "-") {
innerSpanTextNode.value = innerSpanTextNode.value.slice(1);
innerSpanNode.children.unshift({
type: "element",
tagName: "span",
properties: { style: "user-select: none;" },
children: [{ type: "text", value: start }]
});
}
}
}
},
code(node) {
if (inline) {
return node.children[0];
}
},
root(node) {
if (Object.values(experimentalThemes).length) {
return;
}
const themeName = typeof theme === "string" ? theme : theme.name;
if (themeName === "css-variables") {
visit(node, "element", (child) => {
if (child.properties?.style) {
child.properties.style = replaceCssVariables(child.properties.style);
}
});
}
}
},
...transformers
]
});
}
};
}
function normalizePropAsString(value) {
return Array.isArray(value) ? value.join(" ") : value;
}
function replaceCssVariables(str) {
return str.replace(COLOR_REPLACEMENT_REGEX, (match) => ASTRO_COLOR_REPLACEMENTS[match] || match);
}
export {
createShikiHighlighter,
replaceCssVariables
};