import Slugger from "github-slugger"; import { visit } from "unist-util-visit"; import { InvalidAstroDataError, safelyGetAstroData } from "./frontmatter-injection.js"; const rawNodeTypes = /* @__PURE__ */ new Set(["text", "raw", "mdxTextExpression"]); const codeTagNames = /* @__PURE__ */ new Set(["code", "pre"]); function rehypeHeadingIds() { return function(tree, file) { const headings = []; const slugger = new Slugger(); const isMDX = isMDXFile(file); const astroData = safelyGetAstroData(file.data); visit(tree, (node) => { if (node.type !== "element") return; const { tagName } = node; if (tagName[0] !== "h") return; const [, level] = tagName.match(/h([0-6])/) ?? []; if (!level) return; const depth = Number.parseInt(level); let text = ""; visit(node, (child, __, parent) => { if (child.type === "element" || parent == null) { return; } if (child.type === "raw") { if (child.value.match(/^\n?<.*>\n?$/)) { return; } } if (rawNodeTypes.has(child.type)) { if (isMDX || codeTagNames.has(parent.tagName)) { let value = child.value; if (isMdxTextExpression(child) && !(astroData instanceof InvalidAstroDataError)) { const frontmatterPath = getMdxFrontmatterVariablePath(child); if (Array.isArray(frontmatterPath) && frontmatterPath.length > 0) { const frontmatterValue = getMdxFrontmatterVariableValue(astroData, frontmatterPath); if (typeof frontmatterValue === "string") { value = frontmatterValue; } } } text += value; } else { text += child.value.replace(/\{/g, "${"); } } }); node.properties = node.properties || {}; if (typeof node.properties.id !== "string") { let slug = slugger.slug(text); if (slug.endsWith("-")) slug = slug.slice(0, -1); node.properties.id = slug; } headings.push({ depth, slug: node.properties.id, text }); }); file.data.__astroHeadings = headings; }; } function isMDXFile(file) { return Boolean(file.history[0]?.endsWith(".mdx")); } function getMdxFrontmatterVariablePath(node) { if (!node.data?.estree || node.data.estree.body.length !== 1) return new Error(); const statement = node.data.estree.body[0]; if (statement?.type !== "ExpressionStatement" || statement.expression.type !== "MemberExpression") return new Error(); let expression = statement.expression; const expressionPath = []; while (expression.type === "MemberExpression" && expression.property.type === (expression.computed ? "Literal" : "Identifier")) { expressionPath.push( expression.property.type === "Literal" ? String(expression.property.value) : expression.property.name ); expression = expression.object; } if (expression.type !== "Identifier" || expression.name !== "frontmatter") return new Error(); return expressionPath.reverse(); } function getMdxFrontmatterVariableValue(astroData, path) { let value = astroData.frontmatter; for (const key of path) { if (!value[key]) return void 0; value = value[key]; } return value; } function isMdxTextExpression(node) { return node.type === "mdxTextExpression"; } export { rehypeHeadingIds };