reslop 0.1.1 → 0.1.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.
- package/CHANGELOG.md +21 -6
- package/README.md +29 -26
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +0 -1
- package/lib/cli.js +62 -47
- package/lib/clipboard.js +1 -1
- package/lib/deps.js +1440 -0
- package/lib/detect.js +6 -4
- package/lib/diff.js +31 -55
- package/lib/editor.js +1 -1
- package/lib/files.js +58 -15
- package/lib/git.js +649 -69
- package/lib/github.js +28 -34
- package/lib/highlight.js +282 -141
- package/lib/keys.js +35 -39
- package/lib/render.js +250 -153
- package/lib/review.js +22 -42
- package/lib/select.js +16 -18
- package/lib/session.js +301 -227
- package/lib/source.js +7 -3
- package/package.json +1 -1
package/lib/review.js
CHANGED
|
@@ -3,17 +3,13 @@
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
|
-
const { itemPath } = require('./files.js');
|
|
6
|
+
const { itemPath, REVIEW_DIR } = require('./files.js');
|
|
7
7
|
|
|
8
|
-
const REVIEW_DIR = '.review';
|
|
9
8
|
const TEMPLATES_FILE = 'templates.json';
|
|
10
9
|
const TEMPLATE_SHOW = 5;
|
|
11
10
|
const AUTOSAVE_MS = 3000;
|
|
12
11
|
const REVIEW_NAME = /^(\d{4}-\d{2}-\d{2})-(\d+)\.md$/;
|
|
13
12
|
const REVIEW_STATUSES = ['editing', 'ready', 'partial', 'done'];
|
|
14
|
-
const STATUS_ALIAS = {
|
|
15
|
-
pending: 'ready',
|
|
16
|
-
};
|
|
17
13
|
const FEED_HEAD = /^### Feedback `([^`]+)` \+(\d+) \((.*)\)\s*$/;
|
|
18
14
|
const FEED_BLOCK = /^(.*), block (\d+)$/;
|
|
19
15
|
const FEED_BLOCK_ONLY = /^block (\d+)$/;
|
|
@@ -94,7 +90,7 @@ const latestReviewName = (names) => {
|
|
|
94
90
|
|
|
95
91
|
const canonicalStatus = (raw) => {
|
|
96
92
|
if (!raw) return '';
|
|
97
|
-
const name =
|
|
93
|
+
const name = raw === 'pending' ? 'ready' : raw;
|
|
98
94
|
if (REVIEW_STATUSES.includes(name)) return name;
|
|
99
95
|
return '';
|
|
100
96
|
};
|
|
@@ -116,7 +112,8 @@ const parseFrontmatterStatus = (text) => {
|
|
|
116
112
|
|
|
117
113
|
const readReviewStatus = (reviewPath, readFileSync = fs.readFileSync) => {
|
|
118
114
|
try {
|
|
119
|
-
|
|
115
|
+
const text = readFileSync(reviewPath, 'utf8');
|
|
116
|
+
return parseFrontmatterStatus(text);
|
|
120
117
|
} catch {
|
|
121
118
|
return '';
|
|
122
119
|
}
|
|
@@ -133,10 +130,9 @@ const resolveReviewPath = (dir, date, existingNames, options = {}) => {
|
|
|
133
130
|
if (status === 'editing') return { reviewPath, resume: true };
|
|
134
131
|
}
|
|
135
132
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
};
|
|
133
|
+
const reviewPath = allocateReviewPath(dir, date, existingNames);
|
|
134
|
+
const resume = false;
|
|
135
|
+
return { reviewPath, resume };
|
|
140
136
|
};
|
|
141
137
|
|
|
142
138
|
const rankedTemplates = (templates) => {
|
|
@@ -354,25 +350,19 @@ const parseLoc = (raw) => {
|
|
|
354
350
|
fileParts = fileParts.slice(1);
|
|
355
351
|
}
|
|
356
352
|
if (!fileParts.length) return null;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
file: fileParts.join(':'),
|
|
360
|
-
oldStart,
|
|
361
|
-
newStart,
|
|
362
|
-
blockId,
|
|
363
|
-
};
|
|
353
|
+
const file = fileParts.join(':');
|
|
354
|
+
return { origin, file, oldStart, newStart, blockId };
|
|
364
355
|
};
|
|
365
356
|
|
|
366
357
|
const parseFeedSuffix = (textItem) => {
|
|
367
358
|
const match = FEED_SUFFIX.exec(textItem);
|
|
368
359
|
if (!match) return null;
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
};
|
|
360
|
+
const text = match[1];
|
|
361
|
+
const file = match[2];
|
|
362
|
+
const oldStart = toInt(match[3]);
|
|
363
|
+
const newStart = toInt(match[4]);
|
|
364
|
+
const blockId = toInt(match[5]);
|
|
365
|
+
return { text, file, oldStart, newStart, blockId };
|
|
376
366
|
};
|
|
377
367
|
|
|
378
368
|
const fileGroup = (groups, file) => {
|
|
@@ -390,7 +380,8 @@ const groupReviewNotes = (store) => {
|
|
|
390
380
|
if (!todo.text.trim()) continue;
|
|
391
381
|
fileGroup(groups, todo.file).todos.push(todo);
|
|
392
382
|
}
|
|
393
|
-
for (const
|
|
383
|
+
for (const key of store.feedback.keys()) {
|
|
384
|
+
const note = store.feedback.get(key);
|
|
394
385
|
if (!note.text.trim()) continue;
|
|
395
386
|
fileGroup(groups, note.file).feedback.push({ key, note });
|
|
396
387
|
}
|
|
@@ -415,7 +406,8 @@ const reviewHeader = (store) => {
|
|
|
415
406
|
};
|
|
416
407
|
|
|
417
408
|
const emitReviewGroups = (lines, groups) => {
|
|
418
|
-
for (const
|
|
409
|
+
for (const file of groups.keys()) {
|
|
410
|
+
const group = groups.get(file);
|
|
419
411
|
lines.push(`## ${file}`);
|
|
420
412
|
lines.push('');
|
|
421
413
|
for (const todo of group.todos) {
|
|
@@ -448,12 +440,9 @@ const parseFeedbackHeading = (line) => {
|
|
|
448
440
|
if (!withHead) {
|
|
449
441
|
return { file, newStart, header: rest, blockId: 0 };
|
|
450
442
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
header: withHead[1],
|
|
455
|
-
blockId: toInt(withHead[2]),
|
|
456
|
-
};
|
|
443
|
+
const header = withHead[1];
|
|
444
|
+
const blockId = toInt(withHead[2]);
|
|
445
|
+
return { file, newStart, header, blockId };
|
|
457
446
|
};
|
|
458
447
|
|
|
459
448
|
const flushPendingFeedback = (store, pending) => {
|
|
@@ -675,19 +664,12 @@ const mergeTodos = (gitItems, todos, extraFiles = []) => {
|
|
|
675
664
|
};
|
|
676
665
|
|
|
677
666
|
module.exports = {
|
|
678
|
-
REVIEW_DIR,
|
|
679
|
-
TEMPLATES_FILE,
|
|
680
667
|
TEMPLATE_SHOW,
|
|
681
668
|
AUTOSAVE_MS,
|
|
682
|
-
REVIEW_STATUSES,
|
|
683
|
-
AGENT_INSTRUCTIONS,
|
|
684
|
-
dateStamp,
|
|
685
669
|
allocateReviewPath,
|
|
686
670
|
listReviewNames,
|
|
687
|
-
compareReviewNames,
|
|
688
671
|
latestReviewName,
|
|
689
672
|
parseFrontmatterStatus,
|
|
690
|
-
readReviewStatus,
|
|
691
673
|
resolveReviewPath,
|
|
692
674
|
rankedTemplates,
|
|
693
675
|
prefixTemplates,
|
|
@@ -700,7 +682,6 @@ module.exports = {
|
|
|
700
682
|
addTodo,
|
|
701
683
|
removeTodo,
|
|
702
684
|
setTodoText,
|
|
703
|
-
isDoneMark,
|
|
704
685
|
checkLabel,
|
|
705
686
|
feedbackKey,
|
|
706
687
|
applyImportedNotes,
|
|
@@ -709,6 +690,5 @@ module.exports = {
|
|
|
709
690
|
loadReview,
|
|
710
691
|
loadTemplates,
|
|
711
692
|
flushReview,
|
|
712
|
-
makeTodoItem,
|
|
713
693
|
mergeTodos,
|
|
714
694
|
};
|
package/lib/select.js
CHANGED
|
@@ -20,12 +20,12 @@ const isRange = (sel) => {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
const ordered = (sel) => {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
if (
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
return
|
|
23
|
+
const start = sel.start;
|
|
24
|
+
const end = sel.end;
|
|
25
|
+
if (start.y < end.y) return { first: start, last: end };
|
|
26
|
+
if (start.y > end.y) return { first: end, last: start };
|
|
27
|
+
if (start.x <= end.x) return { first: start, last: end };
|
|
28
|
+
return { first: end, last: start };
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const slicePlain = (plain, fromCol, toCol) => {
|
|
@@ -43,25 +43,25 @@ const slicePlain = (plain, fromCol, toCol) => {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
const lineRange = (rowIndex, sel) => {
|
|
46
|
-
const
|
|
46
|
+
const { first, last } = ordered(sel);
|
|
47
47
|
const y = rowIndex + 1;
|
|
48
|
-
if (y <
|
|
48
|
+
if (y < first.y || y > last.y) return null;
|
|
49
49
|
let from = 0;
|
|
50
|
-
let to =
|
|
51
|
-
if (y ===
|
|
52
|
-
if (y ===
|
|
50
|
+
let to = Infinity;
|
|
51
|
+
if (y === first.y) from = first.x - 1;
|
|
52
|
+
if (y === last.y) to = last.x;
|
|
53
53
|
if (to <= from) return null;
|
|
54
54
|
return { from, to };
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
const extractText = (rows, sel) => {
|
|
58
58
|
if (!isRange(sel) || !rows || !rows.length) return '';
|
|
59
|
-
const
|
|
59
|
+
const { first, last } = ordered(sel);
|
|
60
60
|
const lines = [];
|
|
61
|
-
for (let
|
|
62
|
-
const range = lineRange(
|
|
61
|
+
for (let row = first.y - 1; row <= last.y - 1; row++) {
|
|
62
|
+
const range = lineRange(row, sel);
|
|
63
63
|
if (!range) continue;
|
|
64
|
-
const plain = stripAnsi(rows[
|
|
64
|
+
const plain = stripAnsi(rows[row] ?? '');
|
|
65
65
|
const chunk = slicePlain(plain, range.from, range.to);
|
|
66
66
|
lines.push(chunk.replace(/\s+$/g, ''));
|
|
67
67
|
}
|
|
@@ -202,9 +202,7 @@ const overlayRows = (rows, sel) => {
|
|
|
202
202
|
|
|
203
203
|
module.exports = {
|
|
204
204
|
isRange,
|
|
205
|
-
ordered,
|
|
206
205
|
extractText,
|
|
207
|
-
overlayRows,
|
|
208
206
|
overlayRange,
|
|
209
|
-
|
|
207
|
+
overlayRows,
|
|
210
208
|
};
|