build: fix astro mdx/rehype config + dedupe duplicate ids in dist
This commit is contained in:
102
astro.config.mjs
102
astro.config.mjs
@@ -10,41 +10,101 @@ import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import rehypeDetailsSections from "./scripts/rehype-details-sections.mjs";
|
||||
import rehypeParagraphIds from "./src/plugins/rehype-paragraph-ids.js";
|
||||
|
||||
const must = (name, fn) => {
|
||||
if (typeof fn !== "function") {
|
||||
throw new Error(`[astro.config] rehype plugin "${name}" is not a function (export default vs named?)`);
|
||||
}
|
||||
return fn;
|
||||
};
|
||||
/**
|
||||
* Cast minimal pour satisfaire @ts-check sans dépendre de types internes Astro/Unified.
|
||||
* @param {unknown} x
|
||||
* @returns {any}
|
||||
*/
|
||||
const asAny = (x) => /** @type {any} */ (x);
|
||||
|
||||
/**
|
||||
* @param {any} node
|
||||
* @param {string} cls
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasClass(node, cls) {
|
||||
const cn = node?.properties?.className;
|
||||
if (Array.isArray(cn)) return cn.includes(cls);
|
||||
if (typeof cn === "string") return cn.split(/\s+/).includes(cls);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rehype plugin: retire les ids dupliqués en gardant en priorité:
|
||||
* 1) span.details-anchor
|
||||
* 2) h1..h6
|
||||
* 3) sinon: premier rencontré
|
||||
* @returns {(tree: any) => void}
|
||||
*/
|
||||
function rehypeDedupeIds() {
|
||||
/** @param {any} tree */
|
||||
return (tree) => {
|
||||
/** @type {Map<string, Array<{node:any, pref:number, idx:number}>>} */
|
||||
const occ = new Map();
|
||||
let idx = 0;
|
||||
|
||||
/** @param {any} node */
|
||||
const walk = (node) => {
|
||||
if (!node || typeof node !== "object") return;
|
||||
|
||||
if (node.type === "element") {
|
||||
const id = node.properties?.id;
|
||||
if (typeof id === "string" && id) {
|
||||
let pref = 2;
|
||||
if (node.tagName === "span" && hasClass(node, "details-anchor")) pref = 0;
|
||||
else if (/^h[1-6]$/.test(String(node.tagName || ""))) pref = 1;
|
||||
|
||||
const arr = occ.get(id) || [];
|
||||
arr.push({ node, pref, idx: idx++ });
|
||||
occ.set(id, arr);
|
||||
}
|
||||
|
||||
const children = node.children;
|
||||
if (Array.isArray(children)) for (const c of children) walk(c);
|
||||
} else if (Array.isArray(node.children)) {
|
||||
for (const c of node.children) walk(c);
|
||||
}
|
||||
};
|
||||
|
||||
walk(tree);
|
||||
|
||||
for (const [id, items] of occ.entries()) {
|
||||
if (items.length <= 1) continue;
|
||||
|
||||
items.sort((a, b) => (a.pref - b.pref) || (a.idx - b.idx));
|
||||
const keep = items[0];
|
||||
|
||||
for (let i = 1; i < items.length; i++) {
|
||||
const n = items[i].node;
|
||||
if (n?.properties?.id === id) delete n.properties.id;
|
||||
}
|
||||
|
||||
// safety: on s'assure qu'un seul garde bien l'id
|
||||
if (keep?.node?.properties) keep.node.properties.id = id;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
output: "static",
|
||||
trailingSlash: "always",
|
||||
|
||||
site: process.env.PUBLIC_SITE ?? "http://localhost:4321",
|
||||
|
||||
integrations: [
|
||||
mdx(),
|
||||
// Important: MDX hérite du pipeline markdown (ids p-… + autres plugins)
|
||||
mdx({ extendMarkdownConfig: true }),
|
||||
sitemap({
|
||||
filter: (page) => !page.includes("/api/") && !page.endsWith("/robots.txt"),
|
||||
}),
|
||||
],
|
||||
|
||||
// ✅ Plugins appliqués AU MDX
|
||||
mdx: {
|
||||
// ✅ MDX hérite déjà de markdown.rehypePlugins
|
||||
// donc ici on ne met QUE le spécifique MDX
|
||||
rehypePlugins: [
|
||||
must("rehype-details-sections", rehypeDetailsSections),
|
||||
],
|
||||
},
|
||||
|
||||
// ✅ Plugins appliqués au Markdown non-MDX
|
||||
markdown: {
|
||||
rehypePlugins: [
|
||||
must("rehype-slug", rehypeSlug),
|
||||
[must("rehype-autolink-headings", rehypeAutolinkHeadings), { behavior: "append" }],
|
||||
must("rehype-paragraph-ids", rehypeParagraphIds),
|
||||
asAny(rehypeSlug),
|
||||
[asAny(rehypeAutolinkHeadings), { behavior: "append" }],
|
||||
asAny(rehypeDetailsSections),
|
||||
asAny(rehypeParagraphIds),
|
||||
asAny(rehypeDedupeIds),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user