@antdv-next/docs-plugins 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +133 -0
  3. package/dist/demo/formatter.d.ts +17 -0
  4. package/dist/demo/formatter.js +32 -0
  5. package/dist/demo/get-demo-id.d.ts +9 -0
  6. package/dist/demo/get-demo-id.js +19 -0
  7. package/dist/demo/index.d.ts +26 -0
  8. package/dist/demo/index.js +359 -0
  9. package/dist/demo/tsToJs.d.ts +9 -0
  10. package/dist/demo/tsToJs.js +60 -0
  11. package/dist/demo/types.d.ts +23 -0
  12. package/dist/index.d.ts +20 -0
  13. package/dist/index.js +19 -0
  14. package/dist/isolate-styles.d.ts +14 -0
  15. package/dist/isolate-styles.js +30 -0
  16. package/dist/markdown.d.ts +39 -0
  17. package/dist/markdown.js +115 -0
  18. package/dist/md-plugin.d.ts +18 -0
  19. package/dist/md-plugin.js +9 -0
  20. package/dist/md2vue.d.ts +16 -0
  21. package/dist/md2vue.js +106 -0
  22. package/dist/plugins/container.d.ts +16 -0
  23. package/dist/plugins/container.js +53 -0
  24. package/dist/plugins/demo.d.ts +29 -0
  25. package/dist/plugins/demo.js +139 -0
  26. package/dist/plugins/github-alerts.d.ts +6 -0
  27. package/dist/plugins/github-alerts.js +49 -0
  28. package/dist/plugins/image.d.ts +12 -0
  29. package/dist/plugins/image.js +17 -0
  30. package/dist/plugins/link.d.ts +14 -0
  31. package/dist/plugins/link.js +25 -0
  32. package/dist/plugins/pre-wrapper.d.ts +10 -0
  33. package/dist/plugins/pre-wrapper.js +26 -0
  34. package/dist/plugins/stackblitz.d.ts +5 -0
  35. package/dist/plugins/stackblitz.js +21 -0
  36. package/dist/plugins/table.d.ts +5 -0
  37. package/dist/plugins/table.js +25 -0
  38. package/dist/shared.d.ts +7 -0
  39. package/dist/shared.js +7 -0
  40. package/dist/utils/short-hash.d.ts +4 -0
  41. package/dist/utils/short-hash.js +21 -0
  42. package/package.json +94 -0
  43. package/src/components/code-demo/code-editor-bridge.vue +36 -0
  44. package/src/components/code-demo/compile-sfc.ts +207 -0
  45. package/src/components/code-demo/context.ts +86 -0
  46. package/src/components/code-demo/expand-icon.vue +12 -0
  47. package/src/components/code-demo/external-link-icon.vue +5 -0
  48. package/src/components/code-demo/index.vue +682 -0
  49. package/src/components/code-demo/virtual.d.ts +38 -0
  50. package/src/demo/formatter.ts +50 -0
  51. package/src/demo/get-demo-id.ts +33 -0
  52. package/src/demo/index.ts +498 -0
  53. package/src/demo/tsToJs.ts +79 -0
  54. package/src/demo/types.ts +23 -0
  55. package/src/index.ts +19 -0
  56. package/src/isolate-styles.ts +47 -0
  57. package/src/markdown.ts +188 -0
  58. package/src/md-plugin.ts +24 -0
  59. package/src/md2vue.ts +163 -0
  60. package/src/plugins/container.ts +135 -0
  61. package/src/plugins/demo.ts +282 -0
  62. package/src/plugins/github-alerts.ts +69 -0
  63. package/src/plugins/image.ts +29 -0
  64. package/src/plugins/link.ts +32 -0
  65. package/src/plugins/pre-wrapper.ts +49 -0
  66. package/src/plugins/stackblitz.ts +32 -0
  67. package/src/plugins/table.ts +39 -0
  68. package/src/shared.ts +4 -0
  69. package/src/utils/short-hash.ts +27 -0
