|
@@ -10,12 +10,78 @@ class gitCodeStats extends API {
|
|
|
constructor() {
|
|
|
super()
|
|
|
|
|
|
- this.setMethod("POST")
|
|
|
+ this.setMethod("GET")
|
|
|
this.setPath("/Repos/CodeStats")
|
|
|
}
|
|
|
|
|
|
+ // 定义支持的语言后缀
|
|
|
+ languageExtensions = {
|
|
|
+ "JavaScript": [".js", ".jsx", ".mjs", ".cjs"],
|
|
|
+ "TypeScript": [".ts", ".tsx"],
|
|
|
+ "Python": [".py"],
|
|
|
+ "Java": [".java"],
|
|
|
+ "C": [".c"],
|
|
|
+ "C++": [".cpp", ".cc", ".cxx", ".h", ".hpp"],
|
|
|
+ "C#": [".cs"],
|
|
|
+ "Go": [".go"],
|
|
|
+ "PHP": [".php"],
|
|
|
+ "HTML": [".html", ".htm"],
|
|
|
+ "CSS": [".css"],
|
|
|
+ "SCSS": [".scss", ".sass"],
|
|
|
+ "JSON": [".json"],
|
|
|
+ "YAML": [".yml", ".yaml"],
|
|
|
+ "Markdown": [".md"],
|
|
|
+ "Shell": [".sh"],
|
|
|
+ "Bash": [".bash"],
|
|
|
+ "PowerShell": [".ps1"],
|
|
|
+ "Ruby": [".rb"],
|
|
|
+ "Vue": [".vue"], // Vue文件
|
|
|
+ "LESS": [".less"], // LESS样式文件
|
|
|
+ "Sass": [".sass"], // Sass文件
|
|
|
+ "Haml": [".haml"], // Haml文件
|
|
|
+ "Elixir": [".ex", ".exs"], // Elixir语言文件
|
|
|
+ "Erlang": [".erl", ".hrl"], // Erlang语言文件
|
|
|
+ "Swift": [".swift"], // Swift语言文件
|
|
|
+ "Kotlin": [".kt", ".kts"], // Kotlin语言文件
|
|
|
+ "Rust": [".rs"], // Rust语言文件
|
|
|
+ "Dart": [".dart"], // Dart语言文件
|
|
|
+ "Lua": [".lua"], // Lua语言文件
|
|
|
+ "R": [".r"], // R语言文件
|
|
|
+ "Perl": [".pl"], // Perl语言文件
|
|
|
+ "SQL": [".sql"], // SQL文件
|
|
|
+ "Dockerfile": [".dockerfile", "Dockerfile"], // Dockerfile
|
|
|
+ "GraphQL": [".graphql", ".gql"], // GraphQL文件
|
|
|
+ "JSON5": [".json5"], // JSON5文件
|
|
|
+ "TOML": [".toml"], // TOML文件
|
|
|
+ "Text": [".txt", ".text"], // 文本文件
|
|
|
+ "Other": [".bin", ".dat", ".exe", ".dll", ".obj", ".so", ".class"] // 二进制及无法识别的文件
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断文件是否为二进制文件
|
|
|
+ isBinaryFile(filePath) {
|
|
|
+ const binaryExtensions = ['.exe', '.dll', '.obj', '.so', '.bin', '.dat']
|
|
|
+ const ext = path.extname(filePath).toLowerCase()
|
|
|
+ return binaryExtensions.includes(ext)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统计单个文件的行数
|
|
|
+ countLines(filePath) {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ if (this.isBinaryFile(filePath)) {
|
|
|
+ return resolve(0) // 二进制文件直接跳过
|
|
|
+ }
|
|
|
+ let lineCount = 0;
|
|
|
+ const stream = fs.createReadStream(filePath, 'utf8')
|
|
|
+ stream.on("data", (chunk) => {
|
|
|
+ lineCount += chunk.toString().split("\n").length
|
|
|
+ });
|
|
|
+ stream.on("end", () => resolve(lineCount))
|
|
|
+ stream.on("error", () => resolve(0)) // 读取错误默认返回 0
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
async onRequest(req, res) {
|
|
|
- let { uuid, session, id } = req.body
|
|
|
+ let { uuid, session, id } = req.query
|
|
|
|
|
|
if ([uuid, session, id].some(value => value === '' || value === null || value === undefined))
|
|
|
return res.json({
|
|
@@ -28,10 +94,46 @@ class gitCodeStats extends API {
|
|
|
...BaseStdResponse.ACCESS_DENIED
|
|
|
})
|
|
|
|
|
|
- let sql = 'SELECT path, url FROM repos WHERE create_user = ? AND id = ?'
|
|
|
+ let sql = 'SELECT path FROM repos WHERE create_user = ? AND id = ?'
|
|
|
|
|
|
let r = await db.query(sql, [uuid, id])
|
|
|
-
|
|
|
+ if (r && r.length === 0)
|
|
|
+ return res.json({
|
|
|
+ ...BaseStdResponse.ERR,
|
|
|
+ msg: '未找到仓库'
|
|
|
+ })
|
|
|
+
|
|
|
+ const git = simpleGit(r[0].path)
|
|
|
+ const files = await git.raw(["ls-files"]) // 获取所有 Git 跟踪的文件
|
|
|
+ const fileList = files.split("\n").map(f => f.trim()).filter(f => f)
|
|
|
+
|
|
|
+ let totalLines = 0
|
|
|
+ let languageStats = {}
|
|
|
+
|
|
|
+ for (const file of fileList) {
|
|
|
+ const fullPath = path.join(repoPath, file)
|
|
|
+ const ext = path.extname(file)
|
|
|
+ const language = Object.keys(this.languageExtensions).find(lang =>
|
|
|
+ this.languageExtensions[lang].includes(ext)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (language) {
|
|
|
+ const lines = await countLines(fullPath)
|
|
|
+ totalLines += lines
|
|
|
+ languageStats[language] = (languageStats[language] || 0) + lines
|
|
|
+ } else {
|
|
|
+ // 如果文件不属于任何已知语言,归类为其他
|
|
|
+ const lines = await countLines(fullPath)
|
|
|
+ totalLines += lines
|
|
|
+ languageStats["Other"] = (languageStats["Other"] || 0) + lines
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ res.json({
|
|
|
+ ...BaseStdResponse.OK,
|
|
|
+ totalLines,
|
|
|
+ languageStats
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|