-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcreate.js
More file actions
181 lines (163 loc) · 5.34 KB
/
create.js
File metadata and controls
181 lines (163 loc) · 5.34 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import fs from 'fs-extra'
import path from 'path'
import MarkdownIt from 'markdown-it'
import markdownItHighlightjs from 'markdown-it-highlightjs'
import hljs from 'highlight.js'
// Define reusable modes for contains
const longMode = {
className: 'long',
begin: '[…—]+',
returnEnd: false
};
const commentMode = {
className: 'comment',
variants: [
{ begin: '[,;]' },
{ begin: '\\(', end: '\\)', contains: [longMode] },
{ begin: '\\(', end: '\\)', contains: [longMode] }
],
returnEnd: false
};
const stringMode = {
className: 'string',
variants: [
{ begin: '"', end: '"' },
{ begin: '“', end: '”' },
{ begin: "'", end: "'" },
{ begin: "‘", end: "’" },
{ begin: "「", end: "」" }
],
returnEnd: false,
contains: [longMode, commentMode]
};
const titleMode = {
className: 'title',
begin: '^# ',
end: '\n',
returnEnd: true,
contains: [longMode]
};
const quoteMode = {
className: 'quote',
begin: '(?<=\>) ',
end: '\n',
returnEnd: true,
contains: [longMode]
};
const authorMode = {
className: 'author',
begin: '作者:?[\\s\\S]+?\n',
returnEnd: true
};
const myCustomLanguage = {
case_insensitive: true,
contains: [
longMode,
commentMode,
stringMode,
titleMode,
quoteMode,
authorMode
]
};
// 注册自定义语言到 highlight.js
hljs.registerLanguage('liter', ()=>myCustomLanguage);
// hljs
const md = new MarkdownIt({
linkify: true,
html: true
});
md.use(markdownItHighlightjs);
md.use((m)=>{
// 修改链接渲染,处理相对路径为"./assets/..."(考虑当前 Markdown 文件所在目录)
m.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const hrefIndex = tokens[idx].attrIndex('href');
let href = tokens[idx].attrs[hrefIndex][1];
if(!href.startsWith('http') && !href.startsWith('mailto:')){
const base = env && env.base ? env.base.replace(/\\/g, '/') + '/' : '';
href = './assets/' + base + href;
tokens[idx].attrs[hrefIndex][1] = href;
}
return `<a href="${href}" class="a jump">`;
};
m.renderer.rules.code_inline = (tokens, idx, options, env, self) => {
return `<code class="inline">${tokens[idx].content}</code>`;
};
// 修改图片渲染,同样根据 env.base 拼接资源路径
m.renderer.rules.image = (tokens, idx, options, env, self) => {
const srcIndex = tokens[idx].attrIndex('src');
let src = tokens[idx].attrs[srcIndex][1];
if(!src.startsWith('http') && !src.startsWith('mailto:')){
const base = env && env.base ? env.base.replace(/\\/g, '/') + '/' : '';
src = './assets/' + base + src;
tokens[idx].attrs[srcIndex][1] = src;
}
return self.renderToken(tokens, idx, options);
};
})
async function copyAssets(srcDir, destDir) {
const entries = await fs.readdir(srcDir, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(srcDir, entry.name);
const destPath = path.join(destDir, entry.name);
if (entry.isDirectory()) {
await fs.ensureDir(destPath);
await copyAssets(srcPath, destPath);
} else if (entry.isFile() && !entry.name.endsWith('.md') && entry.name !== 'info.json') {
await fs.copy(srcPath, destPath);
}
}
}
async function readDirRecursive(dirPath, name, rootDir) {
rootDir = rootDir || dirPath;
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const result = {
folder: {},
slug: name,
name: name,
detail: '',
file: {},
};
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
// 递归
result.folder[entry.name] = await readDirRecursive(fullPath, entry.name, rootDir);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
const fileContent = await fs.readFile(fullPath, 'utf8');
// 计算当前 Markdown 文件相对于 docs 根目录的子路径,用于构造资源文件路径
const relDir = path.relative(rootDir, path.dirname(fullPath));
const htmlContent = md.render(fileContent.replace(/<!-.*-->/g, ''), { base: relDir });
const slug = path.basename(fullPath, '.md');
const titleMatch = fileContent.match(/^<!-- name=(.+) -->/m);
const title = titleMatch ? titleMatch[1] : slug;
result.file[slug] = {
slug,
title,
content: htmlContent,
};
} else if (entry.isFile() && entry.name == 'info.json') {
const fileContent = await fs.readFile(fullPath, 'utf8');
let info = JSON.parse(fileContent);
result.name = info.name || name;
result.detail = info.detail || '';
}
}
return result;
}
async function generateMarkdownJson() {
const markdownRootDir = '../docs'; // 存放Markdown文件的目录
const outputJsonPath = 'src/posts.js'; // 输出的JSON文件路径
const assetsDest = path.join('public', 'assets'); // 资源文件目标目录
try {
// 先复制资源文件
await fs.ensureDir(assetsDest);
await copyAssets(markdownRootDir, assetsDest);
const formattedPosts = await readDirRecursive(markdownRootDir, 'docs', markdownRootDir);
await fs.writeFile(outputJsonPath, 'export let data=' + JSON.stringify(formattedPosts, null, 2) + ';', 'utf8');
console.log('Markdown JSON generated successfully!');
} catch (err) {
console.error('Error generating Markdown JSON:', err);
}
}
generateMarkdownJson();