difit 2.2.1 → 2.2.3

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.
Files changed (31) hide show
  1. package/LICENSE +2 -2
  2. package/README.ja.md +4 -1
  3. package/README.ko.md +4 -1
  4. package/README.md +4 -1
  5. package/README.zh.md +4 -1
  6. package/dist/cli/index.js +0 -0
  7. package/dist/client/assets/index-D4o04IuQ.css +1 -0
  8. package/dist/client/assets/{index-KydrgTN-.js → index-DdgLWfl6.js} +70 -70
  9. package/dist/client/assets/{prism-csharp-R5PE7dGT.js → prism-csharp-DNLu89K5.js} +1 -1
  10. package/dist/client/assets/{prism-java-BvQgUZlL.js → prism-java-DPmqUWjf.js} +1 -1
  11. package/dist/client/assets/{prism-php-sGBBrTD-.js → prism-php-BERkcwmm.js} +1 -1
  12. package/dist/client/assets/{prism-ruby-CBz5QFG3.js → prism-ruby-BWOjhenp.js} +1 -1
  13. package/dist/client/assets/{prism-solidity-Ck6Q6Nkr.js → prism-solidity-CD2S3KYq.js} +1 -1
  14. package/dist/client/index.html +2 -2
  15. package/dist/server/git-diff.d.ts +4 -0
  16. package/dist/server/git-diff.js +131 -7
  17. package/dist/server/git-diff.test.js +318 -0
  18. package/dist/server/server.js +2 -1
  19. package/dist/types/diff.d.ts +2 -1
  20. package/package.json +4 -3
  21. package/dist/client/assets/index-Bz9yRRZ7.css +0 -1
  22. package/dist/server/schemas/commentSchema.d.ts +0 -22
  23. package/dist/server/schemas/commentSchema.js +0 -16
  24. package/dist/server/schemas/commentSchema.test.d.ts +0 -1
  25. package/dist/server/schemas/commentSchema.test.js +0 -229
  26. package/dist/utils/commentFormatter.d.ts +0 -26
  27. package/dist/utils/commentFormatter.js +0 -50
  28. package/dist/utils/gitUtils.d.ts +0 -4
  29. package/dist/utils/gitUtils.js +0 -29
  30. package/dist/utils/gitUtils.test.d.ts +0 -1
  31. package/dist/utils/gitUtils.test.js +0 -63
