difit 4.0.0 → 4.0.1
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/README.ja.md +15 -14
- package/README.ko.md +15 -14
- package/README.md +15 -14
- package/README.zh.md +15 -14
- package/dist/cli/index.js +16 -0
- package/dist/cli/index.test.js +125 -1
- package/dist/client/assets/{_basePickBy-B9N-f0iT.js → _basePickBy-ChXFkTMC.js} +1 -1
- package/dist/client/assets/{_baseUniq-tbL7nVvN.js → _baseUniq-Mj_sFFQW.js} +1 -1
- package/dist/client/assets/{arc-BOY-7mep.js → arc-BMA6S9F1.js} +1 -1
- package/dist/client/assets/{architectureDiagram-2XIMDMQ5-59AvHaSB.js → architectureDiagram-2XIMDMQ5-0uiM_v5K.js} +1 -1
- package/dist/client/assets/{blockDiagram-WCTKOSBZ-DXIlumQk.js → blockDiagram-WCTKOSBZ-CM7ZLL6F.js} +1 -1
- package/dist/client/assets/{c4Diagram-IC4MRINW-BbfZ0uRn.js → c4Diagram-IC4MRINW-DKtCnVwn.js} +1 -1
- package/dist/client/assets/channel-D057yzDp.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-l7rcB2IW.js → chunk-4BX2VUAB-Wsl8DxEB.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-CrZL3qv9.js → chunk-55IACEB6-CHm9X5i7.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-CrKv7ndg.js → chunk-FMBD7UC4-BSa8SHgd.js} +1 -1
- package/dist/client/assets/{chunk-JSJVCQXG-DyBDhAEM.js → chunk-JSJVCQXG-Cpk76oJ3.js} +1 -1
- package/dist/client/assets/{chunk-KX2RTZJC-By5mkZmU.js → chunk-KX2RTZJC-D8YvfZVu.js} +1 -1
- package/dist/client/assets/{chunk-NQ4KR5QH-C30p9xRx.js → chunk-NQ4KR5QH-BogviJOv.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-DVlhR2wU.js → chunk-QZHKN3VN-DwLJYu26.js} +1 -1
- package/dist/client/assets/{chunk-WL4C6EOR-Cn7a6CO3.js → chunk-WL4C6EOR-BFDpGxW2.js} +1 -1
- package/dist/client/assets/classDiagram-VBA2DB6C---D4iOts.js +1 -0
- package/dist/client/assets/classDiagram-v2-RAHNMMFH---D4iOts.js +1 -0
- package/dist/client/assets/clone-xSR3otEf.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-LyauIk_9.js → cose-bilkent-S5V4N54A-oEosZ_5y.js} +1 -1
- package/dist/client/assets/{dagre-KLK3FWXG-DRWb2KE3.js → dagre-KLK3FWXG-gFld4u1H.js} +1 -1
- package/dist/client/assets/{diagram-E7M64L7V-ChT6mNWK.js → diagram-E7M64L7V-gJq3kSrf.js} +1 -1
- package/dist/client/assets/{diagram-IFDJBPK2-CqbTduoP.js → diagram-IFDJBPK2-BsUm_q22.js} +1 -1
- package/dist/client/assets/{diagram-P4PSJMXO-Bzv5Z3ri.js → diagram-P4PSJMXO-juB-sfcR.js} +1 -1
- package/dist/client/assets/{erDiagram-INFDFZHY-CvXfUZ4L.js → erDiagram-INFDFZHY-Dn77qXAt.js} +1 -1
- package/dist/client/assets/{flowDiagram-PKNHOUZH-CxmpNUKq.js → flowDiagram-PKNHOUZH-DtmvDYdN.js} +1 -1
- package/dist/client/assets/{ganttDiagram-A5KZAMGK-9LpZCsg6.js → ganttDiagram-A5KZAMGK-BlDaKLbQ.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-K3NZZRJ6-C6yZOrQJ.js → gitGraphDiagram-K3NZZRJ6-DeAAeuMS.js} +1 -1
- package/dist/client/assets/{graph-bUZ7uHLW.js → graph-NX9gBP47.js} +1 -1
- package/dist/client/assets/{index-BLNN1bfE.js → index-kJdw4DY-.js} +15 -15
- package/dist/client/assets/{infoDiagram-LFFYTUFH-Djdy3W21.js → infoDiagram-LFFYTUFH-CAaX023c.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-PHBUUO56-oOdwCpeS.js → ishikawaDiagram-PHBUUO56-CmiTQStv.js} +1 -1
- package/dist/client/assets/{journeyDiagram-4ABVD52K-DTb_nGAw.js → journeyDiagram-4ABVD52K-B0SHC7mz.js} +1 -1
- package/dist/client/assets/{kanban-definition-K7BYSVSG-CMtP7pHA.js → kanban-definition-K7BYSVSG-IfRdhzz7.js} +1 -1
- package/dist/client/assets/{layout-CXr5MatK.js → layout-l3OdNQhJ.js} +1 -1
- package/dist/client/assets/{linear-pOMS9pjV.js → linear-CQ0hx5Qs.js} +1 -1
- package/dist/client/assets/{mermaid.core-DV5JJ1Ie.js → mermaid.core-DqlPTabt.js} +4 -4
- package/dist/client/assets/{mindmap-definition-YRQLILUH-DN-sbonc.js → mindmap-definition-YRQLILUH-DIgSmG_f.js} +1 -1
- package/dist/client/assets/{pieDiagram-SKSYHLDU-tAHCkgh1.js → pieDiagram-SKSYHLDU-FzM5qoIB.js} +1 -1
- package/dist/client/assets/{prism-csharp-5CQ0RcEE.js → prism-csharp-DCfUUOUs.js} +1 -1
- package/dist/client/assets/{prism-elixir-BSOTyVg2.js → prism-elixir-riuOL1mm.js} +1 -1
- package/dist/client/assets/{prism-hcl-BYvi1mtM.js → prism-hcl-CizuX1s4.js} +1 -1
- package/dist/client/assets/{prism-java-DMU2FM4X.js → prism-java-DYCKrDUh.js} +1 -1
- package/dist/client/assets/{prism-perl-CpfvaEQk.js → prism-perl-BJwBYR3Y.js} +1 -1
- package/dist/client/assets/{prism-php-SC920LoD.js → prism-php-BMhFuA7y.js} +1 -1
- package/dist/client/assets/{prism-ruby-DZph-YiO.js → prism-ruby-Bcu0cDEh.js} +1 -1
- package/dist/client/assets/{prism-solidity-qTLbmiAT.js → prism-solidity-DDDs3w-w.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-337W2JSQ-B0wODmgR.js → quadrantDiagram-337W2JSQ-BBrApyD7.js} +1 -1
- package/dist/client/assets/{requirementDiagram-Z7DCOOCP-A3aeHC06.js → requirementDiagram-Z7DCOOCP-CLXiwUaA.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-WA2Y5GQK-BWa6kZhG.js → sankeyDiagram-WA2Y5GQK-9Y3Ly5qe.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-2WXFIKYE-Cx_COX9G.js → sequenceDiagram-2WXFIKYE-DEpX1BA5.js} +1 -1
- package/dist/client/assets/{stateDiagram-RAJIS63D-BXGnN6rZ.js → stateDiagram-RAJIS63D-Ck3ullwA.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-FVOUBMTO-X6UiDsar.js +1 -0
- package/dist/client/assets/{timeline-definition-YZTLITO2-DbqaUm9k.js → timeline-definition-YZTLITO2-CMezf3XV.js} +1 -1
- package/dist/client/assets/{treemap-KZPCXAKY-CfEujPCR.js → treemap-KZPCXAKY-DqrcV0gQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-LZ73GAT5-CqJE8CAD.js → vennDiagram-LZ73GAT5-eQg945Fz.js} +1 -1
- package/dist/client/assets/{xychartDiagram-JWTSCODW-CfdDvzHC.js → xychartDiagram-JWTSCODW-_hqdXeX1.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/server/git-diff-tui.d.ts +1 -1
- package/dist/server/git-diff-tui.js +7 -5
- package/dist/server/git-diff-tui.test.d.ts +1 -0
- package/dist/server/git-diff-tui.test.js +60 -0
- package/dist/server/git-diff.d.ts +3 -1
- package/dist/server/git-diff.js +40 -3
- package/dist/server/git-diff.test.js +20 -0
- package/dist/server/server.d.ts +1 -0
- package/dist/server/server.js +4 -3
- package/dist/server/server.test.js +32 -0
- package/dist/tui/App.d.ts +1 -0
- package/dist/tui/App.js +2 -2
- package/dist/types/diff.d.ts +1 -0
- package/package.json +1 -1
- package/dist/client/assets/channel-cZXsTJxA.js +0 -1
- package/dist/client/assets/classDiagram-VBA2DB6C-B_coIPEy.js +0 -1
- package/dist/client/assets/classDiagram-v2-RAHNMMFH-B_coIPEy.js +0 -1
- package/dist/client/assets/clone-BjaT2HOk.js +0 -1
- package/dist/client/assets/stateDiagram-v2-FVOUBMTO-CMw3xNha.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import simpleGit from 'simple-git';
|
|
2
2
|
import { validateDiffArguments, createCommitRangeString } from '../cli/utils.js';
|
|
3
|
-
export async function loadGitDiff(targetCommitish, baseCommitish, repoPath) {
|
|
3
|
+
export async function loadGitDiff(targetCommitish, baseCommitish, repoPath, contextLines) {
|
|
4
4
|
// Validate arguments
|
|
5
5
|
const validation = validateDiffArguments(targetCommitish, baseCommitish);
|
|
6
6
|
if (!validation.valid) {
|
|
@@ -44,34 +44,36 @@ export async function loadGitDiff(targetCommitish, baseCommitish, repoPath) {
|
|
|
44
44
|
const path = pathParts.join('\t');
|
|
45
45
|
return { status, path };
|
|
46
46
|
});
|
|
47
|
+
const contextArgs = contextLines !== undefined ? [`-U${contextLines}`] : [];
|
|
47
48
|
// Get diff for each file individually
|
|
48
49
|
const fileDiffs = await Promise.all(fileChanges.map(async ({ status, path }) => {
|
|
49
50
|
let fileDiff = '';
|
|
50
51
|
// Handle individual file diffs (base is always a regular commit)
|
|
51
52
|
if (targetCommitish === 'working') {
|
|
52
53
|
// Show unstaged changes (working vs staged)
|
|
53
|
-
fileDiff = await git.diff(['--', path]);
|
|
54
|
+
fileDiff = await git.diff([...contextArgs, '--', path]);
|
|
54
55
|
}
|
|
55
56
|
else if (targetCommitish === 'staged') {
|
|
56
57
|
// Show staged changes against base commit
|
|
57
|
-
fileDiff = await git.diff(['--cached', baseCommitish, '--', path]);
|
|
58
|
+
fileDiff = await git.diff(['--cached', baseCommitish, ...contextArgs, '--', path]);
|
|
58
59
|
}
|
|
59
60
|
else if (targetCommitish === '.') {
|
|
60
61
|
// Show all uncommitted changes against base commit
|
|
61
|
-
fileDiff = await git.diff([baseCommitish, '--', path]);
|
|
62
|
+
fileDiff = await git.diff([baseCommitish, ...contextArgs, '--', path]);
|
|
62
63
|
}
|
|
63
64
|
else {
|
|
64
65
|
try {
|
|
65
66
|
// Both are regular commits: standard commit-to-commit comparison
|
|
66
67
|
fileDiff = await git.diff([
|
|
67
68
|
createCommitRangeString(baseCommitish, targetCommitish),
|
|
69
|
+
...contextArgs,
|
|
68
70
|
'--',
|
|
69
71
|
path,
|
|
70
72
|
]);
|
|
71
73
|
}
|
|
72
74
|
catch {
|
|
73
75
|
// For new files or if parent doesn't exist
|
|
74
|
-
fileDiff = await git.diff([targetCommitish, '--', path]);
|
|
76
|
+
fileDiff = await git.diff([targetCommitish, ...contextArgs, '--', path]);
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
const lines = fileDiff.split('\n');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { loadGitDiff } from './git-diff-tui.js';
|
|
3
|
+
const mockDiff = vi.hoisted(() => vi.fn());
|
|
4
|
+
const mockSimpleGit = vi.hoisted(() => vi.fn(() => ({ diff: mockDiff })));
|
|
5
|
+
vi.mock('simple-git', () => ({
|
|
6
|
+
default: mockSimpleGit,
|
|
7
|
+
}));
|
|
8
|
+
describe('loadGitDiff', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
mockDiff.mockReset();
|
|
11
|
+
mockSimpleGit.mockClear();
|
|
12
|
+
});
|
|
13
|
+
it.each([
|
|
14
|
+
{
|
|
15
|
+
name: 'working tree diffs',
|
|
16
|
+
targetCommitish: 'working',
|
|
17
|
+
baseCommitish: 'staged',
|
|
18
|
+
expectedListArgs: ['--name-status'],
|
|
19
|
+
expectedFileArgs: ['-U5', '--', 'src/file.ts'],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'staged diffs',
|
|
23
|
+
targetCommitish: 'staged',
|
|
24
|
+
baseCommitish: 'HEAD',
|
|
25
|
+
expectedListArgs: ['--cached', 'HEAD', '--name-status'],
|
|
26
|
+
expectedFileArgs: ['--cached', 'HEAD', '-U5', '--', 'src/file.ts'],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'working tree against a base commit',
|
|
30
|
+
targetCommitish: '.',
|
|
31
|
+
baseCommitish: 'HEAD',
|
|
32
|
+
expectedListArgs: ['HEAD', '--name-status'],
|
|
33
|
+
expectedFileArgs: ['HEAD', '-U5', '--', 'src/file.ts'],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'commit comparisons',
|
|
37
|
+
targetCommitish: 'HEAD',
|
|
38
|
+
baseCommitish: 'HEAD^',
|
|
39
|
+
expectedListArgs: ['HEAD^...HEAD', '--name-status'],
|
|
40
|
+
expectedFileArgs: ['HEAD^...HEAD', '-U5', '--', 'src/file.ts'],
|
|
41
|
+
},
|
|
42
|
+
])('passes context lines for $name', async ({ targetCommitish, baseCommitish, expectedListArgs, expectedFileArgs }) => {
|
|
43
|
+
mockDiff
|
|
44
|
+
.mockResolvedValueOnce('M\tsrc/file.ts')
|
|
45
|
+
.mockResolvedValueOnce('@@ -1 +1 @@\n-old line\n+new line\n');
|
|
46
|
+
const result = await loadGitDiff(targetCommitish, baseCommitish, '/repo', 5);
|
|
47
|
+
expect(mockSimpleGit).toHaveBeenCalledWith('/repo');
|
|
48
|
+
expect(mockDiff).toHaveBeenNthCalledWith(1, expectedListArgs);
|
|
49
|
+
expect(mockDiff).toHaveBeenNthCalledWith(2, expectedFileArgs);
|
|
50
|
+
expect(result).toEqual([
|
|
51
|
+
{
|
|
52
|
+
path: 'src/file.ts',
|
|
53
|
+
status: 'M',
|
|
54
|
+
diff: '@@ -1 +1 @@\n-old line\n+new line\n',
|
|
55
|
+
additions: 1,
|
|
56
|
+
deletions: 1,
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -7,7 +7,7 @@ export declare class GitDiffParser {
|
|
|
7
7
|
private static readonly GENERATED_HEADER_SCAN_BYTES;
|
|
8
8
|
constructor(repoPath?: string);
|
|
9
9
|
private normalizeRepositoryRelativePath;
|
|
10
|
-
parseDiff(targetCommitish: string, baseCommitish: string, ignoreWhitespace?: boolean): Promise<DiffResponse>;
|
|
10
|
+
parseDiff(targetCommitish: string, baseCommitish: string, ignoreWhitespace?: boolean, contextLines?: number): Promise<DiffResponse>;
|
|
11
11
|
private parseUnifiedDiff;
|
|
12
12
|
private decodeGitPath;
|
|
13
13
|
private extractPathFromLine;
|
|
@@ -27,6 +27,7 @@ export declare class GitDiffParser {
|
|
|
27
27
|
resolveCommitish(commitish: string): Promise<string>;
|
|
28
28
|
clearResolvedCommitCache(): void;
|
|
29
29
|
getDefaultBranch(): Promise<string | null>;
|
|
30
|
+
getOriginDefaultBranch(): Promise<string | null>;
|
|
30
31
|
getRevisionOptions(currentBase?: string, currentTarget?: string): Promise<{
|
|
31
32
|
branches: Array<{
|
|
32
33
|
name: string;
|
|
@@ -37,6 +38,7 @@ export declare class GitDiffParser {
|
|
|
37
38
|
shortHash: string;
|
|
38
39
|
message: string;
|
|
39
40
|
}>;
|
|
41
|
+
originDefaultBranch?: string;
|
|
40
42
|
resolvedBase?: string;
|
|
41
43
|
resolvedTarget?: string;
|
|
42
44
|
}>;
|
package/dist/server/git-diff.js
CHANGED
|
@@ -28,7 +28,7 @@ export class GitDiffParser {
|
|
|
28
28
|
}
|
|
29
29
|
return normalizedFilepath;
|
|
30
30
|
}
|
|
31
|
-
async parseDiff(targetCommitish, baseCommitish, ignoreWhitespace = false) {
|
|
31
|
+
async parseDiff(targetCommitish, baseCommitish, ignoreWhitespace = false, contextLines) {
|
|
32
32
|
try {
|
|
33
33
|
// Validate arguments
|
|
34
34
|
const validation = validateDiffArguments(targetCommitish, baseCommitish);
|
|
@@ -65,6 +65,9 @@ export class GitDiffParser {
|
|
|
65
65
|
if (ignoreWhitespace) {
|
|
66
66
|
diffArgs.push('-w');
|
|
67
67
|
}
|
|
68
|
+
if (contextLines !== undefined) {
|
|
69
|
+
diffArgs.push(`-U${contextLines}`);
|
|
70
|
+
}
|
|
68
71
|
// Ignore external diff-tools to unify output.
|
|
69
72
|
// https://github.com/yoshiko-pg/difit/issues/19
|
|
70
73
|
diffArgs.push('--no-ext-diff', '--color=never');
|
|
@@ -478,11 +481,39 @@ export class GitDiffParser {
|
|
|
478
481
|
}
|
|
479
482
|
return null;
|
|
480
483
|
}
|
|
484
|
+
async getOriginDefaultBranch() {
|
|
485
|
+
try {
|
|
486
|
+
const result = await this.git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']);
|
|
487
|
+
const match = result.trim().match(/refs\/remotes\/origin\/(.+)/);
|
|
488
|
+
if (match) {
|
|
489
|
+
return `origin/${match[1]}`;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
const commonDefaults = ['main', 'master'];
|
|
494
|
+
for (const defaultName of commonDefaults) {
|
|
495
|
+
try {
|
|
496
|
+
await this.git.raw([
|
|
497
|
+
'show-ref',
|
|
498
|
+
'--verify',
|
|
499
|
+
'--quiet',
|
|
500
|
+
`refs/remotes/origin/${defaultName}`,
|
|
501
|
+
]);
|
|
502
|
+
return `origin/${defaultName}`;
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
// Ignore missing refs and continue checking common defaults.
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
481
511
|
async getRevisionOptions(currentBase, currentTarget) {
|
|
482
|
-
const [branchResult, logResult, defaultBranch] = await Promise.all([
|
|
512
|
+
const [branchResult, logResult, defaultBranch, originDefaultBranch] = await Promise.all([
|
|
483
513
|
this.git.branchLocal(),
|
|
484
514
|
this.git.log({ maxCount: 20 }),
|
|
485
515
|
this.getDefaultBranch(),
|
|
516
|
+
this.getOriginDefaultBranch(),
|
|
486
517
|
]);
|
|
487
518
|
const branches = Object.entries(branchResult.branches).map(([name, data]) => ({
|
|
488
519
|
name,
|
|
@@ -526,6 +557,12 @@ export class GitDiffParser {
|
|
|
526
557
|
// If resolution fails, leave undefined
|
|
527
558
|
}
|
|
528
559
|
}
|
|
529
|
-
return {
|
|
560
|
+
return {
|
|
561
|
+
branches,
|
|
562
|
+
commits,
|
|
563
|
+
originDefaultBranch: originDefaultBranch ?? undefined,
|
|
564
|
+
resolvedBase,
|
|
565
|
+
resolvedTarget,
|
|
566
|
+
};
|
|
530
567
|
}
|
|
531
568
|
}
|
|
@@ -1071,6 +1071,26 @@ index abc123..def456 100644
|
|
|
1071
1071
|
});
|
|
1072
1072
|
});
|
|
1073
1073
|
describe('parseDiff', () => {
|
|
1074
|
+
it('passes context lines through to git diff', async () => {
|
|
1075
|
+
const gitDiff = parser.git.diff;
|
|
1076
|
+
const gitRevparse = parser.git.revparse;
|
|
1077
|
+
gitRevparse
|
|
1078
|
+
.mockResolvedValueOnce('1234567890abcdef1234567890abcdef12345678')
|
|
1079
|
+
.mockResolvedValueOnce('abcdef1234567890abcdef1234567890abcdef12');
|
|
1080
|
+
gitDiff.mockResolvedValue('');
|
|
1081
|
+
const response = await parser.parseDiff('HEAD', 'HEAD~1', false, 5);
|
|
1082
|
+
expect(gitDiff).toHaveBeenCalledWith([
|
|
1083
|
+
'abcdef1...1234567',
|
|
1084
|
+
'-U5',
|
|
1085
|
+
'--no-ext-diff',
|
|
1086
|
+
'--color=never',
|
|
1087
|
+
]);
|
|
1088
|
+
expect(response).toEqual({
|
|
1089
|
+
commit: 'abcdef1...1234567',
|
|
1090
|
+
files: [],
|
|
1091
|
+
isEmpty: true,
|
|
1092
|
+
});
|
|
1093
|
+
});
|
|
1074
1094
|
it('accepts branch refs with revision suffixes', async () => {
|
|
1075
1095
|
const gitDiff = parser.git.diff;
|
|
1076
1096
|
const gitRevparse = parser.git.revparse;
|
package/dist/server/server.d.ts
CHANGED
package/dist/server/server.js
CHANGED
|
@@ -51,7 +51,7 @@ export async function startServer(options) {
|
|
|
51
51
|
diffDataCache = parser.parseStdinDiff(options.stdinDiff);
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
diffDataCache = await parser.parseDiff(options.targetCommitish ?? '', options.baseCommitish ?? '', currentIgnoreWhitespace);
|
|
54
|
+
diffDataCache = await parser.parseDiff(options.targetCommitish ?? '', options.baseCommitish ?? '', currentIgnoreWhitespace, options.contextLines);
|
|
55
55
|
}
|
|
56
56
|
// Function to invalidate cache when file changes are detected
|
|
57
57
|
const invalidateCache = () => {
|
|
@@ -92,7 +92,7 @@ export async function startServer(options) {
|
|
|
92
92
|
currentIgnoreWhitespace = ignoreWhitespace;
|
|
93
93
|
currentBaseCommitish = requestedBase;
|
|
94
94
|
currentTargetCommitish = requestedTarget;
|
|
95
|
-
diffDataCache = await parser.parseDiff(requestedTarget, requestedBase, ignoreWhitespace);
|
|
95
|
+
diffDataCache = await parser.parseDiff(requestedTarget, requestedBase, ignoreWhitespace, options.contextLines);
|
|
96
96
|
generatedStatusCache.clear();
|
|
97
97
|
}
|
|
98
98
|
// Resolve symbolic refs like HEAD/HEAD^ to actual hashes for the UI
|
|
@@ -179,7 +179,7 @@ export async function startServer(options) {
|
|
|
179
179
|
return;
|
|
180
180
|
}
|
|
181
181
|
try {
|
|
182
|
-
const { branches, commits, resolvedBase, resolvedTarget } = await parser.getRevisionOptions(currentBaseCommitish, currentTargetCommitish);
|
|
182
|
+
const { branches, commits, originDefaultBranch, resolvedBase, resolvedTarget } = await parser.getRevisionOptions(currentBaseCommitish, currentTargetCommitish);
|
|
183
183
|
const response = {
|
|
184
184
|
specialOptions: [
|
|
185
185
|
{ value: '.', label: 'All Uncommitted Changes' },
|
|
@@ -188,6 +188,7 @@ export async function startServer(options) {
|
|
|
188
188
|
],
|
|
189
189
|
branches,
|
|
190
190
|
commits,
|
|
191
|
+
originDefaultBranch,
|
|
191
192
|
resolvedBase,
|
|
192
193
|
resolvedTarget,
|
|
193
194
|
};
|
|
@@ -5,6 +5,7 @@ import { startServer } from './server.js';
|
|
|
5
5
|
// Add fetch polyfill for Node.js test environment
|
|
6
6
|
const { fetch } = await import('undici');
|
|
7
7
|
globalThis.fetch = fetch;
|
|
8
|
+
const parserInstances = vi.hoisted(() => []);
|
|
8
9
|
// Helper function to get available port
|
|
9
10
|
async function getAvailablePort(preferredPort) {
|
|
10
11
|
let port = preferredPort;
|
|
@@ -25,6 +26,9 @@ async function getAvailablePort(preferredPort) {
|
|
|
25
26
|
// Mock GitDiffParser
|
|
26
27
|
vi.mock('./git-diff.js', () => {
|
|
27
28
|
class GitDiffParserMock {
|
|
29
|
+
constructor() {
|
|
30
|
+
parserInstances.push(this);
|
|
31
|
+
}
|
|
28
32
|
validateCommit = vi.fn().mockResolvedValue(true);
|
|
29
33
|
parseDiff = vi.fn().mockResolvedValue({
|
|
30
34
|
targetCommit: 'abc123',
|
|
@@ -68,6 +72,7 @@ vi.mock('./git-diff.js', () => {
|
|
|
68
72
|
getRevisionOptions = vi.fn().mockResolvedValue({
|
|
69
73
|
branches: [{ name: 'main', current: true }],
|
|
70
74
|
commits: [{ hash: 'abc1234', shortHash: 'abc1234', message: 'Test commit' }],
|
|
75
|
+
originDefaultBranch: 'origin/main',
|
|
71
76
|
resolvedBase: 'abc1234',
|
|
72
77
|
resolvedTarget: 'def5678',
|
|
73
78
|
});
|
|
@@ -167,6 +172,7 @@ describe('Server Integration Tests', () => {
|
|
|
167
172
|
// Mock process.exit to prevent tests from actually exiting
|
|
168
173
|
originalProcessExit = process.exit;
|
|
169
174
|
process.exit = vi.fn();
|
|
175
|
+
parserInstances.length = 0;
|
|
170
176
|
});
|
|
171
177
|
afterEach(async () => {
|
|
172
178
|
// Restore process.exit
|
|
@@ -226,6 +232,17 @@ describe('Server Integration Tests', () => {
|
|
|
226
232
|
servers.push(result.server);
|
|
227
233
|
expect(result.url).toContain('http://localhost:'); // Display host conversion
|
|
228
234
|
});
|
|
235
|
+
it('passes context lines to the initial diff load', async () => {
|
|
236
|
+
const result = await startServer({
|
|
237
|
+
targetCommitish: 'HEAD',
|
|
238
|
+
baseCommitish: 'HEAD^',
|
|
239
|
+
preferredPort: 9025,
|
|
240
|
+
contextLines: 4,
|
|
241
|
+
});
|
|
242
|
+
servers.push(result.server);
|
|
243
|
+
const parser = parserInstances.at(-1);
|
|
244
|
+
expect(parser?.parseDiff).toHaveBeenCalledWith('HEAD', 'HEAD^', false, 4);
|
|
245
|
+
});
|
|
229
246
|
});
|
|
230
247
|
describe('API endpoints', () => {
|
|
231
248
|
let port;
|
|
@@ -256,6 +273,20 @@ describe('Server Integration Tests', () => {
|
|
|
256
273
|
expect(response.ok).toBe(true);
|
|
257
274
|
expect(data).toHaveProperty('ignoreWhitespace', true);
|
|
258
275
|
});
|
|
276
|
+
it('GET /api/diff preserves context lines when recalculating revisions', async () => {
|
|
277
|
+
const result = await startServer({
|
|
278
|
+
targetCommitish: 'HEAD',
|
|
279
|
+
baseCommitish: 'HEAD^',
|
|
280
|
+
preferredPort: 9031,
|
|
281
|
+
contextLines: 2,
|
|
282
|
+
});
|
|
283
|
+
servers.push(result.server);
|
|
284
|
+
const parser = parserInstances.at(-1);
|
|
285
|
+
parser?.parseDiff.mockClear();
|
|
286
|
+
const response = await fetch(`http://localhost:${result.port}/api/diff?base=main&target=feature&ignoreWhitespace=true`);
|
|
287
|
+
expect(response.ok).toBe(true);
|
|
288
|
+
expect(parser?.parseDiff).toHaveBeenCalledWith('feature', 'main', true, 2);
|
|
289
|
+
});
|
|
259
290
|
it('GET /api/diff returns comment import payload when configured', async () => {
|
|
260
291
|
const importedComments = [
|
|
261
292
|
{
|
|
@@ -565,6 +596,7 @@ describe('Server Integration Tests', () => {
|
|
|
565
596
|
expect(data.commits).toEqual([
|
|
566
597
|
{ hash: 'abc1234', shortHash: 'abc1234', message: 'Test commit' },
|
|
567
598
|
]);
|
|
599
|
+
expect(data.originDefaultBranch).toBe('origin/main');
|
|
568
600
|
expect(data.resolvedBase).toBe('abc1234');
|
|
569
601
|
expect(data.resolvedTarget).toBe('def5678');
|
|
570
602
|
});
|
package/dist/tui/App.d.ts
CHANGED
package/dist/tui/App.js
CHANGED
|
@@ -6,7 +6,7 @@ import DiffViewer from './components/DiffViewer.js';
|
|
|
6
6
|
import FileList from './components/FileList.js';
|
|
7
7
|
import SideBySideDiffViewer from './components/SideBySideDiffViewer.js';
|
|
8
8
|
import StatusBar from './components/StatusBar.js';
|
|
9
|
-
const App = ({ targetCommitish, baseCommitish, mode, repoPath }) => {
|
|
9
|
+
const App = ({ targetCommitish, baseCommitish, mode, repoPath, contextLines, }) => {
|
|
10
10
|
const [files, setFiles] = useState([]);
|
|
11
11
|
const [selectedFileIndex, setSelectedFileIndex] = useState(0);
|
|
12
12
|
const [loading, setLoading] = useState(true);
|
|
@@ -17,7 +17,7 @@ const App = ({ targetCommitish, baseCommitish, mode, repoPath }) => {
|
|
|
17
17
|
setLoading(true);
|
|
18
18
|
setError(null);
|
|
19
19
|
try {
|
|
20
|
-
const fileDiffs = await loadGitDiff(targetCommitish, baseCommitish, repoPath);
|
|
20
|
+
const fileDiffs = await loadGitDiff(targetCommitish, baseCommitish, repoPath, contextLines);
|
|
21
21
|
setFiles(fileDiffs);
|
|
22
22
|
setLoading(false);
|
|
23
23
|
}
|
package/dist/types/diff.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{V as a,W as n}from"./mermaid.core-DV5JJ1Ie.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-Cn7a6CO3.js";import{_ as i}from"./mermaid.core-DV5JJ1Ie.js";import"./chunk-FMBD7UC4-CrKv7ndg.js";import"./chunk-JSJVCQXG-DyBDhAEM.js";import"./chunk-55IACEB6-CrZL3qv9.js";import"./chunk-KX2RTZJC-By5mkZmU.js";import"./index-BLNN1bfE.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-Cn7a6CO3.js";import{_ as i}from"./mermaid.core-DV5JJ1Ie.js";import"./chunk-FMBD7UC4-CrKv7ndg.js";import"./chunk-JSJVCQXG-DyBDhAEM.js";import"./chunk-55IACEB6-CrZL3qv9.js";import"./chunk-KX2RTZJC-By5mkZmU.js";import"./index-BLNN1bfE.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./_baseUniq-tbL7nVvN.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as e,b as r,a,S as s}from"./chunk-NQ4KR5QH-C30p9xRx.js";import{_ as i}from"./mermaid.core-DV5JJ1Ie.js";import"./chunk-55IACEB6-CrZL3qv9.js";import"./chunk-KX2RTZJC-By5mkZmU.js";import"./index-BLNN1bfE.js";var p={parser:a,get db(){return new s(2)},renderer:r,styles:e,init:i(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{p as diagram};
|