Git status porcelain output uses leading spaces for status indicators; trim() was stripping them which could break parsing.
57 lines
1.8 KiB
TypeScript
57 lines
1.8 KiB
TypeScript
import { execFileSync } from "node:child_process"
|
|
import { readFileSync } from "node:fs"
|
|
import { join } from "node:path"
|
|
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"],
|
|
}).trimEnd()
|
|
|
|
const statusOutput = execFileSync("git", ["status", "--porcelain"], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trimEnd()
|
|
|
|
const untrackedOutput = execFileSync("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
cwd: directory,
|
|
encoding: "utf-8",
|
|
timeout: 5000,
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}).trimEnd()
|
|
|
|
const untrackedNumstat = untrackedOutput
|
|
? untrackedOutput
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.map((filePath) => {
|
|
try {
|
|
const content = readFileSync(join(directory, filePath), "utf-8")
|
|
const lineCount = content.split("\n").length - (content.endsWith("\n") ? 1 : 0)
|
|
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 []
|
|
}
|
|
}
|