import { fromHtml } from "hast-util-from-html";
import { toText } from "hast-util-to-text";
import { removePosition } from "unist-util-remove-position";
import { visitParents } from "unist-util-visit-parents";
const languagePattern = /\blanguage-(\S+)\b/;
const defaultExcludeLanguages = ["math"];
async function highlightCodeBlocks(tree, highlighter, excludeLanguages = []) {
  const nodes = [];
  visitParents(tree, { type: "element", tagName: "code" }, (node, ancestors) => {
    const parent = ancestors.at(-1);
    if (parent?.type !== "element" || parent.tagName !== "pre") {
      return;
    }
    if (parent.children.length !== 1) {
      return;
    }
    let languageMatch;
    let { className } = node.properties;
    if (typeof className === "string") {
      languageMatch = languagePattern.exec(className);
    } else if (Array.isArray(className)) {
      for (const cls of className) {
        if (typeof cls !== "string") {
          continue;
        }
        languageMatch = languagePattern.exec(cls);
        if (languageMatch) {
          break;
        }
      }
    }
    const language = languageMatch?.[1] || "plaintext";
    if (excludeLanguages.includes(language) || defaultExcludeLanguages.includes(language)) {
      return;
    }
    nodes.push({
      node,
      language,
      parent,
      grandParent: ancestors.at(-2)
    });
  });
  for (const { node, language, grandParent, parent } of nodes) {
    const meta = node.data?.meta ?? node.properties.metastring ?? void 0;
    const code = toText(node, { whitespace: "pre" });
    const result = await highlighter(code, language, { meta });
    let replacement;
    if (typeof result === "string") {
      replacement = fromHtml(result, { fragment: true }).children[0];
      removePosition(replacement);
    } else {
      replacement = result.children[0];
    }
    const index = grandParent.children.indexOf(parent);
    grandParent.children[index] = replacement;
  }
}
export {
  defaultExcludeLanguages,
  highlightCodeBlocks
};
