git-reviewer 2.3.0 → 2.3.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.md +2 -2
- package/lib/comments.js +24 -3
- package/package.json +1 -1
- package/public/app.js +22 -5
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/dheerajjha/reviewer/actions/workflows/ci.yml)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](package.json)
|
|
6
|
-
[](test/)
|
|
7
7
|
[](package.json)
|
|
8
8
|
|
|
9
9
|
When an agent writes the code, reading it becomes the bottleneck — and the tool
|
|
@@ -271,7 +271,7 @@ rather than a public issue.
|
|
|
271
271
|
|
|
272
272
|
```bash
|
|
273
273
|
npm install # 3 dependencies, no build step, ~6MB
|
|
274
|
-
npm test #
|
|
274
|
+
npm test # 264 tests
|
|
275
275
|
npm run test:watch
|
|
276
276
|
npm run test:coverage
|
|
277
277
|
```
|
package/lib/comments.js
CHANGED
|
@@ -30,10 +30,31 @@
|
|
|
30
30
|
* Optional fields are omitted rather than stored as `null` so that an absent
|
|
31
31
|
* selection and an empty one are not two different states on disk.
|
|
32
32
|
*
|
|
33
|
+
* A comment missing its file, line or text is rejected here rather than stored:
|
|
34
|
+
* `JSON.stringify` would silently drop the missing fields, and the record would
|
|
35
|
+
* only surface later, in `reviewer export`, as a comment on a file called
|
|
36
|
+
* `undefined` for an agent to act on.
|
|
37
|
+
*
|
|
33
38
|
* @param {object} comment
|
|
39
|
+
* @param {number} index position in the batch, for the error message
|
|
34
40
|
* @returns {Comment}
|
|
41
|
+
* @throws {TypeError} when a required field is missing or malformed
|
|
35
42
|
*/
|
|
36
|
-
function normalizeComment(comment) {
|
|
43
|
+
function normalizeComment(comment, index) {
|
|
44
|
+
const where = `comments[${index}]`;
|
|
45
|
+
if (comment === null || typeof comment !== 'object' || Array.isArray(comment)) {
|
|
46
|
+
throw new TypeError(`${where} must be an object`);
|
|
47
|
+
}
|
|
48
|
+
if (typeof comment.file !== 'string' || comment.file.trim() === '') {
|
|
49
|
+
throw new TypeError(`${where}.file must be a non-empty string`);
|
|
50
|
+
}
|
|
51
|
+
if (!Number.isInteger(comment.line) || comment.line < 1) {
|
|
52
|
+
throw new TypeError(`${where}.line must be a positive integer`);
|
|
53
|
+
}
|
|
54
|
+
if (typeof comment.text !== 'string' || comment.text.trim() === '') {
|
|
55
|
+
throw new TypeError(`${where}.text must be a non-empty string`);
|
|
56
|
+
}
|
|
57
|
+
|
|
37
58
|
const normalized = {
|
|
38
59
|
file: comment.file,
|
|
39
60
|
line: comment.line,
|
|
@@ -61,13 +82,13 @@ function normalizeComment(comment) {
|
|
|
61
82
|
*
|
|
62
83
|
* @param {object[]} comments
|
|
63
84
|
* @returns {Comment[]}
|
|
64
|
-
* @throws {TypeError} when `comments` is not an array
|
|
85
|
+
* @throws {TypeError} when `comments` is not an array or a comment is malformed
|
|
65
86
|
*/
|
|
66
87
|
function normalizeComments(comments) {
|
|
67
88
|
if (!Array.isArray(comments)) {
|
|
68
89
|
throw new TypeError('comments must be an array');
|
|
69
90
|
}
|
|
70
|
-
return comments.map(normalizeComment);
|
|
91
|
+
return comments.map((comment, index) => normalizeComment(comment, index));
|
|
71
92
|
}
|
|
72
93
|
|
|
73
94
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-reviewer",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Review your coding agent's changes like a pull request — locally, with inline comments and threaded follow-ups, then hand the marked-up review back to the agent",
|
|
5
5
|
"author": "Dheeraj Jha",
|
|
6
6
|
"license": "MIT",
|
package/public/app.js
CHANGED
|
@@ -180,8 +180,10 @@ async function loadRepo() {
|
|
|
180
180
|
// Load saved comments
|
|
181
181
|
const savedComments = await loadCommentsFromBackend();
|
|
182
182
|
if (savedComments.length > 0) {
|
|
183
|
-
//
|
|
184
|
-
|
|
183
|
+
// These went into `window.savedComments` as well, as a second copy for
|
|
184
|
+
// the matcher to read. Nothing reads it now, and leaving a stale copy of
|
|
185
|
+
// the review lying around is how the resurrection happened in the first
|
|
186
|
+
// place -- so there is one list, and it is this one.
|
|
185
187
|
|
|
186
188
|
// Add all saved comments to the comments array immediately
|
|
187
189
|
comments = savedComments.map(c => ({
|
|
@@ -308,9 +310,20 @@ async function loadFile(filePath, index) {
|
|
|
308
310
|
throw new Error(data.error || 'Failed to load file');
|
|
309
311
|
}
|
|
310
312
|
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
// Give this file's comments their position in the diff just rendered.
|
|
314
|
+
//
|
|
315
|
+
// The source here used to be `window.savedComments`, a snapshot taken when
|
|
316
|
+
// the repository was opened and never updated again. Everything else works
|
|
317
|
+
// from `comments`, the live list -- so a comment you deleted was still in
|
|
318
|
+
// the snapshot, was not found in the live list, and the branch below added
|
|
319
|
+
// it straight back. It vanished from disk and reappeared on screen, and
|
|
320
|
+
// the next save wrote the resurrected copy back over the deletion. Editing
|
|
321
|
+
// one did the same thing by a different route: the text no longer matched,
|
|
322
|
+
// so the pre-edit copy was added alongside the edited one (#52).
|
|
323
|
+
//
|
|
324
|
+
// `comments` is what exists. A comment that is not in it does not exist.
|
|
325
|
+
if (comments.length > 0) {
|
|
326
|
+
const matchedComments = matchCommentsToDiff(comments, filePath, data.diffLines);
|
|
314
327
|
|
|
315
328
|
// Update existing comments in the array with matched diff indices
|
|
316
329
|
matchedComments.forEach(mc => {
|
|
@@ -330,6 +343,10 @@ async function loadFile(filePath, index) {
|
|
|
330
343
|
existing.followUps = mc.followUps;
|
|
331
344
|
}
|
|
332
345
|
} else {
|
|
346
|
+
// Unreachable now that the matcher is fed the live list: everything
|
|
347
|
+
// it returns came from there. Kept as a guard rather than removed,
|
|
348
|
+
// because silently dropping a comment is the worse failure of the
|
|
349
|
+
// two, and this is the line that would do it.
|
|
333
350
|
// Add new comment if it doesn't exist
|
|
334
351
|
comments.push({
|
|
335
352
|
file: mc.file,
|