@mhalder/qdrant-mcp-server 2.2.0 → 3.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/CHANGELOG.md +16 -0
- package/README.md +76 -1
- package/build/code/indexer.d.ts +2 -1
- package/build/code/indexer.d.ts.map +1 -1
- package/build/code/indexer.js +37 -7
- package/build/code/indexer.js.map +1 -1
- package/build/git/chunker.d.ts +39 -0
- package/build/git/chunker.d.ts.map +1 -0
- package/build/git/chunker.js +210 -0
- package/build/git/chunker.js.map +1 -0
- package/build/git/chunker.test.d.ts +2 -0
- package/build/git/chunker.test.d.ts.map +1 -0
- package/build/git/chunker.test.js +230 -0
- package/build/git/chunker.test.js.map +1 -0
- package/build/git/config.d.ts +34 -0
- package/build/git/config.d.ts.map +1 -0
- package/build/git/config.js +163 -0
- package/build/git/config.js.map +1 -0
- package/build/git/extractor.d.ts +57 -0
- package/build/git/extractor.d.ts.map +1 -0
- package/build/git/extractor.integration.test.d.ts +6 -0
- package/build/git/extractor.integration.test.d.ts.map +1 -0
- package/build/git/extractor.integration.test.js +166 -0
- package/build/git/extractor.integration.test.js.map +1 -0
- package/build/git/extractor.js +231 -0
- package/build/git/extractor.js.map +1 -0
- package/build/git/extractor.test.d.ts +2 -0
- package/build/git/extractor.test.d.ts.map +1 -0
- package/build/git/extractor.test.js +267 -0
- package/build/git/extractor.test.js.map +1 -0
- package/build/git/index.d.ts +10 -0
- package/build/git/index.d.ts.map +1 -0
- package/build/git/index.js +11 -0
- package/build/git/index.js.map +1 -0
- package/build/git/indexer.d.ts +50 -0
- package/build/git/indexer.d.ts.map +1 -0
- package/build/git/indexer.js +588 -0
- package/build/git/indexer.js.map +1 -0
- package/build/git/indexer.test.d.ts +2 -0
- package/build/git/indexer.test.d.ts.map +1 -0
- package/build/git/indexer.test.js +867 -0
- package/build/git/indexer.test.js.map +1 -0
- package/build/git/sync/synchronizer.d.ts +43 -0
- package/build/git/sync/synchronizer.d.ts.map +1 -0
- package/build/git/sync/synchronizer.js +108 -0
- package/build/git/sync/synchronizer.js.map +1 -0
- package/build/git/sync/synchronizer.test.d.ts +2 -0
- package/build/git/sync/synchronizer.test.d.ts.map +1 -0
- package/build/git/sync/synchronizer.test.js +188 -0
- package/build/git/sync/synchronizer.test.js.map +1 -0
- package/build/git/types.d.ts +159 -0
- package/build/git/types.d.ts.map +1 -0
- package/build/git/types.js +5 -0
- package/build/git/types.js.map +1 -0
- package/build/index.js +18 -0
- package/build/index.js.map +1 -1
- package/build/tools/git-history.d.ts +10 -0
- package/build/tools/git-history.d.ts.map +1 -0
- package/build/tools/git-history.js +144 -0
- package/build/tools/git-history.js.map +1 -0
- package/build/tools/index.d.ts +2 -0
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +4 -0
- package/build/tools/index.js.map +1 -1
- package/build/tools/schemas.d.ts +24 -0
- package/build/tools/schemas.d.ts.map +1 -1
- package/build/tools/schemas.js +64 -0
- package/build/tools/schemas.js.map +1 -1
- package/package.json +1 -1
- package/src/code/indexer.ts +49 -7
- package/src/git/chunker.test.ts +284 -0
- package/src/git/chunker.ts +256 -0
- package/src/git/config.ts +173 -0
- package/src/git/extractor.integration.test.ts +221 -0
- package/src/git/extractor.test.ts +403 -0
- package/src/git/extractor.ts +284 -0
- package/src/git/index.ts +31 -0
- package/src/git/indexer.test.ts +1089 -0
- package/src/git/indexer.ts +745 -0
- package/src/git/sync/synchronizer.test.ts +250 -0
- package/src/git/sync/synchronizer.ts +122 -0
- package/src/git/types.ts +192 -0
- package/src/index.ts +42 -0
- package/src/tools/git-history.ts +208 -0
- package/src/tools/index.ts +7 -0
- package/src/tools/schemas.ts +75 -0
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for GitExtractor
|
|
3
|
+
* These tests run against real git repositories (not mocked)
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
6
|
+
import { GitExtractor } from "./extractor.js";
|
|
7
|
+
import { DEFAULT_GIT_CONFIG } from "./config.js";
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { promisify } from "node:util";
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
describe("GitExtractor Integration Tests", () => {
|
|
12
|
+
let extractor;
|
|
13
|
+
const config = { ...DEFAULT_GIT_CONFIG, maxCommits: 100 };
|
|
14
|
+
// Use the current repository for integration tests
|
|
15
|
+
const repoPath = process.cwd();
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
extractor = new GitExtractor(repoPath, config);
|
|
18
|
+
// Verify we're in a git repository
|
|
19
|
+
const isRepo = await extractor.validateRepository();
|
|
20
|
+
if (!isRepo) {
|
|
21
|
+
throw new Error("Integration tests must be run from a git repository");
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
describe("validateRepository", () => {
|
|
25
|
+
it("should detect valid git repository", async () => {
|
|
26
|
+
const result = await extractor.validateRepository();
|
|
27
|
+
expect(result).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it("should return false for non-existent path", async () => {
|
|
30
|
+
const badExtractor = new GitExtractor("/nonexistent/path", config);
|
|
31
|
+
const result = await badExtractor.validateRepository();
|
|
32
|
+
expect(result).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe("getCommits - data integrity", () => {
|
|
36
|
+
it("should extract commits without data corruption", async () => {
|
|
37
|
+
const commits = await extractor.getCommits({ maxCommits: 50 });
|
|
38
|
+
expect(commits.length).toBeGreaterThan(0);
|
|
39
|
+
expect(commits.length).toBeLessThanOrEqual(50);
|
|
40
|
+
for (const commit of commits) {
|
|
41
|
+
// Verify hash format (40 hex characters)
|
|
42
|
+
expect(commit.hash).toMatch(/^[a-f0-9]{40}$/);
|
|
43
|
+
// Verify short hash format (7+ hex characters)
|
|
44
|
+
expect(commit.shortHash).toMatch(/^[a-f0-9]{7,}$/);
|
|
45
|
+
// Verify author is not empty
|
|
46
|
+
expect(commit.author.length).toBeGreaterThan(0);
|
|
47
|
+
// Verify author email format
|
|
48
|
+
expect(commit.authorEmail).toMatch(/.+@.+/);
|
|
49
|
+
// Verify date is valid
|
|
50
|
+
expect(commit.date).toBeInstanceOf(Date);
|
|
51
|
+
expect(commit.date.getTime()).not.toBeNaN();
|
|
52
|
+
// Verify subject is not empty
|
|
53
|
+
expect(commit.subject.length).toBeGreaterThan(0);
|
|
54
|
+
// CRITICAL: Verify fields don't contain numstat patterns
|
|
55
|
+
// This catches the parsing bug where numstat bleeds into format fields
|
|
56
|
+
const numstatPattern = /^\d+\s+\d+\s+\S+/;
|
|
57
|
+
expect(commit.hash).not.toMatch(numstatPattern);
|
|
58
|
+
expect(commit.author).not.toMatch(numstatPattern);
|
|
59
|
+
expect(commit.subject).not.toMatch(numstatPattern);
|
|
60
|
+
// Verify insertions/deletions are non-negative integers
|
|
61
|
+
expect(commit.insertions).toBeGreaterThanOrEqual(0);
|
|
62
|
+
expect(commit.deletions).toBeGreaterThanOrEqual(0);
|
|
63
|
+
expect(Number.isInteger(commit.insertions)).toBe(true);
|
|
64
|
+
expect(Number.isInteger(commit.deletions)).toBe(true);
|
|
65
|
+
// Verify files array
|
|
66
|
+
expect(Array.isArray(commit.files)).toBe(true);
|
|
67
|
+
for (const file of commit.files) {
|
|
68
|
+
expect(typeof file).toBe("string");
|
|
69
|
+
expect(file.length).toBeGreaterThan(0);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
it("should return correct commit count matching git rev-list", async () => {
|
|
74
|
+
// Get expected count from git directly
|
|
75
|
+
const { stdout } = await execFileAsync("git", ["rev-list", "--count", "-n", "50", "HEAD"], { cwd: repoPath });
|
|
76
|
+
const expectedCount = Math.min(parseInt(stdout.trim(), 10), 50);
|
|
77
|
+
// Get commits via extractor
|
|
78
|
+
const commits = await extractor.getCommits({ maxCommits: 50 });
|
|
79
|
+
// Should match exactly
|
|
80
|
+
expect(commits.length).toBe(expectedCount);
|
|
81
|
+
});
|
|
82
|
+
it("should extract files correctly with stats", async () => {
|
|
83
|
+
// Find a commit with files using git log
|
|
84
|
+
const { stdout: logOutput } = await execFileAsync("git", ["log", "--oneline", "--shortstat", "-n", "10", "HEAD"], { cwd: repoPath });
|
|
85
|
+
// If there are commits with files changed, verify our extractor gets them
|
|
86
|
+
if (logOutput.includes("file")) {
|
|
87
|
+
const commits = await extractor.getCommits({ maxCommits: 10 });
|
|
88
|
+
const commitsWithFiles = commits.filter((c) => c.files.length > 0);
|
|
89
|
+
// At least some commits should have files
|
|
90
|
+
expect(commitsWithFiles.length).toBeGreaterThan(0);
|
|
91
|
+
// Verify files and stats are consistent
|
|
92
|
+
for (const commit of commitsWithFiles) {
|
|
93
|
+
// If there are files, there should typically be insertions or deletions
|
|
94
|
+
// (unless all files are renames with no changes)
|
|
95
|
+
expect(commit.files.length).toBeGreaterThan(0);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe("getCommits - range filtering", () => {
|
|
101
|
+
it("should support sinceCommit range filtering", async () => {
|
|
102
|
+
// Get all commits first
|
|
103
|
+
const allCommits = await extractor.getCommits({ maxCommits: 20 });
|
|
104
|
+
if (allCommits.length >= 5) {
|
|
105
|
+
// Use the 5th commit as the "since" point
|
|
106
|
+
const sinceHash = allCommits[4].hash;
|
|
107
|
+
// Get commits since that point
|
|
108
|
+
const recentCommits = await extractor.getCommits({
|
|
109
|
+
sinceCommit: sinceHash,
|
|
110
|
+
maxCommits: 20,
|
|
111
|
+
});
|
|
112
|
+
// Should have fewer commits (the 4 before the since point)
|
|
113
|
+
expect(recentCommits.length).toBeLessThan(allCommits.length);
|
|
114
|
+
expect(recentCommits.length).toBe(4);
|
|
115
|
+
// Verify the commits are the expected ones
|
|
116
|
+
for (let i = 0; i < recentCommits.length; i++) {
|
|
117
|
+
expect(recentCommits[i].hash).toBe(allCommits[i].hash);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
describe("getCommitDiff", () => {
|
|
123
|
+
it("should return diff for a valid commit", async () => {
|
|
124
|
+
const commits = await extractor.getCommits({ maxCommits: 1 });
|
|
125
|
+
if (commits.length > 0) {
|
|
126
|
+
const diff = await extractor.getCommitDiff(commits[0].hash);
|
|
127
|
+
// Diff should contain commit information
|
|
128
|
+
expect(diff).toContain("commit");
|
|
129
|
+
expect(diff).toContain(commits[0].hash);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
it("should return empty string for invalid commit", async () => {
|
|
133
|
+
const diff = await extractor.getCommitDiff("0000000000000000000000000000000000000000");
|
|
134
|
+
expect(diff).toBe("");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe("getLatestCommitHash", () => {
|
|
138
|
+
it("should return the HEAD commit hash", async () => {
|
|
139
|
+
const hash = await extractor.getLatestCommitHash();
|
|
140
|
+
// Verify format
|
|
141
|
+
expect(hash).toMatch(/^[a-f0-9]{40}$/);
|
|
142
|
+
// Verify it matches git rev-parse HEAD
|
|
143
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"], {
|
|
144
|
+
cwd: repoPath,
|
|
145
|
+
});
|
|
146
|
+
expect(hash).toBe(stdout.trim());
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe("getCommitCount", () => {
|
|
150
|
+
it("should return total commit count", async () => {
|
|
151
|
+
const count = await extractor.getCommitCount();
|
|
152
|
+
// Verify against git rev-list
|
|
153
|
+
const { stdout } = await execFileAsync("git", ["rev-list", "--count", "HEAD"], { cwd: repoPath });
|
|
154
|
+
expect(count).toBe(parseInt(stdout.trim(), 10));
|
|
155
|
+
});
|
|
156
|
+
it("should return count since specific commit", async () => {
|
|
157
|
+
const commits = await extractor.getCommits({ maxCommits: 10 });
|
|
158
|
+
if (commits.length >= 5) {
|
|
159
|
+
const sinceHash = commits[4].hash;
|
|
160
|
+
const count = await extractor.getCommitCount(sinceHash);
|
|
161
|
+
expect(count).toBe(4); // 4 commits between sinceHash and HEAD
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
//# sourceMappingURL=extractor.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.integration.test.js","sourceRoot":"","sources":["../../src/git/extractor.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitExtractor - Extract commit data from git repositories
|
|
3
|
+
* Uses child_process.execFile for security (no shell injection)
|
|
4
|
+
*/
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import { GIT_LOG_COMMIT_DELIMITER, GIT_LOG_FORMAT, GIT_MAX_BUFFER, } from "./config.js";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
/**
|
|
10
|
+
* Normalize git remote URL to consistent format for hashing.
|
|
11
|
+
* Handles both SSH and HTTPS URL formats.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* normalizeRemoteUrl("git@github.com:user/repo.git") // → "user/repo"
|
|
15
|
+
* normalizeRemoteUrl("https://github.com/user/repo.git") // → "user/repo"
|
|
16
|
+
* normalizeRemoteUrl("") // → ""
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeRemoteUrl(url) {
|
|
19
|
+
if (!url)
|
|
20
|
+
return "";
|
|
21
|
+
return url
|
|
22
|
+
.replace(/^git@[^:]+:/, "") // git@github.com:user/repo → user/repo
|
|
23
|
+
.replace(/^https?:\/\/[^/]+\//, "") // https://github.com/user/repo → user/repo
|
|
24
|
+
.replace(/\.git$/, ""); // user/repo.git → user/repo
|
|
25
|
+
}
|
|
26
|
+
export class GitExtractor {
|
|
27
|
+
repoPath;
|
|
28
|
+
config;
|
|
29
|
+
constructor(repoPath, config) {
|
|
30
|
+
this.repoPath = repoPath;
|
|
31
|
+
this.config = config;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate that the path is a git repository
|
|
35
|
+
*/
|
|
36
|
+
async validateRepository() {
|
|
37
|
+
try {
|
|
38
|
+
await execFileAsync("git", ["rev-parse", "--git-dir"], {
|
|
39
|
+
cwd: this.repoPath,
|
|
40
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
41
|
+
timeout: this.config.gitTimeout,
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the latest commit hash
|
|
51
|
+
*/
|
|
52
|
+
async getLatestCommitHash() {
|
|
53
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"], {
|
|
54
|
+
cwd: this.repoPath,
|
|
55
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
56
|
+
timeout: this.config.gitTimeout,
|
|
57
|
+
});
|
|
58
|
+
return stdout.trim();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get the remote origin URL, or empty string if not configured
|
|
62
|
+
*/
|
|
63
|
+
async getRemoteUrl() {
|
|
64
|
+
try {
|
|
65
|
+
const { stdout } = await execFileAsync("git", ["remote", "get-url", "origin"], {
|
|
66
|
+
cwd: this.repoPath,
|
|
67
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
68
|
+
timeout: this.config.gitTimeout,
|
|
69
|
+
});
|
|
70
|
+
return stdout.trim();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return ""; // No remote configured
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get total commit count (optionally after a specific commit)
|
|
78
|
+
*/
|
|
79
|
+
async getCommitCount(sinceCommit) {
|
|
80
|
+
const args = ["rev-list", "--count"];
|
|
81
|
+
if (sinceCommit) {
|
|
82
|
+
args.push(`${sinceCommit}..HEAD`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
args.push("HEAD");
|
|
86
|
+
}
|
|
87
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
88
|
+
cwd: this.repoPath,
|
|
89
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
90
|
+
timeout: this.config.gitTimeout,
|
|
91
|
+
});
|
|
92
|
+
return parseInt(stdout.trim(), 10);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Extract commits from the repository
|
|
96
|
+
*/
|
|
97
|
+
async getCommits(options) {
|
|
98
|
+
const maxCommits = options?.maxCommits ?? this.config.maxCommits;
|
|
99
|
+
// Build git log arguments
|
|
100
|
+
const args = [
|
|
101
|
+
"log",
|
|
102
|
+
`--pretty=format:${GIT_LOG_COMMIT_DELIMITER}${GIT_LOG_FORMAT}`,
|
|
103
|
+
"--numstat", // Include insertions/deletions per file
|
|
104
|
+
`-n${maxCommits}`,
|
|
105
|
+
];
|
|
106
|
+
// Add range if sinceCommit is specified
|
|
107
|
+
if (options?.sinceCommit) {
|
|
108
|
+
args.push(`${options.sinceCommit}..HEAD`);
|
|
109
|
+
}
|
|
110
|
+
// Add date filter if sinceDate is specified
|
|
111
|
+
if (options?.sinceDate) {
|
|
112
|
+
args.push(`--since=${options.sinceDate}`);
|
|
113
|
+
}
|
|
114
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
115
|
+
cwd: this.repoPath,
|
|
116
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
117
|
+
timeout: this.config.gitTimeout,
|
|
118
|
+
});
|
|
119
|
+
return this.parseGitLog(stdout);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the diff for a specific commit
|
|
123
|
+
*/
|
|
124
|
+
async getCommitDiff(commitHash) {
|
|
125
|
+
try {
|
|
126
|
+
const { stdout } = await execFileAsync("git", ["show", "--no-color", "-p", commitHash], {
|
|
127
|
+
cwd: this.repoPath,
|
|
128
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
129
|
+
timeout: this.config.gitTimeout,
|
|
130
|
+
});
|
|
131
|
+
// Truncate diff if it exceeds maxDiffSize
|
|
132
|
+
if (stdout.length > this.config.maxDiffSize) {
|
|
133
|
+
return (stdout.substring(0, this.config.maxDiffSize) +
|
|
134
|
+
`\n\n[diff truncated: showing ${this.config.maxDiffSize} of ${stdout.length} bytes]`);
|
|
135
|
+
}
|
|
136
|
+
return stdout;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return "";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Parse git log output into structured commits
|
|
144
|
+
*/
|
|
145
|
+
parseGitLog(output) {
|
|
146
|
+
const commits = [];
|
|
147
|
+
// Split by commit delimiter
|
|
148
|
+
const commitBlocks = output.split(GIT_LOG_COMMIT_DELIMITER);
|
|
149
|
+
for (const block of commitBlocks) {
|
|
150
|
+
const trimmed = block.trim();
|
|
151
|
+
if (!trimmed)
|
|
152
|
+
continue;
|
|
153
|
+
const commit = this.parseCommitBlock(trimmed);
|
|
154
|
+
if (commit) {
|
|
155
|
+
commits.push(commit);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return commits;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Parse a single commit block
|
|
162
|
+
*/
|
|
163
|
+
parseCommitBlock(block) {
|
|
164
|
+
// The format line is first, followed by numstat output
|
|
165
|
+
const lines = block.split("\n");
|
|
166
|
+
if (lines.length === 0)
|
|
167
|
+
return null;
|
|
168
|
+
// Parse the format line: hash|shortHash|author|authorEmail|date|subject|body
|
|
169
|
+
const formatLine = lines[0];
|
|
170
|
+
const parts = formatLine.split("|");
|
|
171
|
+
if (parts.length < 6)
|
|
172
|
+
return null;
|
|
173
|
+
const [hash, shortHash, author, authorEmail, dateStr, subject, ...bodyParts] = parts;
|
|
174
|
+
// Parse files and stats from numstat output
|
|
175
|
+
const { files, insertions, deletions } = this.parseNumstat(lines.slice(1));
|
|
176
|
+
return {
|
|
177
|
+
hash,
|
|
178
|
+
shortHash,
|
|
179
|
+
author,
|
|
180
|
+
authorEmail,
|
|
181
|
+
date: new Date(dateStr),
|
|
182
|
+
subject,
|
|
183
|
+
body: bodyParts.join("|").trim(), // Body might contain | characters
|
|
184
|
+
files,
|
|
185
|
+
insertions,
|
|
186
|
+
deletions,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Parse numstat output (lines after the format line)
|
|
191
|
+
*/
|
|
192
|
+
parseNumstat(lines) {
|
|
193
|
+
const files = [];
|
|
194
|
+
let insertions = 0;
|
|
195
|
+
let deletions = 0;
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
const trimmed = line.trim();
|
|
198
|
+
if (!trimmed)
|
|
199
|
+
continue;
|
|
200
|
+
// numstat format: insertions<tab>deletions<tab>filename
|
|
201
|
+
// Binary files show as "-" for insertions/deletions
|
|
202
|
+
const match = trimmed.match(/^(\d+|-)\s+(\d+|-)\s+(.+)$/);
|
|
203
|
+
if (match) {
|
|
204
|
+
const [, ins, del, filename] = match;
|
|
205
|
+
// Handle binary files (marked with -)
|
|
206
|
+
if (ins !== "-") {
|
|
207
|
+
insertions += parseInt(ins, 10);
|
|
208
|
+
}
|
|
209
|
+
if (del !== "-") {
|
|
210
|
+
deletions += parseInt(del, 10);
|
|
211
|
+
}
|
|
212
|
+
// Handle renamed files (old -> new)
|
|
213
|
+
if (filename.includes(" => ")) {
|
|
214
|
+
const renameParts = filename.match(/(.+)\{(.+) => (.+)\}(.+)?/);
|
|
215
|
+
if (renameParts) {
|
|
216
|
+
files.push(`${renameParts[1]}${renameParts[3]}${renameParts[4] || ""}`);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const simpleRename = filename.split(" => ");
|
|
220
|
+
files.push(simpleRename[1] || filename);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
files.push(filename);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { files, insertions, deletions };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/git/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.test.d.ts","sourceRoot":"","sources":["../../src/git/extractor.test.ts"],"names":[],"mappings":""}
|