64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import { execFileSync } from "node:child_process"
|
|
import { parseGitStatusPorcelain } from "./parse-status-porcelain"
|
|
import { parseGitDiffNumstat } from "./parse-diff-numstat"
|
|
import type { GitFileStat } from "./types"
|
|
|
|
export function collectGitDiffStats(directory: string): GitFileStat[] {
|
|
try {
|
|
const diffOutput = execFileSync("git", ["diff", "--numstat", "HEAD"], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trim()
|
|
|
|
const statusOutput = execFileSync("git", ["status", "--porcelain"], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trim()
|
|
|
|
const untrackedOutput = execFileSync("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trim()
|
|
|
|
const untrackedNumstat = untrackedOutput
|
|
? untrackedOutput
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.map((filePath) => {
|
|
try {
|
|
const wcOutput = execFileSync("wc", ["-l", "--", filePath], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trim()
|
|
|
|
const [lineCountToken] = wcOutput.split(/\s+/)
|
|
const lineCount = Number(lineCountToken)
|
|
if (!Number.isFinite(lineCount)) return `0\t0\t${filePath}`
|
|
|
|
return `${lineCount}\t0\t${filePath}`
|
|
} catch {
|
|
return `0\t0\t${filePath}`
|
|
}
|
|
})
|
|
.join("\n")
|
|
: ""
|
|
|
|
const combinedNumstat = [diffOutput, untrackedNumstat].filter(Boolean).join("\n").trim()
|
|
|
|
if (!combinedNumstat) return []
|
|
|
|
const statusMap = parseGitStatusPorcelain(statusOutput)
|
|
return parseGitDiffNumstat(combinedNumstat, statusMap)
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|