2026-05-31 13:54:31 +02:00

350 lines
11 KiB
JavaScript

var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
// src/index.ts
import { createFilter } from "@rollup/pluginutils";
import { createUnplugin } from "unplugin";
// node_modules/.pnpm/@antfu+utils@0.7.10/node_modules/@antfu/utils/dist/index.mjs
function toArray(array) {
array = array ?? [];
return Array.isArray(array) ? array : [array];
}
function uniq(array) {
return Array.from(new Set(array));
}
var VOID = Symbol("p-void");
// src/core/markdown.ts
import { componentPlugin } from "@mdit-vue/plugin-component";
import { frontmatterPlugin } from "@mdit-vue/plugin-frontmatter";
import MarkdownIt from "markdown-it-async";
// src/core/head.ts
var headProperties = [
"title",
"meta",
"link",
"base",
"style",
"script",
"htmlAttrs",
"bodyAttrs"
];
function preprocessHead(frontmatter, options) {
if (!options.headEnabled)
return frontmatter;
const head = options.headField ? frontmatter[options.headField] || {} : frontmatter;
const meta = head.meta = head.meta || [];
if (head.title) {
if (!meta.find((i) => i.property === "og:title"))
meta.push({ property: "og:title", content: head.title });
if (!meta.find((i) => i.name === "twitter:title"))
meta.push({ name: "twitter:title", content: head.title });
}
if (head.description) {
if (!meta.find((i) => i.name === "description"))
meta.push({ name: "description", content: head.description });
if (!meta.find((i) => i.property === "og:description"))
meta.push({ property: "og:description", content: head.description });
if (!meta.find((i) => i.name === "twitter:description"))
meta.push({ name: "twitter:description", content: head.description });
}
if (head.image) {
if (!meta.find((i) => i.property === "og:image"))
meta.push({ property: "og:image", content: head.image });
if (!meta.find((i) => i.name === "twitter:image"))
meta.push({ name: "twitter:image", content: head.image });
if (!meta.find((i) => i.property === "twitter:card"))
meta.push({ name: "twitter:card", content: "summary_large_image" });
}
const result = {};
for (const [key, value] of Object.entries(head)) {
if (headProperties.includes(key))
result[key] = value;
}
return Object.entries(result).length === 0 ? null : result;
}
// src/core/markdown.ts
var scriptSetupRE = /<\s*script([^>]*)\bsetup\b([^>]*)>([\s\S]*)<\/script>/g;
var defineExposeRE = /defineExpose\s*\(/g;
var EXPORTS_KEYWORDS = [
"class",
"default",
"export",
"function",
"import",
"let",
"var",
"const",
"from",
"as",
"return",
"if",
"else",
"switch",
"case",
"break",
"for",
"while",
"do"
];
function extractScriptSetup(html) {
const scripts = [];
html = html.replace(scriptSetupRE, (_, attr1, attr2, code) => {
scripts.push({
code,
attr: `${attr1} ${attr2}`.trim()
});
return "";
});
return { html, scripts };
}
function extractCustomBlock(html, options) {
const blocks = [];
for (const tag of options.customSfcBlocks) {
html = html.replace(new RegExp(`<${tag}[^>]*\\b[^>]*>[^<]*<\\/${tag}>`, "gm"), (code) => {
blocks.push(code);
return "";
});
}
return { html, blocks };
}
function createMarkdown(options) {
const isVue2 = options.vueVersion.startsWith("2.");
const markdown = MarkdownIt({
html: true,
linkify: true,
typographer: true,
...options.markdownItOptions
});
markdown.use(componentPlugin, options.componentOptions);
if (options.frontmatter || options.excerpt) {
markdown.use(frontmatterPlugin, {
...options.frontmatterOptions,
grayMatterOptions: {
excerpt: options.excerpt,
...options.frontmatterOptions.grayMatterOptions
}
});
}
markdown.linkify.set({ fuzzyLink: false });
options.markdownItUses.forEach((e) => {
const [plugin, options2] = toArray(e);
markdown.use(plugin, options2);
});
const setupPromise = (async () => {
await options.markdownItSetup(markdown);
})();
return async (id, raw) => {
await setupPromise;
const {
wrapperClasses,
wrapperComponent,
transforms,
headEnabled,
frontmatterPreprocess
} = options;
raw = raw.trimStart();
raw = transforms.before?.(raw, id) ?? raw;
const env = { id };
let html = await markdown.renderAsync(raw, env);
const { excerpt = "", frontmatter: data = null } = env;
const wrapperClassesResolved = toArray(
typeof wrapperClasses === "function" ? wrapperClasses(id, raw) : wrapperClasses
).filter(Boolean).join(" ");
if (wrapperClassesResolved)
html = `<div class="${wrapperClassesResolved}">${html}</div>`;
else
html = `<div>${html}</div>`;
const wrapperComponentName = typeof wrapperComponent === "function" ? wrapperComponent(id, raw) : wrapperComponent;
if (wrapperComponentName) {
const attrs2 = [
options.frontmatter && ':frontmatter="frontmatter"',
options.excerpt && ':excerpt="excerpt"'
].filter(Boolean).join(" ");
html = `<${wrapperComponentName} ${attrs2}>${html}</${wrapperComponentName}>`;
}
html = transforms.after?.(html, id) ?? html;
if (options.escapeCodeTagInterpolation) {
html = html.replace(/<code(.*?)>/g, "<code$1 v-pre>");
}
const hoistScripts = extractScriptSetup(html);
html = hoistScripts.html;
const customBlocks = extractCustomBlock(html, options);
html = customBlocks.html;
const scriptLines = [];
let frontmatterExportsLines = [];
let excerptExportsLine = "";
let excerptKeyOverlapping = false;
function hasExplicitExports() {
return defineExposeRE.test(hoistScripts.scripts.map((i) => i.code).join(""));
}
if (options.frontmatter) {
if (options.excerpt && data) {
if (data.excerpt !== void 0)
excerptKeyOverlapping = true;
data.excerpt = excerpt;
}
const { head, frontmatter } = frontmatterPreprocess(data || {}, options, id, preprocessHead);
if (options.excerpt && !excerptKeyOverlapping && frontmatter.excerpt !== void 0)
delete frontmatter.excerpt;
scriptLines.push(`const frontmatter = ${JSON.stringify(frontmatter)}`);
if (options.exportFrontmatter) {
frontmatterExportsLines = Object.entries(frontmatter).map(([key, value]) => {
if (EXPORTS_KEYWORDS.includes(key))
key = `_${key}`;
return `export const ${key} = ${JSON.stringify(value)}`;
});
}
if (!isVue2 && options.exposeFrontmatter && !hasExplicitExports())
scriptLines.push("defineExpose({ frontmatter })");
if (!isVue2 && headEnabled && head) {
if (headEnabled === "vueuse")
throw new Error("unplugin-vue-markdown no longer supports @vueuse/head. Change `headEnabled` to `true` and install `@unhead/vue` instead.");
scriptLines.push(`const head = ${JSON.stringify(head)}`);
scriptLines.unshift(`import { useHead } from "@unhead/vue"`);
scriptLines.push("useHead(head)");
}
scriptLines.push(...transforms.extraScripts?.(frontmatter, id) || []);
}
if (options.excerpt) {
scriptLines.push(`const excerpt = ${JSON.stringify(excerpt)}`);
if (!excerptKeyOverlapping)
excerptExportsLine = `export const excerpt = ${JSON.stringify(excerpt)}
`;
if (!isVue2 && options.exposeExcerpt && !hasExplicitExports())
scriptLines.push("defineExpose({ excerpt })");
}
scriptLines.push(...hoistScripts.scripts.map((i) => i.code));
let attrs = uniq(hoistScripts.scripts.map((i) => i.attr)).join(" ").trim();
if (attrs)
attrs = ` ${attrs}`;
const scripts = isVue2 ? [
`<script${attrs}>`,
...scriptLines,
...frontmatterExportsLines,
excerptExportsLine,
"export default { data() { return { frontmatter } } }",
"</script>"
] : [
`<script setup${attrs}>`,
...scriptLines,
"</script>",
...frontmatterExportsLines.length || excerptExportsLine ? [
`<script${attrs}>`,
...frontmatterExportsLines,
excerptExportsLine,
"</script>"
] : []
];
const code = [
`<template>${html}</template>`,
...scripts.map((i) => i.trim()).filter(Boolean),
...customBlocks.blocks
].join("\n");
return {
code,
map: { mappings: "" }
};
};
}
// src/core/utils.ts
import { createRequire } from "node:module";
var _require = typeof __require === "undefined" ? createRequire(import.meta.url) : __require;
function getVueVersion(defaultVersion = "3.2.0") {
try {
let v = _require("vue");
if (v.default)
v = v.default;
return v.version || defaultVersion;
} catch {
return defaultVersion;
}
}
// src/core/options.ts
function resolveOptions(userOptions) {
const defaultOptions = {
headEnabled: false,
headField: "",
frontmatter: true,
excerpt: false,
exposeFrontmatter: true,
exposeExcerpt: false,
exportFrontmatter: true,
escapeCodeTagInterpolation: true,
customSfcBlocks: ["route", "i18n", "style"],
componentOptions: {},
frontmatterOptions: {},
markdownItOptions: {},
markdownItUses: [],
markdownItSetup: () => {
},
wrapperComponent: null,
transforms: {},
vueVersion: userOptions.vueVersion || getVueVersion(),
wrapperClasses: "markdown-body",
include: null,
exclude: null,
frontmatterPreprocess: (frontmatter, options2, _id, defaults) => {
return {
head: defaults(frontmatter, options2),
frontmatter
};
}
};
const options = {
...defaultOptions,
...userOptions
};
return options;
}
// src/index.ts
var cssIdRE = /\.(css|postcss|sass|scss|less|stylus|styl)($|\?)/;
var unpluginFactory = (userOptions = {}) => {
const options = resolveOptions(userOptions);
const markdownToVue = createMarkdown(options);
const filter = createFilter(
userOptions.include || /\.md$|\.md\?vue/,
userOptions.exclude || cssIdRE
);
return {
name: "unplugin-vue-markdown",
enforce: "pre",
transformInclude(id) {
return filter(id);
},
async transform(raw, id) {
try {
return await markdownToVue(id, raw);
} catch (e) {
this.error(e);
}
},
vite: {
async handleHotUpdate(ctx) {
if (!filter(ctx.file))
return;
const defaultRead = ctx.read;
ctx.read = async function() {
return (await markdownToVue(ctx.file, await defaultRead())).code;
};
}
}
};
};
var src_default = /* @__PURE__ */ createUnplugin(unpluginFactory);
export {
unpluginFactory,
src_default
};