markdown-loader.js
4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const MarkdownIt = require("markdown-it");
const MarkdownItAnchor = require('markdown-it-anchor')
const MarkdownItContainer = require("markdown-it-container");
const VueTemplateComplier = require("vue-template-compiler");
const hljs = require("highlight.js");
const slugify = require('transliteration').slugify; // 引入transliteration中的slugify方法
const { parse, compileTemplate } = require("@vue/component-compiler-utils");
module.exports = function(source) {
// 需要解析成vue代码块集合
const componentCodeList = [];
let styleCodeList = [];
// 初始还MarkdownIt用于转换md文件为html
const markdownIt = MarkdownIt({
// 将markdown中的代码块用hljs高亮显示
highlight: function(str, lang) {
if (lang && hljs.getLanguage(lang)) {
return `<pre class="hljs" style="white-space: pre-wrap;word-wrap: break-word;"><code>${
hljs.highlight(lang, str, true).value
}</code></pre>`;
}
return `<pre class="hljs" style="white-space: pre-wrap;word-wrap: break-word;"><code>${markdownIt.utils.escapeHtml(
str
)}</code></pre>`;
}
});
// 使用【markdown-it-anchor】插件为markdown创建锚点
markdownIt.use(MarkdownItAnchor, {
level: 2, // 添加超链接锚点的最小标题级别, 如: #标题 不会添加锚点
slugify: slugify, // 自定义slugify, 我们使用的是将中文转为汉语拼音,最终生成为标题id属性
permalink: true, // 开启标题锚点功能
// permalinkBefore: true, // 在标题前创建锚点
permalinkSymbol: '#', // 锚点标志
});
// 使用【markdown-it-container】插件解析【:::snippet :::】代码块为vue渲染
markdownIt.use(MarkdownItContainer, "snippet", {
// 验证代码块为【:::snippet :::】才进行渲染
validate(params) {
return params.trim().match(/^snippet\s*(.*)$/);
},
// 代码块渲染
render(tokens, index) {
const token = tokens[index];
const tokenInfo = token.info.trim().match(/^snippet\s*(.*)$/);
if (token.nesting === 1) {
// 获取snippet第一行的表述内容
const desc = tokenInfo && tokenInfo.length > 1 ? tokenInfo[1] : "";
// 获取vue组件示例的代码
const nextIndex = tokens[index + 1];
const content = nextIndex.type === "fence" ? nextIndex.content : "";
// 将content解析为vue组件基本属性对象;
let { template, script, styles } = parse({
source: content,
compiler: VueTemplateComplier,
needMap: false
});
styleCodeList = styleCodeList.concat(styles);
// 将template的转为render函数
const { code } = compileTemplate({
source: template.content,
compiler: VueTemplateComplier
});
// 获取script的代码
script = script ? script.content : "";
if (script) {
script = script.replace(
/export\s+default/,
"const exportJavaScript ="
);
} else {
script = "const exportJavaScript = {} ;";
}
// 代码块解析将需要解析vue组件的存储,渲染html用组件名称替代
const name = `eagle-snippent-${componentCodeList.length}`;
// 渲染组件代码添加到数据集合
componentCodeList.push(`"${name}":(function () {
${code}
${script}
return {
...exportJavaScript,
render,
staticRenderFns
}
})()`);
// 将需要渲染的示例用eagle-code-snippet组件包裹替换插槽显示示例效果
return `<eagle-code-snippet>
<div slot="desc">${markdownIt.render(desc)}</div>
<${name} slot="source" />
<div slot="code">`;
}
return ` </div>
</eagle-code-snippet> `;
}
});
// 使用【markdown-it-container】插件解析【:::html :::】代码块为vue渲染
markdownIt.use(MarkdownItContainer, "html", {
// 验证代码块为【:::html :::】才进行渲染
validate(params) {
return params.trim().match(/^html\s*(.*)$/);
},
// 代码块渲染
render(tokens, idx) {
var m = tokens[idx].info.trim().match(/^html\s+(.*)$/);
if (tokens[idx].nesting === 1) {
return `<div> ${markdownIt.utils.escapeHtml(m[1])}`;
} else {
return '</div>';
}
}
});
// 将所有转换好的代码字符串拼接成vue单组件template、script、style格式
return `
<template>
<div class="eagle-snippet-doc">
${markdownIt.render(source)}
</div>
</template>
<script>
export default {
name: 'eagle-component-doc',
components: {
${componentCodeList.join(",")}
}
}
</script>
<style>
${Array.from(styleCodeList, m => m.content).join("\n")}
</style>`;
};