@ruan-cat/vitepress-preset-config 2.5.1 → 2.7.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 +93 -2
- package/dist/config.mjs +303 -28
- package/package.json +3 -2
- package/src/config/add-changelog-to-doc.ts +29 -0
- package/src/config/changelog-nav.ts +30 -0
- package/src/config/copy-claude-agents.ts +194 -0
- package/src/config/copy-readme.ts +60 -0
- package/src/config/index.ts +6 -0
- package/src/config/page-order-config.ts +17 -0
- package/src/config/prompts-nav.ts +241 -0
- package/src/config.mts +8 -34
- package/src/utils/copy-changelog.ts +29 -0
package/dist/config.d.mts
CHANGED
|
@@ -5,7 +5,6 @@ import { generateSidebar } from 'vitepress-sidebar';
|
|
|
5
5
|
import llmstxt from 'vitepress-plugin-llms';
|
|
6
6
|
import { GitChangelog, GitChangelogMarkdownSectionOptions } from '@nolebase/vitepress-plugin-git-changelog/vite';
|
|
7
7
|
import { defineTeekConfig } from 'vitepress-theme-teek/config';
|
|
8
|
-
export { addChangelog2doc, copyChangelogMd, copyClaudeAgents, copyReadmeMd } from '@ruan-cat/utils/node-esm';
|
|
9
8
|
|
|
10
9
|
type LlmstxtSettings = NonNullable<Parameters<typeof llmstxt>[0]>;
|
|
11
10
|
type GitChangelogOptions = NonNullable<Parameters<typeof GitChangelog>[0]>;
|
|
@@ -45,6 +44,98 @@ interface ExtraConfig {
|
|
|
45
44
|
teekConfig?: TeekConfigOptions;
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
/**
|
|
48
|
+
* 将 README.md 文件移动到指定要求的位置内,并重命名为 index.md
|
|
49
|
+
* @description
|
|
50
|
+
* 该函数相当于实现 `cpx README.md docs` 命令
|
|
51
|
+
*/
|
|
52
|
+
declare function copyReadmeMd(/** 目标文件夹 */ target: string): void;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 将 .claude/agents 文件夹复制到指定位置的配置选项
|
|
56
|
+
*/
|
|
57
|
+
interface CopyClaudeAgentsOptions {
|
|
58
|
+
/**
|
|
59
|
+
* 目标文件夹路径(必须是相对路径,相对于当前工作目录)
|
|
60
|
+
* @description
|
|
61
|
+
* **重要**:此参数仅接受相对路径,不接受绝对路径(禁止以 `/` 或盘符如 `C:\` 开头)。
|
|
62
|
+
* 使用绝对路径会抛出错误,这是为了防止意外覆盖系统目录。
|
|
63
|
+
*
|
|
64
|
+
* 该地址是写相对路径的 不能写绝对路径,容易导致意外。
|
|
65
|
+
* vitepress 命令运行在 apps/admin 目录内,该地址是相对于该运行目录的。
|
|
66
|
+
* 比如期望将 `.claude/agents` 复制到 `apps/admin/src/docs/prompts/agents` 文件夹。
|
|
67
|
+
* 则写 `src/docs/prompts/agents` 即可。
|
|
68
|
+
*
|
|
69
|
+
* @throws {Error} 当传入绝对路径时抛出错误
|
|
70
|
+
* @example
|
|
71
|
+
* // ✅ 正确:相对路径
|
|
72
|
+
* "src/docs/prompts/agents"
|
|
73
|
+
* "dist/agents"
|
|
74
|
+
* "./public/claude"
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // ❌ 错误:绝对路径(会抛出错误)
|
|
78
|
+
* "/var/www/agents" // Unix 绝对路径
|
|
79
|
+
* "C:\\Users\\agents" // Windows 绝对路径
|
|
80
|
+
*/
|
|
81
|
+
target: string;
|
|
82
|
+
/**
|
|
83
|
+
* 可选的根目录路径,支持相对路径(如 `../../../` 表示向上三级目录)
|
|
84
|
+
* @description
|
|
85
|
+
* - 如果不传入,将自动向上查找包含 pnpm-workspace.yaml 的 monorepo 根目录
|
|
86
|
+
* - 相对路径会基于当前工作目录 (process.cwd()) 解析为绝对路径
|
|
87
|
+
* - 绝对路径将直接使用
|
|
88
|
+
* @example
|
|
89
|
+
* // 相对路径:向上三级目录
|
|
90
|
+
* '../../../'
|
|
91
|
+
*
|
|
92
|
+
* // 绝对路径
|
|
93
|
+
* '/absolute/path/to/monorepo'
|
|
94
|
+
*/
|
|
95
|
+
rootDir?: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 将 .claude/agents 文件夹复制到指定位置
|
|
99
|
+
* @param options - 配置选项
|
|
100
|
+
* @throws {Error} 当 `options.target` 为绝对路径时抛出错误
|
|
101
|
+
* @description
|
|
102
|
+
* 该函数相当于实现 `cpx .claude/agents <target>` 命令。
|
|
103
|
+
* 从根目录的 .claude/agents 复制到目标位置。
|
|
104
|
+
*
|
|
105
|
+
* **安全限制**:`target` 参数必须是相对路径,禁止使用绝对路径,以防止意外覆盖系统目录。
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* // ✅ 自动检测 monorepo 根目录,复制到当前目录的 dist 文件夹
|
|
109
|
+
* copyClaudeAgents({ target: 'dist' })
|
|
110
|
+
*
|
|
111
|
+
* // ✅ 手动指定根目录为向上三级,复制到 build 文件夹
|
|
112
|
+
* copyClaudeAgents({
|
|
113
|
+
* target: 'build',
|
|
114
|
+
* rootDir: '../../../'
|
|
115
|
+
* })
|
|
116
|
+
*
|
|
117
|
+
* // ✅ 使用绝对路径指定根目录(rootDir 允许绝对路径)
|
|
118
|
+
* copyClaudeAgents({
|
|
119
|
+
* target: 'dist', // target 必须是相对路径
|
|
120
|
+
* rootDir: '/absolute/path/to/monorepo' // rootDir 可以是绝对路径
|
|
121
|
+
* })
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* // ❌ 错误用法:target 使用绝对路径会抛出错误
|
|
125
|
+
* copyClaudeAgents({ target: '/var/www/agents' }) // 抛出 Error
|
|
126
|
+
* copyClaudeAgents({ target: 'C:\\Windows\\agents' }) // 抛出 Error
|
|
127
|
+
*/
|
|
128
|
+
declare function copyClaudeAgents(options: CopyClaudeAgentsOptions): void;
|
|
129
|
+
|
|
130
|
+
interface AddChangelog2docOptions<T = Record<string, any>> {
|
|
131
|
+
/** 目标文件夹 */
|
|
132
|
+
target: string;
|
|
133
|
+
/** 被插入到md头部的数据 */
|
|
134
|
+
data: T;
|
|
135
|
+
}
|
|
136
|
+
/** 将变更日志添加到指定的文档目录内 并提供参数 */
|
|
137
|
+
declare function addChangelog2doc<T>(options: AddChangelog2docOptions<T>): void;
|
|
138
|
+
|
|
48
139
|
type VitePressSidebarOptions = Parameters<typeof generateSidebar>[0];
|
|
49
140
|
/**
|
|
50
141
|
* 设置自动生成侧边栏的配置
|
|
@@ -54,4 +145,4 @@ declare function setGenerateSidebar(options?: VitePressSidebarOptions): vitepres
|
|
|
54
145
|
/** 设置vitepress主配置 */
|
|
55
146
|
declare function setUserConfig(config?: UserConfig<DefaultTheme.Config>, extraConfig?: ExtraConfig): UserConfig<DefaultTheme.Config>;
|
|
56
147
|
|
|
57
|
-
export { setGenerateSidebar, setUserConfig };
|
|
148
|
+
export { addChangelog2doc, copyClaudeAgents, copyReadmeMd, setGenerateSidebar, setUserConfig };
|
package/dist/config.mjs
CHANGED
|
@@ -2,17 +2,159 @@
|
|
|
2
2
|
import { defineConfig } from "vitepress";
|
|
3
3
|
import { generateSidebar } from "vitepress-sidebar";
|
|
4
4
|
import { vitepressDemoPlugin } from "vitepress-demo-plugin";
|
|
5
|
-
import { merge as
|
|
5
|
+
import { merge as merge3, isUndefined as isUndefined3, cloneDeep as cloneDeep2 } from "lodash-es";
|
|
6
|
+
|
|
7
|
+
// src/config/page-order-config.ts
|
|
8
|
+
var pageOrderConfig = {
|
|
9
|
+
/** 提示词页面排序 */
|
|
10
|
+
prompts: {
|
|
11
|
+
order: 8e3
|
|
12
|
+
},
|
|
13
|
+
/** 变更日志页面排序 */
|
|
14
|
+
changelog: {
|
|
15
|
+
order: 9e3
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/config/copy-readme.ts
|
|
20
|
+
import fs from "fs";
|
|
21
|
+
import path from "path";
|
|
6
22
|
import consola from "consola";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
import { isConditionsSome } from "@ruan-cat/utils";
|
|
24
|
+
var capitalReadmeMd = "README.md";
|
|
25
|
+
var lowerCaseReadmeMd = "readme.md";
|
|
26
|
+
function hasCapitalReadmeMd() {
|
|
27
|
+
const res = fs.existsSync(path.resolve(process.cwd(), capitalReadmeMd));
|
|
28
|
+
if (!res) {
|
|
29
|
+
consola.warn(`\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E0D\u5B58\u5728 ${capitalReadmeMd} \u6587\u4EF6`);
|
|
30
|
+
}
|
|
31
|
+
return res;
|
|
32
|
+
}
|
|
33
|
+
function hasLowerCaseReadmeMd() {
|
|
34
|
+
const res = fs.existsSync(path.resolve(process.cwd(), lowerCaseReadmeMd));
|
|
35
|
+
if (!res) {
|
|
36
|
+
consola.log(`\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E0D\u5B58\u5728 ${lowerCaseReadmeMd} \u6587\u4EF6`);
|
|
37
|
+
}
|
|
38
|
+
return res;
|
|
39
|
+
}
|
|
40
|
+
function hasReadmeMd() {
|
|
41
|
+
const res = isConditionsSome([() => hasCapitalReadmeMd(), () => hasCapitalReadmeMd()]);
|
|
42
|
+
return res;
|
|
43
|
+
}
|
|
44
|
+
function copyReadmeMd(target) {
|
|
45
|
+
if (!hasReadmeMd()) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let readmeFileName = capitalReadmeMd;
|
|
49
|
+
if (hasCapitalReadmeMd()) {
|
|
50
|
+
readmeFileName = capitalReadmeMd;
|
|
51
|
+
} else if (hasLowerCaseReadmeMd()) {
|
|
52
|
+
readmeFileName = lowerCaseReadmeMd;
|
|
53
|
+
}
|
|
54
|
+
const source = path.resolve(process.cwd(), readmeFileName);
|
|
55
|
+
const destination = path.resolve(process.cwd(), target, "index.md");
|
|
56
|
+
fs.copyFileSync(source, destination);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/config/copy-claude-agents.ts
|
|
60
|
+
import fs2 from "fs";
|
|
61
|
+
import path2 from "path";
|
|
62
|
+
import consola2 from "consola";
|
|
63
|
+
function findMonorepoRoot() {
|
|
64
|
+
let currentDir = process.cwd();
|
|
65
|
+
const root = path2.parse(currentDir).root;
|
|
66
|
+
while (currentDir !== root) {
|
|
67
|
+
const workspaceFile2 = path2.join(currentDir, "pnpm-workspace.yaml");
|
|
68
|
+
if (fs2.existsSync(workspaceFile2)) {
|
|
69
|
+
return currentDir;
|
|
70
|
+
}
|
|
71
|
+
currentDir = path2.dirname(currentDir);
|
|
72
|
+
}
|
|
73
|
+
const workspaceFile = path2.join(root, "pnpm-workspace.yaml");
|
|
74
|
+
if (fs2.existsSync(workspaceFile)) {
|
|
75
|
+
return root;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function resolveRootDir(rootDir) {
|
|
80
|
+
if (rootDir) {
|
|
81
|
+
return path2.resolve(process.cwd(), rootDir);
|
|
82
|
+
}
|
|
83
|
+
const monorepoRoot = findMonorepoRoot();
|
|
84
|
+
if (monorepoRoot) {
|
|
85
|
+
return monorepoRoot;
|
|
86
|
+
}
|
|
87
|
+
return process.cwd();
|
|
88
|
+
}
|
|
89
|
+
function hasClaudeAgents(options) {
|
|
90
|
+
const root = resolveRootDir(options == null ? void 0 : options.rootDir);
|
|
91
|
+
const claudeAgentsPath = path2.join(root, ".claude/agents");
|
|
92
|
+
const exists = fs2.existsSync(claudeAgentsPath);
|
|
93
|
+
if (!exists) {
|
|
94
|
+
consola2.log("\u68C0\u6D4B\u7684\u6839\u76EE\u5F55\u4E3A\uFF1A", root);
|
|
95
|
+
consola2.warn("\u8BE5\u6839\u76EE\u5F55\u4E0D\u5B58\u5728 .claude/agents \u6587\u4EF6\u5939");
|
|
96
|
+
}
|
|
97
|
+
return exists;
|
|
98
|
+
}
|
|
99
|
+
function copyClaudeAgents(options) {
|
|
100
|
+
if (path2.isAbsolute(options.target)) {
|
|
101
|
+
const errorMessage = [
|
|
102
|
+
`target \u53C2\u6570\u4E0D\u5141\u8BB8\u4F7F\u7528\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8FD9\u53EF\u80FD\u5BFC\u81F4\u610F\u5916\u7684\u6587\u4EF6\u8986\u76D6\u3002`,
|
|
103
|
+
`\u5F53\u524D\u4F20\u5165\u7684\u8DEF\u5F84: "${options.target}"`,
|
|
104
|
+
`\u8BF7\u4F7F\u7528\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982: "src/docs/prompts/agents"`
|
|
105
|
+
].join("\n");
|
|
106
|
+
consola2.error(errorMessage);
|
|
107
|
+
throw new Error(errorMessage);
|
|
108
|
+
}
|
|
109
|
+
if (!hasClaudeAgents({ rootDir: options.rootDir })) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const root = resolveRootDir(options.rootDir);
|
|
113
|
+
const source = path2.join(root, ".claude/agents");
|
|
114
|
+
const destination = path2.resolve(process.cwd(), options.target);
|
|
115
|
+
fs2.mkdirSync(path2.dirname(destination), { recursive: true });
|
|
116
|
+
fs2.cpSync(source, destination, { recursive: true });
|
|
117
|
+
consola2.success(`\u5DF2\u6210\u529F\u590D\u5236 .claude/agents \u5230 ${destination}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/config/add-changelog-to-doc.ts
|
|
121
|
+
import path4 from "path";
|
|
122
|
+
|
|
123
|
+
// src/utils/copy-changelog.ts
|
|
124
|
+
import fs3 from "fs";
|
|
125
|
+
import path3 from "path";
|
|
126
|
+
import consola3 from "consola";
|
|
127
|
+
function hasChangelogMd() {
|
|
128
|
+
const res = fs3.existsSync(path3.resolve(process.cwd(), "CHANGELOG.md"));
|
|
129
|
+
if (!res) {
|
|
130
|
+
consola3.log("\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E3A\uFF1A", process.cwd());
|
|
131
|
+
consola3.warn("\u5F53\u524D\u9879\u76EE\u6839\u76EE\u5F55\u4E0D\u5B58\u5728 CHANGELOG.md \u6587\u4EF6");
|
|
132
|
+
}
|
|
133
|
+
return res;
|
|
134
|
+
}
|
|
135
|
+
function copyChangelogMd(target) {
|
|
136
|
+
if (!hasChangelogMd()) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const source = path3.resolve(process.cwd(), "CHANGELOG.md");
|
|
140
|
+
const destination = path3.resolve(process.cwd(), target, "CHANGELOG.md");
|
|
141
|
+
fs3.copyFileSync(source, destination);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/config/add-changelog-to-doc.ts
|
|
145
|
+
import { writeYaml2md } from "@ruan-cat/utils/node-esm";
|
|
146
|
+
function addChangelog2doc(options) {
|
|
147
|
+
const { data, target } = options;
|
|
148
|
+
if (!hasChangelogMd()) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
copyChangelogMd(target);
|
|
152
|
+
const mdPath = path4.resolve(process.cwd(), target, "CHANGELOG.md");
|
|
153
|
+
writeYaml2md({
|
|
154
|
+
mdPath,
|
|
155
|
+
data
|
|
156
|
+
});
|
|
157
|
+
}
|
|
16
158
|
|
|
17
159
|
// src/config/plugins.ts
|
|
18
160
|
import vitepressPluginLlmstxt from "vitepress-plugin-llms";
|
|
@@ -48,9 +190,153 @@ function handlePlugins(userConfig, extraConfig) {
|
|
|
48
190
|
userConfig.vite.plugins = getPlugins(extraConfig);
|
|
49
191
|
}
|
|
50
192
|
|
|
193
|
+
// src/config/changelog-nav.ts
|
|
194
|
+
import consola4 from "consola";
|
|
195
|
+
import { isUndefined } from "lodash-es";
|
|
196
|
+
function handleChangeLog(userConfig) {
|
|
197
|
+
var _a;
|
|
198
|
+
if (!hasChangelogMd()) {
|
|
199
|
+
consola4.warn(` \u672A\u627E\u5230\u53D8\u66F4\u65E5\u5FD7\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u53D8\u66F4\u65E5\u5FD7\u5BFC\u822A\u680F\u3002 `);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
203
|
+
if (isUndefined(nav)) {
|
|
204
|
+
consola4.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
205
|
+
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 `);
|
|
206
|
+
}
|
|
207
|
+
nav.push({ text: "\u66F4\u65B0\u65E5\u5FD7", link: "/CHANGELOG.md" });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/config/prompts-nav.ts
|
|
211
|
+
import fs4 from "fs";
|
|
212
|
+
import path5 from "path";
|
|
213
|
+
import consola5 from "consola";
|
|
214
|
+
import { isUndefined as isUndefined2, merge } from "lodash-es";
|
|
215
|
+
import matter from "gray-matter";
|
|
216
|
+
var PROMPTS_INDEX_MD_PATH = "prompts/index.md";
|
|
217
|
+
function getProjectRootFromArgs() {
|
|
218
|
+
const args = process.argv;
|
|
219
|
+
const vitepressIndex = args.findIndex((arg) => arg.includes("vitepress"));
|
|
220
|
+
if (vitepressIndex === -1) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
for (let i = vitepressIndex + 1; i < args.length; i++) {
|
|
224
|
+
const arg = args[i];
|
|
225
|
+
if (arg === "dev" || arg === "build" || arg === "serve" || arg === "preview") {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (arg.startsWith("-")) {
|
|
229
|
+
if (arg.startsWith("--") && !arg.includes("=")) {
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
return path5.resolve(process.cwd(), arg);
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
function getVitepressProjectRoot() {
|
|
239
|
+
const projectRootFromArgs = getProjectRootFromArgs();
|
|
240
|
+
if (projectRootFromArgs) {
|
|
241
|
+
const vitepressDir2 = path5.join(projectRootFromArgs, ".vitepress");
|
|
242
|
+
if (fs4.existsSync(vitepressDir2)) {
|
|
243
|
+
consola5.log("\u4ECE\u547D\u4EE4\u884C\u53C2\u6570\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", projectRootFromArgs);
|
|
244
|
+
return projectRootFromArgs;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
let currentDir = process.cwd();
|
|
248
|
+
const root = path5.parse(currentDir).root;
|
|
249
|
+
while (currentDir !== root) {
|
|
250
|
+
const vitepressDir2 = path5.join(currentDir, ".vitepress");
|
|
251
|
+
if (fs4.existsSync(vitepressDir2)) {
|
|
252
|
+
consola5.log("\u901A\u8FC7\u5411\u4E0A\u67E5\u627E\u83B7\u53D6\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", currentDir);
|
|
253
|
+
return currentDir;
|
|
254
|
+
}
|
|
255
|
+
currentDir = path5.dirname(currentDir);
|
|
256
|
+
}
|
|
257
|
+
const vitepressDir = path5.join(root, ".vitepress");
|
|
258
|
+
if (fs4.existsSync(vitepressDir)) {
|
|
259
|
+
consola5.log("\u5728\u6587\u4EF6\u7CFB\u7EDF\u6839\u76EE\u5F55\u627E\u5230 VitePress \u9879\u76EE\u6839\u76EE\u5F55\uFF1A", root);
|
|
260
|
+
return root;
|
|
261
|
+
}
|
|
262
|
+
const fallbackDir = process.cwd();
|
|
263
|
+
consola5.warn("\u672A\u627E\u5230 .vitepress \u76EE\u5F55\uFF0C\u56DE\u9000\u5230\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF1A", fallbackDir);
|
|
264
|
+
return fallbackDir;
|
|
265
|
+
}
|
|
266
|
+
function getVitepressSourceDirectory(userConfig) {
|
|
267
|
+
const projectRoot = getVitepressProjectRoot();
|
|
268
|
+
const srcDir = userConfig.srcDir;
|
|
269
|
+
if (srcDir) {
|
|
270
|
+
const sourceDirectory = path5.resolve(projectRoot, srcDir);
|
|
271
|
+
consola5.log("\u4ECE\u914D\u7F6E\u4E2D\u83B7\u53D6\u5230 srcDir:", srcDir);
|
|
272
|
+
consola5.log("VitePress \u6E90\u76EE\u5F55\u4E3A\uFF1A", sourceDirectory);
|
|
273
|
+
return sourceDirectory;
|
|
274
|
+
}
|
|
275
|
+
consola5.log("\u914D\u7F6E\u4E2D\u672A\u6307\u5B9A srcDir\uFF0C\u6E90\u76EE\u5F55\u7B49\u4E8E\u9879\u76EE\u6839\u76EE\u5F55\uFF1A", projectRoot);
|
|
276
|
+
return projectRoot;
|
|
277
|
+
}
|
|
278
|
+
function hasPromptsIndexMd(userConfig) {
|
|
279
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
280
|
+
const res = fs4.existsSync(path5.resolve(sourceDir, PROMPTS_INDEX_MD_PATH));
|
|
281
|
+
if (!res) {
|
|
282
|
+
consola5.log("\u5F53\u524D\u9879\u76EE\u7684vitepress\u6E90\u76EE\u5F55\u4E3A\uFF1A", sourceDir);
|
|
283
|
+
consola5.warn(`\u5F53\u524D\u9879\u76EE\u7684vitepress\u6E90\u76EE\u5F55\u4E0D\u5B58\u5728 ${PROMPTS_INDEX_MD_PATH} \u6587\u4EF6`);
|
|
284
|
+
}
|
|
285
|
+
return res;
|
|
286
|
+
}
|
|
287
|
+
function writeYaml2PromptsIndexMd(userConfig, data) {
|
|
288
|
+
const newData = data ?? pageOrderConfig.prompts;
|
|
289
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
290
|
+
const mdPath = path5.resolve(sourceDir, PROMPTS_INDEX_MD_PATH);
|
|
291
|
+
try {
|
|
292
|
+
let fileContent = "";
|
|
293
|
+
let existingData = {};
|
|
294
|
+
if (fs4.existsSync(mdPath)) {
|
|
295
|
+
fileContent = fs4.readFileSync(mdPath, "utf-8");
|
|
296
|
+
const parsed = matter(fileContent);
|
|
297
|
+
if (parsed.data && Object.keys(parsed.data).length > 0) {
|
|
298
|
+
existingData = parsed.data;
|
|
299
|
+
consola5.log("\u68C0\u6D4B\u5230\u5DF2\u6709 YAML frontmatter\uFF0C\u5C06\u8FDB\u884C\u6570\u636E\u5408\u5E76");
|
|
300
|
+
} else {
|
|
301
|
+
consola5.log("\u6587\u4EF6\u5B58\u5728\u4F46\u6CA1\u6709 YAML frontmatter\uFF0C\u5C06\u5199\u5165\u65B0\u7684 frontmatter");
|
|
302
|
+
}
|
|
303
|
+
const mergedData = merge({}, existingData, newData);
|
|
304
|
+
const newContent = matter.stringify(parsed.content, mergedData);
|
|
305
|
+
fs4.writeFileSync(mdPath, newContent, "utf-8");
|
|
306
|
+
consola5.success(`\u5DF2\u5C06YAML\u6570\u636E\u5199\u5165\u5230 ${mdPath}`);
|
|
307
|
+
} else {
|
|
308
|
+
consola5.warn(`\u6587\u4EF6 ${mdPath} \u4E0D\u5B58\u5728\uFF0C\u5C06\u521B\u5EFA\u65B0\u6587\u4EF6`);
|
|
309
|
+
const dir = path5.dirname(mdPath);
|
|
310
|
+
if (!fs4.existsSync(dir)) {
|
|
311
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
312
|
+
}
|
|
313
|
+
const newContent = matter.stringify("", newData);
|
|
314
|
+
fs4.writeFileSync(mdPath, newContent, "utf-8");
|
|
315
|
+
consola5.success(`\u5DF2\u521B\u5EFA\u6587\u4EF6\u5E76\u5199\u5165YAML\u6570\u636E\u5230 ${mdPath}`);
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
consola5.error(`\u5199\u5165 YAML \u6570\u636E\u5230 ${mdPath} \u65F6\u53D1\u751F\u9519\u8BEF:`, error);
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function handlePrompts(userConfig) {
|
|
323
|
+
var _a;
|
|
324
|
+
if (!hasPromptsIndexMd(userConfig)) {
|
|
325
|
+
consola5.warn(` \u672A\u627E\u5230\u63D0\u793A\u8BCD\u7D22\u5F15\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u63D0\u793A\u8BCD\u5BFC\u822A\u680F\u3002 `);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
writeYaml2PromptsIndexMd(userConfig);
|
|
329
|
+
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
330
|
+
if (isUndefined2(nav)) {
|
|
331
|
+
consola5.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
332
|
+
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 `);
|
|
333
|
+
}
|
|
334
|
+
nav.push({ text: "\u63D0\u793A\u8BCD", link: `/${PROMPTS_INDEX_MD_PATH}` });
|
|
335
|
+
}
|
|
336
|
+
|
|
51
337
|
// src/config/teek.ts
|
|
52
338
|
import { defineTeekConfig } from "vitepress-theme-teek/config";
|
|
53
|
-
import { merge, cloneDeep } from "lodash-es";
|
|
339
|
+
import { merge as merge2, cloneDeep } from "lodash-es";
|
|
54
340
|
var defaultTeekConfig = {
|
|
55
341
|
/**
|
|
56
342
|
* 启用侧边栏展开/折叠触发器
|
|
@@ -113,10 +399,12 @@ var defaultTeekConfig = {
|
|
|
113
399
|
};
|
|
114
400
|
function handleTeekConfig(userConfig, extraConfig) {
|
|
115
401
|
const { teekConfig = defaultTeekConfig } = extraConfig ?? {};
|
|
116
|
-
userConfig.extends = defineTeekConfig(
|
|
402
|
+
userConfig.extends = defineTeekConfig(merge2({}, cloneDeep(defaultTeekConfig), teekConfig));
|
|
117
403
|
}
|
|
118
404
|
|
|
119
405
|
// src/config.mts
|
|
406
|
+
import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
|
|
407
|
+
import { copyOrDownloadAsMarkdownButtons } from "vitepress-plugin-llms";
|
|
120
408
|
import { MermaidPlugin } from "@leelaa/vitepress-plugin-extended";
|
|
121
409
|
import { defineTeekConfig as defineTeekConfig2 } from "vitepress-theme-teek/config";
|
|
122
410
|
var defaultSidebarOptions = {
|
|
@@ -145,7 +433,7 @@ var defaultSidebarOptions = {
|
|
|
145
433
|
debugPrint: false
|
|
146
434
|
};
|
|
147
435
|
function getMergeSidebarOptions(options) {
|
|
148
|
-
return
|
|
436
|
+
return merge3({}, cloneDeep2(defaultSidebarOptions), isUndefined3(options) ? {} : options);
|
|
149
437
|
}
|
|
150
438
|
function setGenerateSidebar(options) {
|
|
151
439
|
return generateSidebar(getMergeSidebarOptions(options));
|
|
@@ -222,21 +510,9 @@ var defaultUserConfig = {
|
|
|
222
510
|
}
|
|
223
511
|
}
|
|
224
512
|
};
|
|
225
|
-
function handleChangeLog(userConfig) {
|
|
226
|
-
var _a;
|
|
227
|
-
if (!hasChangelogMd()) {
|
|
228
|
-
consola.warn(` \u672A\u627E\u5230\u53D8\u66F4\u65E5\u5FD7\u6587\u4EF6\uFF0C\u4E0D\u6DFB\u52A0\u53D8\u66F4\u65E5\u5FD7\u5BFC\u822A\u680F\u3002 `);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const nav = (_a = userConfig == null ? void 0 : userConfig.themeConfig) == null ? void 0 : _a.nav;
|
|
232
|
-
if (isUndefined(nav)) {
|
|
233
|
-
consola.error(` \u5F53\u524D\u7684\u7528\u6237\u914D\u7F6E\u4E3A\uFF1A `, userConfig);
|
|
234
|
-
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 `);
|
|
235
|
-
}
|
|
236
|
-
nav.push({ text: "\u66F4\u65B0\u65E5\u5FD7", link: "/CHANGELOG.md" });
|
|
237
|
-
}
|
|
238
513
|
function setUserConfig(config, extraConfig) {
|
|
239
|
-
const resUserConfig =
|
|
514
|
+
const resUserConfig = merge3({}, cloneDeep2(defaultUserConfig), isUndefined3(config) ? {} : config);
|
|
515
|
+
handlePrompts(resUserConfig);
|
|
240
516
|
handleChangeLog(resUserConfig);
|
|
241
517
|
handlePlugins(resUserConfig, extraConfig);
|
|
242
518
|
handleTeekConfig(resUserConfig, extraConfig);
|
|
@@ -244,7 +520,6 @@ function setUserConfig(config, extraConfig) {
|
|
|
244
520
|
}
|
|
245
521
|
export {
|
|
246
522
|
addChangelog2doc,
|
|
247
|
-
copyChangelogMd,
|
|
248
523
|
copyClaudeAgents,
|
|
249
524
|
copyReadmeMd,
|
|
250
525
|
defineConfig,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ruan-cat/vitepress-preset-config",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "用于给大多数的vitepress项目提供一个预设的配置文件。",
|
|
5
5
|
"homepage": "https://vitepress-preset.ruancat6312.top",
|
|
6
6
|
"types": "./src/config.mts",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"@nolebase/vitepress-plugin-git-changelog": "^2.18.2",
|
|
11
11
|
"@shikijs/vitepress-twoslash": "^3.13.0",
|
|
12
12
|
"consola": "^3.4.2",
|
|
13
|
+
"gray-matter": "^4.0.3",
|
|
13
14
|
"js-yaml": "^4.1.0",
|
|
14
15
|
"lodash-es": "^4.17.21",
|
|
15
16
|
"markdown-it-async": "^2.2.0",
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"vitepress-sidebar": "^1.33.0",
|
|
20
21
|
"vitepress-theme-teek": "^1.4.6",
|
|
21
22
|
"vue": "^3.5.21",
|
|
22
|
-
"@ruan-cat/utils": "^4.
|
|
23
|
+
"@ruan-cat/utils": "^4.14.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { copyChangelogMd, hasChangelogMd } from "../utils/copy-changelog";
|
|
4
|
+
import { writeYaml2md } from "@ruan-cat/utils/node-esm";
|
|
5
|
+
|
|
6
|
+
export interface AddChangelog2docOptions<T = Record<string, any>> {
|
|
7
|
+
/** 目标文件夹 */
|
|
8
|
+
target: string;
|
|
9
|
+
|
|
10
|
+
/** 被插入到md头部的数据 */
|
|
11
|
+
data: T;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** 将变更日志添加到指定的文档目录内 并提供参数 */
|
|
15
|
+
export function addChangelog2doc<T>(options: AddChangelog2docOptions<T>) {
|
|
16
|
+
const { data, target } = options;
|
|
17
|
+
|
|
18
|
+
if (!hasChangelogMd()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
copyChangelogMd(target);
|
|
23
|
+
|
|
24
|
+
const mdPath = path.resolve(process.cwd(), target, "CHANGELOG.md");
|
|
25
|
+
writeYaml2md({
|
|
26
|
+
mdPath,
|
|
27
|
+
data,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// 为变更日志写入vitepress侧边栏排序yaml信息 并在导航栏内增加顶部入口便于快速阅读
|
|
2
|
+
|
|
3
|
+
import { type UserConfig, type DefaultTheme } from "vitepress";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { isUndefined } from "lodash-es";
|
|
6
|
+
import { hasChangelogMd } from "../utils/copy-changelog";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 设置导航栏的变更日志
|
|
10
|
+
* @description
|
|
11
|
+
* 在导航栏内添加一行 变更日志 的入口
|
|
12
|
+
*
|
|
13
|
+
* 直接修改外部传递进来的配置对象即可
|
|
14
|
+
* @private 内部使用即可
|
|
15
|
+
*/
|
|
16
|
+
export function handleChangeLog(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
17
|
+
if (!hasChangelogMd()) {
|
|
18
|
+
consola.warn(` 未找到变更日志文件,不添加变更日志导航栏。 `);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const nav = userConfig?.themeConfig?.nav;
|
|
23
|
+
|
|
24
|
+
if (isUndefined(nav)) {
|
|
25
|
+
consola.error(` 当前的用户配置为: `, userConfig);
|
|
26
|
+
throw new Error(` nav 默认提供的导航栏配置为空。不符合默认配置,请检查。 `);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
nav.push({ text: "更新日志", link: "/CHANGELOG.md" });
|
|
30
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 从当前工作目录向上查找 monorepo 根目录
|
|
7
|
+
* @returns monorepo 根目录的绝对路径,如果找不到则返回 null
|
|
8
|
+
* @description
|
|
9
|
+
* 通过查找 pnpm-workspace.yaml 文件来定位 monorepo 根目录。
|
|
10
|
+
* 从 process.cwd() 开始向上遍历,直到找到该文件或到达文件系统根目录。
|
|
11
|
+
*/
|
|
12
|
+
function findMonorepoRoot(): string | null {
|
|
13
|
+
let currentDir = process.cwd();
|
|
14
|
+
const root = path.parse(currentDir).root;
|
|
15
|
+
|
|
16
|
+
while (currentDir !== root) {
|
|
17
|
+
const workspaceFile = path.join(currentDir, "pnpm-workspace.yaml");
|
|
18
|
+
if (fs.existsSync(workspaceFile)) {
|
|
19
|
+
return currentDir;
|
|
20
|
+
}
|
|
21
|
+
currentDir = path.dirname(currentDir);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 检查根目录本身
|
|
25
|
+
const workspaceFile = path.join(root, "pnpm-workspace.yaml");
|
|
26
|
+
if (fs.existsSync(workspaceFile)) {
|
|
27
|
+
return root;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 解析根目录路径
|
|
35
|
+
* @param rootDir - 根目录路径,支持相对路径(如 `../../../`)或绝对路径
|
|
36
|
+
* @returns 解析后的绝对路径
|
|
37
|
+
* @description
|
|
38
|
+
* 路径解析优先级:
|
|
39
|
+
* 1. 如果传入 rootDir,将相对路径基于 process.cwd() 解析为绝对路径
|
|
40
|
+
* 2. 如果未传入 rootDir,自动向上查找包含 pnpm-workspace.yaml 的 monorepo 根目录
|
|
41
|
+
* 3. 如果自动查找失败,回退到 process.cwd()
|
|
42
|
+
*/
|
|
43
|
+
function resolveRootDir(rootDir?: string): string {
|
|
44
|
+
if (rootDir) {
|
|
45
|
+
// 将相对路径或绝对路径解析为绝对路径
|
|
46
|
+
return path.resolve(process.cwd(), rootDir);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 自动查找 monorepo 根目录
|
|
50
|
+
const monorepoRoot = findMonorepoRoot();
|
|
51
|
+
if (monorepoRoot) {
|
|
52
|
+
return monorepoRoot;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 回退到当前工作目录
|
|
56
|
+
return process.cwd();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 检查指定根目录是否存在 .claude/agents 文件夹
|
|
61
|
+
* @param options - 配置选项
|
|
62
|
+
* @param options.rootDir - 可选的根目录路径,支持相对路径(如 `../../../` 表示向上三级目录)。
|
|
63
|
+
* 如果不传入,将自动向上查找包含 pnpm-workspace.yaml 的 monorepo 根目录。
|
|
64
|
+
* 相对路径会基于当前工作目录 (process.cwd()) 解析为绝对路径。
|
|
65
|
+
* @returns 是否存在 .claude/agents 文件夹
|
|
66
|
+
* @example
|
|
67
|
+
* // 自动检测 monorepo 根目录
|
|
68
|
+
* hasClaudeAgents()
|
|
69
|
+
*
|
|
70
|
+
* // 手动指定相对路径(从当前工作目录向上三级)
|
|
71
|
+
* hasClaudeAgents({ rootDir: '../../../' })
|
|
72
|
+
*
|
|
73
|
+
* // 手动指定绝对路径
|
|
74
|
+
* hasClaudeAgents({ rootDir: '/path/to/monorepo' })
|
|
75
|
+
*/
|
|
76
|
+
function hasClaudeAgents(options?: { rootDir?: string }): boolean {
|
|
77
|
+
const root = resolveRootDir(options?.rootDir);
|
|
78
|
+
const claudeAgentsPath = path.join(root, ".claude/agents");
|
|
79
|
+
const exists = fs.existsSync(claudeAgentsPath);
|
|
80
|
+
|
|
81
|
+
if (!exists) {
|
|
82
|
+
consola.log("检测的根目录为:", root);
|
|
83
|
+
consola.warn("该根目录不存在 .claude/agents 文件夹");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return exists;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 将 .claude/agents 文件夹复制到指定位置的配置选项
|
|
91
|
+
*/
|
|
92
|
+
export interface CopyClaudeAgentsOptions {
|
|
93
|
+
/**
|
|
94
|
+
* 目标文件夹路径(必须是相对路径,相对于当前工作目录)
|
|
95
|
+
* @description
|
|
96
|
+
* **重要**:此参数仅接受相对路径,不接受绝对路径(禁止以 `/` 或盘符如 `C:\` 开头)。
|
|
97
|
+
* 使用绝对路径会抛出错误,这是为了防止意外覆盖系统目录。
|
|
98
|
+
*
|
|
99
|
+
* 该地址是写相对路径的 不能写绝对路径,容易导致意外。
|
|
100
|
+
* vitepress 命令运行在 apps/admin 目录内,该地址是相对于该运行目录的。
|
|
101
|
+
* 比如期望将 `.claude/agents` 复制到 `apps/admin/src/docs/prompts/agents` 文件夹。
|
|
102
|
+
* 则写 `src/docs/prompts/agents` 即可。
|
|
103
|
+
*
|
|
104
|
+
* @throws {Error} 当传入绝对路径时抛出错误
|
|
105
|
+
* @example
|
|
106
|
+
* // ✅ 正确:相对路径
|
|
107
|
+
* "src/docs/prompts/agents"
|
|
108
|
+
* "dist/agents"
|
|
109
|
+
* "./public/claude"
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // ❌ 错误:绝对路径(会抛出错误)
|
|
113
|
+
* "/var/www/agents" // Unix 绝对路径
|
|
114
|
+
* "C:\\Users\\agents" // Windows 绝对路径
|
|
115
|
+
*/
|
|
116
|
+
target: string;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 可选的根目录路径,支持相对路径(如 `../../../` 表示向上三级目录)
|
|
120
|
+
* @description
|
|
121
|
+
* - 如果不传入,将自动向上查找包含 pnpm-workspace.yaml 的 monorepo 根目录
|
|
122
|
+
* - 相对路径会基于当前工作目录 (process.cwd()) 解析为绝对路径
|
|
123
|
+
* - 绝对路径将直接使用
|
|
124
|
+
* @example
|
|
125
|
+
* // 相对路径:向上三级目录
|
|
126
|
+
* '../../../'
|
|
127
|
+
*
|
|
128
|
+
* // 绝对路径
|
|
129
|
+
* '/absolute/path/to/monorepo'
|
|
130
|
+
*/
|
|
131
|
+
rootDir?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 将 .claude/agents 文件夹复制到指定位置
|
|
136
|
+
* @param options - 配置选项
|
|
137
|
+
* @throws {Error} 当 `options.target` 为绝对路径时抛出错误
|
|
138
|
+
* @description
|
|
139
|
+
* 该函数相当于实现 `cpx .claude/agents <target>` 命令。
|
|
140
|
+
* 从根目录的 .claude/agents 复制到目标位置。
|
|
141
|
+
*
|
|
142
|
+
* **安全限制**:`target` 参数必须是相对路径,禁止使用绝对路径,以防止意外覆盖系统目录。
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* // ✅ 自动检测 monorepo 根目录,复制到当前目录的 dist 文件夹
|
|
146
|
+
* copyClaudeAgents({ target: 'dist' })
|
|
147
|
+
*
|
|
148
|
+
* // ✅ 手动指定根目录为向上三级,复制到 build 文件夹
|
|
149
|
+
* copyClaudeAgents({
|
|
150
|
+
* target: 'build',
|
|
151
|
+
* rootDir: '../../../'
|
|
152
|
+
* })
|
|
153
|
+
*
|
|
154
|
+
* // ✅ 使用绝对路径指定根目录(rootDir 允许绝对路径)
|
|
155
|
+
* copyClaudeAgents({
|
|
156
|
+
* target: 'dist', // target 必须是相对路径
|
|
157
|
+
* rootDir: '/absolute/path/to/monorepo' // rootDir 可以是绝对路径
|
|
158
|
+
* })
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* // ❌ 错误用法:target 使用绝对路径会抛出错误
|
|
162
|
+
* copyClaudeAgents({ target: '/var/www/agents' }) // 抛出 Error
|
|
163
|
+
* copyClaudeAgents({ target: 'C:\\Windows\\agents' }) // 抛出 Error
|
|
164
|
+
*/
|
|
165
|
+
export function copyClaudeAgents(options: CopyClaudeAgentsOptions): void {
|
|
166
|
+
// 验证 target 不能是绝对路径
|
|
167
|
+
if (path.isAbsolute(options.target)) {
|
|
168
|
+
const errorMessage = [
|
|
169
|
+
`target 参数不允许使用绝对路径,这可能导致意外的文件覆盖。`,
|
|
170
|
+
`当前传入的路径: "${options.target}"`,
|
|
171
|
+
`请使用相对路径,例如: "src/docs/prompts/agents"`,
|
|
172
|
+
].join("\n");
|
|
173
|
+
|
|
174
|
+
consola.error(errorMessage);
|
|
175
|
+
throw new Error(errorMessage);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 检查源目录是否存在
|
|
179
|
+
if (!hasClaudeAgents({ rootDir: options.rootDir })) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const root = resolveRootDir(options.rootDir);
|
|
184
|
+
const source = path.join(root, ".claude/agents");
|
|
185
|
+
const destination = path.resolve(process.cwd(), options.target);
|
|
186
|
+
|
|
187
|
+
// 确保目标文件夹的父目录存在
|
|
188
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
189
|
+
|
|
190
|
+
// 递归复制文件夹
|
|
191
|
+
fs.cpSync(source, destination, { recursive: true });
|
|
192
|
+
|
|
193
|
+
consola.success(`已成功复制 .claude/agents 到 ${destination}`);
|
|
194
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
|
|
5
|
+
// 有疑惑 这个写法都不对么? 这个写法对于 vitepress 文档构建来说 是会引发报错的
|
|
6
|
+
// import { isConditionsSome } from "@ruan-cat/utils/src/conditions.ts";
|
|
7
|
+
import { isConditionsSome } from "@ruan-cat/utils";
|
|
8
|
+
|
|
9
|
+
/** 大写字母的文件 */
|
|
10
|
+
const capitalReadmeMd = "README.md" as const;
|
|
11
|
+
|
|
12
|
+
/** 小写字母的文件 */
|
|
13
|
+
const lowerCaseReadmeMd = "readme.md" as const;
|
|
14
|
+
|
|
15
|
+
/** 检查当前运行的根目录 是否存在文件名大写的 `README.md` 文件 */
|
|
16
|
+
function hasCapitalReadmeMd() {
|
|
17
|
+
const res = fs.existsSync(path.resolve(process.cwd(), capitalReadmeMd));
|
|
18
|
+
if (!res) {
|
|
19
|
+
consola.warn(`当前项目根目录不存在 ${capitalReadmeMd} 文件`);
|
|
20
|
+
}
|
|
21
|
+
return res;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 检查当前运行的根目录 是否存在文件名小写的 `readme.md` 文件 */
|
|
25
|
+
function hasLowerCaseReadmeMd() {
|
|
26
|
+
const res = fs.existsSync(path.resolve(process.cwd(), lowerCaseReadmeMd));
|
|
27
|
+
if (!res) {
|
|
28
|
+
consola.log(`当前项目根目录不存在 ${lowerCaseReadmeMd} 文件`);
|
|
29
|
+
}
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** 检查当前运行的根目录 是否存在任意一个大小写命名的 README.md 文件 */
|
|
34
|
+
function hasReadmeMd() {
|
|
35
|
+
const res = isConditionsSome([() => hasCapitalReadmeMd(), () => hasCapitalReadmeMd()]);
|
|
36
|
+
return res;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 将 README.md 文件移动到指定要求的位置内,并重命名为 index.md
|
|
41
|
+
* @description
|
|
42
|
+
* 该函数相当于实现 `cpx README.md docs` 命令
|
|
43
|
+
*/
|
|
44
|
+
export function copyReadmeMd(/** 目标文件夹 */ target: string) {
|
|
45
|
+
if (!hasReadmeMd()) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let readmeFileName: string = capitalReadmeMd;
|
|
50
|
+
if (hasCapitalReadmeMd()) {
|
|
51
|
+
readmeFileName = capitalReadmeMd;
|
|
52
|
+
} else if (hasLowerCaseReadmeMd()) {
|
|
53
|
+
readmeFileName = lowerCaseReadmeMd;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const source = path.resolve(process.cwd(), readmeFileName);
|
|
57
|
+
const destination = path.resolve(process.cwd(), target, "index.md");
|
|
58
|
+
|
|
59
|
+
fs.copyFileSync(source, destination);
|
|
60
|
+
}
|
package/src/config/index.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
// 专门为 packages\vitepress-preset-config\src\config.mts 服务的文件 提供额外配置
|
|
2
2
|
|
|
3
|
+
export * from "./page-order-config";
|
|
4
|
+
export * from "./copy-readme";
|
|
5
|
+
export * from "./copy-claude-agents";
|
|
6
|
+
export * from "./add-changelog-to-doc";
|
|
3
7
|
export * from "./plugins";
|
|
8
|
+
export * from "./changelog-nav";
|
|
9
|
+
export * from "./prompts-nav";
|
|
4
10
|
export * from "./teek";
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { type UserConfig, type DefaultTheme } from "vitepress";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { isUndefined, merge } from "lodash-es";
|
|
6
|
+
import matter from "gray-matter";
|
|
7
|
+
|
|
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
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* 将YAML数据写入到提示词索引文件内
|
|
149
|
+
* @description
|
|
150
|
+
* - 读取 markdown 文件
|
|
151
|
+
* - 检查是否已经包含了预先准备好的 yaml 信息
|
|
152
|
+
* - 如果有 yaml 信息,就用提供的数据做数据拓展(使用 lodash merge)
|
|
153
|
+
* - 如果没有 yaml 信息,就写入顶部 yaml 信息
|
|
154
|
+
*
|
|
155
|
+
* @param userConfig - VitePress 用户配置对象
|
|
156
|
+
* @param data - 要写入或合并的 YAML 数据
|
|
157
|
+
* @private 目前仅设计为内部使用
|
|
158
|
+
*/
|
|
159
|
+
function writeYaml2PromptsIndexMd(userConfig: UserConfig<DefaultTheme.Config>, data?: Record<string, any>) {
|
|
160
|
+
// 获取要写入的数据
|
|
161
|
+
const newData = data ?? pageOrderConfig.prompts;
|
|
162
|
+
|
|
163
|
+
// 获取文件路径
|
|
164
|
+
const sourceDir = getVitepressSourceDirectory(userConfig);
|
|
165
|
+
const mdPath = path.resolve(sourceDir, PROMPTS_INDEX_MD_PATH);
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
// 读取 markdown 文件
|
|
169
|
+
let fileContent = "";
|
|
170
|
+
let existingData: Record<string, any> = {};
|
|
171
|
+
|
|
172
|
+
if (fs.existsSync(mdPath)) {
|
|
173
|
+
fileContent = fs.readFileSync(mdPath, "utf-8");
|
|
174
|
+
|
|
175
|
+
// 使用 gray-matter 解析文件
|
|
176
|
+
const parsed = matter(fileContent);
|
|
177
|
+
|
|
178
|
+
// 如果有 frontmatter,获取已有数据
|
|
179
|
+
if (parsed.data && Object.keys(parsed.data).length > 0) {
|
|
180
|
+
existingData = parsed.data;
|
|
181
|
+
consola.log("检测到已有 YAML frontmatter,将进行数据合并");
|
|
182
|
+
} else {
|
|
183
|
+
consola.log("文件存在但没有 YAML frontmatter,将写入新的 frontmatter");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 使用 lodash merge 合并数据
|
|
187
|
+
// merge 会深度合并对象,新数据会覆盖旧数据
|
|
188
|
+
const mergedData = merge({}, existingData, newData);
|
|
189
|
+
|
|
190
|
+
// 使用 gray-matter 的 stringify 方法生成新的文件内容
|
|
191
|
+
const newContent = matter.stringify(parsed.content, mergedData);
|
|
192
|
+
|
|
193
|
+
// 写入文件
|
|
194
|
+
fs.writeFileSync(mdPath, newContent, "utf-8");
|
|
195
|
+
consola.success(`已将YAML数据写入到 ${mdPath}`);
|
|
196
|
+
} else {
|
|
197
|
+
// 文件不存在,创建新文件
|
|
198
|
+
consola.warn(`文件 ${mdPath} 不存在,将创建新文件`);
|
|
199
|
+
|
|
200
|
+
// 确保目录存在
|
|
201
|
+
const dir = path.dirname(mdPath);
|
|
202
|
+
if (!fs.existsSync(dir)) {
|
|
203
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 创建带有 frontmatter 的空文件
|
|
207
|
+
const newContent = matter.stringify("", newData);
|
|
208
|
+
fs.writeFileSync(mdPath, newContent, "utf-8");
|
|
209
|
+
consola.success(`已创建文件并写入YAML数据到 ${mdPath}`);
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
consola.error(`写入 YAML 数据到 ${mdPath} 时发生错误:`, error);
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 处理提示词文件
|
|
219
|
+
* @description
|
|
220
|
+
* - 检查当前文档的运行目录内 是否包含有约定格式的提示词文档。
|
|
221
|
+
* - 如果存在 就给目标文件增加一个顶部yaml信息,做排序使用。
|
|
222
|
+
* - 并且文档的顶部导航栏内,增加一个固定的提示词入口。
|
|
223
|
+
*/
|
|
224
|
+
export function handlePrompts(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
225
|
+
if (!hasPromptsIndexMd(userConfig)) {
|
|
226
|
+
consola.warn(` 未找到提示词索引文件,不添加提示词导航栏。 `);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 给提示词索引文件 写入排序值
|
|
231
|
+
writeYaml2PromptsIndexMd(userConfig);
|
|
232
|
+
|
|
233
|
+
const nav = userConfig?.themeConfig?.nav;
|
|
234
|
+
|
|
235
|
+
if (isUndefined(nav)) {
|
|
236
|
+
consola.error(` 当前的用户配置为: `, userConfig);
|
|
237
|
+
throw new Error(` nav 默认提供的导航栏配置为空。不符合默认配置,请检查。 `);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
nav.push({ text: "提示词", link: `/${PROMPTS_INDEX_MD_PATH}` });
|
|
241
|
+
}
|
package/src/config.mts
CHANGED
|
@@ -9,20 +9,15 @@ import { merge, isUndefined, cloneDeep } from "lodash-es";
|
|
|
9
9
|
import consola from "consola";
|
|
10
10
|
import type { ExtraConfig } from "./types.ts";
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
copyReadmeMd,
|
|
16
|
-
copyClaudeAgents,
|
|
17
|
-
copyChangelogMd,
|
|
18
|
-
} from "@ruan-cat/utils/node-esm";
|
|
19
|
-
export { addChangelog2doc, copyReadmeMd, copyClaudeAgents, copyChangelogMd };
|
|
12
|
+
// import { addChangelog2doc, copyReadmeMd, copyClaudeAgents } from "@ruan-cat/utils/node-esm";
|
|
13
|
+
import { addChangelog2doc, copyReadmeMd, copyClaudeAgents } from "./config/index.ts";
|
|
14
|
+
export { addChangelog2doc, copyReadmeMd, copyClaudeAgents };
|
|
20
15
|
|
|
21
16
|
import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
|
|
22
17
|
|
|
23
18
|
import llmstxt, { copyOrDownloadAsMarkdownButtons } from "vitepress-plugin-llms";
|
|
24
19
|
|
|
25
|
-
import { defaultTeekConfig, handleTeekConfig, handlePlugins } from "./config/index.ts";
|
|
20
|
+
import { defaultTeekConfig, handleTeekConfig, handlePlugins, handleChangeLog, handlePrompts } from "./config/index.ts";
|
|
26
21
|
|
|
27
22
|
/** @see https://vitepress-ext.leelaa.cn/Mermaid.html#扩展-md-插件 */
|
|
28
23
|
import { MermaidPlugin } from "@leelaa/vitepress-plugin-extended";
|
|
@@ -180,30 +175,6 @@ const defaultUserConfig: UserConfig<DefaultTheme.Config> = {
|
|
|
180
175
|
},
|
|
181
176
|
};
|
|
182
177
|
|
|
183
|
-
/**
|
|
184
|
-
* 设置导航栏的变更日志
|
|
185
|
-
* @description
|
|
186
|
-
* 在导航栏内添加一行 变更日志 的入口
|
|
187
|
-
*
|
|
188
|
-
* 直接修改外部传递进来的配置对象即可
|
|
189
|
-
* @private 内部使用即可
|
|
190
|
-
*/
|
|
191
|
-
function handleChangeLog(userConfig: UserConfig<DefaultTheme.Config>) {
|
|
192
|
-
if (!hasChangelogMd()) {
|
|
193
|
-
consola.warn(` 未找到变更日志文件,不添加变更日志导航栏。 `);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const nav = userConfig?.themeConfig?.nav;
|
|
198
|
-
|
|
199
|
-
if (isUndefined(nav)) {
|
|
200
|
-
consola.error(` 当前的用户配置为: `, userConfig);
|
|
201
|
-
throw new Error(` nav 默认提供的导航栏配置为空。不符合默认配置,请检查。 `);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
nav.push({ text: "更新日志", link: "/CHANGELOG.md" });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
178
|
/** 设置vitepress主配置 */
|
|
208
179
|
export function setUserConfig(
|
|
209
180
|
config?: UserConfig<DefaultTheme.Config>,
|
|
@@ -212,7 +183,10 @@ export function setUserConfig(
|
|
|
212
183
|
/** 最终的用户数据 */
|
|
213
184
|
const resUserConfig = merge({}, cloneDeep(defaultUserConfig), isUndefined(config) ? {} : config);
|
|
214
185
|
|
|
215
|
-
//
|
|
186
|
+
// 处理提示词导航栏
|
|
187
|
+
handlePrompts(resUserConfig);
|
|
188
|
+
|
|
189
|
+
// 处理变更日志导航栏
|
|
216
190
|
handleChangeLog(resUserConfig);
|
|
217
191
|
|
|
218
192
|
// 设置插件
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
|
|
5
|
+
/** 检查当前运行的根目录 是否存在 CHANGELOG.md 文件 */
|
|
6
|
+
export function hasChangelogMd() {
|
|
7
|
+
const res = fs.existsSync(path.resolve(process.cwd(), "CHANGELOG.md"));
|
|
8
|
+
if (!res) {
|
|
9
|
+
consola.log("当前项目根目录为:", process.cwd());
|
|
10
|
+
consola.warn("当前项目根目录不存在 CHANGELOG.md 文件");
|
|
11
|
+
}
|
|
12
|
+
return res;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 将 CHANGELOG.md 文件移动到指定要求的位置内
|
|
17
|
+
* @description
|
|
18
|
+
* 该函数相当于实现 `cpx CHANGELOG.md docs` 命令
|
|
19
|
+
*/
|
|
20
|
+
export function copyChangelogMd(/** 目标文件夹 */ target: string) {
|
|
21
|
+
if (!hasChangelogMd()) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const source = path.resolve(process.cwd(), "CHANGELOG.md");
|
|
26
|
+
const destination = path.resolve(process.cwd(), target, "CHANGELOG.md");
|
|
27
|
+
|
|
28
|
+
fs.copyFileSync(source, destination);
|
|
29
|
+
}
|