mirror of
https://github.com/sern-handler/website
synced 2026-06-18 05:42:20 +00:00
206 lines
8.5 KiB
JavaScript
206 lines
8.5 KiB
JavaScript
import fs from "node:fs/promises";
|
|
import { fileURLToPath } from "node:url";
|
|
import { markdownConfigDefaults, setVfileFrontmatter } from "@astrojs/markdown-remark";
|
|
import astroJSXRenderer from "astro/jsx/renderer.js";
|
|
import { parse as parseESM } from "es-module-lexer";
|
|
import { VFile } from "vfile";
|
|
import { createMdxProcessor } from "./plugins.js";
|
|
import {
|
|
ASTRO_IMAGE_ELEMENT,
|
|
ASTRO_IMAGE_IMPORT,
|
|
USES_ASTRO_IMAGE_FLAG
|
|
} from "./remark-images-to-component.js";
|
|
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from "./utils.js";
|
|
function mdx(partialMdxOptions = {}) {
|
|
return {
|
|
name: "@astrojs/mdx",
|
|
hooks: {
|
|
"astro:config:setup": async (params) => {
|
|
const { updateConfig, config, addPageExtension, addContentEntryType, addRenderer } = params;
|
|
addRenderer(astroJSXRenderer);
|
|
addPageExtension(".mdx");
|
|
addContentEntryType({
|
|
extensions: [".mdx"],
|
|
async getEntryInfo({ fileUrl, contents }) {
|
|
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
return {
|
|
data: parsed.data,
|
|
body: parsed.content,
|
|
slug: parsed.data.slug,
|
|
rawData: parsed.matter
|
|
};
|
|
},
|
|
contentModuleTypes: await fs.readFile(
|
|
new URL("../template/content-module-types.d.ts", import.meta.url),
|
|
"utf-8"
|
|
),
|
|
// MDX can import scripts and styles,
|
|
// so wrap all MDX files with script / style propagation checks
|
|
handlePropagation: true
|
|
});
|
|
const extendMarkdownConfig = partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;
|
|
const mdxOptions = applyDefaultOptions({
|
|
options: partialMdxOptions,
|
|
defaults: markdownConfigToMdxOptions(
|
|
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
|
|
)
|
|
});
|
|
let processor;
|
|
updateConfig({
|
|
vite: {
|
|
plugins: [
|
|
{
|
|
name: "@mdx-js/rollup",
|
|
enforce: "pre",
|
|
buildEnd() {
|
|
processor = void 0;
|
|
},
|
|
configResolved(resolved) {
|
|
processor = createMdxProcessor(mdxOptions, {
|
|
sourcemap: !!resolved.build.sourcemap
|
|
});
|
|
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === "astro:jsx");
|
|
if (jsxPluginIndex !== -1) {
|
|
const myPluginIndex = resolved.plugins.findIndex(
|
|
(p) => p.name === "@mdx-js/rollup"
|
|
);
|
|
if (myPluginIndex !== -1) {
|
|
const myPlugin = resolved.plugins[myPluginIndex];
|
|
resolved.plugins.splice(myPluginIndex, 1);
|
|
resolved.plugins.splice(jsxPluginIndex, 0, myPlugin);
|
|
}
|
|
}
|
|
},
|
|
async resolveId(source, importer, options) {
|
|
if (importer?.endsWith(".mdx") && source[0] !== "/") {
|
|
let resolved = await this.resolve(source, importer, options);
|
|
if (!resolved)
|
|
resolved = await this.resolve("./" + source, importer, options);
|
|
return resolved;
|
|
}
|
|
},
|
|
// Override transform to alter code before MDX compilation
|
|
// ex. inject layouts
|
|
async transform(_, id) {
|
|
if (!id.endsWith(".mdx"))
|
|
return;
|
|
const { fileId } = getFileInfo(id, config);
|
|
const code = await fs.readFile(fileId, "utf-8");
|
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
const vfile = new VFile({ value: pageContent, path: id });
|
|
setVfileFrontmatter(vfile, frontmatter);
|
|
if (!processor) {
|
|
return this.error(
|
|
"MDX processor is not initialized. This is an internal error. Please file an issue."
|
|
);
|
|
}
|
|
try {
|
|
const compiled = await processor.process(vfile);
|
|
return {
|
|
code: String(compiled.value),
|
|
map: compiled.map
|
|
};
|
|
} catch (e) {
|
|
const err = e;
|
|
err.name = "MDXError";
|
|
err.loc = { file: fileId, line: e.line, column: e.column };
|
|
Error.captureStackTrace(err);
|
|
throw err;
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: "@astrojs/mdx-postprocess",
|
|
// These transforms must happen *after* JSX runtime transformations
|
|
transform(code, id) {
|
|
if (!id.endsWith(".mdx"))
|
|
return;
|
|
const [moduleImports, moduleExports] = parseESM(code);
|
|
const importsFromJSXRuntime = moduleImports.filter(({ n }) => n === "astro/jsx-runtime").map(({ ss, se }) => code.substring(ss, se));
|
|
const hasFragmentImport = importsFromJSXRuntime.some(
|
|
(statement) => /[\s,{](?:Fragment,|Fragment\s*\})/.test(statement)
|
|
);
|
|
if (!hasFragmentImport) {
|
|
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
}
|
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
if (!moduleExports.find(({ n }) => n === "url")) {
|
|
code += `
|
|
export const url = ${JSON.stringify(fileUrl)};`;
|
|
}
|
|
if (!moduleExports.find(({ n }) => n === "file")) {
|
|
code += `
|
|
export const file = ${JSON.stringify(fileId)};`;
|
|
}
|
|
if (!moduleExports.find(({ n }) => n === "Content")) {
|
|
const hasComponents = moduleExports.find(({ n }) => n === "components");
|
|
const usesAstroImage = moduleExports.find(
|
|
({ n }) => n === USES_ASTRO_IMAGE_FLAG
|
|
);
|
|
let componentsCode = `{ Fragment${hasComponents ? ", ...components" : ""}, ...props.components,`;
|
|
if (usesAstroImage) {
|
|
componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${hasComponents ? "components.img ?? " : ""} props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`;
|
|
}
|
|
componentsCode += " }";
|
|
code = code.replace(
|
|
"export default function MDXContent",
|
|
"function MDXContent"
|
|
);
|
|
code += `
|
|
export const Content = (props = {}) => MDXContent({
|
|
...props,
|
|
components: ${componentsCode},
|
|
});
|
|
export default Content;`;
|
|
}
|
|
code += `
|
|
Content[Symbol.for('mdx-component')] = true`;
|
|
code += `
|
|
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
code += `
|
|
Content.moduleId = ${JSON.stringify(id)};`;
|
|
return { code, map: null };
|
|
}
|
|
}
|
|
]
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
const defaultMdxOptions = {
|
|
extendMarkdownConfig: true,
|
|
recmaPlugins: []
|
|
};
|
|
function markdownConfigToMdxOptions(markdownConfig) {
|
|
return {
|
|
...defaultMdxOptions,
|
|
...markdownConfig,
|
|
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
|
|
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
|
|
remarkRehype: markdownConfig.remarkRehype ?? {},
|
|
optimize: false
|
|
};
|
|
}
|
|
function applyDefaultOptions({
|
|
options,
|
|
defaults
|
|
}) {
|
|
return {
|
|
syntaxHighlight: options.syntaxHighlight ?? defaults.syntaxHighlight,
|
|
extendMarkdownConfig: options.extendMarkdownConfig ?? defaults.extendMarkdownConfig,
|
|
recmaPlugins: options.recmaPlugins ?? defaults.recmaPlugins,
|
|
remarkRehype: options.remarkRehype ?? defaults.remarkRehype,
|
|
gfm: options.gfm ?? defaults.gfm,
|
|
smartypants: options.smartypants ?? defaults.smartypants,
|
|
remarkPlugins: options.remarkPlugins ?? defaults.remarkPlugins,
|
|
rehypePlugins: options.rehypePlugins ?? defaults.rehypePlugins,
|
|
shikiConfig: options.shikiConfig ?? defaults.shikiConfig,
|
|
optimize: options.optimize ?? defaults.optimize
|
|
};
|
|
}
|
|
export {
|
|
mdx as default
|
|
};
|