@anren-utils/mcp-audit 1.0.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/.editorconfig +13 -0
- package/dist/audit/auditUtils.d.ts +12 -0
- package/dist/audit/auditUtils.d.ts.map +1 -0
- package/dist/audit/auditUtils.js +22 -0
- package/dist/audit/auditUtils.js.map +1 -0
- package/dist/audit/currentAudit.d.ts +53 -0
- package/dist/audit/currentAudit.d.ts.map +1 -0
- package/dist/audit/currentAudit.js +54 -0
- package/dist/audit/currentAudit.js.map +1 -0
- package/dist/audit/getDepChain.d.ts +16 -0
- package/dist/audit/getDepChain.d.ts.map +1 -0
- package/dist/audit/getDepChain.js +60 -0
- package/dist/audit/getDepChain.js.map +1 -0
- package/dist/audit/index.d.ts +11 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +64 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/normalizeAuditResult.d.ts +13 -0
- package/dist/audit/normalizeAuditResult.d.ts.map +1 -0
- package/dist/audit/normalizeAuditResult.js +81 -0
- package/dist/audit/normalizeAuditResult.js.map +1 -0
- package/dist/audit/remoteAudit.d.ts +3 -0
- package/dist/audit/remoteAudit.d.ts.map +1 -0
- package/dist/audit/remoteAudit.js +24 -0
- package/dist/audit/remoteAudit.js.map +1 -0
- package/dist/generateLock/index.d.ts +17 -0
- package/dist/generateLock/index.d.ts.map +1 -0
- package/dist/generateLock/index.js +141 -0
- package/dist/generateLock/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpServer.d.ts +2 -0
- package/dist/mcpServer.d.ts.map +1 -0
- package/dist/mcpServer.js +34 -0
- package/dist/mcpServer.js.map +1 -0
- package/dist/parseProject/detectPackageManager.d.ts +8 -0
- package/dist/parseProject/detectPackageManager.d.ts.map +1 -0
- package/dist/parseProject/detectPackageManager.js +22 -0
- package/dist/parseProject/detectPackageManager.js.map +1 -0
- package/dist/parseProject/index.d.ts +11 -0
- package/dist/parseProject/index.d.ts.map +1 -0
- package/dist/parseProject/index.js +20 -0
- package/dist/parseProject/index.js.map +1 -0
- package/dist/parseProject/parseLocalProject.d.ts +17 -0
- package/dist/parseProject/parseLocalProject.d.ts.map +1 -0
- package/dist/parseProject/parseLocalProject.js +28 -0
- package/dist/parseProject/parseLocalProject.js.map +1 -0
- package/dist/parseProject/parseLocalWorkspace.d.ts +2 -0
- package/dist/parseProject/parseLocalWorkspace.d.ts.map +1 -0
- package/dist/parseProject/parseLocalWorkspace.js +2 -0
- package/dist/parseProject/parseLocalWorkspace.js.map +1 -0
- package/dist/parseProject/parseRemoteProject.d.ts +41 -0
- package/dist/parseProject/parseRemoteProject.d.ts.map +1 -0
- package/dist/parseProject/parseRemoteProject.js +180 -0
- package/dist/parseProject/parseRemoteProject.js.map +1 -0
- package/dist/parseProject/parseRemoteWorkspace.d.ts +2 -0
- package/dist/parseProject/parseRemoteWorkspace.d.ts.map +1 -0
- package/dist/parseProject/parseRemoteWorkspace.js +2 -0
- package/dist/parseProject/parseRemoteWorkspace.js.map +1 -0
- package/dist/parseProject/parseWorkspace.d.ts +19 -0
- package/dist/parseProject/parseWorkspace.d.ts.map +1 -0
- package/dist/parseProject/parseWorkspace.js +140 -0
- package/dist/parseProject/parseWorkspace.js.map +1 -0
- package/dist/render/index.d.ts +9 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +24 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/markdown.d.ts +12 -0
- package/dist/render/markdown.d.ts.map +1 -0
- package/dist/render/markdown.js +16 -0
- package/dist/render/markdown.js.map +1 -0
- package/dist/render/template/audit.ejs +30 -0
- package/dist/render/template/detail-item.ejs +32 -0
- package/dist/render/template/detail.ejs +7 -0
- package/dist/render/template/index.ejs +8 -0
- package/dist/types.d.ts +371 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/dirUtils.d.ts +11 -0
- package/dist/utils/dirUtils.d.ts.map +1 -0
- package/dist/utils/dirUtils.js +28 -0
- package/dist/utils/dirUtils.js.map +1 -0
- package/dist/utils/index.d.ts +34 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +74 -0
- package/dist/utils/index.js.map +1 -0
- package/eslint.config.js +38 -0
- package/package.json +38 -0
- package/src/audit/auditUtils.ts +24 -0
- package/src/audit/currentAudit.ts +116 -0
- package/src/audit/getDepChain.ts +71 -0
- package/src/audit/index.ts +90 -0
- package/src/audit/normalizeAuditResult.ts +99 -0
- package/src/audit/remoteAudit.ts +26 -0
- package/src/generateLock/index.ts +203 -0
- package/src/index.ts +48 -0
- package/src/mcpServer.ts +43 -0
- package/src/parseProject/detectPackageManager.ts +24 -0
- package/src/parseProject/index.ts +20 -0
- package/src/parseProject/parseLocalProject.ts +39 -0
- package/src/parseProject/parseRemoteProject.ts +225 -0
- package/src/parseProject/parseWorkspace.ts +202 -0
- package/src/render/index.ts +30 -0
- package/src/render/markdown.ts +29 -0
- package/src/render/template/audit.ejs +30 -0
- package/src/render/template/detail-item.ejs +32 -0
- package/src/render/template/detail.ejs +7 -0
- package/src/render/template/index.ejs +8 -0
- package/src/types.ts +429 -0
- package/src/utils/dirUtils.ts +31 -0
- package/src/utils/index.ts +88 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { getReadFileUrl, runCommand } from "../utils/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* @Desc: 处理 package.json 中的 workspace 依赖
|
|
6
|
+
* @param {Object} packageJson package.json文件内容
|
|
7
|
+
* @returns {Object} 处理后的 package.json 文件内容
|
|
8
|
+
*/
|
|
9
|
+
function processPackageJson(packageJson) {
|
|
10
|
+
// 深拷贝 packageJson 以避免修改原始对象
|
|
11
|
+
const processedPackageJson = JSON.parse(JSON.stringify(packageJson));
|
|
12
|
+
// 处理 dependencies
|
|
13
|
+
if (processedPackageJson.dependencies) {
|
|
14
|
+
for (const [key, value] of Object.entries(processedPackageJson.dependencies)) {
|
|
15
|
+
if (typeof value === "string" && value.startsWith("workspace:")) {
|
|
16
|
+
delete processedPackageJson.dependencies[key];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// 处理 devDependencies
|
|
21
|
+
if (processedPackageJson.devDependencies) {
|
|
22
|
+
for (const [key, value] of Object.entries(processedPackageJson.devDependencies)) {
|
|
23
|
+
if (typeof value === "string" && value.startsWith("workspace:")) {
|
|
24
|
+
delete processedPackageJson.devDependencies[key];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 处理 peerDependencies
|
|
29
|
+
if (processedPackageJson.peerDependencies) {
|
|
30
|
+
for (const [key, value] of Object.entries(processedPackageJson.peerDependencies)) {
|
|
31
|
+
if (typeof value === "string" && value.startsWith("workspace:")) {
|
|
32
|
+
delete processedPackageJson.peerDependencies[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// 处理 optionalDependencies
|
|
37
|
+
if (processedPackageJson.optionalDependencies) {
|
|
38
|
+
for (const [key, value] of Object.entries(processedPackageJson.optionalDependencies)) {
|
|
39
|
+
if (typeof value === "string" && value.startsWith("workspace:")) {
|
|
40
|
+
delete processedPackageJson.optionalDependencies[key];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return processedPackageJson;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @Desc: 根据子包的信息,生成子包的package.json文件
|
|
48
|
+
* @param {string} workDir 工作目录
|
|
49
|
+
* @param {string} projectRoot 项目根目录
|
|
50
|
+
* @param {RemoteWorkspaceInfo} subPackageInfos 子包信息
|
|
51
|
+
*/
|
|
52
|
+
async function writeSubPackageJson(workDir, projectRoot, subPackageInfos) {
|
|
53
|
+
const { gitInfo, branchName, subPackageNames } = subPackageInfos;
|
|
54
|
+
// 根据subPackageNames,在workDir下创建子包目录并写入package.json文件
|
|
55
|
+
const dirPaths = subPackageNames.map((subPackageName) => join(workDir, subPackageName));
|
|
56
|
+
// 创建子包目录
|
|
57
|
+
dirPaths.forEach((dirPath) => {
|
|
58
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
59
|
+
});
|
|
60
|
+
if (gitInfo && branchName) {
|
|
61
|
+
for (const subPackageName of subPackageNames) {
|
|
62
|
+
const filePath = subPackageName + "/package.json";
|
|
63
|
+
const packageJsonUrl = getReadFileUrl(gitInfo, branchName, filePath);
|
|
64
|
+
const subPackageJson = (await fetch(packageJsonUrl).then((resp) => resp.json()));
|
|
65
|
+
// 处理 package.json 中的 workspace 依赖
|
|
66
|
+
const processedPackageJson = processPackageJson(subPackageJson);
|
|
67
|
+
const packageJsonPath = join(workDir, subPackageName, "package.json");
|
|
68
|
+
// 将处理后的 packageJson 写入文件
|
|
69
|
+
await fs.promises.writeFile(packageJsonPath, JSON.stringify(processedPackageJson), "utf8");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// 解析本地工程根目录下的package.json文件
|
|
74
|
+
for (const subPackageName of subPackageNames) {
|
|
75
|
+
const subPackageJsonPath = join(projectRoot, subPackageName, "package.json");
|
|
76
|
+
const subPackageJson = await fs.promises.readFile(subPackageJsonPath, "utf8");
|
|
77
|
+
const processedPackageJson = processPackageJson(JSON.parse(subPackageJson));
|
|
78
|
+
await fs.promises.writeFile(join(workDir, subPackageName, "package.json"), JSON.stringify(processedPackageJson), "utf8");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* @Desc: 向工作目录添加package.json文件
|
|
84
|
+
* @param {string} workDir 工作目录
|
|
85
|
+
* @param {Object} packageJson package.json文件内容
|
|
86
|
+
*/
|
|
87
|
+
async function writePackageJson(options) {
|
|
88
|
+
const { workDir, packageJson, subPackageInfos, projectRoot } = options;
|
|
89
|
+
const packageJsonPath = join(workDir, "package.json");
|
|
90
|
+
fs.mkdirSync(dirname(packageJsonPath), { recursive: true });
|
|
91
|
+
if (subPackageInfos?.subPackageNames) {
|
|
92
|
+
// 处理 package.json 中的 workspace 依赖
|
|
93
|
+
const processedPackageJson = processPackageJson(packageJson);
|
|
94
|
+
// 处理子包
|
|
95
|
+
await writeSubPackageJson(workDir, projectRoot, subPackageInfos);
|
|
96
|
+
// 将处理后的 packageJson 写入文件
|
|
97
|
+
await fs.promises.writeFile(packageJsonPath, JSON.stringify(processedPackageJson), "utf8");
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageJson), "utf8");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @Desc: 在指定工作目录中生成lock文件
|
|
105
|
+
* @param {string} workDir 工作目录
|
|
106
|
+
*/
|
|
107
|
+
async function createLockFile(workDir, subPackageInfos, currentPackageManager) {
|
|
108
|
+
// 只支持pnpm和npm
|
|
109
|
+
if (!subPackageInfos) {
|
|
110
|
+
const cmd = "npm install --package-lock-only --force";
|
|
111
|
+
// 在工作目录中执行命令
|
|
112
|
+
await runCommand(cmd, workDir);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const { subPackageNames } = subPackageInfos;
|
|
116
|
+
const cmd = currentPackageManager === "pnpm"
|
|
117
|
+
? `pnpm install --lockfile-only`
|
|
118
|
+
: `npm install --package-lock-only --force`;
|
|
119
|
+
// 在不同的工作目录中执行命令
|
|
120
|
+
for (const subPackageName of subPackageNames) {
|
|
121
|
+
const subPackageDir = join(workDir, subPackageName);
|
|
122
|
+
await runCommand(cmd, subPackageDir);
|
|
123
|
+
}
|
|
124
|
+
// 最后在工作目录中执行命令
|
|
125
|
+
await runCommand(cmd, workDir);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* @Desc: 向工作目录添加package.json文件,然后生成lock文件
|
|
130
|
+
* @param {string} workDir 工作目录
|
|
131
|
+
* @param {Object} packageJson package.json文件内容
|
|
132
|
+
*/
|
|
133
|
+
export async function generateLock(options) {
|
|
134
|
+
const { workDir, subPackageInfos, currentPackageManager } = options;
|
|
135
|
+
// 1. 将 package.json 写入工作目录
|
|
136
|
+
// NOTE:不管是npm还是pnpm,package.json文件基本都是相同的
|
|
137
|
+
await writePackageJson(options);
|
|
138
|
+
// 2. 生成 lock 文件
|
|
139
|
+
await createLockFile(workDir, subPackageInfos, currentPackageManager);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generateLock/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 根据项目根目录,审计项目中所有的包(含项目本身)
|
|
3
|
+
* @param {string} projectRoot 项目根目录,可以是本地目录的绝对路径,也可以是远程仓库的URL
|
|
4
|
+
* @param {string} savePath 保存审计结果的文件名,审计结果是一个标准格式的markdown字符串
|
|
5
|
+
*/
|
|
6
|
+
export declare function auditProject(projectRoot: string, savePath: string): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,iBAiCvE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { audit } from "./audit/index.js";
|
|
2
|
+
import { generateLock } from "./generateLock/index.js";
|
|
3
|
+
import { detectPackageManager } from "./parseProject/detectPackageManager.js";
|
|
4
|
+
import { parseProject } from "./parseProject/index.js";
|
|
5
|
+
import { parseWorkspace } from "./parseProject/parseWorkspace.js";
|
|
6
|
+
import { render } from "./render/index.js";
|
|
7
|
+
import { createWorkDir, deleteWorkDir } from "./utils/dirUtils.js";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
/**
|
|
10
|
+
* 根据项目根目录,审计项目中所有的包(含项目本身)
|
|
11
|
+
* @param {string} projectRoot 项目根目录,可以是本地目录的绝对路径,也可以是远程仓库的URL
|
|
12
|
+
* @param {string} savePath 保存审计结果的文件名,审计结果是一个标准格式的markdown字符串
|
|
13
|
+
*/
|
|
14
|
+
export async function auditProject(projectRoot, savePath) {
|
|
15
|
+
// 1. 创建工作目录
|
|
16
|
+
const workDir = await createWorkDir();
|
|
17
|
+
// 2. 判断项目的包管理器类型
|
|
18
|
+
const currentPackageManager = detectPackageManager(projectRoot);
|
|
19
|
+
// 3. 解析项目的package.json文件
|
|
20
|
+
const packageJson = await parseProject(projectRoot);
|
|
21
|
+
// 4· 判断项目是否是monorepo工程
|
|
22
|
+
const subPackageInfos = await parseWorkspace({
|
|
23
|
+
projectRoot,
|
|
24
|
+
packageJsonRoot: packageJson,
|
|
25
|
+
});
|
|
26
|
+
// 5. 向工作目录添加package.json文件,然后生成lock文件
|
|
27
|
+
await generateLock({
|
|
28
|
+
workDir,
|
|
29
|
+
packageJson,
|
|
30
|
+
subPackageInfos,
|
|
31
|
+
projectRoot,
|
|
32
|
+
currentPackageManager,
|
|
33
|
+
});
|
|
34
|
+
// 6. 对工作目录进行审计
|
|
35
|
+
const auditResult = await audit({
|
|
36
|
+
workDir,
|
|
37
|
+
packageJson,
|
|
38
|
+
subPackageInfos,
|
|
39
|
+
currentPackageManager,
|
|
40
|
+
});
|
|
41
|
+
// 7. 渲染审计结果
|
|
42
|
+
const renderedResult = await render(auditResult, packageJson);
|
|
43
|
+
// 8. 删除工作目录
|
|
44
|
+
await deleteWorkDir(workDir);
|
|
45
|
+
// 9. 将结果保存到指定路径
|
|
46
|
+
await fs.promises.writeFile(savePath, renderedResult);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB,EAAE,QAAgB;IACtE,YAAY;IACZ,MAAM,OAAO,GAAG,MAAM,aAAa,EAAE,CAAC;IACtC,iBAAiB;IACjB,MAAM,qBAAqB,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAChE,yBAAyB;IACzB,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;IACpD,uBAAuB;IACvB,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC;QAC3C,WAAW;QACX,eAAe,EAAE,WAAW;KAC7B,CAAC,CAAC;IACH,sCAAsC;IACtC,MAAM,YAAY,CAAC;QACjB,OAAO;QACP,WAAW;QACX,eAAe;QACf,WAAW;QACX,qBAAqB;KACtB,CAAC,CAAC;IACH,eAAe;IACf,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC;QAC9B,OAAO;QACP,WAAW;QACX,eAAe;QACf,qBAAqB;KACtB,CAAC,CAAC;IACH,YAAY;IACZ,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9D,YAAY;IACZ,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IAC7B,gBAAgB;IAChB,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpServer.d.ts","sourceRoot":"","sources":["../src/mcpServer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { auditProject } from "./index.js";
|
|
5
|
+
const server = new McpServer({
|
|
6
|
+
name: "audit-server",
|
|
7
|
+
title: "前端工程安全审计服务",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
server.registerTool("auditProject", {
|
|
11
|
+
title: "审计前端工程",
|
|
12
|
+
description: "审计前端工程的所有直接和间接依赖,得到安全审计结果。支持本地工程的审计,也支持远程仓库的审计。审计结果为标准格式的markdown字符串,不用修改,直接用于展示即可。",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
projectRoot: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("本地工程的根路径,或者远程仓库的URL地址"),
|
|
17
|
+
savePath: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("保存审计结果的路径,传递当前工程的根路径下的工程明audit.md,如果没有当前工程,则传递桌面路径下的audit.md(注意,桌面路径必须传入绝对路径)"),
|
|
20
|
+
},
|
|
21
|
+
}, async ({ projectRoot, savePath }) => {
|
|
22
|
+
await auditProject(projectRoot, savePath);
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `审计完成,结果已保存到: ${savePath}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
server.connect(transport);
|
|
34
|
+
//# sourceMappingURL=mcpServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpServer.js","sourceRoot":"","sources":["../src/mcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,YAAY;IACnB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;IACE,KAAK,EAAE,QAAQ;IACf,WAAW,EACT,qFAAqF;IACvF,WAAW,EAAE;QACX,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,CAAC,uBAAuB,CAAC;QACpC,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CACP,+EAA+E,CAChF;KACJ;CACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;IAClC,MAAM,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC1C,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,gBAAgB,QAAQ,EAAE;aACjC;SACF;KACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PackageManager } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 检测当前项目使用的包管理器
|
|
4
|
+
* @param projectRoot - 项目根目录
|
|
5
|
+
* @returns 'npm' | 'pnpm' | 'yarn',默认返回 'npm'
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectPackageManager(projectRoot: string): PackageManager;
|
|
8
|
+
//# sourceMappingURL=detectPackageManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectPackageManager.d.ts","sourceRoot":"","sources":["../../src/parseProject/detectPackageManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAcxE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* 检测当前项目使用的包管理器
|
|
5
|
+
* @param projectRoot - 项目根目录
|
|
6
|
+
* @returns 'npm' | 'pnpm' | 'yarn',默认返回 'npm'
|
|
7
|
+
*/
|
|
8
|
+
export function detectPackageManager(projectRoot) {
|
|
9
|
+
// 检查锁文件
|
|
10
|
+
if (fs.existsSync(path.join(projectRoot, "pnpm-lock.yaml"))) {
|
|
11
|
+
return "pnpm";
|
|
12
|
+
}
|
|
13
|
+
if (fs.existsSync(path.join(projectRoot, "package-lock.json"))) {
|
|
14
|
+
return "npm";
|
|
15
|
+
}
|
|
16
|
+
if (fs.existsSync(path.join(projectRoot, "yarn.lock"))) {
|
|
17
|
+
return "yarn";
|
|
18
|
+
}
|
|
19
|
+
// 默认返回 npm 作为兜底
|
|
20
|
+
return "npm";
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=detectPackageManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectPackageManager.js","sourceRoot":"","sources":["../../src/parseProject/detectPackageManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,QAAQ;IACR,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,gBAAgB;IAChB,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析工程根目录下的package.json文件,得到文件内容
|
|
3
|
+
* @param {string} projectRoot 工程本地的根目录或远程仓库的URL
|
|
4
|
+
* @example
|
|
5
|
+
* parseProject('/path/to/local/project');
|
|
6
|
+
* parseProject('https://github.com/webpack/webpack');
|
|
7
|
+
* @returns {Promise<Object>} 返回解析后的package.json内容
|
|
8
|
+
* @throws {Error} 如果解析失败或文件不存在
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseProject(projectRoot: string): Promise<import("../types.js").PackageJsonInfo>;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parseProject/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,kDAO/C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseLocalProject } from "./parseLocalProject.js";
|
|
2
|
+
import { parseRemoteProject } from "./parseRemoteProject.js";
|
|
3
|
+
/**
|
|
4
|
+
* 解析工程根目录下的package.json文件,得到文件内容
|
|
5
|
+
* @param {string} projectRoot 工程本地的根目录或远程仓库的URL
|
|
6
|
+
* @example
|
|
7
|
+
* parseProject('/path/to/local/project');
|
|
8
|
+
* parseProject('https://github.com/webpack/webpack');
|
|
9
|
+
* @returns {Promise<Object>} 返回解析后的package.json内容
|
|
10
|
+
* @throws {Error} 如果解析失败或文件不存在
|
|
11
|
+
*/
|
|
12
|
+
export function parseProject(projectRoot) {
|
|
13
|
+
// 分辨是本地工程还是远程仓库
|
|
14
|
+
if (projectRoot.startsWith("http://") || projectRoot.startsWith("https://")) {
|
|
15
|
+
// 远程项目
|
|
16
|
+
return parseRemoteProject(projectRoot);
|
|
17
|
+
}
|
|
18
|
+
return parseLocalProject(projectRoot);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parseProject/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,gBAAgB;IAChB,IAAI,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5E,OAAO;QACP,OAAO,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PackageJsonInfo } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* @Desc: 解析本地工程根目录下的package.json文件
|
|
4
|
+
* @param {string} projectRoot 本地工程的根目录
|
|
5
|
+
* @return {Promise<Object>} 返回解析后的package.json内容
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseLocalProject(projectRoot: string): Promise<PackageJsonInfo>;
|
|
8
|
+
/**
|
|
9
|
+
* @Desc: 解析本地monorepo工程根目录下的package.json文件
|
|
10
|
+
* @param {string} projectRoot 本地工程的根目录
|
|
11
|
+
* @param {string[]} workspaceNames 工作空间名称列表,每个元素为一个子包的名称
|
|
12
|
+
* @return {Promise<Object[]>} 返回解析后的package.json内容列表
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseMonorepoProject(projectRoot: string, workspaceNames: string[]): Promise<{
|
|
15
|
+
[x: string]: Object;
|
|
16
|
+
}[]>;
|
|
17
|
+
//# sourceMappingURL=parseLocalProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseLocalProject.d.ts","sourceRoot":"","sources":["../../src/parseProject/parseLocalProject.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,4BAI1D;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EAAE;;KAezB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
/**
|
|
4
|
+
* @Desc: 解析本地工程根目录下的package.json文件
|
|
5
|
+
* @param {string} projectRoot 本地工程的根目录
|
|
6
|
+
* @return {Promise<Object>} 返回解析后的package.json内容
|
|
7
|
+
*/
|
|
8
|
+
export async function parseLocalProject(projectRoot) {
|
|
9
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
10
|
+
const json = await fs.promises.readFile(packageJsonPath, "utf8");
|
|
11
|
+
return JSON.parse(json);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @Desc: 解析本地monorepo工程根目录下的package.json文件
|
|
15
|
+
* @param {string} projectRoot 本地工程的根目录
|
|
16
|
+
* @param {string[]} workspaceNames 工作空间名称列表,每个元素为一个子包的名称
|
|
17
|
+
* @return {Promise<Object[]>} 返回解析后的package.json内容列表
|
|
18
|
+
*/
|
|
19
|
+
export async function parseMonorepoProject(projectRoot, workspaceNames) {
|
|
20
|
+
// 获取workspaceNames对应的package.json文件内容
|
|
21
|
+
const packageJsonList = await Promise.all(workspaceNames.map(async (workspaceName) => {
|
|
22
|
+
const packageJsonPath = path.join(projectRoot, workspaceName, "package.json");
|
|
23
|
+
const json = await fs.promises.readFile(packageJsonPath, "utf8");
|
|
24
|
+
return { [workspaceName]: JSON.parse(json) };
|
|
25
|
+
}));
|
|
26
|
+
return packageJsonList;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=parseLocalProject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseLocalProject.js","sourceRoot":"","sources":["../../src/parseProject/parseLocalProject.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IACzD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,cAAwB;IAExB,sCAAsC;IACtC,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE;QACzC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAC/B,WAAW,EACX,aAAa,EACb,cAAc,CACf,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;QACjE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAW,EAAE,CAAC;IACzD,CAAC,CAAC,CACH,CAAC;IACF,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseLocalWorkspace.d.ts","sourceRoot":"","sources":["../../src/parseProject/parseLocalWorkspace.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseLocalWorkspace.js","sourceRoot":"","sources":["../../src/parseProject/parseLocalWorkspace.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PackageJsonInfo } from "../types.js";
|
|
2
|
+
export interface RemoteProjectUrlInfo {
|
|
3
|
+
owner: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
path: string;
|
|
6
|
+
platform: string;
|
|
7
|
+
originalUrl: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PackageJsonUrlInfo {
|
|
10
|
+
branchName: string;
|
|
11
|
+
packageJsonUrl: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 解析 Git 仓库 URL,提取 owner、repo、platform 和后续路径
|
|
15
|
+
* 支持格式:
|
|
16
|
+
* - https://github.com/owner/repo
|
|
17
|
+
* - https://github.com/owner/repo/tree/branch
|
|
18
|
+
* - https://github.com/owner/repo/blame
|
|
19
|
+
* - https://gitee.com/he_kai1/creat-exam-ts
|
|
20
|
+
* - https://gitee.com/he_kai1/creat-exam-ts/tree/dev/
|
|
21
|
+
* - https://gitlab.com/owner/repo
|
|
22
|
+
* - https://gitlab.com/owner/repo/-/tree/branch
|
|
23
|
+
* - ...
|
|
24
|
+
* @param {string} url - Git 仓库 URL
|
|
25
|
+
* @returns {Object} { owner, repo, path, platform, originalUrl }
|
|
26
|
+
* @throws {Error} 如果 URL 格式不合法或无法解析
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseGitUrl(url: string): RemoteProjectUrlInfo;
|
|
29
|
+
/**
|
|
30
|
+
* @Desc: 获取 Git 仓库的 package.json URL
|
|
31
|
+
* @return {string} package.json 的 URL
|
|
32
|
+
* @param {Object} gitUrlInfo - 解析后的 Git 仓库信息 { owner, repo, path, platform }
|
|
33
|
+
*/
|
|
34
|
+
export declare function getPackageJsonUrl(gitUrlInfo: RemoteProjectUrlInfo): Promise<PackageJsonUrlInfo>;
|
|
35
|
+
/**
|
|
36
|
+
* @Desc: 获取远程仓库的 package.json文件内容
|
|
37
|
+
* @return {*}
|
|
38
|
+
* @param {string} gitUrl
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseRemoteProject(gitUrl: string): Promise<PackageJsonInfo>;
|
|
41
|
+
//# sourceMappingURL=parseRemoteProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseRemoteProject.d.ts","sourceRoot":"","sources":["../../src/parseProject/parseRemoteProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,wBAgDtC;AAkFD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,oBAAoB,+BAYvE;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,4BAOtD"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析 Git 仓库 URL,提取 owner、repo、platform 和后续路径
|
|
3
|
+
* 支持格式:
|
|
4
|
+
* - https://github.com/owner/repo
|
|
5
|
+
* - https://github.com/owner/repo/tree/branch
|
|
6
|
+
* - https://github.com/owner/repo/blame
|
|
7
|
+
* - https://gitee.com/he_kai1/creat-exam-ts
|
|
8
|
+
* - https://gitee.com/he_kai1/creat-exam-ts/tree/dev/
|
|
9
|
+
* - https://gitlab.com/owner/repo
|
|
10
|
+
* - https://gitlab.com/owner/repo/-/tree/branch
|
|
11
|
+
* - ...
|
|
12
|
+
* @param {string} url - Git 仓库 URL
|
|
13
|
+
* @returns {Object} { owner, repo, path, platform, originalUrl }
|
|
14
|
+
* @throws {Error} 如果 URL 格式不合法或无法解析
|
|
15
|
+
*/
|
|
16
|
+
export function parseGitUrl(url) {
|
|
17
|
+
try {
|
|
18
|
+
const parsedUrl = new URL(url);
|
|
19
|
+
const hostname = parsedUrl.hostname;
|
|
20
|
+
// 确定平台
|
|
21
|
+
let platform;
|
|
22
|
+
if (hostname === "github.com" || hostname.endsWith(".github.com")) {
|
|
23
|
+
platform = "github";
|
|
24
|
+
}
|
|
25
|
+
else if (hostname === "gitee.com" || hostname.endsWith(".gitee.com")) {
|
|
26
|
+
platform = "gitee";
|
|
27
|
+
}
|
|
28
|
+
else if (hostname === "gitlab.com" || hostname.endsWith(".gitlab.com")) {
|
|
29
|
+
platform = "gitlab";
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
platform = "unknown";
|
|
33
|
+
}
|
|
34
|
+
// 获取路径并去除空字符串(如开头的 /)
|
|
35
|
+
const parts = parsedUrl.pathname.split("/").filter(Boolean);
|
|
36
|
+
// 至少需要 owner(项目所属者) 和 repo(项目名称) 两段
|
|
37
|
+
// https://github.com/anren-hk/slt-erp
|
|
38
|
+
if (parts.length < 2) {
|
|
39
|
+
throw new Error("Invalid repository URL: insufficient path segments");
|
|
40
|
+
}
|
|
41
|
+
const owner = parts[0];
|
|
42
|
+
const repo = parts[1];
|
|
43
|
+
// https://github.com/anren-hk/webpack-vue-create/tree/gh-pages
|
|
44
|
+
const restPath = parts.slice(2); // 剩余路径,如 ['tree', 'v5.2.2'],即分支名称或者版本号
|
|
45
|
+
// 构造 path:如果有后续路径,则以 '/' 开头拼接;否则为空字符串
|
|
46
|
+
const path = restPath.length > 0 ? "/" + restPath.join("/") : "";
|
|
47
|
+
const projectUrlInfo = {
|
|
48
|
+
owner,
|
|
49
|
+
repo,
|
|
50
|
+
path,
|
|
51
|
+
platform,
|
|
52
|
+
originalUrl: url,
|
|
53
|
+
};
|
|
54
|
+
return projectUrlInfo;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof TypeError) {
|
|
58
|
+
throw new Error("Invalid URL: malformed or missing");
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @Desc: 获取 GitHub 仓库的 package.json URL
|
|
65
|
+
*/
|
|
66
|
+
async function getGithubPackageJsonUrl(projectUrlInfo) {
|
|
67
|
+
const { owner, repo, path } = projectUrlInfo;
|
|
68
|
+
let branchName;
|
|
69
|
+
// 如果path以 /tree/ 开头,则表示是分支路径,如 /tree/v5.2.2或者/tree/dev,则取分支名称 v5.2.2
|
|
70
|
+
if (path.startsWith("/tree/")) {
|
|
71
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
72
|
+
branchName = pathParts[1];
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// 通过 API 获取仓库信息,获取默认分支名称
|
|
76
|
+
const url = `https://api.github.com/repos/${owner}/${repo}`;
|
|
77
|
+
const info = (await fetch(url).then((resp) => resp.json()));
|
|
78
|
+
branchName = info.default_branch;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
branchName,
|
|
82
|
+
packageJsonUrl: `https://raw.githubusercontent.com/${owner}/${repo}/${branchName}/package.json`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* @Desc: 获取 Gitee 仓库的 package.json URL
|
|
87
|
+
*/
|
|
88
|
+
async function getGiteePackageJsonUrl(projectUrlInfo) {
|
|
89
|
+
const { owner, repo, path } = projectUrlInfo;
|
|
90
|
+
let branchName;
|
|
91
|
+
if (path.startsWith("/tree/")) {
|
|
92
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
93
|
+
branchName = pathParts[1];
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// 通过 API 获取仓库信息,获取默认分支名称
|
|
97
|
+
const url = `https://gitee.com/api/v5/repos/${owner}/${repo}`;
|
|
98
|
+
const info = (await fetch(url).then((resp) => resp.json()));
|
|
99
|
+
branchName = info.default_branch;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
branchName,
|
|
103
|
+
packageJsonUrl: `https://gitee.com/${owner}/${repo}/raw/${branchName}/package.json`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @Desc: 获取 GitLab 仓库的 package.json URL
|
|
108
|
+
*/
|
|
109
|
+
async function getGitlabPackageJsonUrl(projectUrlInfo) {
|
|
110
|
+
const { owner, repo, path } = projectUrlInfo;
|
|
111
|
+
let branchName;
|
|
112
|
+
if (path.startsWith("/tree/")) {
|
|
113
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
114
|
+
branchName = `${pathParts[1]}`;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// 通过 API 获取仓库信息,获取默认分支名称
|
|
118
|
+
// TODO:地址可能有问题
|
|
119
|
+
const url = `https://gitlab.com/api/v4/projects/${owner}/${repo}`;
|
|
120
|
+
const info = (await fetch(url).then((resp) => resp.json()));
|
|
121
|
+
branchName = info.default_branch;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
branchName,
|
|
125
|
+
packageJsonUrl: `https://gitlab.com/${owner}/${repo}/-/raw/${branchName}/package.json`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* @Desc: 获取 Git 仓库的 package.json URL
|
|
130
|
+
* @return {string} package.json 的 URL
|
|
131
|
+
* @param {Object} gitUrlInfo - 解析后的 Git 仓库信息 { owner, repo, path, platform }
|
|
132
|
+
*/
|
|
133
|
+
export async function getPackageJsonUrl(gitUrlInfo) {
|
|
134
|
+
// 具体是何种远程仓库,根据平台选择不同的 URL 构造函数
|
|
135
|
+
switch (gitUrlInfo.platform) {
|
|
136
|
+
case "github":
|
|
137
|
+
return await getGithubPackageJsonUrl(gitUrlInfo);
|
|
138
|
+
case "gitee":
|
|
139
|
+
return await getGiteePackageJsonUrl(gitUrlInfo);
|
|
140
|
+
case "gitlab":
|
|
141
|
+
return await getGitlabPackageJsonUrl(gitUrlInfo);
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(`Unsupported platform: ${gitUrlInfo.platform}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* @Desc: 获取远程仓库的 package.json文件内容
|
|
148
|
+
* @return {*}
|
|
149
|
+
* @param {string} gitUrl
|
|
150
|
+
*/
|
|
151
|
+
export async function parseRemoteProject(gitUrl) {
|
|
152
|
+
const gitInfo = parseGitUrl(gitUrl);
|
|
153
|
+
const { packageJsonUrl } = await getPackageJsonUrl(gitInfo);
|
|
154
|
+
// 返回json
|
|
155
|
+
return (await fetch(packageJsonUrl).then((resp) => resp.json()));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @Desc: 获取 GitHub 仓库的 package.json URL
|
|
159
|
+
* @param {Object} projectUrlInfo - 解析后的 Git 仓库信息 { owner, repo, path, platform }
|
|
160
|
+
* @param {string[]} workspaceNames - 工作空间名称列表,每个元素为一个子包的名称
|
|
161
|
+
* @return {Promise<string>} package.json 的 URL
|
|
162
|
+
*/
|
|
163
|
+
async function getGithubSubPackagePackageJsonUrl(projectUrlInfo, workspaceNames) {
|
|
164
|
+
const { owner, repo, path } = projectUrlInfo;
|
|
165
|
+
let branchName;
|
|
166
|
+
// 如果path以 /tree/ 开头,则表示是分支路径,如 /tree/v5.2.2或者/tree/dev,则取分支名称 v5.2.2
|
|
167
|
+
if (path.startsWith("/tree/")) {
|
|
168
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
169
|
+
branchName = pathParts[1];
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// 通过 API 获取仓库信息,获取默认分支名称
|
|
173
|
+
const url = `https://api.github.com/repos/${owner}/${repo}`;
|
|
174
|
+
const info = (await fetch(url).then((resp) => resp.json()));
|
|
175
|
+
branchName = info.default_branch;
|
|
176
|
+
}
|
|
177
|
+
// return `https://raw.githubusercontent.com/${owner}/${repo}/${branchName}/package.json`;
|
|
178
|
+
return `https://raw.githubusercontent.com/anren-hk/slt-erp/main/packages/net/package.json`;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=parseRemoteProject.js.map
|