@ruan-cat/vitepress-preset-config 2.14.0 → 3.1.0
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.
- package/dist/config.d.mts +5 -2
- package/dist/config.mjs +216 -73
- package/dist/theme.mjs +0 -1
- package/package.json +1 -1
- package/src/config/add-changelog-to-doc.ts +10 -4
- package/src/config/changelog-nav.ts +3 -7
- package/src/config/index.ts +1 -0
- package/src/config/multi-sidebar.ts +161 -0
- package/src/config/prompts-nav.ts +1 -137
- package/src/config.mts +21 -4
- package/src/theme.ts +2 -2
- package/src/utils/copy-changelog.ts +11 -5
- package/src/utils/vitepress-project.ts +196 -0
package/dist/config.d.mts
CHANGED
|
@@ -158,19 +158,22 @@ interface CopyClaudeFilesOptions {
|
|
|
158
158
|
*/
|
|
159
159
|
declare function copyClaudeFiles(options: CopyClaudeFilesOptions): void;
|
|
160
160
|
|
|
161
|
-
interface AddChangelog2docOptions<T extends Record<string,
|
|
161
|
+
interface AddChangelog2docOptions<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
162
162
|
/** 目标文件夹 */
|
|
163
163
|
target: string;
|
|
164
164
|
/** 被插入到md头部的数据 */
|
|
165
165
|
data?: T;
|
|
166
166
|
}
|
|
167
167
|
/** 将变更日志添加到指定的文档目录内 并提供参数 */
|
|
168
|
-
declare function addChangelog2doc<T extends Record<string,
|
|
168
|
+
declare function addChangelog2doc<T extends Record<string, unknown>>(options: AddChangelog2docOptions<T>): void;
|
|
169
169
|
|
|
170
170
|
type VitePressSidebarOptions = Parameters<typeof generateSidebar>[0];
|
|
171
171
|
/**
|
|
172
172
|
* 设置自动生成侧边栏的配置
|
|
173
173
|
* @see https://vitepress-sidebar.cdget.com/zhHans/guide/options
|
|
174
|
+
*
|
|
175
|
+
* 注意:在 Windows 环境下,必须使用相对路径(如 "./docs")而不是绝对路径,
|
|
176
|
+
* 否则 vitepress-sidebar 内部的 path.join 会导致路径拼接错误。
|
|
174
177
|
*/
|
|
175
178
|
declare function setGenerateSidebar(options?: VitePressSidebarOptions): vitepress_sidebar_types.Sidebar;
|
|
176
179
|
/** 设置vitepress主配置 */
|
package/dist/config.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/config.mts
|
|
2
2
|
import { defineConfig } from "vitepress";
|
|
3
|
-
import { generateSidebar } from "vitepress-sidebar";
|
|
3
|
+
import { generateSidebar as generateSidebar2 } from "vitepress-sidebar";
|
|
4
4
|
import { vitepressDemoPlugin } from "vitepress-demo-plugin";
|
|
5
|
-
import { merge as
|
|
5
|
+
import { merge as merge4, isUndefined as isUndefined3, cloneDeep as cloneDeep3 } from "lodash-es";
|
|
6
6
|
|
|
7
7
|
// src/config/page-order-config.ts
|
|
8
8
|
var pageOrderConfig = {
|
|
@@ -136,8 +136,9 @@ import matter from "gray-matter";
|
|
|
136
136
|
import fs3 from "fs";
|
|
137
137
|
import path3 from "path";
|
|
138
138
|
import consola3 from "consola";
|
|
139
|
-
function
|
|
140
|
-
const
|
|
139
|
+
function checkChangelogExists() {
|
|
140
|
+
const sourceDir = path3.resolve(process.cwd(), "CHANGELOG.md");
|
|
141
|
+
const res = fs3.existsSync(sourceDir);
|
|
141
142
|
if (!res) {
|
|
142
143
|
consola3.log("\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E3A\uFF1A", process.cwd());
|
|
143
144
|
consola3.warn("\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E0D\u5B58\u5728 CHANGELOG.md \u6587\u4EF6");
|
|
@@ -145,7 +146,7 @@ function hasChangelogMd() {
|
|
|
145
146
|
return res;
|
|
146
147
|
}
|
|
147
148
|
function copyChangelogMd(target) {
|
|
148
|
-
if (!
|
|
149
|
+
if (!checkChangelogExists()) {
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
151
152
|
const source = path3.resolve(process.cwd(), "CHANGELOG.md");
|
|
@@ -154,9 +155,13 @@ function copyChangelogMd(target) {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
// src/config/add-changelog-to-doc.ts
|
|
158
|
+
function hasChangelogInRoot() {
|
|
159
|
+
const changelogPath = path4.resolve(process.cwd(), "CHANGELOG.md");
|
|
160
|
+
return fs4.existsSync(changelogPath);
|
|
161
|
+
}
|
|
157
162
|
function addChangelog2doc(options) {
|
|
158
163
|
const { data = pageOrderConfig.changelog, target } = options;
|
|
159
|
-
if (!
|
|
164
|
+
if (!hasChangelogInRoot()) {
|
|
160
165
|
return;
|
|
161
166
|
}
|
|
162
167
|
copyChangelogMd(target);
|
|
@@ -212,31 +217,15 @@ function handlePlugins(userConfig, extraConfig) {
|
|
|
212
217
|
}
|
|
213
218
|
|
|
214
219
|
// src/config/changelog-nav.ts
|
|
215
|
-
import
|
|
220
|
+
import consola6 from "consola";
|
|
216
221
|
import { isUndefined } from "lodash-es";
|
|
217
|
-
import { printFormat } from "@ruan-cat/utils";
|
|
218
|
-
function handleChangeLog(userConfig) {
|
|
219
|
-
var _a;
|
|
220
|
-
if (!hasChangelogMd()) {
|
|
221
|
-
consola5.warn(` \u672A\u627E\u5230\u53D8\u66F4\u65E5\u5FD7\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u53D8\u66F4\u65E5\u5FD7\u5BFC\u822A\u680F\u3002 `);
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
225
|
-
if (isUndefined(nav)) {
|
|
226
|
-
consola5.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
227
|
-
throw new Error(` nav \u9ED8\u8BA4\u63D0\u4F9B\u7684\u5BFC\u822A\u680F\u914D\u7F6E\u4E3A\u7A7A\u3002\u4E0D\u7B26\u5408\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5\u3002 `);
|
|
228
|
-
}
|
|
229
|
-
nav.push({ text: "\u66F4\u65B0\u65E5\u5FD7", link: "/CHANGELOG.md" });
|
|
230
|
-
console.log(" \u67E5\u770B\u4FA7\u8FB9\u680F\u6570\u636E ", printFormat(userConfig == null ? void 0 : userConfig.themeConfig.sidebar));
|
|
231
|
-
}
|
|
232
222
|
|
|
233
|
-
// src/
|
|
223
|
+
// src/utils/vitepress-project.ts
|
|
234
224
|
import fs5 from "fs";
|
|
235
225
|
import path5 from "path";
|
|
236
|
-
import
|
|
237
|
-
import { isUndefined as isUndefined2, merge } from "lodash-es";
|
|
238
|
-
import matter2 from "gray-matter";
|
|
226
|
+
import consola5 from "consola";
|
|
239
227
|
var PROMPTS_INDEX_MD_PATH = "prompts/index.md";
|
|
228
|
+
var CHANGELOG_MD_FILENAME = "CHANGELOG.md";
|
|
240
229
|
function getProjectRootFromArgs() {
|
|
241
230
|
const args = process.argv;
|
|
242
231
|
const vitepressIndex = args.findIndex((arg) => arg.includes("vitepress"));
|
|
@@ -254,36 +243,60 @@ function getProjectRootFromArgs() {
|
|
|
254
243
|
}
|
|
255
244
|
continue;
|
|
256
245
|
}
|
|
257
|
-
|
|
246
|
+
let inputPath = path5.resolve(process.cwd(), arg);
|
|
247
|
+
let currentDir = inputPath;
|
|
248
|
+
const root = path5.parse(currentDir).root;
|
|
249
|
+
while (currentDir !== root) {
|
|
250
|
+
if (fs5.existsSync(path5.join(currentDir, ".vitepress"))) {
|
|
251
|
+
consola5.log("\u4ECE\u547D\u4EE4\u884C\u53C2\u6570\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", currentDir);
|
|
252
|
+
return currentDir;
|
|
253
|
+
}
|
|
254
|
+
currentDir = path5.dirname(currentDir);
|
|
255
|
+
}
|
|
256
|
+
if (fs5.existsSync(path5.join(root, ".vitepress"))) {
|
|
257
|
+
consola5.log("\u4ECE\u547D\u4EE4\u884C\u53C2\u6570\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", root);
|
|
258
|
+
return root;
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
258
261
|
}
|
|
259
262
|
return null;
|
|
260
263
|
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
const vitepressDir2 = path5.join(projectRootFromArgs, ".vitepress");
|
|
265
|
-
if (fs5.existsSync(vitepressDir2)) {
|
|
266
|
-
consola6.log("\u4ECE\u547D\u4EE4\u884C\u53C2\u6570\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", projectRootFromArgs);
|
|
267
|
-
return projectRootFromArgs;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
let currentDir = process.cwd();
|
|
271
|
-
const root = path5.parse(currentDir).root;
|
|
264
|
+
function findProjectRootFromDir(startDir) {
|
|
265
|
+
const root = path5.parse(startDir).root;
|
|
266
|
+
let currentDir = startDir;
|
|
272
267
|
while (currentDir !== root) {
|
|
273
|
-
const
|
|
274
|
-
if (fs5.existsSync(
|
|
275
|
-
consola6.log("\u901A\u8FC7\u5411\u4E0A\u67E5\u627E\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", currentDir);
|
|
268
|
+
const vitepressDir = path5.join(currentDir, ".vitepress");
|
|
269
|
+
if (fs5.existsSync(vitepressDir)) {
|
|
276
270
|
return currentDir;
|
|
277
271
|
}
|
|
278
272
|
currentDir = path5.dirname(currentDir);
|
|
279
273
|
}
|
|
280
|
-
const
|
|
281
|
-
if (fs5.existsSync(
|
|
282
|
-
consola6.log("\u5728\u6587\u4EF6\u7CFB\u7EDF\u6839\u76EE\u5F55\u627E\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", root);
|
|
274
|
+
const rootVitepressDir = path5.join(root, ".vitepress");
|
|
275
|
+
if (fs5.existsSync(rootVitepressDir)) {
|
|
283
276
|
return root;
|
|
284
277
|
}
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
function getVitepressProjectRoot() {
|
|
281
|
+
const projectRootFromArgs = getProjectRootFromArgs();
|
|
282
|
+
if (projectRootFromArgs) {
|
|
283
|
+
const foundRoot = findProjectRootFromDir(projectRootFromArgs);
|
|
284
|
+
if (foundRoot) {
|
|
285
|
+
consola5.log("\u4ECE\u547D\u4EE4\u884C\u53C2\u6570\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", foundRoot);
|
|
286
|
+
return foundRoot;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const foundFromCwd = findProjectRootFromDir(process.cwd());
|
|
290
|
+
if (foundFromCwd) {
|
|
291
|
+
consola5.log("\u901A\u8FC7\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", foundFromCwd);
|
|
292
|
+
return foundFromCwd;
|
|
293
|
+
}
|
|
294
|
+
if (projectRootFromArgs) {
|
|
295
|
+
consola5.warn("\u672A\u627E\u5230 .vitepress \u76EE\u5F55\uFF0C\u56DE\u9000\u5230\u547D\u4EE4\u884C\u53C2\u6570\u8DEF\u5F84\uFF1A", projectRootFromArgs);
|
|
296
|
+
return projectRootFromArgs;
|
|
297
|
+
}
|
|
285
298
|
const fallbackDir = process.cwd();
|
|
286
|
-
|
|
299
|
+
consola5.warn("\u672A\u627E\u5230 .vitepress \u76EE\u5F55\uFF0C\u56DE\u9000\u5230\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A", fallbackDir);
|
|
287
300
|
return fallbackDir;
|
|
288
301
|
}
|
|
289
302
|
function getVitepressSourceDirectory(userConfig) {
|
|
@@ -291,67 +304,98 @@ function getVitepressSourceDirectory(userConfig) {
|
|
|
291
304
|
const srcDir = userConfig.srcDir;
|
|
292
305
|
if (srcDir) {
|
|
293
306
|
const sourceDirectory = path5.resolve(projectRoot, srcDir);
|
|
294
|
-
|
|
295
|
-
|
|
307
|
+
consola5.log("\u4ECE\u914D\u7F6E\u4E2D\u83B7\u53D6\u5230 srcDir:", srcDir);
|
|
308
|
+
consola5.log("VitePress \u6E90\u76EE\u5F55\u4E3A\uFF1A", sourceDirectory);
|
|
296
309
|
return sourceDirectory;
|
|
297
310
|
}
|
|
298
|
-
|
|
311
|
+
consola5.log("\u914D\u7F6E\u4E2D\u672A\u6307\u5B9A srcDir\uFF0C\u6E90\u76EE\u5F55\u7B49\u4E8E\u9879\u76EE\u6839\u76EE\u5F55\uFF1A", projectRoot);
|
|
299
312
|
return projectRoot;
|
|
300
313
|
}
|
|
301
314
|
function hasPromptsIndexMd(userConfig) {
|
|
302
315
|
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
303
316
|
const res = fs5.existsSync(path5.resolve(sourceDir, PROMPTS_INDEX_MD_PATH));
|
|
304
317
|
if (!res) {
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
consola5.log("\u5F53\u524D\u9879\u76EE\u7684 vitepress \u6E90\u76EE\u5F55\u4E3A\uFF1A", sourceDir);
|
|
319
|
+
consola5.warn(`\u5F53\u524D\u9879\u76EE\u7684 vitepress \u6E90\u76EE\u5F55\u4E0D\u5B58\u5728 ${PROMPTS_INDEX_MD_PATH} \u6587\u4EF6`);
|
|
320
|
+
}
|
|
321
|
+
return res;
|
|
322
|
+
}
|
|
323
|
+
function hasChangelogMd(userConfig) {
|
|
324
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
325
|
+
const res = fs5.existsSync(path5.resolve(sourceDir, CHANGELOG_MD_FILENAME));
|
|
326
|
+
if (!res) {
|
|
327
|
+
consola5.log("\u5F53\u524D\u9879\u76EE\u7684 vitepress \u6E90\u76EE\u5F55\u4E3A\uFF1A", sourceDir);
|
|
328
|
+
consola5.warn(`\u5F53\u524D\u9879\u76EE\u7684 vitepress \u6E90\u76EE\u5F55\u4E0D\u5B58\u5728 ${CHANGELOG_MD_FILENAME} \u6587\u4EF6`);
|
|
307
329
|
}
|
|
308
330
|
return res;
|
|
309
331
|
}
|
|
332
|
+
|
|
333
|
+
// src/config/changelog-nav.ts
|
|
334
|
+
function handleChangeLog(userConfig) {
|
|
335
|
+
var _a;
|
|
336
|
+
if (!hasChangelogMd(userConfig)) {
|
|
337
|
+
consola6.warn(` \u672A\u627E\u5230\u53D8\u66F4\u65E5\u5FD7\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u53D8\u66F4\u65E5\u5FD7\u5BFC\u822A\u680F\u3002 `);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
341
|
+
if (isUndefined(nav)) {
|
|
342
|
+
consola6.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
343
|
+
throw new Error(` nav \u9ED8\u8BA4\u63D0\u4F9B\u7684\u5BFC\u822A\u680F\u914D\u7F6E\u4E3A\u7A7A\u3002\u4E0D\u7B26\u5408\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5\u3002 `);
|
|
344
|
+
}
|
|
345
|
+
nav.push({ text: "\u66F4\u65B0\u65E5\u5FD7", link: "/CHANGELOG.md" });
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/config/prompts-nav.ts
|
|
349
|
+
import fs6 from "fs";
|
|
350
|
+
import path6 from "path";
|
|
351
|
+
import consola7 from "consola";
|
|
352
|
+
import { isUndefined as isUndefined2, merge } from "lodash-es";
|
|
353
|
+
import matter2 from "gray-matter";
|
|
310
354
|
function writeYaml2PromptsIndexMd(userConfig, data) {
|
|
311
355
|
const newData = data ?? pageOrderConfig.prompts;
|
|
312
356
|
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
313
|
-
const mdPath =
|
|
357
|
+
const mdPath = path6.resolve(sourceDir, PROMPTS_INDEX_MD_PATH);
|
|
314
358
|
try {
|
|
315
359
|
let fileContent = "";
|
|
316
360
|
let existingData = {};
|
|
317
|
-
if (
|
|
318
|
-
fileContent =
|
|
361
|
+
if (fs6.existsSync(mdPath)) {
|
|
362
|
+
fileContent = fs6.readFileSync(mdPath, "utf-8");
|
|
319
363
|
const parsed = matter2(fileContent);
|
|
320
364
|
if (parsed.data && Object.keys(parsed.data).length > 0) {
|
|
321
365
|
existingData = parsed.data;
|
|
322
|
-
|
|
366
|
+
consola7.log("\u68C0\u6D4B\u5230\u5DF2\u6709 YAML frontmatter\uFF0C\u5C06\u8FDB\u884C\u6570\u636E\u5408\u5E76");
|
|
323
367
|
} else {
|
|
324
|
-
|
|
368
|
+
consola7.log("\u6587\u4EF6\u5B58\u5728\u4F46\u6CA1\u6709 YAML frontmatter\uFF0C\u5C06\u5199\u5165\u65B0\u7684 frontmatter");
|
|
325
369
|
}
|
|
326
370
|
const mergedData = merge({}, existingData, newData);
|
|
327
371
|
const newContent = matter2.stringify(parsed.content, mergedData);
|
|
328
|
-
|
|
329
|
-
|
|
372
|
+
fs6.writeFileSync(mdPath, newContent, "utf-8");
|
|
373
|
+
consola7.success(`\u5DF2\u5C06YAML\u6570\u636E\u5199\u5165\u5230 ${mdPath}`);
|
|
330
374
|
} else {
|
|
331
|
-
|
|
332
|
-
const dir =
|
|
333
|
-
if (!
|
|
334
|
-
|
|
375
|
+
consola7.warn(`\u6587\u4EF6 ${mdPath} \u4E0D\u5B58\u5728\uFF0C\u5C06\u521B\u5EFA\u65B0\u6587\u4EF6`);
|
|
376
|
+
const dir = path6.dirname(mdPath);
|
|
377
|
+
if (!fs6.existsSync(dir)) {
|
|
378
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
335
379
|
}
|
|
336
380
|
const newContent = matter2.stringify("", newData);
|
|
337
|
-
|
|
338
|
-
|
|
381
|
+
fs6.writeFileSync(mdPath, newContent, "utf-8");
|
|
382
|
+
consola7.success(`\u5DF2\u521B\u5EFA\u6587\u4EF6\u5E76\u5199\u5165YAML\u6570\u636E\u5230 ${mdPath}`);
|
|
339
383
|
}
|
|
340
384
|
} catch (error) {
|
|
341
|
-
|
|
385
|
+
consola7.error(`\u5199\u5165 YAML \u6570\u636E\u5230 ${mdPath} \u65F6\u53D1\u751F\u9519\u8BEF:`, error);
|
|
342
386
|
throw error;
|
|
343
387
|
}
|
|
344
388
|
}
|
|
345
389
|
function handlePrompts(userConfig) {
|
|
346
390
|
var _a;
|
|
347
391
|
if (!hasPromptsIndexMd(userConfig)) {
|
|
348
|
-
|
|
392
|
+
consola7.warn(` \u672A\u627E\u5230\u63D0\u793A\u8BCD\u7D22\u5F15\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u63D0\u793A\u8BCD\u5BFC\u822A\u680F\u3002 `);
|
|
349
393
|
return;
|
|
350
394
|
}
|
|
351
395
|
writeYaml2PromptsIndexMd(userConfig);
|
|
352
396
|
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
353
397
|
if (isUndefined2(nav)) {
|
|
354
|
-
|
|
398
|
+
consola7.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
355
399
|
throw new Error(` nav \u9ED8\u8BA4\u63D0\u4F9B\u7684\u5BFC\u822A\u680F\u914D\u7F6E\u4E3A\u7A7A\u3002\u4E0D\u7B26\u5408\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8BF7\u68C0\u67E5\u3002 `);
|
|
356
400
|
}
|
|
357
401
|
nav.push({ text: "\u63D0\u793A\u8BCD", link: `/${PROMPTS_INDEX_MD_PATH}` });
|
|
@@ -425,12 +469,106 @@ function handleTeekConfig(userConfig, extraConfig) {
|
|
|
425
469
|
userConfig.extends = defineTeekConfig(merge2({}, cloneDeep(defaultTeekConfig), teekConfig));
|
|
426
470
|
}
|
|
427
471
|
|
|
472
|
+
// src/config/multi-sidebar.ts
|
|
473
|
+
import { generateSidebar } from "vitepress-sidebar";
|
|
474
|
+
import path7 from "path";
|
|
475
|
+
import consola8 from "consola";
|
|
476
|
+
import { merge as merge3, cloneDeep as cloneDeep2 } from "lodash-es";
|
|
477
|
+
var defaultSidebarOptions = {
|
|
478
|
+
// 侧边栏需要折叠
|
|
479
|
+
collapsed: true,
|
|
480
|
+
// 用文件的 h1 标题作为侧边栏标题
|
|
481
|
+
useTitleFromFileHeading: true,
|
|
482
|
+
// 用index文件的标题作为折叠栏的标题
|
|
483
|
+
useFolderTitleFromIndexFile: true,
|
|
484
|
+
// 折叠栏链接到index文件
|
|
485
|
+
useFolderLinkFromIndexFile: true,
|
|
486
|
+
// 用order字段做菜单排序
|
|
487
|
+
sortMenusByFrontmatterOrder: true,
|
|
488
|
+
// 不使用名称排序
|
|
489
|
+
sortMenusByName: false,
|
|
490
|
+
useFolderLinkFromSameNameSubFile: true,
|
|
491
|
+
// 不输出调试信息了
|
|
492
|
+
debugPrint: false
|
|
493
|
+
};
|
|
494
|
+
function getMergeSidebarOptions(options) {
|
|
495
|
+
return merge3({}, cloneDeep2(defaultSidebarOptions), options ?? {});
|
|
496
|
+
}
|
|
497
|
+
function getSourceDirRelativePathFromCwd(userConfig) {
|
|
498
|
+
const projectRoot = getVitepressProjectRoot();
|
|
499
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
500
|
+
const relativePath = path7.relative(process.cwd(), sourceDir);
|
|
501
|
+
consola8.log("\u9879\u76EE\u6839\u76EE\u5F55:", projectRoot);
|
|
502
|
+
consola8.log("\u6E90\u76EE\u5F55:", sourceDir);
|
|
503
|
+
consola8.log("cwd:", process.cwd());
|
|
504
|
+
consola8.log("\u6E90\u76EE\u5F55\u76F8\u5BF9\u4E8E cwd \u7684\u8DEF\u5F84:", relativePath);
|
|
505
|
+
if (!relativePath || relativePath.startsWith("..")) {
|
|
506
|
+
return ".";
|
|
507
|
+
}
|
|
508
|
+
return relativePath.replace(/\\/g, "/");
|
|
509
|
+
}
|
|
510
|
+
function prefixSidebarLinks(items, prefix) {
|
|
511
|
+
return items.map((item) => {
|
|
512
|
+
const newItem = { ...item };
|
|
513
|
+
if (newItem.link && typeof newItem.link === "string") {
|
|
514
|
+
const link = newItem.link.startsWith("/") ? newItem.link : `/${newItem.link}`;
|
|
515
|
+
newItem.link = `${prefix}${link}`;
|
|
516
|
+
}
|
|
517
|
+
if (Array.isArray(newItem.items)) {
|
|
518
|
+
newItem.items = prefixSidebarLinks(newItem.items, prefix);
|
|
519
|
+
}
|
|
520
|
+
return newItem;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function setupMultiSidebar(userConfig) {
|
|
524
|
+
const hasPrompts = hasPromptsIndexMd(userConfig);
|
|
525
|
+
const hasChangelog = hasChangelogMd(userConfig);
|
|
526
|
+
if (!hasPrompts && !hasChangelog) {
|
|
527
|
+
consola8.log("\u672A\u68C0\u6D4B\u5230 prompts \u76EE\u5F55\u6216 CHANGELOG.md\uFF0C\u4E0D\u9700\u8981\u591A\u4FA7\u8FB9\u680F");
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const themeConfig = userConfig.themeConfig;
|
|
531
|
+
const extraSidebars = {};
|
|
532
|
+
if (hasPrompts) {
|
|
533
|
+
const sourceDirRelativePathFromCwd = getSourceDirRelativePathFromCwd(userConfig);
|
|
534
|
+
const promptsFullPath = sourceDirRelativePathFromCwd === "." ? "prompts" : `${sourceDirRelativePathFromCwd}/prompts`;
|
|
535
|
+
consola8.log("promptsFullPath:", promptsFullPath);
|
|
536
|
+
const promptsSidebar = generateSidebar(
|
|
537
|
+
getMergeSidebarOptions({
|
|
538
|
+
documentRootPath: promptsFullPath
|
|
539
|
+
})
|
|
540
|
+
);
|
|
541
|
+
extraSidebars["/prompts/"] = Array.isArray(promptsSidebar) ? prefixSidebarLinks(promptsSidebar, "/prompts") : promptsSidebar;
|
|
542
|
+
}
|
|
543
|
+
if (hasChangelog) {
|
|
544
|
+
extraSidebars["/CHANGELOG"] = [];
|
|
545
|
+
}
|
|
546
|
+
let businessSidebar = themeConfig.sidebar;
|
|
547
|
+
Object.defineProperty(themeConfig, "sidebar", {
|
|
548
|
+
configurable: true,
|
|
549
|
+
enumerable: true,
|
|
550
|
+
get() {
|
|
551
|
+
const result = { ...extraSidebars };
|
|
552
|
+
if (Array.isArray(businessSidebar)) {
|
|
553
|
+
result["/"] = businessSidebar;
|
|
554
|
+
} else if (typeof businessSidebar === "object" && businessSidebar !== null) {
|
|
555
|
+
Object.assign(result, businessSidebar);
|
|
556
|
+
}
|
|
557
|
+
return result;
|
|
558
|
+
},
|
|
559
|
+
set(value) {
|
|
560
|
+
businessSidebar = value;
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
consola8.success("\u591A\u4FA7\u8FB9\u680F defineProperty \u62E6\u622A\u5DF2\u8BBE\u7F6E");
|
|
564
|
+
}
|
|
565
|
+
|
|
428
566
|
// src/config.mts
|
|
429
567
|
import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
|
|
430
568
|
import { copyOrDownloadAsMarkdownButtons } from "vitepress-plugin-llms";
|
|
431
569
|
import { MermaidPlugin } from "@leelaa/vitepress-plugin-extended";
|
|
432
570
|
import { defineTeekConfig as defineTeekConfig2 } from "vitepress-theme-teek/config";
|
|
433
|
-
var
|
|
571
|
+
var defaultSidebarOptions2 = {
|
|
434
572
|
// documentRootPath: "./src",
|
|
435
573
|
// 侧边栏需要折叠
|
|
436
574
|
collapsed: true,
|
|
@@ -455,11 +593,15 @@ var defaultSidebarOptions = {
|
|
|
455
593
|
// 不输出调试信息了
|
|
456
594
|
debugPrint: false
|
|
457
595
|
};
|
|
458
|
-
function
|
|
459
|
-
return
|
|
596
|
+
function getMergeSidebarOptions2(options) {
|
|
597
|
+
return merge4({}, cloneDeep3(defaultSidebarOptions2), isUndefined3(options) ? {} : options);
|
|
460
598
|
}
|
|
461
599
|
function setGenerateSidebar(options) {
|
|
462
|
-
|
|
600
|
+
const merged = getMergeSidebarOptions2(options);
|
|
601
|
+
if (!Array.isArray(merged)) {
|
|
602
|
+
merged.excludeByGlobPattern = [...merged.excludeByGlobPattern ?? [], "**/prompts/**", "**/CHANGELOG.md"];
|
|
603
|
+
}
|
|
604
|
+
return generateSidebar2(merged);
|
|
463
605
|
}
|
|
464
606
|
var defaultUserConfig = {
|
|
465
607
|
/**
|
|
@@ -481,8 +623,8 @@ var defaultUserConfig = {
|
|
|
481
623
|
label: "\u672C\u9875\u76EE\u5F55",
|
|
482
624
|
level: "deep"
|
|
483
625
|
},
|
|
484
|
-
//
|
|
485
|
-
sidebar
|
|
626
|
+
// 自动化侧边栏(多侧边栏)
|
|
627
|
+
// sidebar 在 setUserConfig 中动态生成
|
|
486
628
|
socialLinks: [{ icon: "github", link: "https://github.com/ruan-cat" }],
|
|
487
629
|
editLink: {
|
|
488
630
|
pattern: "https://github.com/ruan-cat/monorepo/blob/dev/packages/vitepress-preset-config/src/docs/please-reset-themeConfig-editLink.md",
|
|
@@ -534,11 +676,12 @@ var defaultUserConfig = {
|
|
|
534
676
|
}
|
|
535
677
|
};
|
|
536
678
|
function setUserConfig(config, extraConfig) {
|
|
537
|
-
const resUserConfig =
|
|
679
|
+
const resUserConfig = merge4({}, cloneDeep3(defaultUserConfig), isUndefined3(config) ? {} : config);
|
|
538
680
|
handlePrompts(resUserConfig);
|
|
539
681
|
handleChangeLog(resUserConfig);
|
|
540
682
|
handlePlugins(resUserConfig, extraConfig);
|
|
541
683
|
handleTeekConfig(resUserConfig, extraConfig);
|
|
684
|
+
setupMultiSidebar(resUserConfig);
|
|
542
685
|
return resUserConfig;
|
|
543
686
|
}
|
|
544
687
|
export {
|
package/dist/theme.mjs
CHANGED
|
@@ -9,7 +9,6 @@ import "vitepress-theme-teek/index.css";
|
|
|
9
9
|
import "vitepress-theme-teek/theme-chalk/tk-doc-h1-gradient.css";
|
|
10
10
|
import "vitepress-theme-teek/theme-chalk/tk-nav-blur.css";
|
|
11
11
|
import "vitepress-theme-teek/theme-chalk/tk-scrollbar.css";
|
|
12
|
-
import "vitepress-theme-teek/theme-chalk/tk-sidebar.css";
|
|
13
12
|
import "vitepress-theme-teek/theme-chalk/tk-aside.css";
|
|
14
13
|
import "vitepress-theme-teek/theme-chalk/tk-fade-up-animation.css";
|
|
15
14
|
import { Mermaid } from "@leelaa/vitepress-plugin-extended";
|
package/package.json
CHANGED
|
@@ -3,10 +3,10 @@ import fs from "node:fs";
|
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
import matter from "gray-matter";
|
|
5
5
|
|
|
6
|
-
import { copyChangelogMd
|
|
6
|
+
import { copyChangelogMd } from "../utils/copy-changelog";
|
|
7
7
|
import { pageOrderConfig } from "./page-order-config";
|
|
8
8
|
|
|
9
|
-
export interface AddChangelog2docOptions<T extends Record<string,
|
|
9
|
+
export interface AddChangelog2docOptions<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
10
10
|
/** 目标文件夹 */
|
|
11
11
|
target: string;
|
|
12
12
|
|
|
@@ -14,11 +14,17 @@ export interface AddChangelog2docOptions<T extends Record<string, any> = Record<
|
|
|
14
14
|
data?: T;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/** 检查项目根目录是否存在 CHANGELOG.md */
|
|
18
|
+
function hasChangelogInRoot(): boolean {
|
|
19
|
+
const changelogPath = path.resolve(process.cwd(), "CHANGELOG.md");
|
|
20
|
+
return fs.existsSync(changelogPath);
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
/** 将变更日志添加到指定的文档目录内 并提供参数 */
|
|
18
|
-
export function addChangelog2doc<T extends Record<string,
|
|
24
|
+
export function addChangelog2doc<T extends Record<string, unknown>>(options: AddChangelog2docOptions<T>) {
|
|
19
25
|
const { data = pageOrderConfig.changelog, target } = options;
|
|
20
26
|
|
|
21
|
-
if (!
|
|
27
|
+
if (!hasChangelogInRoot()) {
|
|
22
28
|
return;
|
|
23
29
|
}
|
|
24
30
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { type UserConfig, type DefaultTheme } from "vitepress";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import { isUndefined } from "lodash-es";
|
|
6
|
-
|
|
7
|
-
import {
|
|
6
|
+
|
|
7
|
+
import { hasChangelogMd } from "../utils/vitepress-project.ts";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 设置导航栏的变更日志
|
|
@@ -15,7 +15,7 @@ import { printFormat } from "@ruan-cat/utils";
|
|
|
15
15
|
* @private 内部使用即可
|
|
16
16
|
*/
|
|
17
17
|
export function handleChangeLog(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
18
|
-
if (!hasChangelogMd()) {
|
|
18
|
+
if (!hasChangelogMd(userConfig)) {
|
|
19
19
|
consola.warn(` 未找到变更日志文件,不添加变更日志导航栏。 `);
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
@@ -28,8 +28,4 @@ export function handleChangeLog(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
nav.push({ text: "更新日志", link: "/CHANGELOG.md" });
|
|
31
|
-
|
|
32
|
-
// TODO: 持续完成特殊侧边栏的处理
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
console.log(" 查看侧边栏数据 ", printFormat(userConfig?.themeConfig.sidebar));
|
|
35
31
|
}
|
package/src/config/index.ts
CHANGED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// 多侧边栏配置 - 使用 Object.defineProperty 拦截实现透明多侧边栏
|
|
2
|
+
|
|
3
|
+
import { type UserConfig, type DefaultTheme } from "vitepress";
|
|
4
|
+
import { generateSidebar } from "vitepress-sidebar";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import consola from "consola";
|
|
7
|
+
import { merge, cloneDeep } from "lodash-es";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
getVitepressProjectRoot,
|
|
11
|
+
getVitepressSourceDirectory,
|
|
12
|
+
hasPromptsIndexMd,
|
|
13
|
+
hasChangelogMd,
|
|
14
|
+
} from "../utils/vitepress-project.ts";
|
|
15
|
+
|
|
16
|
+
/** 从 generateSidebar 函数参数中提取类型 */
|
|
17
|
+
type VitePressSidebarOptions = Parameters<typeof generateSidebar>[0];
|
|
18
|
+
|
|
19
|
+
/** 默认侧边栏配置选项 */
|
|
20
|
+
export const defaultSidebarOptions: VitePressSidebarOptions = {
|
|
21
|
+
// 侧边栏需要折叠
|
|
22
|
+
collapsed: true,
|
|
23
|
+
|
|
24
|
+
// 用文件的 h1 标题作为侧边栏标题
|
|
25
|
+
useTitleFromFileHeading: true,
|
|
26
|
+
|
|
27
|
+
// 用index文件的标题作为折叠栏的标题
|
|
28
|
+
useFolderTitleFromIndexFile: true,
|
|
29
|
+
|
|
30
|
+
// 折叠栏链接到index文件
|
|
31
|
+
useFolderLinkFromIndexFile: true,
|
|
32
|
+
|
|
33
|
+
// 用order字段做菜单排序
|
|
34
|
+
sortMenusByFrontmatterOrder: true,
|
|
35
|
+
|
|
36
|
+
// 不使用名称排序
|
|
37
|
+
sortMenusByName: false,
|
|
38
|
+
|
|
39
|
+
useFolderLinkFromSameNameSubFile: true,
|
|
40
|
+
|
|
41
|
+
// 不输出调试信息了
|
|
42
|
+
debugPrint: false,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 获取合并后的侧边栏配置
|
|
47
|
+
*/
|
|
48
|
+
export function getMergeSidebarOptions(options?: VitePressSidebarOptions) {
|
|
49
|
+
return merge({}, cloneDeep(defaultSidebarOptions), options ?? {});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 获取源目录相对于 process.cwd() 的路径
|
|
54
|
+
* @description 用于 vitepress-sidebar 的配置
|
|
55
|
+
*/
|
|
56
|
+
export function getSourceDirRelativePathFromCwd(userConfig: UserConfig<DefaultTheme.Config>): string {
|
|
57
|
+
const projectRoot = getVitepressProjectRoot();
|
|
58
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
59
|
+
const relativePath = path.relative(process.cwd(), sourceDir);
|
|
60
|
+
|
|
61
|
+
consola.log("项目根目录:", projectRoot);
|
|
62
|
+
consola.log("源目录:", sourceDir);
|
|
63
|
+
consola.log("cwd:", process.cwd());
|
|
64
|
+
consola.log("源目录相对于 cwd 的路径:", relativePath);
|
|
65
|
+
|
|
66
|
+
if (!relativePath || relativePath.startsWith("..")) {
|
|
67
|
+
return ".";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return relativePath.replace(/\\/g, "/");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 递归为侧边栏项的 link 添加路径前缀
|
|
75
|
+
* @description
|
|
76
|
+
* generateSidebar 以子目录为根扫描时,生成的 link 缺少父路径前缀。
|
|
77
|
+
* 例如扫描 prompts 目录时,link 为 "/make-dynamic-routes",
|
|
78
|
+
* 需要补充为 "/prompts/make-dynamic-routes"。
|
|
79
|
+
*/
|
|
80
|
+
function prefixSidebarLinks(items: any[], prefix: string): any[] {
|
|
81
|
+
return items.map((item) => {
|
|
82
|
+
const newItem = { ...item };
|
|
83
|
+
if (newItem.link && typeof newItem.link === "string") {
|
|
84
|
+
// 处理带和不带前导斜杠的情况
|
|
85
|
+
const link = newItem.link.startsWith("/") ? newItem.link : `/${newItem.link}`;
|
|
86
|
+
newItem.link = `${prefix}${link}`;
|
|
87
|
+
}
|
|
88
|
+
if (Array.isArray(newItem.items)) {
|
|
89
|
+
newItem.items = prefixSidebarLinks(newItem.items, prefix);
|
|
90
|
+
}
|
|
91
|
+
return newItem;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 设置多侧边栏拦截
|
|
97
|
+
* @description
|
|
98
|
+
* 使用 Object.defineProperty 在 themeConfig.sidebar 上设置 getter/setter:
|
|
99
|
+
* - setter: 消费者赋值时,存储为业务侧边栏内容
|
|
100
|
+
* - getter: VitePress 读取时,返回包含 prompts/CHANGELOG 的多侧边栏对象
|
|
101
|
+
*
|
|
102
|
+
* 对消费者完全透明,无需修改任何消费者代码。
|
|
103
|
+
*/
|
|
104
|
+
export function setupMultiSidebar(userConfig: UserConfig<DefaultTheme.Config>): void {
|
|
105
|
+
const hasPrompts = hasPromptsIndexMd(userConfig);
|
|
106
|
+
const hasChangelog = hasChangelogMd(userConfig);
|
|
107
|
+
|
|
108
|
+
if (!hasPrompts && !hasChangelog) {
|
|
109
|
+
consola.log("未检测到 prompts 目录或 CHANGELOG.md,不需要多侧边栏");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const themeConfig = userConfig.themeConfig!;
|
|
114
|
+
|
|
115
|
+
// 预生成额外侧边栏
|
|
116
|
+
const extraSidebars: Record<string, any> = {};
|
|
117
|
+
|
|
118
|
+
if (hasPrompts) {
|
|
119
|
+
const sourceDirRelativePathFromCwd = getSourceDirRelativePathFromCwd(userConfig);
|
|
120
|
+
const promptsFullPath =
|
|
121
|
+
sourceDirRelativePathFromCwd === "." ? "prompts" : `${sourceDirRelativePathFromCwd}/prompts`;
|
|
122
|
+
|
|
123
|
+
consola.log("promptsFullPath:", promptsFullPath);
|
|
124
|
+
|
|
125
|
+
const promptsSidebar = generateSidebar(
|
|
126
|
+
getMergeSidebarOptions({
|
|
127
|
+
documentRootPath: promptsFullPath,
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
extraSidebars["/prompts/"] = Array.isArray(promptsSidebar)
|
|
132
|
+
? prefixSidebarLinks(promptsSidebar, "/prompts")
|
|
133
|
+
: promptsSidebar;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (hasChangelog) {
|
|
137
|
+
extraSidebars["/CHANGELOG"] = [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 设置 getter/setter 拦截
|
|
141
|
+
let businessSidebar: any = themeConfig.sidebar;
|
|
142
|
+
|
|
143
|
+
Object.defineProperty(themeConfig, "sidebar", {
|
|
144
|
+
configurable: true,
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get() {
|
|
147
|
+
const result: Record<string, any> = { ...extraSidebars };
|
|
148
|
+
if (Array.isArray(businessSidebar)) {
|
|
149
|
+
result["/"] = businessSidebar;
|
|
150
|
+
} else if (typeof businessSidebar === "object" && businessSidebar !== null) {
|
|
151
|
+
Object.assign(result, businessSidebar);
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
},
|
|
155
|
+
set(value: any) {
|
|
156
|
+
businessSidebar = value;
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
consola.success("多侧边栏 defineProperty 拦截已设置");
|
|
161
|
+
}
|
|
@@ -6,143 +6,7 @@ import { isUndefined, merge } from "lodash-es";
|
|
|
6
6
|
import matter from "gray-matter";
|
|
7
7
|
|
|
8
8
|
import { pageOrderConfig } from "./page-order-config";
|
|
9
|
-
|
|
10
|
-
/** 提示词索引文件的相对路径 */
|
|
11
|
-
const PROMPTS_INDEX_MD_PATH = "prompts/index.md" as const;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 从命令行参数中获取 VitePress 项目根目录
|
|
15
|
-
* @description
|
|
16
|
-
* 解析命令行参数,查找 vitepress dev/build 命令后的第一个路径参数
|
|
17
|
-
* @private 目前仅设计为内部使用
|
|
18
|
-
*/
|
|
19
|
-
function getProjectRootFromArgs(): string | null {
|
|
20
|
-
const args = process.argv;
|
|
21
|
-
|
|
22
|
-
// 查找 vitepress 命令的索引
|
|
23
|
-
const vitepressIndex = args.findIndex((arg) => arg.includes("vitepress"));
|
|
24
|
-
|
|
25
|
-
if (vitepressIndex === -1) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// 查找 dev 或 build 命令后的第一个非选项参数(不以 - 或 -- 开头)
|
|
30
|
-
for (let i = vitepressIndex + 1; i < args.length; i++) {
|
|
31
|
-
const arg = args[i];
|
|
32
|
-
|
|
33
|
-
// 跳过命令本身(dev, build等)和选项参数
|
|
34
|
-
if (arg === "dev" || arg === "build" || arg === "serve" || arg === "preview") {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 跳过选项和选项值
|
|
39
|
-
if (arg.startsWith("-")) {
|
|
40
|
-
// 如果是 --port 这样的选项,也跳过下一个值
|
|
41
|
-
if (arg.startsWith("--") && !arg.includes("=")) {
|
|
42
|
-
i++; // 跳过选项值
|
|
43
|
-
}
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 找到路径参数,解析为绝对路径
|
|
48
|
-
return path.resolve(process.cwd(), arg);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 获得 vitepress 项目的 `项目根目录 (project root)`
|
|
56
|
-
* @description
|
|
57
|
-
* 检查出当前运行vitepress build 命令时,所使用的项目根目录,并对外返回该目录。
|
|
58
|
-
* @see https://vitepress.dev/zh/guide/routing#root-and-source-directory
|
|
59
|
-
* @private 目前仅设计为内部使用
|
|
60
|
-
*/
|
|
61
|
-
function getVitepressProjectRoot(): string {
|
|
62
|
-
// 首先尝试从命令行参数获取
|
|
63
|
-
const projectRootFromArgs = getProjectRootFromArgs();
|
|
64
|
-
if (projectRootFromArgs) {
|
|
65
|
-
const vitepressDir = path.join(projectRootFromArgs, ".vitepress");
|
|
66
|
-
if (fs.existsSync(vitepressDir)) {
|
|
67
|
-
consola.log("从命令行参数获取到 VitePress 项目根目录:", projectRootFromArgs);
|
|
68
|
-
return projectRootFromArgs;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 如果命令行参数没有提供或无效,尝试向上查找 .vitepress 目录
|
|
73
|
-
let currentDir = process.cwd();
|
|
74
|
-
const root = path.parse(currentDir).root;
|
|
75
|
-
|
|
76
|
-
while (currentDir !== root) {
|
|
77
|
-
const vitepressDir = path.join(currentDir, ".vitepress");
|
|
78
|
-
if (fs.existsSync(vitepressDir)) {
|
|
79
|
-
consola.log("通过向上查找获取到 VitePress 项目根目录:", currentDir);
|
|
80
|
-
return currentDir;
|
|
81
|
-
}
|
|
82
|
-
currentDir = path.dirname(currentDir);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 检查根目录本身
|
|
86
|
-
const vitepressDir = path.join(root, ".vitepress");
|
|
87
|
-
if (fs.existsSync(vitepressDir)) {
|
|
88
|
-
consola.log("在文件系统根目录找到 VitePress 项目根目录:", root);
|
|
89
|
-
return root;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 如果找不到 .vitepress 目录,回退到当前工作目录
|
|
93
|
-
const fallbackDir = process.cwd();
|
|
94
|
-
consola.warn("未找到 .vitepress 目录,回退到当前工作目录:", fallbackDir);
|
|
95
|
-
return fallbackDir;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* 获取vitepress项目的源目录
|
|
100
|
-
* @description
|
|
101
|
-
* 获取vitepress项目的源目录 并对外返回该目录。
|
|
102
|
-
*
|
|
103
|
-
* 源目录的计算规则:
|
|
104
|
-
* 1. 如果配置中指定了 srcDir,则源目录 = 项目根目录 + srcDir
|
|
105
|
-
* 2. 如果没有指定 srcDir,则源目录 = 项目根目录
|
|
106
|
-
*
|
|
107
|
-
* @param userConfig - VitePress 用户配置对象
|
|
108
|
-
* @see https://vitepress.dev/zh/guide/routing#source-directory
|
|
109
|
-
* @private 目前仅设计为内部使用
|
|
110
|
-
*/
|
|
111
|
-
function getVitepressSourceDirectory(userConfig: UserConfig<DefaultTheme.Config>): string {
|
|
112
|
-
// 获取项目根目录
|
|
113
|
-
const projectRoot = getVitepressProjectRoot();
|
|
114
|
-
|
|
115
|
-
// 读取配置中的 srcDir(如果有)
|
|
116
|
-
const srcDir = (userConfig as any).srcDir as string | undefined;
|
|
117
|
-
|
|
118
|
-
// 如果配置了 srcDir,将其与项目根目录拼接;否则返回项目根目录
|
|
119
|
-
if (srcDir) {
|
|
120
|
-
const sourceDirectory = path.resolve(projectRoot, srcDir);
|
|
121
|
-
consola.log("从配置中获取到 srcDir:", srcDir);
|
|
122
|
-
consola.log("VitePress 源目录为:", sourceDirectory);
|
|
123
|
-
return sourceDirectory;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 默认情况下,源目录等于项目根目录
|
|
127
|
-
consola.log("配置中未指定 srcDir,源目录等于项目根目录:", projectRoot);
|
|
128
|
-
return projectRoot;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 检查当前运行的 `源目录` 是否存在 `prompts/index.md` 文件
|
|
133
|
-
* @description
|
|
134
|
-
* 检查当前运行的 `源目录` 是否存在 `prompts/index.md` 文件,并对外返回检查结果。
|
|
135
|
-
* @private 目前仅设计为内部使用·
|
|
136
|
-
*/
|
|
137
|
-
function hasPromptsIndexMd(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
138
|
-
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
139
|
-
const res = fs.existsSync(path.resolve(sourceDir, PROMPTS_INDEX_MD_PATH));
|
|
140
|
-
if (!res) {
|
|
141
|
-
consola.log("当前项目的vitepress源目录为:", sourceDir);
|
|
142
|
-
consola.warn(`当前项目的vitepress源目录不存在 ${PROMPTS_INDEX_MD_PATH} 文件`);
|
|
143
|
-
}
|
|
144
|
-
return res;
|
|
145
|
-
}
|
|
9
|
+
import { getVitepressSourceDirectory, hasPromptsIndexMd, PROMPTS_INDEX_MD_PATH } from "../utils/vitepress-project.ts";
|
|
146
10
|
|
|
147
11
|
/**
|
|
148
12
|
* 将YAML数据写入到提示词索引文件内
|
package/src/config.mts
CHANGED
|
@@ -15,7 +15,14 @@ import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
|
|
|
15
15
|
|
|
16
16
|
import llmstxt, { copyOrDownloadAsMarkdownButtons } from "vitepress-plugin-llms";
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
defaultTeekConfig,
|
|
20
|
+
handleTeekConfig,
|
|
21
|
+
handlePlugins,
|
|
22
|
+
handleChangeLog,
|
|
23
|
+
handlePrompts,
|
|
24
|
+
setupMultiSidebar,
|
|
25
|
+
} from "./config/index.ts";
|
|
19
26
|
|
|
20
27
|
/** @see https://vitepress-ext.leelaa.cn/Mermaid.html#扩展-md-插件 */
|
|
21
28
|
import { MermaidPlugin } from "@leelaa/vitepress-plugin-extended";
|
|
@@ -71,9 +78,16 @@ function getMergeSidebarOptions(options?: VitePressSidebarOptions) {
|
|
|
71
78
|
/**
|
|
72
79
|
* 设置自动生成侧边栏的配置
|
|
73
80
|
* @see https://vitepress-sidebar.cdget.com/zhHans/guide/options
|
|
81
|
+
*
|
|
82
|
+
* 注意:在 Windows 环境下,必须使用相对路径(如 "./docs")而不是绝对路径,
|
|
83
|
+
* 否则 vitepress-sidebar 内部的 path.join 会导致路径拼接错误。
|
|
74
84
|
*/
|
|
75
85
|
export function setGenerateSidebar(options?: VitePressSidebarOptions) {
|
|
76
|
-
|
|
86
|
+
const merged = getMergeSidebarOptions(options);
|
|
87
|
+
if (!Array.isArray(merged)) {
|
|
88
|
+
merged.excludeByGlobPattern = [...(merged.excludeByGlobPattern ?? []), "**/prompts/**", "**/CHANGELOG.md"];
|
|
89
|
+
}
|
|
90
|
+
return generateSidebar(merged);
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
/** 默认用户配置 */
|
|
@@ -104,8 +118,8 @@ const defaultUserConfig: UserConfig<DefaultTheme.Config> = {
|
|
|
104
118
|
level: "deep",
|
|
105
119
|
},
|
|
106
120
|
|
|
107
|
-
//
|
|
108
|
-
sidebar
|
|
121
|
+
// 自动化侧边栏(多侧边栏)
|
|
122
|
+
// sidebar 在 setUserConfig 中动态生成
|
|
109
123
|
|
|
110
124
|
socialLinks: [{ icon: "github", link: "https://github.com/ruan-cat" }],
|
|
111
125
|
|
|
@@ -193,5 +207,8 @@ export function setUserConfig(
|
|
|
193
207
|
// 设置 Teek 主题配置
|
|
194
208
|
handleTeekConfig(resUserConfig, extraConfig);
|
|
195
209
|
|
|
210
|
+
// 设置多侧边栏拦截
|
|
211
|
+
setupMultiSidebar(resUserConfig);
|
|
212
|
+
|
|
196
213
|
return resUserConfig;
|
|
197
214
|
}
|
package/src/theme.ts
CHANGED
|
@@ -28,8 +28,8 @@ import "vitepress-theme-teek/theme-chalk/tk-doc-h1-gradient.css";
|
|
|
28
28
|
import "vitepress-theme-teek/theme-chalk/tk-nav-blur.css";
|
|
29
29
|
// 滚动条样式
|
|
30
30
|
import "vitepress-theme-teek/theme-chalk/tk-scrollbar.css";
|
|
31
|
-
// 侧边栏样式
|
|
32
|
-
import "vitepress-theme-teek/theme-chalk/tk-sidebar.css";
|
|
31
|
+
// 侧边栏样式 这个侧边栏标题不好看 打算关闭掉
|
|
32
|
+
// import "vitepress-theme-teek/theme-chalk/tk-sidebar.css";
|
|
33
33
|
// 右侧目栏录文字悬停和激活样式
|
|
34
34
|
import "vitepress-theme-teek/theme-chalk/tk-aside.css";
|
|
35
35
|
// 首次进入页面添加渐显动画
|
|
@@ -2,9 +2,14 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 检查当前运行的根目录是否存在 CHANGELOG.md 文件
|
|
7
|
+
* @description
|
|
8
|
+
* 此函数检查的是项目根目录(process.cwd()),而非 VitePress 的 source directory
|
|
9
|
+
*/
|
|
10
|
+
function checkChangelogExists(): boolean {
|
|
11
|
+
const sourceDir = path.resolve(process.cwd(), "CHANGELOG.md");
|
|
12
|
+
const res = fs.existsSync(sourceDir);
|
|
8
13
|
if (!res) {
|
|
9
14
|
consola.log("当前项目根目录为:", process.cwd());
|
|
10
15
|
consola.warn("当前项目根目录不存在 CHANGELOG.md 文件");
|
|
@@ -16,9 +21,10 @@ export function hasChangelogMd() {
|
|
|
16
21
|
* 将 CHANGELOG.md 文件移动到指定要求的位置内
|
|
17
22
|
* @description
|
|
18
23
|
* 该函数相当于实现 `cpx CHANGELOG.md docs` 命令
|
|
24
|
+
* @param target - 目标文件夹
|
|
19
25
|
*/
|
|
20
|
-
export function copyChangelogMd(
|
|
21
|
-
if (!
|
|
26
|
+
export function copyChangelogMd(target: string) {
|
|
27
|
+
if (!checkChangelogExists()) {
|
|
22
28
|
return;
|
|
23
29
|
}
|
|
24
30
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VitePress 项目工具函数
|
|
3
|
+
* @description 提供 VitePress 项目相关的公共工具函数,用于获取项目根目录、源目录等
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { type UserConfig, type DefaultTheme } from "vitepress";
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import consola from "consola";
|
|
10
|
+
|
|
11
|
+
/** 提示词索引文件的相对路径 */
|
|
12
|
+
export const PROMPTS_INDEX_MD_PATH = "prompts/index.md" as const;
|
|
13
|
+
|
|
14
|
+
/** CHANGELOG.md 文件名 */
|
|
15
|
+
export const CHANGELOG_MD_FILENAME = "CHANGELOG.md" as const;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 从命令行参数中获取 VitePress 项目根目录
|
|
19
|
+
* @description
|
|
20
|
+
* 解析命令行参数,查找 vitepress dev/build 命令后的第一个路径参数
|
|
21
|
+
* 返回项目根目录(.vitepress 所在目录),而非源目录
|
|
22
|
+
*
|
|
23
|
+
* 支持的场景:
|
|
24
|
+
* 1. vitepress dev - 使用当前目录
|
|
25
|
+
* 2. vitepress dev docs - docs 是源目录,项目根目录在父目录
|
|
26
|
+
* 3. vitepress dev src/docs - src/docs 是源目录,项目根目录需要向上查找
|
|
27
|
+
*/
|
|
28
|
+
export function getProjectRootFromArgs(): string | null {
|
|
29
|
+
const args = process.argv;
|
|
30
|
+
const vitepressIndex = args.findIndex((arg) => arg.includes("vitepress"));
|
|
31
|
+
|
|
32
|
+
if (vitepressIndex === -1) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (let i = vitepressIndex + 1; i < args.length; i++) {
|
|
37
|
+
const arg = args[i];
|
|
38
|
+
|
|
39
|
+
// 跳过命令关键字
|
|
40
|
+
if (arg === "dev" || arg === "build" || arg === "serve" || arg === "preview") {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 跳过选项参数
|
|
45
|
+
if (arg.startsWith("-")) {
|
|
46
|
+
if (arg.startsWith("--") && !arg.includes("=")) {
|
|
47
|
+
i++; // 跳过选项值
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 解析传入的路径(可能是源目录或项目根目录)
|
|
53
|
+
let inputPath = path.resolve(process.cwd(), arg);
|
|
54
|
+
|
|
55
|
+
// 向上查找直到找到 .vitepress 目录或到达根目录
|
|
56
|
+
let currentDir = inputPath;
|
|
57
|
+
const root = path.parse(currentDir).root;
|
|
58
|
+
|
|
59
|
+
while (currentDir !== root) {
|
|
60
|
+
if (fs.existsSync(path.join(currentDir, ".vitepress"))) {
|
|
61
|
+
consola.log("从命令行参数获取到 VitePress 项目根目录:", currentDir);
|
|
62
|
+
return currentDir;
|
|
63
|
+
}
|
|
64
|
+
currentDir = path.dirname(currentDir);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 检查根目录本身
|
|
68
|
+
if (fs.existsSync(path.join(root, ".vitepress"))) {
|
|
69
|
+
consola.log("从命令行参数获取到 VitePress 项目根目录:", root);
|
|
70
|
+
return root;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 找不到,返回 null
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 从指定目录向上查找 VitePress 项目根目录
|
|
82
|
+
* @description 递归向上查找包含 .vitepress 目录的目录
|
|
83
|
+
*/
|
|
84
|
+
function findProjectRootFromDir(startDir: string): string | null {
|
|
85
|
+
const root = path.parse(startDir).root;
|
|
86
|
+
let currentDir = startDir;
|
|
87
|
+
|
|
88
|
+
while (currentDir !== root) {
|
|
89
|
+
const vitepressDir = path.join(currentDir, ".vitepress");
|
|
90
|
+
if (fs.existsSync(vitepressDir)) {
|
|
91
|
+
return currentDir;
|
|
92
|
+
}
|
|
93
|
+
currentDir = path.dirname(currentDir);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 检查根目录本身
|
|
97
|
+
const rootVitepressDir = path.join(root, ".vitepress");
|
|
98
|
+
if (fs.existsSync(rootVitepressDir)) {
|
|
99
|
+
return root;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 获得 vitepress 项目的 `项目根目录 (project root)`
|
|
107
|
+
* @description
|
|
108
|
+
* 检查出当前运行 vitepress build 命令时,所使用的项目根目录,并对外返回该目录。
|
|
109
|
+
* @see https://vitepress.dev/zh/guide/routing#root-and-source-directory
|
|
110
|
+
*/
|
|
111
|
+
export function getVitepressProjectRoot(): string {
|
|
112
|
+
// 首先尝试从命令行参数提供的路径开始查找
|
|
113
|
+
const projectRootFromArgs = getProjectRootFromArgs();
|
|
114
|
+
if (projectRootFromArgs) {
|
|
115
|
+
const foundRoot = findProjectRootFromDir(projectRootFromArgs);
|
|
116
|
+
if (foundRoot) {
|
|
117
|
+
consola.log("从命令行参数获取到 VitePress 项目根目录:", foundRoot);
|
|
118
|
+
return foundRoot;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 如果命令行参数无效,使用当前工作目录查找
|
|
123
|
+
const foundFromCwd = findProjectRootFromDir(process.cwd());
|
|
124
|
+
if (foundFromCwd) {
|
|
125
|
+
consola.log("通过当前工作目录获取到 VitePress 项目根目录:", foundFromCwd);
|
|
126
|
+
return foundFromCwd;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 如果找不到 .vitepress 目录,回退到命令行参数提供的路径(如果存在)
|
|
130
|
+
if (projectRootFromArgs) {
|
|
131
|
+
consola.warn("未找到 .vitepress 目录,回退到命令行参数路径:", projectRootFromArgs);
|
|
132
|
+
return projectRootFromArgs;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 最后回退到当前工作目录
|
|
136
|
+
const fallbackDir = process.cwd();
|
|
137
|
+
consola.warn("未找到 .vitepress 目录,回退到当前工作目录:", fallbackDir);
|
|
138
|
+
return fallbackDir;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 获取 vitepress 项目的源目录
|
|
143
|
+
* @description
|
|
144
|
+
* 获取 vitepress 项目的源目录并对外返回该目录。
|
|
145
|
+
*
|
|
146
|
+
* 源目录的计算规则:
|
|
147
|
+
* 1. 如果配置中指定了 srcDir,则源目录 = 项目根目录 + srcDir
|
|
148
|
+
* 2. 如果没有指定 srcDir,则源目录 = 项目根目录
|
|
149
|
+
*
|
|
150
|
+
* @param userConfig - VitePress 用户配置对象
|
|
151
|
+
* @see https://vitepress.dev/zh/guide/routing#source-directory
|
|
152
|
+
*/
|
|
153
|
+
export function getVitepressSourceDirectory(userConfig: UserConfig<DefaultTheme.Config>): string {
|
|
154
|
+
const projectRoot = getVitepressProjectRoot();
|
|
155
|
+
const srcDir = (userConfig as Record<string, unknown>).srcDir as string | undefined;
|
|
156
|
+
|
|
157
|
+
if (srcDir) {
|
|
158
|
+
const sourceDirectory = path.resolve(projectRoot, srcDir);
|
|
159
|
+
consola.log("从配置中获取到 srcDir:", srcDir);
|
|
160
|
+
consola.log("VitePress 源目录为:", sourceDirectory);
|
|
161
|
+
return sourceDirectory;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
consola.log("配置中未指定 srcDir,源目录等于项目根目录:", projectRoot);
|
|
165
|
+
return projectRoot;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 检查源目录是否存在 prompts/index.md 文件
|
|
170
|
+
* @description
|
|
171
|
+
* 检查当前文档的运行目录内是否存在 prompts/index.md 文件
|
|
172
|
+
*/
|
|
173
|
+
export function hasPromptsIndexMd(userConfig: UserConfig<DefaultTheme.Config>): boolean {
|
|
174
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
175
|
+
const res = fs.existsSync(path.resolve(sourceDir, PROMPTS_INDEX_MD_PATH));
|
|
176
|
+
if (!res) {
|
|
177
|
+
consola.log("当前项目的 vitepress 源目录为:", sourceDir);
|
|
178
|
+
consola.warn(`当前项目的 vitepress 源目录不存在 ${PROMPTS_INDEX_MD_PATH} 文件`);
|
|
179
|
+
}
|
|
180
|
+
return res;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 检查源目录是否存在 CHANGELOG.md 文件
|
|
185
|
+
* @description
|
|
186
|
+
* 检查当前文档的运行目录内是否存在 CHANGELOG.md 文件
|
|
187
|
+
*/
|
|
188
|
+
export function hasChangelogMd(userConfig: UserConfig<DefaultTheme.Config>): boolean {
|
|
189
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
190
|
+
const res = fs.existsSync(path.resolve(sourceDir, CHANGELOG_MD_FILENAME));
|
|
191
|
+
if (!res) {
|
|
192
|
+
consola.log("当前项目的 vitepress 源目录为:", sourceDir);
|
|
193
|
+
consola.warn(`当前项目的 vitepress 源目录不存在 ${CHANGELOG_MD_FILENAME} 文件`);
|
|
194
|
+
}
|
|
195
|
+
return res;
|
|
196
|
+
}
|