@@ -1,229 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { CommentSchema, CommentsPayloadSchema, LineNumberSchema } from './commentSchema';
3
- describe('Comment Schema Validation', () => {
4
- describe('LineNumberSchema', () => {
5
- it('should accept single number', () => {
6
- const result = LineNumberSchema.safeParse(42);
7
- expect(result.success).toBe(true);
8
- if (result.success) {
9
- expect(result.data).toBe(42);
10
- }
11
- });
12
- it('should accept tuple of two numbers', () => {
13
- const result = LineNumberSchema.safeParse([10, 20]);
14
- expect(result.success).toBe(true);
15
- if (result.success) {
16
- expect(result.data).toEqual([10, 20]);
17
- }
18
- });
19
- it('should reject string', () => {
20
- const result = LineNumberSchema.safeParse('42');
21
- expect(result.success).toBe(false);
22
- });
23
- it('should reject array with more than 2 numbers', () => {
24
- const result = LineNumberSchema.safeParse([1, 2, 3]);
25
- expect(result.success).toBe(false);
26
- });
27
- it('should reject array with less than 2 numbers', () => {
28
- const result = LineNumberSchema.safeParse([1]);
29
- expect(result.success).toBe(false);
30
- });
31
- });
32
- describe('CommentSchema', () => {
33
- it('should accept valid comment with single line number', () => {
34
- const comment = {
35
- id: '123',
36
- file: 'src/app.ts',
37
- line: 42,
38
- body: 'Test comment',
39
- timestamp: '2024-01-01T00:00:00Z',
40
- };
41
- const result = CommentSchema.safeParse(comment);
42
- expect(result.success).toBe(true);
43
- if (result.success) {
44
- expect(result.data).toEqual(comment);
45
- }
46
- });
47
- it('should accept valid comment with line range', () => {
48
- const comment = {
49
- id: '456',
50
- file: 'src/utils.ts',
51
- line: [10, 20],
52
- body: 'Range comment',
53
- timestamp: '2024-01-01T00:00:00Z',
54
- };
55
- const result = CommentSchema.safeParse(comment);
56
- expect(result.success).toBe(true);
57
- if (result.success) {
58
- expect(result.data).toEqual(comment);
59
- }
60
- });
61
- it('should accept comment with optional codeContent', () => {
62
- const comment = {
63
- id: '789',
64
- file: 'src/index.ts',
65
- line: 1,
66
- body: 'Comment with code',
67
- timestamp: '2024-01-01T00:00:00Z',
68
- codeContent: 'const x = 42;',
69
- };
70
- const result = CommentSchema.safeParse(comment);
71
- expect(result.success).toBe(true);
72
- if (result.success) {
73
- expect(result.data.codeContent).toBe('const x = 42;');
74
- }
75
- });
76
- it('should reject comment without required fields', () => {
77
- const invalidComment = {
78
- id: '123',
79
- // missing file
80
- line: 42,
81
- body: 'Test',
82
- timestamp: '2024-01-01T00:00:00Z',
83
- };
84
- const result = CommentSchema.safeParse(invalidComment);
85
- expect(result.success).toBe(false);
86
- if (!result.success) {
87
- expect(result.error.issues[0]?.path).toContain('file');
88
- }
89
- });
90
- it('should reject comment with wrong type for file', () => {
91
- const invalidComment = {
92
- id: '123',
93
- file: 123, // should be string
94
- line: 42,
95
- body: 'Test',
96
- timestamp: '2024-01-01T00:00:00Z',
97
- };
98
- const result = CommentSchema.safeParse(invalidComment);
99
- expect(result.success).toBe(false);
100
- });
101
- it('should reject comment with invalid line format', () => {
102
- const invalidComment = {
103
- id: '123',
104
- file: 'test.ts',
105
- line: 'invalid', // should be number or [number, number]
106
- body: 'Test',
107
- timestamp: '2024-01-01T00:00:00Z',
108
- };
109
- const result = CommentSchema.safeParse(invalidComment);
110
- expect(result.success).toBe(false);
111
- });
112
- });
113
- describe('CommentsPayloadSchema', () => {
114
- it('should accept valid payload with comments array', () => {
115
- const payload = {
116
- comments: [
117
- {
118
- id: '1',
119
- file: 'file1.ts',
120
- line: 10,
121
- body: 'Comment 1',
122
- timestamp: '2024-01-01T00:00:00Z',
123
- },
124
- {
125
- id: '2',
126
- file: 'file2.ts',
127
- line: [20, 30],
128
- body: 'Comment 2',
129
- timestamp: '2024-01-01T00:01:00Z',
130
- },
131
- ],
132
- };
133
- const result = CommentsPayloadSchema.safeParse(payload);
134
- expect(result.success).toBe(true);
135
- if (result.success) {
136
- expect(result.data.comments).toHaveLength(2);
137
- }
138
- });
139
- it('should accept empty comments array', () => {
140
- const payload = { comments: [] };
141
- const result = CommentsPayloadSchema.safeParse(payload);
142
- expect(result.success).toBe(true);
143
- if (result.success) {
144
- expect(result.data.comments).toEqual([]);
145
- }
146
- });
147
- it('should accept payload without comments property', () => {
148
- const payload = {};
149
- const result = CommentsPayloadSchema.safeParse(payload);
150
- expect(result.success).toBe(true);
151
- if (result.success) {
152
- expect(result.data.comments).toBeUndefined();
153
- }
154
- });
155
- it('should reject payload with invalid comment in array', () => {
156
- const payload = {
157
- comments: [
158
- {
159
- id: '1',
160
- file: 'file1.ts',
161
- line: 10,
162
- body: 'Valid comment',
163
- timestamp: '2024-01-01T00:00:00Z',
164
- },
165
- {
166
- id: '2',
167
- // missing file property
168
- line: 20,
169
- body: 'Invalid comment',
170
- timestamp: '2024-01-01T00:01:00Z',
171
- },
172
- ],
173
- };
174
- const result = CommentsPayloadSchema.safeParse(payload);
175
- expect(result.success).toBe(false);
176
- });
177
- it('should reject payload with comments as non-array', () => {
178
- const payload = {
179
- comments: 'not an array',
180
- };
181
- const result = CommentsPayloadSchema.safeParse(payload);
182
- expect(result.success).toBe(false);
183
- });
184
- it('should handle real-world DiffComment format from client', () => {
185
- // This simulates the actual DiffComment format sent from client
186
- const diffCommentPayload = {
187
- comments: [
188
- {
189
- id: 'abc123',
190
- filePath: 'src/components/Button.tsx', // Note: 'filePath' instead of 'file'
191
- position: {
192
- line: 42,
193
- side: 'new',
194
- },
195
- body: 'Fix this button',
196
- createdAt: '2024-01-01T00:00:00Z',
197
- },
198
- ],
199
- };
200
- const result = CommentsPayloadSchema.safeParse(diffCommentPayload);
201
- expect(result.success).toBe(false); // Should fail because of incorrect property names
202
- if (!result.success) {
203
- // Check that it fails because 'file' is missing
204
- const fileIssue = result.error.issues.find((issue) => issue.path.includes('file'));
205
- expect(fileIssue).toBeDefined();
206
- }
207
- });
208
- it('should accept properly transformed comments from client', () => {
209
- // This is what the client should send after transformation
210
- const transformedPayload = {
211
- comments: [
212
- {
213
- id: 'abc123',
214
- file: 'src/components/Button.tsx', // Correct property name
215
- line: 42, // Extracted from position.line
216
- body: 'Fix this button',
217
- timestamp: '2024-01-01T00:00:00Z', // Renamed from createdAt
218
- },
219
- ],
220
- };
221
- const result = CommentsPayloadSchema.safeParse(transformedPayload);
222
- expect(result.success).toBe(true);
223
- if (result.success) {
224
- expect(result.data.comments).toHaveLength(1);
225
- expect(result.data.comments[0].file).toBe('src/components/Button.tsx');
226
- }
227
- });
228
- });
229
- });
@@ -1,26 +0,0 @@
1
- import { type Comment, type LineNumber } from '../types/diff';
2
- /**
3
- * Formats a line number or range for display
4
- * @param line - Single line number or line range
5
- * @returns Formatted string like "L10" or "L10-L20", or empty string if line is undefined
6
- */
7
- export declare function formatLineNumber(line: LineNumber | undefined): string;
8
- /**
9
- * Formats a single comment for prompt output
10
- * @param comment - The comment to format
11
- * @returns Formatted string like "file.ts:L10\nComment body"
12
- */
13
- export declare function formatCommentPrompt(comment: Comment): string;
14
- /**
15
- * Formats multiple comments for batch output
16
- * @param comments - Array of comments to format
17
- * @param separator - Separator between comments (default: "=====")
18
- * @returns Formatted string with all comments separated
19
- */
20
- export declare function formatCommentsPrompt(comments: Comment[], separator?: string): string;
21
- /**
22
- * Formats comments for server output with decorative elements
23
- * @param comments - Array of comments to format
24
- * @returns Formatted string with header and footer
25
- */
26
- export declare function formatCommentsOutput(comments: Comment[]): string;
@@ -1,50 +0,0 @@
1
- /**
2
- * Formats a line number or range for display
3
- * @param line - Single line number or line range
4
- * @returns Formatted string like "L10" or "L10-L20", or empty string if line is undefined
5
- */
6
- export function formatLineNumber(line) {
7
- if (!line)
8
- return '';
9
- if (Array.isArray(line)) {
10
- return `L${line[0]}-L${line[1]}`;
11
- }
12
- return `L${line}`;
13
- }
14
- /**
15
- * Formats a single comment for prompt output
16
- * @param comment - The comment to format
17
- * @returns Formatted string like "file.ts:L10\nComment body"
18
- */
19
- export function formatCommentPrompt(comment) {
20
- const lineDisplay = formatLineNumber(comment.line);
21
- const location = lineDisplay ? `${comment.file}:${lineDisplay}` : comment.file;
22
- return `${location}\n${comment.body}`;
23
- }
24
- /**
25
- * Formats multiple comments for batch output
26
- * @param comments - Array of comments to format
27
- * @param separator - Separator between comments (default: "=====")
28
- * @returns Formatted string with all comments separated
29
- */
30
- export function formatCommentsPrompt(comments, separator = '=====') {
31
- if (comments.length === 0) {
32
- return 'No comments available.';
33
- }
34
- return comments.map(formatCommentPrompt).join(`\n${separator}\n`);
35
- }
36
- /**
37
- * Formats comments for server output with decorative elements
38
- * @param comments - Array of comments to format
39
- * @returns Formatted string with header and footer
40
- */
41
- export function formatCommentsOutput(comments) {
42
- const prompts = formatCommentsPrompt(comments);
43
- return [
44
- '\n📝 Comments from review session:',
45
- '='.repeat(50),
46
- prompts,
47
- '='.repeat(50),
48
- `Total comments: ${comments.length}\n`,
49
- ].join('\n');
50
- }
@@ -1,4 +0,0 @@
1
- import type { SimpleGit } from 'simple-git';
2
- export declare function shortHash(hash: string): string;
3
- export declare function createCommitRangeString(baseHash: string, targetHash: string): string;
4
- export declare function resolveCommitDisplayString(baseCommitish: string, targetCommitish: string, git: SimpleGit): Promise<string>;
@@ -1,29 +0,0 @@
1
- export function shortHash(hash) {
2
- return hash.substring(0, 7);
3
- }
4
- export function createCommitRangeString(baseHash, targetHash) {
5
- return `${baseHash}...${targetHash}`;
6
- }
7
- export async function resolveCommitDisplayString(baseCommitish, targetCommitish, git) {
8
- // Handle target special chars (base is always a regular commit)
9
- if (targetCommitish === 'working') {
10
- // Show unstaged changes (working vs staged)
11
- return 'Working Directory (unstaged changes)';
12
- }
13
- else if (targetCommitish === 'staged') {
14
- // Show staged changes against base commit
15
- const baseHash = await git.revparse([baseCommitish]);
16
- return `${shortHash(baseHash)} vs Staging Area (staged changes)`;
17
- }
18
- else if (targetCommitish === '.') {
19
- // Show all uncommitted changes against base commit
20
- const baseHash = await git.revparse([baseCommitish]);
21
- return `${shortHash(baseHash)} vs Working Directory (all uncommitted changes)`;
22
- }
23
- else {
24
- // Both are regular commits: standard commit-to-commit comparison
25
- const targetHash = await git.revparse([targetCommitish]);
26
- const baseHash = await git.revparse([baseCommitish]);
27
- return createCommitRangeString(shortHash(baseHash), shortHash(targetHash));
28
- }
29
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,63 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { shortHash, createCommitRangeString, resolveCommitDisplayString } from './gitUtils';
3
- describe('Git Utils', () => {
4
- describe('shortHash', () => {
5
- it('should return first 7 characters of hash', () => {
6
- expect(shortHash('a1b2c3d4e5f6789012345678901234567890abcd')).toBe('a1b2c3d');
7
- expect(shortHash('1234567890abcdef')).toBe('1234567');
8
- expect(shortHash('abc123')).toBe('abc123');
9
- });
10
- it('should handle short hashes', () => {
11
- expect(shortHash('abc')).toBe('abc');
12
- expect(shortHash('')).toBe('');
13
- expect(shortHash('a')).toBe('a');
14
- });
15
- });
16
- describe('createCommitRangeString', () => {
17
- it('should create commit range string with triple dots', () => {
18
- expect(createCommitRangeString('abc1234', 'def5678')).toBe('abc1234...def5678');
19
- expect(createCommitRangeString('a1b2c3d', '4e5f6g7')).toBe('a1b2c3d...4e5f6g7');
20
- });
21
- it('should handle empty strings', () => {
22
- expect(createCommitRangeString('', '')).toBe('...');
23
- expect(createCommitRangeString('abc123', '')).toBe('abc123...');
24
- expect(createCommitRangeString('', 'def456')).toBe('...def456');
25
- });
26
- });
27
- describe('resolveCommitDisplayString', () => {
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- const mockGit = {
30
- revparse: vi.fn(),
31
- };
32
- beforeEach(() => {
33
- vi.clearAllMocks();
34
- });
35
- it('should handle working directory target', async () => {
36
- const result = await resolveCommitDisplayString('main', 'working', mockGit);
37
- expect(result).toBe('Working Directory (unstaged changes)');
38
- expect(mockGit.revparse).not.toHaveBeenCalled();
39
- });
40
- it('should handle staged target', async () => {
41
- mockGit.revparse.mockResolvedValue('a1b2c3d4e5f6789012345678901234567890abcd');
42
- const result = await resolveCommitDisplayString('main', 'staged', mockGit);
43
- expect(result).toBe('a1b2c3d vs Staging Area (staged changes)');
44
- expect(mockGit.revparse).toHaveBeenCalledWith(['main']);
45
- });
46
- it('should handle dot (.) target', async () => {
47
- mockGit.revparse.mockResolvedValue('a1b2c3d4e5f6789012345678901234567890abcd');
48
- const result = await resolveCommitDisplayString('main', '.', mockGit);
49
- expect(result).toBe('a1b2c3d vs Working Directory (all uncommitted changes)');
50
- expect(mockGit.revparse).toHaveBeenCalledWith(['main']);
51
- });
52
- it('should handle regular commit to commit comparison', async () => {
53
- mockGit.revparse
54
- .mockResolvedValueOnce('def4567890abcdef1234567890abcdef12345678') // target (called first)
55
- .mockResolvedValueOnce('a1b2c3d4e5f6789012345678901234567890abcd'); // base (called second)
56
- const result = await resolveCommitDisplayString('main', 'develop', mockGit);
57
- expect(result).toBe('a1b2c3d...def4567');
58
- expect(mockGit.revparse).toHaveBeenCalledWith(['develop']);
59
- expect(mockGit.revparse).toHaveBeenCalledWith(['main']);
60
- expect(mockGit.revparse).toHaveBeenCalledTimes(2);
61
- });
62
- });
63
- });