@@ -0,0 +1,23 @@
1
+ //#region src/demo/types.d.ts
2
+ interface DemoLocale {
3
+ html?: string;
4
+ title?: string;
5
+ }
6
+ interface DemoExtraFile {
7
+ name: string;
8
+ lang: string;
9
+ code: string;
10
+ }
11
+ interface DemoSourceData {
12
+ source: string;
13
+ jsSource: string;
14
+ extraFiles: DemoExtraFile[];
15
+ }
16
+ interface DemoModule {
17
+ component?: () => Promise<unknown>;
18
+ locales?: Record<string, DemoLocale>;
19
+ sourceVersion: number;
20
+ loadSource: (signal?: AbortSignal) => Promise<DemoSourceData>;
21
+ }
22
+ //#endregion
23
+ export { DemoExtraFile, DemoLocale, DemoModule, DemoSourceData };
@@ -0,0 +1,20 @@
1
+ import { JsFormatter, tsToJs } from "./demo/tsToJs.js";
2
+ import { OxfmtStyleOptions, createOxfmtJsFormatter } from "./demo/formatter.js";
3
+ import { getDemoId } from "./demo/get-demo-id.js";
4
+ import { DemoPluginOptions, demoPlugin, toRelativePath } from "./demo/index.js";
5
+ import { DemoExtraFile, DemoLocale, DemoModule, DemoSourceData } from "./demo/types.js";
6
+ import { postcssIsolateStyles } from "./isolate-styles.js";
7
+ import { DemoMarkdownPluginOptions, demoMarkdownPlugin, replaceSrcPath } from "./plugins/demo.js";
8
+ import { CreateMarkdownOptions, createMarkdown, loadBaseMd, loadShiki, useMarkdown } from "./markdown.js";
9
+ import { addScriptSetup, checkPkgImport, formatPageData, md2Vue, md2VuePlugin } from "./md2vue.js";
10
+ import { DocsPluginsOptions, mdPlugin } from "./md-plugin.js";
11
+ import { Options, extractTitle, getAdaptiveThemeMarker, preWrapperPlugin } from "./plugins/pre-wrapper.js";
12
+ import { ContainerOptions, containerPlugin } from "./plugins/container.js";
13
+ import { gitHubAlertsPlugin } from "./plugins/github-alerts.js";
14
+ import { ImagePluginOptions, imagePlugin } from "./plugins/image.js";
15
+ import { linkPlugin } from "./plugins/link.js";
16
+ import { stackblitzPlugin } from "./plugins/stackblitz.js";
17
+ import { tablePlugin } from "./plugins/table.js";
18
+ import { DOCS_REGEX, EXTERNAL_URL_RE, SCRIPT_REGEX, STYLE_REGEX } from "./shared.js";
19
+ import { shortHash } from "./utils/short-hash.js";
20
+ export { ContainerOptions, CreateMarkdownOptions, DOCS_REGEX, DemoExtraFile, DemoLocale, DemoMarkdownPluginOptions, DemoModule, DemoPluginOptions, DemoSourceData, DocsPluginsOptions, EXTERNAL_URL_RE, ImagePluginOptions, JsFormatter, Options, OxfmtStyleOptions, SCRIPT_REGEX, STYLE_REGEX, addScriptSetup, checkPkgImport, containerPlugin, createMarkdown, createOxfmtJsFormatter, demoMarkdownPlugin, demoPlugin, extractTitle, formatPageData, getAdaptiveThemeMarker, getDemoId, gitHubAlertsPlugin, imagePlugin, linkPlugin, loadBaseMd, loadShiki, md2Vue, md2VuePlugin, mdPlugin, postcssIsolateStyles, preWrapperPlugin, replaceSrcPath, shortHash, stackblitzPlugin, tablePlugin, toRelativePath, tsToJs, useMarkdown };
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import { createOxfmtJsFormatter } from "./demo/formatter.js";
2
+ import { getDemoId } from "./demo/get-demo-id.js";
3
+ import { extractTitle, getAdaptiveThemeMarker, preWrapperPlugin } from "./plugins/pre-wrapper.js";
4
+ import { containerPlugin } from "./plugins/container.js";
5
+ import { demoMarkdownPlugin, replaceSrcPath } from "./plugins/demo.js";
6
+ import { gitHubAlertsPlugin } from "./plugins/github-alerts.js";
7
+ import { DOCS_REGEX, EXTERNAL_URL_RE, SCRIPT_REGEX, STYLE_REGEX } from "./shared.js";
8
+ import { imagePlugin } from "./plugins/image.js";
9
+ import { linkPlugin } from "./plugins/link.js";
10
+ import { stackblitzPlugin } from "./plugins/stackblitz.js";
11
+ import { tablePlugin } from "./plugins/table.js";
12
+ import { createMarkdown, loadBaseMd, loadShiki, useMarkdown } from "./markdown.js";
13
+ import { tsToJs } from "./demo/tsToJs.js";
14
+ import { demoPlugin, toRelativePath } from "./demo/index.js";
15
+ import { postcssIsolateStyles } from "./isolate-styles.js";
16
+ import { shortHash } from "./utils/short-hash.js";
17
+ import { addScriptSetup, checkPkgImport, formatPageData, md2Vue, md2VuePlugin } from "./md2vue.js";
18
+ import { mdPlugin } from "./md-plugin.js";
19
+ export { DOCS_REGEX, EXTERNAL_URL_RE, SCRIPT_REGEX, STYLE_REGEX, addScriptSetup, checkPkgImport, containerPlugin, createMarkdown, createOxfmtJsFormatter, demoMarkdownPlugin, demoPlugin, extractTitle, formatPageData, getAdaptiveThemeMarker, getDemoId, gitHubAlertsPlugin, imagePlugin, linkPlugin, loadBaseMd, loadShiki, md2Vue, md2VuePlugin, mdPlugin, postcssIsolateStyles, preWrapperPlugin, replaceSrcPath, shortHash, stackblitzPlugin, tablePlugin, toRelativePath, tsToJs, useMarkdown };
@@ -0,0 +1,14 @@
1
+ import { Plugin } from "postcss";
2
+ //#region src/isolate-styles.d.ts
3
+ interface Options {
4
+ includeFiles?: RegExp[];
5
+ ignoreFiles?: RegExp[];
6
+ prefix?: string;
7
+ }
8
+ /**
9
+ * PostCSS 插件:为 markdown 样式添加隔离前缀,
10
+ * 避免文档站点样式污染组件演示区(`.vp-raw` 内不做隔离)。
11
+ */
12
+ declare function postcssIsolateStyles({ includeFiles, ignoreFiles, prefix }?: Options): Plugin;
13
+ //#endregion
14
+ export { postcssIsolateStyles };
@@ -0,0 +1,30 @@
1
+ import selectorParser from "postcss-selector-parser";
2
+ //#region src/isolate-styles.ts
3
+ /**
4
+ * PostCSS 插件:为 markdown 样式添加隔离前缀,
5
+ * 避免文档站点样式污染组件演示区(`.vp-raw` 内不做隔离)。
6
+ */
7
+ function postcssIsolateStyles({ includeFiles = [/styles\/markdown\/index\.css/], ignoreFiles, prefix = ":not(:where(.vp-raw, .vp-raw *))" } = {}) {
8
+ const prefixNodes = selectorParser().astSync(prefix).first.nodes;
9
+ return {
10
+ postcssPlugin: "postcss-isolate-styles",
11
+ Once(root) {
12
+ const file = root.source?.input.file;
13
+ if (file && includeFiles?.length && !includeFiles.some((re) => re.test(file))) return;
14
+ if (file && ignoreFiles?.length && ignoreFiles.some((re) => re.test(file))) return;
15
+ root.walkRules((rule) => {
16
+ if (!rule.selector || rule.selector.includes(prefix)) return;
17
+ if (rule.parent?.type === "atrule" && /\bkeyframes$/i.test(rule.parent.name)) return;
18
+ rule.selector = selectorParser((selectors) => {
19
+ selectors.each((sel) => {
20
+ if (!sel.nodes.length) return;
21
+ const insertionIndex = sel.nodes.findLastIndex((n) => n.type !== "pseudo") + 1;
22
+ sel.nodes.splice(insertionIndex, 0, ...prefixNodes.map((n) => n.clone()));
23
+ });
24
+ }).processSync(rule.selector);
25
+ });
26
+ }
27
+ };
28
+ }
29
+ //#endregion
30
+ export { postcssIsolateStyles };
@@ -0,0 +1,39 @@
1
+ import { DemoMarkdownPluginOptions } from "./plugins/demo.js";
2
+ import { MarkdownItAsync } from "markdown-it-async";
3
+ //#region src/markdown.d.ts
4
+ interface CreateMarkdownOptions {
5
+ /**
6
+ * 是否加载插件
7
+ * @default true
8
+ */
9
+ withPlugin?: boolean;
10
+ /**
11
+ * 自定义插件前的钩子
12
+ */
13
+ preConfig?: (md: MarkdownItAsync) => void;
14
+ /**
15
+ * 自定义插件后的钩子
16
+ */
17
+ config?: (md: MarkdownItAsync) => void;
18
+ /**
19
+ * 资源路径配置
20
+ */
21
+ root?: string;
22
+ /**
23
+ * markdown-it 层 demo 插件选项
24
+ */
25
+ demo?: DemoMarkdownPluginOptions;
26
+ /**
27
+ * 外部链接在新标签页打开
28
+ * @default true
29
+ */
30
+ externalLink?: boolean;
31
+ }
32
+ declare function loadShiki(md: MarkdownItAsync, cls?: string): void;
33
+ declare function loadBaseMd(md: MarkdownItAsync, options?: {
34
+ externalLink?: boolean;
35
+ }): void;
36
+ declare function createMarkdown(): (options?: CreateMarkdownOptions) => MarkdownItAsync;
37
+ declare const useMarkdown: (options?: CreateMarkdownOptions) => MarkdownItAsync;
38
+ //#endregion
39
+ export { CreateMarkdownOptions, createMarkdown, loadBaseMd, loadShiki, useMarkdown };
@@ -0,0 +1,115 @@
1
+ import { preWrapperPlugin } from "./plugins/pre-wrapper.js";
2
+ import { containerPlugin } from "./plugins/container.js";
3
+ import { demoMarkdownPlugin } from "./plugins/demo.js";
4
+ import { gitHubAlertsPlugin } from "./plugins/github-alerts.js";
5
+ import { imagePlugin } from "./plugins/image.js";
6
+ import { linkPlugin } from "./plugins/link.js";
7
+ import { stackblitzPlugin } from "./plugins/stackblitz.js";
8
+ import { tablePlugin } from "./plugins/table.js";
9
+ import { frontmatterPlugin } from "@mdit-vue/plugin-frontmatter";
10
+ import { headersPlugin } from "@mdit-vue/plugin-headers";
11
+ import { titlePlugin } from "@mdit-vue/plugin-title";
12
+ import { tocPlugin } from "@mdit-vue/plugin-toc";
13
+ import { slugify } from "@mdit-vue/shared";
14
+ import { fromAsyncCodeToHtml } from "@shikijs/markdown-it/async";
15
+ import { transformerMetaHighlight, transformerMetaWordHighlight, transformerNotationDiff, transformerNotationErrorLevel, transformerNotationFocus, transformerNotationHighlight, transformerNotationWordHighlight } from "@shikijs/transformers";
16
+ import anchorPlugin from "markdown-it-anchor";
17
+ import MarkdownIt from "markdown-it-async";
18
+ import attrsPlugin from "markdown-it-attrs";
19
+ import { full } from "markdown-it-emoji";
20
+ import { codeToHtml } from "shiki";
21
+ //#region src/markdown.ts
22
+ function loadShiki(md, cls = "ant-doc-code") {
23
+ md.use(fromAsyncCodeToHtml(codeToHtml, {
24
+ themes: {
25
+ light: "vitesse-light",
26
+ dark: "vitesse-dark"
27
+ },
28
+ defaultColor: false,
29
+ cssVariablePrefix: "--ant-doc-",
30
+ transformers: [
31
+ transformerMetaHighlight(),
32
+ transformerMetaWordHighlight(),
33
+ transformerNotationDiff(),
34
+ transformerNotationErrorLevel(),
35
+ transformerNotationFocus(),
36
+ transformerNotationHighlight(),
37
+ transformerNotationWordHighlight(),
38
+ {
39
+ name: "remove:clean-up",
40
+ code(element) {
41
+ if (element.tagName === "code" && element.properties.class) delete element.properties.class;
42
+ },
43
+ pre(element) {
44
+ delete element.properties.tabindex;
45
+ delete element.properties.style;
46
+ this.addClassToHast(element, cls);
47
+ }
48
+ }
49
+ ]
50
+ }));
51
+ }
52
+ function loadBaseMd(md, options = {}) {
53
+ md.use(frontmatterPlugin);
54
+ md.use(headersPlugin, {
55
+ level: [
56
+ 2,
57
+ 3,
58
+ 4,
59
+ 5,
60
+ 6
61
+ ],
62
+ slugify
63
+ });
64
+ md.use(titlePlugin);
65
+ md.use(full);
66
+ md.use(attrsPlugin);
67
+ if (options.externalLink !== false) md.use(linkPlugin);
68
+ md.use(containerPlugin);
69
+ md.use(gitHubAlertsPlugin);
70
+ }
71
+ function withPlugins(md, options) {
72
+ md.use(demoMarkdownPlugin, {
73
+ root: options.root,
74
+ ...options.demo
75
+ });
76
+ loadBaseMd(md, options);
77
+ md.use(tocPlugin);
78
+ md.use(anchorPlugin, {
79
+ slugify,
80
+ permalink: anchorPlugin.permalink.linkInsideHeader({
81
+ symbol: "&ZeroWidthSpace;",
82
+ renderAttrs: (slug, state) => {
83
+ const idx = state.tokens.findIndex((token) => {
84
+ const id = token.attrs?.find((attr) => attr[0] === "id");
85
+ return id && slug === id[1];
86
+ });
87
+ return { "aria-label": `Permalink to "${state.tokens[idx + 1]?.content || ""}"` };
88
+ }
89
+ })
90
+ });
91
+ loadShiki(md);
92
+ md.use(imagePlugin);
93
+ md.use(preWrapperPlugin, { hasSingleTheme: false });
94
+ md.use(tablePlugin);
95
+ md.use(stackblitzPlugin);
96
+ md.linkify.set({ fuzzyLink: false });
97
+ }
98
+ function createMarkdown() {
99
+ let md;
100
+ return (options = {}) => {
101
+ if (md) return md;
102
+ md = MarkdownIt({
103
+ html: true,
104
+ linkify: true,
105
+ typographer: true
106
+ });
107
+ if (options.preConfig) options.preConfig(md);
108
+ if (options.withPlugin !== false) withPlugins(md, options);
109
+ if (options.config) options.config(md);
110
+ return md;
111
+ };
112
+ }
113
+ const useMarkdown = createMarkdown();
114
+ //#endregion
115
+ export { createMarkdown, loadBaseMd, loadShiki, useMarkdown };
@@ -0,0 +1,18 @@
1
+ import { DemoPluginOptions } from "./demo/index.js";
2
+ import { CreateMarkdownOptions } from "./markdown.js";
3
+ import { PluginOption } from "vite";
4
+ //#region src/md-plugin.d.ts
5
+ interface DocsPluginsOptions {
6
+ /**
7
+ * markdown-it 渲染链路选项(传给 md2vue / createMarkdown)
8
+ */
9
+ markdown?: CreateMarkdownOptions;
10
+ /**
11
+ * vite demo 插件选项
12
+ */
13
+ demo?: DemoPluginOptions;
14
+ }
15
+ /** docs 站点默认的 markdown 处理插件组合 */
16
+ declare function mdPlugin(options?: DocsPluginsOptions): PluginOption[];
17
+ //#endregion
18
+ export { DocsPluginsOptions, mdPlugin };
@@ -0,0 +1,9 @@
1
+ import { demoPlugin } from "./demo/index.js";
2
+ import { md2VuePlugin } from "./md2vue.js";
3
+ //#region src/md-plugin.ts
4
+ /** docs 站点默认的 markdown 处理插件组合 */
5
+ function mdPlugin(options = {}) {
6
+ return [md2VuePlugin(options.markdown), demoPlugin(options.demo)];
7
+ }
8
+ //#endregion
9
+ export { mdPlugin };
@@ -0,0 +1,16 @@
1
+ import { CreateMarkdownOptions } from "./markdown.js";
2
+ import { PluginOption } from "vite";
3
+ import { MarkdownItEnv } from "@mdit-vue/types";
4
+ //#region src/md2vue.d.ts
5
+ declare function formatPageData(env: MarkdownItEnv): {
6
+ title: string;
7
+ frontmatter: Record<string, unknown>;
8
+ headers: import("@mdit-vue/types").MarkdownItHeader[];
9
+ description: string;
10
+ };
11
+ declare function checkPkgImport(findCode: string, pkg: string, importName: string): boolean;
12
+ declare function addScriptSetup(scriptTags: RegExpMatchArray | null, env: MarkdownItEnv): string;
13
+ declare function md2Vue(code: string, env: MarkdownItEnv): string;
14
+ declare function md2VuePlugin(options?: CreateMarkdownOptions): PluginOption;
15
+ //#endregion
16
+ export { addScriptSetup, checkPkgImport, formatPageData, md2Vue, md2VuePlugin };
package/dist/md2vue.js ADDED
@@ -0,0 +1,106 @@
1
+ import { SCRIPT_REGEX, STYLE_REGEX } from "./shared.js";
2
+ import { useMarkdown } from "./markdown.js";
3
+ import { shortHash } from "./utils/short-hash.js";
4
+ import pathe from "pathe";
5
+ import { LRUCache } from "lru-cache";
6
+ import { findStaticImports } from "mlly";
7
+ //#region src/md2vue.ts
8
+ function formatPageData(env) {
9
+ const pageData = {
10
+ title: env.title ?? "",
11
+ frontmatter: env.frontmatter ?? {},
12
+ headers: env.headers ?? [],
13
+ description: ""
14
+ };
15
+ if (typeof env.frontmatter?.description === "string") pageData.description = env.frontmatter.description;
16
+ if (typeof env.frontmatter?.title === "string" && !env.title) pageData.title = env.frontmatter.title;
17
+ return pageData;
18
+ }
19
+ function checkPkgImport(findCode, pkg, importName) {
20
+ if (!findCode) return false;
21
+ return findStaticImports(findCode).some((item) => item.specifier === pkg && item.imports.includes(importName));
22
+ }
23
+ function addScriptSetup(scriptTags, env) {
24
+ const pageData = formatPageData(env);
25
+ const baseCode = `const __pageData = ${JSON.stringify(pageData)};\nconst frontmatter = ${JSON.stringify(env.frontmatter ?? {})};\n`;
26
+ const importsCode = `import { inject, provide, ref } from 'vue';\n`;
27
+ const injectedCode = `const __parentPageData = ref({});provide('__pageData__',(data)=>{__parentPageData.value=data});const __pageDataFunc__ = inject('__pageData__',null);if(__pageDataFunc__)__pageDataFunc__(__pageData);provide('__pageInfo__',__pageData);defineExpose({frontmatter,pageData:__pageData})`;
28
+ if (!scriptTags || !scriptTags.length) return `<script setup lang="ts">\n${importsCode}${baseCode}${injectedCode}\n<\/script>\n`;
29
+ const scriptSetupCode = scriptTags.find((v) => {
30
+ return /<script\b[^>]+\bsetup\b[^>]*>/i.test(v);
31
+ });
32
+ if (!scriptSetupCode) return `<script setup lang="ts">\n${importsCode}${baseCode}${injectedCode}\n<\/script>\n${scriptTags.join("\n")}\n`;
33
+ const restScriptTags = scriptTags.filter((v) => {
34
+ return v !== scriptSetupCode;
35
+ });
36
+ const scriptContent = scriptSetupCode ? scriptSetupCode.replace(/<script\b[^>]+\bsetup\b[^>]*>/i, "").replace(/<\/script>/i, "") : "";
37
+ const importArr = [];
38
+ if (!checkPkgImport(scriptContent, "vue", "provide")) importArr.push("provide");
39
+ if (!checkPkgImport(scriptContent, "vue", "inject")) importArr.push("inject");
40
+ if (!checkPkgImport(scriptContent, "vue", "ref")) importArr.push("ref");
41
+ return `<script setup lang="ts">\n${importArr.length ? `import { ${importArr.join(", ")} } from 'vue';\n` : ""}${scriptContent}${baseCode}${injectedCode}\n<\/script>\n${restScriptTags.join("\n")}\n`;
42
+ }
43
+ function md2Vue(code, env) {
44
+ code = code.replace(/<pre\b[^>]*>[\s\S]*?<\/pre>/gi, (match) => {
45
+ return match.replace(/\{/g, "&#123;").replace(/\}/g, "&#125;");
46
+ });
47
+ const scriptTags = code.match(SCRIPT_REGEX);
48
+ const styleTags = code.match(STYLE_REGEX);
49
+ const vueComponent = `<template>\n<div class="ant-doc vp-doc">${code.replace(SCRIPT_REGEX, "").replace(STYLE_REGEX, "")}</div>\n</template>\n`;
50
+ return `${addScriptSetup(scriptTags, env)}\n${vueComponent}\n${styleTags ? styleTags.join("\n") : ""}`;
51
+ }
52
+ function md2VuePlugin(options = {}) {
53
+ let md;
54
+ const cache = new LRUCache({
55
+ max: 500,
56
+ ttl: 6e5,
57
+ allowStale: true,
58
+ updateAgeOnGet: true
59
+ });
60
+ async function transform(code, id) {
61
+ const hash = shortHash(code);
62
+ const cached = cache.get(id);
63
+ if (cached && cached.hash === hash) return cached.code;
64
+ const env = { id };
65
+ const vueCode = md2Vue(await md.renderAsync(code, env), env);
66
+ cache.set(id, {
67
+ hash,
68
+ code: vueCode
69
+ });
70
+ return vueCode;
71
+ }
72
+ function shouldSkipTransform(id) {
73
+ if (id.includes("?vue")) return true;
74
+ const query = id.split("?")[1];
75
+ if (!query) return false;
76
+ const params = new URLSearchParams(query);
77
+ return params.has("raw") || params.has("url");
78
+ }
79
+ return {
80
+ enforce: "pre",
81
+ name: "vite:md2vue",
82
+ configResolved(config) {
83
+ md = useMarkdown({
84
+ root: pathe.resolve(config.root ?? process.cwd(), "."),
85
+ ...options
86
+ });
87
+ },
88
+ transform: {
89
+ filter: { id: /\.md($|\?)/ },
90
+ async handler(code, id) {
91
+ if (shouldSkipTransform(id)) return null;
92
+ return transform(code, id);
93
+ }
94
+ },
95
+ handleHotUpdate(ctx) {
96
+ const { file, read } = ctx;
97
+ if (!file.endsWith(".md")) return;
98
+ const defaultRead = read;
99
+ ctx.read = async () => {
100
+ return transform(await defaultRead(), file);
101
+ };
102
+ }
103
+ };
104
+ }
105
+ //#endregion
106
+ export { addScriptSetup, checkPkgImport, formatPageData, md2Vue, md2VuePlugin };
@@ -0,0 +1,16 @@
1
+ import { Options } from "./pre-wrapper.js";
2
+ import MarkdownIt from "markdown-it";
3
+ //#region src/plugins/container.d.ts
4
+ declare function containerPlugin(md: MarkdownIt, options: Options, containerOptions?: ContainerOptions): void;
5
+ interface ContainerOptions {
6
+ infoLabel?: string;
7
+ noteLabel?: string;
8
+ tipLabel?: string;
9
+ warningLabel?: string;
10
+ dangerLabel?: string;
11
+ detailsLabel?: string;
12
+ importantLabel?: string;
13
+ cautionLabel?: string;
14
+ }
15
+ //#endregion
16
+ export { ContainerOptions, containerPlugin };
@@ -0,0 +1,53 @@
1
+ import { extractTitle, getAdaptiveThemeMarker } from "./pre-wrapper.js";
2
+ import container from "markdown-it-container";
3
+ import { nanoid } from "nanoid";
4
+ //#region src/plugins/container.ts
5
+ function containerPlugin(md, options, containerOptions) {
6
+ md.use(...createContainer("tip", containerOptions?.tipLabel || "TIP", md)).use(...createContainer("info", containerOptions?.infoLabel || "INFO", md)).use(...createContainer("warning", containerOptions?.warningLabel || "WARNING", md)).use(...createContainer("danger", containerOptions?.dangerLabel || "DANGER", md)).use(...createContainer("details", containerOptions?.detailsLabel || "Details", md)).use(container, "v-pre", { render: (tokens, idx) => tokens[idx].nesting === 1 ? `<div v-pre>\n` : `</div>\n` }).use(container, "raw", { render: (tokens, idx) => tokens[idx].nesting === 1 ? `<div class="vp-raw">\n` : `</div>\n` }).use(...createCodeGroup(options));
7
+ }
8
+ function createContainer(klass, defaultTitle, md) {
9
+ return [
10
+ container,
11
+ klass,
12
+ { render(tokens, idx, _options, env) {
13
+ const token = tokens[idx];
14
+ const info = token.info.trim().slice(klass.length).trim();
15
+ const attrs = md.renderer.renderAttrs(token);
16
+ if (token.nesting === 1) {
17
+ const title = md.renderInline(info || defaultTitle, { references: env.references });
18
+ if (klass === "details") return `<details class="${klass} custom-block"${attrs}><summary>${title}</summary>\n`;
19
+ return `<div class="${klass} custom-block"${attrs}><p class="custom-block-title">${title}</p>\n`;
20
+ } else return klass === "details" ? `</details>\n` : `</div>\n`;
21
+ } }
22
+ ];
23
+ }
24
+ function createCodeGroup(options) {
25
+ return [
26
+ container,
27
+ "code-group",
28
+ { render(tokens, idx) {
29
+ if (tokens[idx].nesting === 1) {
30
+ const name = nanoid(5);
31
+ let tabs = "";
32
+ let checked = "checked=\"checked\"";
33
+ for (let i = idx + 1; !(tokens[i].nesting === -1 && tokens[i].type === "container_code-group_close"); ++i) {
34
+ const token = tokens[i];
35
+ const isHtml = token.type === "html_block";
36
+ if (token.type === "fence" && token.tag === "code" || isHtml) {
37
+ const title = extractTitle(isHtml ? token.content : token.info, isHtml);
38
+ if (title) {
39
+ const id = nanoid(7);
40
+ tabs += `<input type="radio" name="group-${name}" id="tab-${id}" ${checked}><label for="tab-${id}">${title}</label>`;
41
+ if (checked && !isHtml) token.info += " active";
42
+ checked = "";
43
+ }
44
+ }
45
+ }
46
+ return `<div class="vp-code-group${getAdaptiveThemeMarker(options)}"><div class="tabs">${tabs}</div><div class="blocks">\n`;
47
+ }
48
+ return `</div></div>\n`;
49
+ } }
50
+ ];
51
+ }
52
+ //#endregion
53
+ export { containerPlugin };
@@ -0,0 +1,29 @@
1
+ import { MarkdownItHeader } from "@mdit-vue/types";
2
+ import MarkdownIt from "markdown-it";
3
+ //#region src/plugins/demo.d.ts
4
+ interface DemoMarkdownPluginOptions {
5
+ /** 包裹 demo 的标签名,默认 `demo` */
6
+ wrapper?: string;
7
+ /**
8
+ * demo 锚点归属模式:
9
+ * - `examples`:demo 统一挂到 slug 为 `examples` 的标题下(antdv-next 约定,默认)
10
+ * - `section`:demo 挂到当前所在章节标题下(跟随标题层级)
11
+ */
12
+ headerMode?: 'examples' | 'section';
13
+ /**
14
+ * 生产构建时跳过 `debug` demo 的目录收集
15
+ * @default true
16
+ */
17
+ debugDemo?: boolean;
18
+ }
19
+ declare module '@mdit-vue/types' {
20
+ interface MarkdownItEnv {
21
+ id?: string;
22
+ }
23
+ }
24
+ declare function replaceSrcPath(content: string, id: string, root: string, wrapper?: string, parentHeader?: MarkdownItHeader, skipDebugDemo?: boolean): string;
25
+ declare function demoMarkdownPlugin(md: MarkdownIt, config?: {
26
+ root?: string;
27
+ } & DemoMarkdownPluginOptions): void;
28
+ //#endregion
29
+ export { DemoMarkdownPluginOptions, demoMarkdownPlugin, replaceSrcPath };
@@ -0,0 +1,139 @@
1
+ import { getDemoId } from "../demo/get-demo-id.js";
2
+ import pathe from "pathe";
3
+ //#region src/plugins/demo.ts
4
+ const HEADING_LEVEL_RE = /^h([2-6])$/;
5
+ const SRC_ATTR_RE = /(\s|^)src=(['"])(.*?)\2/gi;
6
+ function checkWrapper(content, wrapper = "demo") {
7
+ return new RegExp(`<${wrapper}(\\s|>|/)`, "i").test(content);
8
+ }
9
+ function isProdDebugDemo(tag) {
10
+ if (process.env.NODE_ENV !== "production") return false;
11
+ const debugAttr = tag.match(/(?:^|\s)debug(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s/>]+)))?/i);
12
+ if (!debugAttr) return false;
13
+ const value = debugAttr[1] ?? debugAttr[2] ?? debugAttr[3];
14
+ return value === void 0 || value === "" || value === "true";
15
+ }
16
+ function flattenHeaders(headers = []) {
17
+ const headerMap = /* @__PURE__ */ new Map();
18
+ const visit = (items) => {
19
+ for (const item of items) {
20
+ headerMap.set(item.slug, item);
21
+ if (item.children?.length) visit(item.children);
22
+ }
23
+ };
24
+ visit(headers);
25
+ return headerMap;
26
+ }
27
+ function flattenHeadersInOrder(headers = []) {
28
+ const flat = [];
29
+ const visit = (items) => {
30
+ for (const item of items) {
31
+ flat.push(item);
32
+ if (item.children?.length) visit(item.children);
33
+ }
34
+ };
35
+ visit(headers);
36
+ return flat;
37
+ }
38
+ function getHeadingSlug(token) {
39
+ return token.attrs?.find((attr) => attr[0] === "id")?.[1];
40
+ }
41
+ function getHeadingTitle(token) {
42
+ if (token?.type !== "inline") return "";
43
+ return token.content?.trim() ?? "";
44
+ }
45
+ function getHeadingLevel(token) {
46
+ const match = token.tag?.match(HEADING_LEVEL_RE);
47
+ if (!match) return null;
48
+ return Number(match[1]);
49
+ }
50
+ function replaceSrcPath(content, id, root, wrapper = "demo", parentHeader, skipDebugDemo = false) {
51
+ function replaceSrcInTag(tagMatch, titleContent) {
52
+ return tagMatch.replace(SRC_ATTR_RE, (srcMatch, prefix, quote, srcValue) => {
53
+ if (!srcValue || srcValue.startsWith("/")) return srcMatch;
54
+ const dir = pathe.dirname(id);
55
+ const filePath = pathe.resolve(dir, srcValue);
56
+ const relative = pathe.relative(root, filePath);
57
+ if (parentHeader && titleContent && !(skipDebugDemo && isProdDebugDemo(tagMatch))) {
58
+ const slug = getDemoId(filePath);
59
+ const item = {
60
+ level: parentHeader.level + 1,
61
+ title: titleContent,
62
+ slug,
63
+ link: `#${slug}`,
64
+ children: []
65
+ };
66
+ if (parentHeader.children) parentHeader.children.push(item);
67
+ else parentHeader.children = [item];
68
+ }
69
+ return `${prefix}src=${quote}${relative.startsWith("/") ? relative : `/${relative}`}${quote}`;
70
+ });
71
+ }
72
+ const closedTag = new RegExp(`(<${wrapper}(?!-)\\b[^>]*>)([\\s\\S]*?)<\\/${wrapper}>`, "gi");
73
+ let result = content.replace(closedTag, (tagMatch, openTag, titleContent) => {
74
+ return tagMatch.replace(openTag, replaceSrcInTag(openTag, titleContent?.trim()));
75
+ });
76
+ const selfClosing = new RegExp(`<${wrapper}(?!-)\\b[^>]*/\\s*>`, "gi");
77
+ result = result.replace(selfClosing, (tagMatch) => replaceSrcInTag(tagMatch));
78
+ const openTag = new RegExp(`<${wrapper}(?!-)\\b[^>]*>`, "gi");
79
+ return result.replace(openTag, (tagMatch) => replaceSrcInTag(tagMatch));
80
+ }
81
+ function demoMarkdownPlugin(md, config = {}) {
82
+ const wrapper = config.wrapper ?? "demo";
83
+ const headerMode = config.headerMode ?? "examples";
84
+ const skipDebugDemo = config.debugDemo ?? true;
85
+ const originalRender = md.renderer.render.bind(md.renderer);
86
+ md.renderer.render = function render(tokens, options, env) {
87
+ const root = config.root ?? process.cwd();
88
+ const currentId = env.id || "";
89
+ const headers = env.headers;
90
+ const fixedHeader = headerMode === "examples" ? headers?.find((item) => item.slug === "examples") : void 0;
91
+ const headerMap = flattenHeaders(headers);
92
+ const orderedHeaders = flattenHeadersInOrder(headers);
93
+ const headerIndexBySlug = new Map(orderedHeaders.map((item, index) => [item.slug, index]));
94
+ const activeHeaders = /* @__PURE__ */ new Map();
95
+ let headerCursor = 0;
96
+ function getCurrentHeader() {
97
+ const nearestLevel = Array.from(activeHeaders.keys()).sort((left, right) => right - left)[0];
98
+ return nearestLevel ? activeHeaders.get(nearestLevel) : void 0;
99
+ }
100
+ function resolveHeading(headingLevel, headingSlug, headingTitle) {
101
+ if (headingSlug) {
102
+ const bySlug = headerMap.get(headingSlug);
103
+ if (bySlug) {
104
+ const index = headerIndexBySlug.get(headingSlug);
105
+ if (typeof index === "number") headerCursor = Math.max(headerCursor, index + 1);
106
+ return bySlug;
107
+ }
108
+ }
109
+ for (let index = headerCursor; index < orderedHeaders.length; index += 1) {
110
+ const header = orderedHeaders[index];
111
+ if (header.level !== headingLevel) continue;
112
+ if (headingTitle && header.title !== headingTitle) continue;
113
+ headerCursor = index + 1;
114
+ return header;
115
+ }
116
+ }
117
+ function processToken(token) {
118
+ const tokenType = token.type ?? "";
119
+ const tokenContent = token.content ?? "";
120
+ if ((tokenType === "html_block" || tokenType === "html_inline" || tokenType === "inline") && checkWrapper(tokenContent, wrapper)) token.content = replaceSrcPath(tokenContent, currentId, root, wrapper, headerMode === "examples" ? fixedHeader : getCurrentHeader(), skipDebugDemo);
121
+ if (token.children) for (const child of token.children) processToken(child);
122
+ }
123
+ const typedTokens = tokens;
124
+ typedTokens.forEach((token, index) => {
125
+ if (token.type === "heading_open") {
126
+ const headingLevel = getHeadingLevel(token);
127
+ if (headingLevel) {
128
+ for (const level of activeHeaders.keys()) if (level >= headingLevel) activeHeaders.delete(level);
129
+ const header = resolveHeading(headingLevel, getHeadingSlug(token), getHeadingTitle(typedTokens[index + 1]));
130
+ if (header) activeHeaders.set(headingLevel, header);
131
+ }
132
+ }
133
+ processToken(token);
134
+ });
135
+ return originalRender(tokens, options, env);
136
+ };
137
+ }
138
+ //#endregion
139
+ export { demoMarkdownPlugin, replaceSrcPath };
@@ -0,0 +1,6 @@
1
+ import { ContainerOptions } from "./container.js";
2
+ import MarkdownIt from "markdown-it";
3
+ //#region src/plugins/github-alerts.d.ts
4
+ declare function gitHubAlertsPlugin(md: MarkdownIt, options?: ContainerOptions): void;
5
+ //#endregion
6
+ export { gitHubAlertsPlugin };