Files
oh-my-opencode/src/shared/git-worktree/collect-git-diff-stats.ts
T

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 []
}
}