2025-09-05 14:59:21 +08:00

113 lines
3.9 KiB
JavaScript

import { unified } from "unified";
import remarkParse from "remark-parse";
import remark2rehype from "remark-rehype";
import { parseFrontMatter } from "remark-mdc";
import { defu } from "defu";
import { nodeTextContent } from "../utils/node.js";
import { useProcessorPlugins } from "./utils/plugins.js";
import { defaults } from "./options.js";
import { generateToc } from "./toc.js";
import { compileHast } from "./compiler.js";
let moduleOptions;
let generatedMdcConfigs;
export const createMarkdownParser = async (inlineOptions = {}) => {
if (!moduleOptions) {
moduleOptions = await import(
"#mdc-imports"
/* @vite-ignore */
).catch(() => ({}));
}
if (!generatedMdcConfigs) {
generatedMdcConfigs = await import(
"#mdc-configs"
/* @vite-ignore */
).then((r) => r.getMdcConfigs()).catch(() => []);
}
const mdcConfigs = [
...generatedMdcConfigs || [],
...inlineOptions.configs || []
];
if (inlineOptions.highlight != null && inlineOptions.highlight != false && inlineOptions.highlight.highlighter !== void 0 && typeof inlineOptions.highlight.highlighter !== "function") {
if (process.dev)
console.warn("[@nuxtjs/mdc] `highlighter` passed to `parseMarkdown` is should be a function, but got " + JSON.stringify(inlineOptions.highlight.highlighter) + ", ignored.");
inlineOptions = {
...inlineOptions,
highlight: {
...inlineOptions.highlight
}
};
delete inlineOptions.highlight.highlighter;
}
const options = defu(inlineOptions, {
remark: { plugins: moduleOptions?.remarkPlugins },
rehype: { plugins: moduleOptions?.rehypePlugins },
highlight: moduleOptions?.highlight
}, defaults);
if (options.rehype?.plugins?.highlight) {
options.rehype.plugins.highlight.options = {
...options.rehype.plugins.highlight.options || {},
...options.highlight || {}
};
}
let processor = unified();
for (const config of mdcConfigs) {
processor = await config.unified?.pre?.(processor) || processor;
}
processor.use(remarkParse);
for (const config of mdcConfigs) {
processor = await config.unified?.remark?.(processor) || processor;
}
await useProcessorPlugins(processor, options.remark?.plugins);
processor.use(remark2rehype, options.rehype?.options);
for (const config of mdcConfigs) {
processor = await config.unified?.rehype?.(processor) || processor;
}
await useProcessorPlugins(processor, options.rehype?.plugins);
processor.use(compileHast, options);
for (const config of mdcConfigs) {
processor = await config.unified?.post?.(processor) || processor;
}
return async function parse(md, { fileOptions } = {}) {
const { content, data: frontmatter } = await parseFrontMatter(md);
const processedFile = await processor.process({ ...fileOptions, value: content, data: frontmatter });
const result = processedFile.result;
const data = Object.assign(
contentHeading(result.body),
frontmatter,
processedFile?.data || {}
);
let toc;
if (data.toc !== false) {
const tocOption = defu(data.toc || {}, options.toc);
toc = generateToc(result.body, tocOption);
}
return {
data,
body: result.body,
excerpt: result.excerpt,
toc
};
};
};
export const parseMarkdown = async (md, markdownParserOptions = {}, parseOptions = {}) => {
const parser = await createMarkdownParser(markdownParserOptions);
return parser(md, parseOptions);
};
export function contentHeading(body) {
let title = "";
let description = "";
const children = body.children.filter((node) => node.type === "element" && node.tag !== "hr");
if (children.length && children[0].tag === "h1") {
const node = children.shift();
title = nodeTextContent(node);
}
if (children.length && children[0].tag === "p") {
const node = children.shift();
description = nodeTextContent(node);
}
return {
title,
description
};
}