astro-ghostcms/.pnpm-store/v3/files/31/76b981365bdc9eb0ebfeaea7475...

98 lines
3.4 KiB
Plaintext

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
};