diff-hound 1.0.2 → 1.2.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/README.md +105 -25
- package/dist/cli/index.js +14 -3
- package/dist/config/index.js +3 -3
- package/dist/config/index.test.d.ts +1 -0
- package/dist/config/index.test.js +330 -0
- package/dist/core/parseUnifiedDiff.test.d.ts +1 -0
- package/dist/core/parseUnifiedDiff.test.js +310 -0
- package/dist/index.js +17 -9
- package/dist/models/base.d.ts +74 -0
- package/dist/models/base.js +236 -0
- package/dist/models/base.test.d.ts +1 -0
- package/dist/models/base.test.js +241 -0
- package/dist/models/index.d.ts +6 -2
- package/dist/models/index.js +9 -2
- package/dist/models/ollama.d.ts +28 -0
- package/dist/models/ollama.js +88 -0
- package/dist/models/ollama.test.d.ts +1 -0
- package/dist/models/ollama.test.js +235 -0
- package/dist/models/openai.d.ts +14 -17
- package/dist/models/openai.js +41 -125
- package/dist/models/openai.test.d.ts +1 -0
- package/dist/models/openai.test.js +209 -0
- package/dist/platforms/index.d.ts +3 -2
- package/dist/platforms/index.js +8 -1
- package/dist/platforms/local.d.ts +41 -0
- package/dist/platforms/local.js +247 -0
- package/dist/schemas/review-response.d.ts +37 -0
- package/dist/schemas/review-response.js +39 -0
- package/dist/schemas/review-response.json +68 -0
- package/dist/schemas/validate.d.ts +27 -0
- package/dist/schemas/validate.js +108 -0
- package/dist/schemas/validate.test.d.ts +1 -0
- package/dist/schemas/validate.test.js +484 -0
- package/dist/types/index.d.ts +7 -2
- package/package.json +12 -3
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const validate_1 = require("./validate");
|
|
5
|
+
const review_response_1 = require("./review-response");
|
|
6
|
+
(0, vitest_1.describe)("Schema Validation", () => {
|
|
7
|
+
(0, vitest_1.describe)("validateStructuredResponse", () => {
|
|
8
|
+
(0, vitest_1.it)("should validate a valid structured response", () => {
|
|
9
|
+
const response = {
|
|
10
|
+
summary: "Overall review",
|
|
11
|
+
comments: [
|
|
12
|
+
{
|
|
13
|
+
file: "src/utils.ts",
|
|
14
|
+
line: 10,
|
|
15
|
+
severity: "warning",
|
|
16
|
+
category: "style",
|
|
17
|
+
confidence: 0.85,
|
|
18
|
+
title: "Use const instead of let",
|
|
19
|
+
explanation: "The variable is never reassigned",
|
|
20
|
+
suggestion: "",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
25
|
+
(0, vitest_1.expect)(result.valid).toBe(true);
|
|
26
|
+
(0, vitest_1.expect)(result.errors).toHaveLength(0);
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)("should validate response with empty summary", () => {
|
|
29
|
+
const response = {
|
|
30
|
+
summary: "",
|
|
31
|
+
comments: [
|
|
32
|
+
{
|
|
33
|
+
file: "src/utils.ts",
|
|
34
|
+
line: 10,
|
|
35
|
+
severity: "warning",
|
|
36
|
+
category: "style",
|
|
37
|
+
confidence: 0.85,
|
|
38
|
+
title: "Use const instead of let",
|
|
39
|
+
explanation: "The variable is never reassigned",
|
|
40
|
+
suggestion: "",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
45
|
+
(0, vitest_1.expect)(result.valid).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)("should fail for non-object response", () => {
|
|
48
|
+
const result = (0, validate_1.validateStructuredResponse)("not an object");
|
|
49
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
50
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("must be an object");
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)("should fail for missing comments array", () => {
|
|
53
|
+
const response = { summary: "No comments" };
|
|
54
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
55
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
56
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("'comments' must be an array");
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)("should fail for invalid severity", () => {
|
|
59
|
+
const response = {
|
|
60
|
+
comments: [
|
|
61
|
+
{
|
|
62
|
+
file: "src/utils.ts",
|
|
63
|
+
line: 10,
|
|
64
|
+
severity: "invalid",
|
|
65
|
+
category: "style",
|
|
66
|
+
confidence: 0.85,
|
|
67
|
+
title: "Test",
|
|
68
|
+
explanation: "Test",
|
|
69
|
+
suggestion: "",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
74
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
75
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("severity");
|
|
76
|
+
});
|
|
77
|
+
(0, vitest_1.it)("should fail for invalid category", () => {
|
|
78
|
+
const response = {
|
|
79
|
+
comments: [
|
|
80
|
+
{
|
|
81
|
+
file: "src/utils.ts",
|
|
82
|
+
line: 10,
|
|
83
|
+
severity: "warning",
|
|
84
|
+
category: "invalid",
|
|
85
|
+
confidence: 0.85,
|
|
86
|
+
title: "Test",
|
|
87
|
+
explanation: "Test",
|
|
88
|
+
suggestion: "",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
93
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
94
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("category");
|
|
95
|
+
});
|
|
96
|
+
(0, vitest_1.it)("should fail for confidence out of range", () => {
|
|
97
|
+
const response = {
|
|
98
|
+
comments: [
|
|
99
|
+
{
|
|
100
|
+
file: "src/utils.ts",
|
|
101
|
+
line: 10,
|
|
102
|
+
severity: "warning",
|
|
103
|
+
category: "style",
|
|
104
|
+
confidence: 1.5,
|
|
105
|
+
title: "Test",
|
|
106
|
+
explanation: "Test",
|
|
107
|
+
suggestion: "",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
112
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
113
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("confidence");
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)("should fail for negative confidence", () => {
|
|
116
|
+
const response = {
|
|
117
|
+
comments: [
|
|
118
|
+
{
|
|
119
|
+
file: "src/utils.ts",
|
|
120
|
+
line: 10,
|
|
121
|
+
severity: "warning",
|
|
122
|
+
category: "style",
|
|
123
|
+
confidence: -0.1,
|
|
124
|
+
title: "Test",
|
|
125
|
+
explanation: "Test",
|
|
126
|
+
suggestion: "",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
131
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
132
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("confidence");
|
|
133
|
+
});
|
|
134
|
+
(0, vitest_1.it)("should fail for line number less than 1", () => {
|
|
135
|
+
const response = {
|
|
136
|
+
comments: [
|
|
137
|
+
{
|
|
138
|
+
file: "src/utils.ts",
|
|
139
|
+
line: 0,
|
|
140
|
+
severity: "warning",
|
|
141
|
+
category: "style",
|
|
142
|
+
confidence: 0.85,
|
|
143
|
+
title: "Test",
|
|
144
|
+
explanation: "Test",
|
|
145
|
+
suggestion: "",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
150
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
151
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("line");
|
|
152
|
+
});
|
|
153
|
+
(0, vitest_1.it)("should fail for non-integer line number", () => {
|
|
154
|
+
const response = {
|
|
155
|
+
comments: [
|
|
156
|
+
{
|
|
157
|
+
file: "src/utils.ts",
|
|
158
|
+
line: 10.5,
|
|
159
|
+
severity: "warning",
|
|
160
|
+
category: "style",
|
|
161
|
+
confidence: 0.85,
|
|
162
|
+
title: "Test",
|
|
163
|
+
explanation: "Test",
|
|
164
|
+
suggestion: "",
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
169
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
170
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("line");
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.it)("should fail for empty file path", () => {
|
|
173
|
+
const response = {
|
|
174
|
+
comments: [
|
|
175
|
+
{
|
|
176
|
+
file: "",
|
|
177
|
+
line: 10,
|
|
178
|
+
severity: "warning",
|
|
179
|
+
category: "style",
|
|
180
|
+
confidence: 0.85,
|
|
181
|
+
title: "Test",
|
|
182
|
+
explanation: "Test",
|
|
183
|
+
suggestion: "",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
188
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
189
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("file");
|
|
190
|
+
});
|
|
191
|
+
(0, vitest_1.it)("should fail for empty title", () => {
|
|
192
|
+
const response = {
|
|
193
|
+
comments: [
|
|
194
|
+
{
|
|
195
|
+
file: "src/utils.ts",
|
|
196
|
+
line: 10,
|
|
197
|
+
severity: "warning",
|
|
198
|
+
category: "style",
|
|
199
|
+
confidence: 0.85,
|
|
200
|
+
title: "",
|
|
201
|
+
explanation: "Test",
|
|
202
|
+
suggestion: "",
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
207
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
208
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("title");
|
|
209
|
+
});
|
|
210
|
+
(0, vitest_1.it)("should fail for empty explanation", () => {
|
|
211
|
+
const response = {
|
|
212
|
+
comments: [
|
|
213
|
+
{
|
|
214
|
+
file: "src/utils.ts",
|
|
215
|
+
line: 10,
|
|
216
|
+
severity: "warning",
|
|
217
|
+
category: "style",
|
|
218
|
+
confidence: 0.85,
|
|
219
|
+
title: "Test",
|
|
220
|
+
explanation: "",
|
|
221
|
+
suggestion: "",
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
226
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
227
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("explanation");
|
|
228
|
+
});
|
|
229
|
+
(0, vitest_1.it)("should validate all valid severity values", () => {
|
|
230
|
+
const severities = ["critical", "warning", "suggestion", "nitpick"];
|
|
231
|
+
for (const severity of severities) {
|
|
232
|
+
const response = {
|
|
233
|
+
summary: "",
|
|
234
|
+
comments: [
|
|
235
|
+
{
|
|
236
|
+
file: "src/utils.ts",
|
|
237
|
+
line: 10,
|
|
238
|
+
severity,
|
|
239
|
+
category: "style",
|
|
240
|
+
confidence: 0.85,
|
|
241
|
+
title: "Test",
|
|
242
|
+
explanation: "Test",
|
|
243
|
+
suggestion: "",
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
};
|
|
247
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
248
|
+
(0, vitest_1.expect)(result.valid).toBe(true);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
(0, vitest_1.it)("should validate all valid category values", () => {
|
|
252
|
+
const categories = ["bug", "security", "performance", "style", "architecture", "testing"];
|
|
253
|
+
for (const category of categories) {
|
|
254
|
+
const response = {
|
|
255
|
+
summary: "",
|
|
256
|
+
comments: [
|
|
257
|
+
{
|
|
258
|
+
file: "src/utils.ts",
|
|
259
|
+
line: 10,
|
|
260
|
+
severity: "warning",
|
|
261
|
+
category,
|
|
262
|
+
confidence: 0.85,
|
|
263
|
+
title: "Test",
|
|
264
|
+
explanation: "Test",
|
|
265
|
+
suggestion: "",
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
270
|
+
(0, vitest_1.expect)(result.valid).toBe(true);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
(0, vitest_1.it)("should validate response with suggestion", () => {
|
|
274
|
+
const response = {
|
|
275
|
+
summary: "",
|
|
276
|
+
comments: [
|
|
277
|
+
{
|
|
278
|
+
file: "src/utils.ts",
|
|
279
|
+
line: 10,
|
|
280
|
+
severity: "warning",
|
|
281
|
+
category: "style",
|
|
282
|
+
confidence: 0.85,
|
|
283
|
+
title: "Use const",
|
|
284
|
+
explanation: "Variable is not reassigned",
|
|
285
|
+
suggestion: "const x = 5;",
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
290
|
+
(0, vitest_1.expect)(result.valid).toBe(true);
|
|
291
|
+
});
|
|
292
|
+
(0, vitest_1.it)("should fail for non-string suggestion", () => {
|
|
293
|
+
const response = {
|
|
294
|
+
comments: [
|
|
295
|
+
{
|
|
296
|
+
file: "src/utils.ts",
|
|
297
|
+
line: 10,
|
|
298
|
+
severity: "warning",
|
|
299
|
+
category: "style",
|
|
300
|
+
confidence: 0.85,
|
|
301
|
+
title: "Test",
|
|
302
|
+
explanation: "Test",
|
|
303
|
+
suggestion: 123,
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
};
|
|
307
|
+
const result = (0, validate_1.validateStructuredResponse)(response);
|
|
308
|
+
(0, vitest_1.expect)(result.valid).toBe(false);
|
|
309
|
+
(0, vitest_1.expect)(result.errors[0]).toContain("suggestion");
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
(0, vitest_1.describe)("parseStructuredResponse", () => {
|
|
313
|
+
(0, vitest_1.it)("should parse valid JSON string", () => {
|
|
314
|
+
const json = JSON.stringify({
|
|
315
|
+
summary: "Test summary",
|
|
316
|
+
comments: [
|
|
317
|
+
{
|
|
318
|
+
file: "src/utils.ts",
|
|
319
|
+
line: 10,
|
|
320
|
+
severity: "warning",
|
|
321
|
+
category: "style",
|
|
322
|
+
confidence: 0.85,
|
|
323
|
+
title: "Test",
|
|
324
|
+
explanation: "Test",
|
|
325
|
+
suggestion: "",
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
});
|
|
329
|
+
const result = (0, validate_1.parseStructuredResponse)(json);
|
|
330
|
+
(0, vitest_1.expect)(result.success).toBe(true);
|
|
331
|
+
(0, vitest_1.expect)(result.data).toBeDefined();
|
|
332
|
+
(0, vitest_1.expect)(result.data?.comments).toHaveLength(1);
|
|
333
|
+
});
|
|
334
|
+
(0, vitest_1.it)("should return error for invalid JSON", () => {
|
|
335
|
+
const result = (0, validate_1.parseStructuredResponse)("not json");
|
|
336
|
+
(0, vitest_1.expect)(result.success).toBe(false);
|
|
337
|
+
(0, vitest_1.expect)(result.error).toContain("JSON parse error");
|
|
338
|
+
});
|
|
339
|
+
(0, vitest_1.it)("should return error for invalid structure", () => {
|
|
340
|
+
const json = JSON.stringify({ comments: "not an array" });
|
|
341
|
+
const result = (0, validate_1.parseStructuredResponse)(json);
|
|
342
|
+
(0, vitest_1.expect)(result.success).toBe(false);
|
|
343
|
+
(0, vitest_1.expect)(result.error).toContain("Validation failed");
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
(0, vitest_1.describe)("looksLikeStructuredResponse", () => {
|
|
347
|
+
(0, vitest_1.it)("should return true for JSON with comments array", () => {
|
|
348
|
+
const response = '{"comments": []}';
|
|
349
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)(response)).toBe(true);
|
|
350
|
+
});
|
|
351
|
+
(0, vitest_1.it)("should return true for JSON with comments and summary", () => {
|
|
352
|
+
const response = '{"summary": "test", "comments": [{"file": "test.ts"}]}';
|
|
353
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)(response)).toBe(true);
|
|
354
|
+
});
|
|
355
|
+
(0, vitest_1.it)("should return false for non-JSON string", () => {
|
|
356
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)("not json")).toBe(false);
|
|
357
|
+
});
|
|
358
|
+
(0, vitest_1.it)("should return false for JSON without comments array", () => {
|
|
359
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)('{"summary": "test"}')).toBe(false);
|
|
360
|
+
});
|
|
361
|
+
(0, vitest_1.it)("should return false for JSON array", () => {
|
|
362
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)('["item1", "item2"]')).toBe(false);
|
|
363
|
+
});
|
|
364
|
+
(0, vitest_1.it)("should return false for empty string", () => {
|
|
365
|
+
(0, vitest_1.expect)((0, validate_1.looksLikeStructuredResponse)("")).toBe(false);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
(0, vitest_1.describe)("toAIComment", () => {
|
|
369
|
+
(0, vitest_1.it)("should convert critical severity to error", () => {
|
|
370
|
+
const comment = {
|
|
371
|
+
file: "src/test.ts",
|
|
372
|
+
line: 10,
|
|
373
|
+
severity: "critical",
|
|
374
|
+
category: "security",
|
|
375
|
+
confidence: 0.95,
|
|
376
|
+
title: "SQL injection risk",
|
|
377
|
+
explanation: "User input is not sanitized",
|
|
378
|
+
suggestion: "Use parameterized queries",
|
|
379
|
+
};
|
|
380
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
381
|
+
(0, vitest_1.expect)(result.severity).toBe("error");
|
|
382
|
+
(0, vitest_1.expect)(result.type).toBe("inline");
|
|
383
|
+
(0, vitest_1.expect)(result.path).toBe("src/test.ts");
|
|
384
|
+
(0, vitest_1.expect)(result.line).toBe(10);
|
|
385
|
+
});
|
|
386
|
+
(0, vitest_1.it)("should convert warning severity to warning", () => {
|
|
387
|
+
const comment = {
|
|
388
|
+
file: "src/test.ts",
|
|
389
|
+
line: 10,
|
|
390
|
+
severity: "warning",
|
|
391
|
+
category: "performance",
|
|
392
|
+
confidence: 0.8,
|
|
393
|
+
title: "N+1 query",
|
|
394
|
+
explanation: "Consider eager loading",
|
|
395
|
+
suggestion: "",
|
|
396
|
+
};
|
|
397
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
398
|
+
(0, vitest_1.expect)(result.severity).toBe("warning");
|
|
399
|
+
});
|
|
400
|
+
(0, vitest_1.it)("should convert suggestion and nitpick to suggestion", () => {
|
|
401
|
+
const suggestionComment = {
|
|
402
|
+
file: "src/test.ts",
|
|
403
|
+
line: 10,
|
|
404
|
+
severity: "suggestion",
|
|
405
|
+
category: "style",
|
|
406
|
+
confidence: 0.7,
|
|
407
|
+
title: "Use const",
|
|
408
|
+
explanation: "Variable is not reassigned",
|
|
409
|
+
suggestion: "const x = 5;",
|
|
410
|
+
};
|
|
411
|
+
const nitpickComment = {
|
|
412
|
+
file: "src/test.ts",
|
|
413
|
+
line: 11,
|
|
414
|
+
severity: "nitpick",
|
|
415
|
+
category: "style",
|
|
416
|
+
confidence: 0.6,
|
|
417
|
+
title: "Spacing issue",
|
|
418
|
+
explanation: "Missing space after comma",
|
|
419
|
+
suggestion: "",
|
|
420
|
+
};
|
|
421
|
+
(0, vitest_1.expect)((0, review_response_1.toAIComment)(suggestionComment).severity).toBe("suggestion");
|
|
422
|
+
(0, vitest_1.expect)((0, review_response_1.toAIComment)(nitpickComment).severity).toBe("suggestion");
|
|
423
|
+
});
|
|
424
|
+
(0, vitest_1.it)("should include category in title", () => {
|
|
425
|
+
const comment = {
|
|
426
|
+
file: "src/test.ts",
|
|
427
|
+
line: 10,
|
|
428
|
+
severity: "warning",
|
|
429
|
+
category: "security",
|
|
430
|
+
suggestion: "",
|
|
431
|
+
confidence: 0.9,
|
|
432
|
+
title: "Hardcoded secret",
|
|
433
|
+
explanation: "API key should be in environment variable",
|
|
434
|
+
};
|
|
435
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
436
|
+
(0, vitest_1.expect)(result.content).toContain("**[Security]");
|
|
437
|
+
(0, vitest_1.expect)(result.content).toContain("Hardcoded secret");
|
|
438
|
+
});
|
|
439
|
+
(0, vitest_1.it)("should include confidence percentage", () => {
|
|
440
|
+
const comment = {
|
|
441
|
+
file: "src/test.ts",
|
|
442
|
+
line: 10,
|
|
443
|
+
severity: "warning",
|
|
444
|
+
category: "bug",
|
|
445
|
+
confidence: 0.87,
|
|
446
|
+
title: "Null check missing",
|
|
447
|
+
explanation: "Object could be null",
|
|
448
|
+
suggestion: "Add null check",
|
|
449
|
+
};
|
|
450
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
451
|
+
(0, vitest_1.expect)(result.content).toContain("(confidence: 87%)");
|
|
452
|
+
});
|
|
453
|
+
(0, vitest_1.it)("should include suggestion when provided", () => {
|
|
454
|
+
const comment = {
|
|
455
|
+
file: "src/test.ts",
|
|
456
|
+
line: 10,
|
|
457
|
+
severity: "warning",
|
|
458
|
+
category: "style",
|
|
459
|
+
confidence: 0.85,
|
|
460
|
+
title: "Use const",
|
|
461
|
+
explanation: "Variable is not reassigned",
|
|
462
|
+
suggestion: "const x = 5;",
|
|
463
|
+
};
|
|
464
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
465
|
+
(0, vitest_1.expect)(result.content).toContain("**Suggestion:**");
|
|
466
|
+
(0, vitest_1.expect)(result.content).toContain("```");
|
|
467
|
+
(0, vitest_1.expect)(result.content).toContain("const x = 5;");
|
|
468
|
+
});
|
|
469
|
+
(0, vitest_1.it)("should not include suggestion section when not provided", () => {
|
|
470
|
+
const comment = {
|
|
471
|
+
file: "src/test.ts",
|
|
472
|
+
line: 10,
|
|
473
|
+
severity: "warning",
|
|
474
|
+
category: "style",
|
|
475
|
+
confidence: 0.85,
|
|
476
|
+
title: "Use const",
|
|
477
|
+
explanation: "Variable is not reassigned",
|
|
478
|
+
suggestion: "",
|
|
479
|
+
};
|
|
480
|
+
const result = (0, review_response_1.toAIComment)(comment);
|
|
481
|
+
(0, vitest_1.expect)(result.content).not.toContain("**Suggestion:**");
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core types for the AI Code Reviewer
|
|
3
3
|
*/
|
|
4
|
-
export type Platform = "github";
|
|
5
|
-
export type Provider = "openai";
|
|
4
|
+
export type Platform = "github" | "local";
|
|
5
|
+
export type Provider = "openai" | "ollama";
|
|
6
6
|
export interface ReviewConfig {
|
|
7
7
|
provider: Provider;
|
|
8
8
|
model: string;
|
|
@@ -17,6 +17,11 @@ export interface ReviewConfig {
|
|
|
17
17
|
ignoreFiles?: string[];
|
|
18
18
|
rules?: string[];
|
|
19
19
|
customPrompt?: string;
|
|
20
|
+
requestTimeout?: number;
|
|
21
|
+
local?: boolean;
|
|
22
|
+
base?: string;
|
|
23
|
+
head?: string;
|
|
24
|
+
patch?: string;
|
|
20
25
|
}
|
|
21
26
|
export interface PullRequest {
|
|
22
27
|
id: string | number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diff-hound",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "AI-powered code review bot for GitHub, GitLab, and Bitbucket",
|
|
5
5
|
"main": "./bin/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,14 @@
|
|
|
16
16
|
"build": "tsc",
|
|
17
17
|
"start": "node dist/index.js",
|
|
18
18
|
"dev": "ts-node src/index.ts",
|
|
19
|
-
"lint": "eslint src/**/*.ts"
|
|
19
|
+
"lint": "eslint src/**/*.ts",
|
|
20
|
+
"test": "vitest run --config vitest.config.mts",
|
|
21
|
+
"test:watch": "vitest --config vitest.config.mts",
|
|
22
|
+
"test:coverage": "vitest run --config vitest.config.mts --coverage",
|
|
23
|
+
"release": "changeset publish"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"provenance": true
|
|
20
27
|
},
|
|
21
28
|
"keywords": [
|
|
22
29
|
"code-review",
|
|
@@ -50,8 +57,10 @@
|
|
|
50
57
|
"@types/node": "^20.6.0",
|
|
51
58
|
"@typescript-eslint/eslint-plugin": "^6.7.0",
|
|
52
59
|
"@typescript-eslint/parser": "^6.7.0",
|
|
60
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
53
61
|
"eslint": "^8.49.0",
|
|
54
62
|
"ts-node": "^10.9.1",
|
|
55
|
-
"typescript": "^5.2.2"
|
|
63
|
+
"typescript": "^5.2.2",
|
|
64
|
+
"vitest": "^4.0.18"
|
|
56
65
|
}
|
|
57
66
|
}
|