reslop 0.1.8 → 0.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +27 -38
  3. package/bin/reslop.js +2 -2
  4. package/lib/ansi.js +6 -2
  5. package/lib/api.js +2 -2
  6. package/lib/capabilities.js +10 -14
  7. package/lib/cli.js +28 -47
  8. package/lib/clipboard.js +1 -1
  9. package/lib/deps-diff.js +712 -0
  10. package/lib/deps.js +556 -32
  11. package/lib/detect.js +1 -7
  12. package/lib/diff/align.js +7 -10
  13. package/lib/diff/diff.js +53 -0
  14. package/lib/diff/display.js +5 -4
  15. package/lib/diff/inline.js +26 -21
  16. package/lib/diff/items.js +6 -4
  17. package/lib/diff/patch.js +1 -3
  18. package/lib/diff/unit.js +392 -0
  19. package/lib/files.js +34 -8
  20. package/lib/{git/branches.js → git-branches.js} +103 -10
  21. package/lib/{git/dependencies.js → git-deps.js} +111 -38
  22. package/lib/git.js +592 -65
  23. package/lib/github.js +28 -197
  24. package/lib/gitlab.js +24 -195
  25. package/lib/highlight/bash.js +1 -3
  26. package/lib/highlight/css.js +1 -3
  27. package/lib/highlight/js.js +11 -14
  28. package/lib/highlight.js +6 -9
  29. package/lib/keys.js +22 -9
  30. package/lib/manifest.js +330 -0
  31. package/lib/remote.js +374 -0
  32. package/lib/render/branches.js +34 -66
  33. package/lib/render/chrome.js +57 -22
  34. package/lib/render/commits.js +85 -0
  35. package/lib/render/diff.js +16 -16
  36. package/lib/render/files.js +29 -37
  37. package/lib/render/frame.js +29 -13
  38. package/lib/render/notes.js +4 -3
  39. package/lib/render/primitives.js +46 -1
  40. package/lib/{render.js → render/render.js} +6 -7
  41. package/lib/render/unit.js +41 -0
  42. package/lib/review.js +750 -14
  43. package/lib/select.js +5 -10
  44. package/lib/session/accessors.js +9 -1
  45. package/lib/session/actions.js +93 -36
  46. package/lib/session/branches.js +130 -144
  47. package/lib/session/change-actions.js +206 -124
  48. package/lib/session/commit.js +217 -62
  49. package/lib/session/compose.js +158 -13
  50. package/lib/session/dispatch.js +109 -55
  51. package/lib/session/files-pane.js +145 -142
  52. package/lib/session/items.js +131 -34
  53. package/lib/session/lifecycle.js +82 -42
  54. package/lib/session/load.js +19 -33
  55. package/lib/session/navigation.js +15 -3
  56. package/lib/session/ops.js +28 -41
  57. package/lib/session/pointer.js +58 -54
  58. package/lib/session/review.js +23 -37
  59. package/lib/session/terminal.js +6 -12
  60. package/lib/session/todos.js +8 -12
  61. package/lib/session/unit.js +208 -0
  62. package/lib/session/update.js +33 -46
  63. package/lib/session/view.js +82 -11
  64. package/lib/session/watch.js +11 -19
  65. package/lib/session.js +29 -226
  66. package/lib/source.js +3 -3
  67. package/lib/update.js +40 -75
  68. package/lib/{git/proc.js → utilities.js} +75 -11
  69. package/lib/wrap.js +1 -3
  70. package/package.json +2 -2
  71. package/lib/deps/changes.js +0 -331
  72. package/lib/deps/items.js +0 -131
  73. package/lib/deps/manifest.js +0 -145
  74. package/lib/deps/merge.js +0 -120
  75. package/lib/deps/proposals.js +0 -164
  76. package/lib/deps/reports.js +0 -180
  77. package/lib/deps/rows.js +0 -177
  78. package/lib/deps/scan.js +0 -138
  79. package/lib/deps/usage.js +0 -68
  80. package/lib/deps/versions.js +0 -119
  81. package/lib/diff.js +0 -33
  82. package/lib/git/changes.js +0 -164
  83. package/lib/git/read.js +0 -253
  84. package/lib/git/run.js +0 -100
  85. package/lib/npm/commands.js +0 -100
  86. package/lib/remote/changes.js +0 -37
  87. package/lib/remote/headers.js +0 -36
  88. package/lib/remote/http.js +0 -122
  89. package/lib/remote/notes.js +0 -94
  90. package/lib/review/format.js +0 -434
  91. package/lib/review/storage.js +0 -150
  92. package/lib/review/store.js +0 -178
  93. package/lib/review/templates.js +0 -49
  94. package/lib/session/origins.js +0 -7
  95. package/lib/sys.js +0 -84
@@ -1,178 +0,0 @@
1
- 'use strict';
2
-
3
- const createStore = (reviewPath, templates = []) => ({
4
- reviewPath,
5
- dirty: false,
6
- nextTodoId: 1,
7
- feedback: new Map(),
8
- code: new Map(),
9
- todos: [],
10
- templates: [...templates],
11
- status: 'editing',
12
- });
13
-
14
- const noteCounts = (store) => {
15
- const counts = { feedback: 0, todo: 0, todoDone: 0, code: 0 };
16
- if (!store) return counts;
17
- for (const todo of store.todos) {
18
- if (!todo.text.trim()) continue;
19
- counts.todo += 1;
20
- if (todo.done) counts.todoDone += 1;
21
- }
22
- for (const note of store.feedback.values()) {
23
- if (note.text.trim()) counts.feedback += 1;
24
- }
25
- counts.code = store.code.size;
26
- return counts;
27
- };
28
-
29
- const hasNotes = (store) => {
30
- const counts = noteCounts(store);
31
- return counts.feedback > 0 || counts.todo > 0 || counts.code > 0;
32
- };
33
-
34
- const setFeedback = (store, key, note) => {
35
- const text = note.text ?? '';
36
- const trimmed = text.trim();
37
- const prev = store.feedback.get(key);
38
- if (!trimmed) {
39
- if (!prev) return;
40
- store.feedback.delete(key);
41
- store.dirty = true;
42
- return;
43
- }
44
- if (prev && prev.text === text) return;
45
- store.feedback.set(key, {
46
- file: note.file,
47
- oldStart: note.oldStart ?? 0,
48
- newStart: note.newStart ?? 0,
49
- blockId: note.blockId ?? 0,
50
- origin: note.origin ?? '',
51
- header: note.header ?? '',
52
- text,
53
- done: note.done ?? prev?.done ?? false,
54
- });
55
- store.dirty = true;
56
- };
57
-
58
- const setCode = (store, key, note) => {
59
- const prev = store.code.get(key);
60
- if (note.clear) {
61
- if (!prev) return;
62
- store.code.delete(key);
63
- store.dirty = true;
64
- return;
65
- }
66
- const text = note.text ?? '';
67
- if (prev && prev.text === text) return;
68
- store.code.set(key, {
69
- file: note.file,
70
- oldStart: note.oldStart ?? 0,
71
- newStart: note.newStart ?? 0,
72
- blockId: note.blockId ?? 0,
73
- origin: note.origin ?? '',
74
- header: note.header ?? '',
75
- text,
76
- done: note.done ?? prev?.done ?? false,
77
- });
78
- store.dirty = true;
79
- };
80
-
81
- const addTodo = (store, file, text = '') => {
82
- const id = store.nextTodoId;
83
- store.nextTodoId += 1;
84
- const todo = { id, file, text, done: false };
85
- store.todos.push(todo);
86
- store.dirty = true;
87
- return todo;
88
- };
89
-
90
- const removeTodo = (store, id) => {
91
- const next = [];
92
- let found = false;
93
- for (const todo of store.todos) {
94
- if (todo.id === id) {
95
- found = true;
96
- continue;
97
- }
98
- next.push(todo);
99
- }
100
- if (!found) return false;
101
- store.todos = next;
102
- store.dirty = true;
103
- return true;
104
- };
105
-
106
- const setTodoText = (store, id, text) => {
107
- const i = store.todos.findIndex((todo) => todo.id === id);
108
- if (i < 0) return;
109
- const prev = store.todos[i];
110
- const trimmed = text.trim();
111
- if (!trimmed) {
112
- removeTodo(store, id);
113
- return;
114
- }
115
- if (prev.text === text) return;
116
- store.todos[i] = { id: prev.id, file: prev.file, text, done: prev.done };
117
- store.dirty = true;
118
- };
119
-
120
- const checkLabel = (text, done) => {
121
- const mark = done ? 'x' : ' ';
122
- return `[${mark}] ${text}`;
123
- };
124
-
125
- const feedbackKey = (note) => {
126
- const file = note.file ?? '';
127
- const oldStart = note.oldStart ?? 0;
128
- const newStart = note.newStart ?? 0;
129
- const block = note.blockId ?? 0;
130
- return `${file}:${oldStart}:${newStart}:${block}`;
131
- };
132
-
133
- const applyImportedNotes = (store, imported) => {
134
- if (!store || !imported) return;
135
- const feedbacks = imported.feedback ?? [];
136
- for (const note of feedbacks) {
137
- const key = feedbackKey(note);
138
- const prev = store.feedback.get(key);
139
- const text = prev ? `${prev.text}\n\n${note.text}` : note.text;
140
- const done = prev ? prev.done && !!note.done : !!note.done;
141
- setFeedback(store, key, {
142
- file: note.file,
143
- oldStart: note.oldStart ?? 0,
144
- newStart: note.newStart ?? 0,
145
- blockId: note.blockId ?? 0,
146
- origin: note.origin ?? '',
147
- header: note.header ?? '',
148
- text,
149
- done,
150
- });
151
- }
152
- const todos = imported.todos ?? [];
153
- for (const todo of todos) {
154
- const added = addTodo(store, todo.file || '', todo.text ?? '');
155
- if (todo.done) added.done = true;
156
- }
157
- };
158
-
159
- const setStatus = (store, status) => {
160
- if (!store) return;
161
- store.status = status;
162
- store.dirty = true;
163
- };
164
-
165
- module.exports = {
166
- createStore,
167
- noteCounts,
168
- hasNotes,
169
- setFeedback,
170
- setCode,
171
- addTodo,
172
- removeTodo,
173
- setTodoText,
174
- checkLabel,
175
- feedbackKey,
176
- applyImportedNotes,
177
- setStatus,
178
- };
@@ -1,49 +0,0 @@
1
- 'use strict';
2
-
3
- const TEMPLATE_SHOW = 5;
4
-
5
- const rankedTemplates = (templates) => {
6
- const ranked = [...templates];
7
- ranked.sort((a, b) => {
8
- const byCount = b.count - a.count;
9
- if (byCount) return byCount;
10
- return a.text.localeCompare(b.text);
11
- });
12
- return ranked;
13
- };
14
-
15
- const prefixTemplates = (templates, prefix) => {
16
- if (!prefix) return templates;
17
- return templates.filter((entry) => entry.text.startsWith(prefix));
18
- };
19
-
20
- const upsertTemplate = (templates, text) => {
21
- const trimmed = text.trim();
22
- if (!trimmed) return templates;
23
- const next = [...templates];
24
- const i = next.findIndex((entry) => entry.text === trimmed);
25
- if (i < 0) {
26
- next.push({ text: trimmed, count: 1 });
27
- return next;
28
- }
29
- const prev = next[i];
30
- next[i] = { text: prev.text, count: prev.count + 1 };
31
- return next;
32
- };
33
-
34
- const rememberTemplate = (store, prevText, nextText) => {
35
- const trimmed = nextText.trim();
36
- if (!trimmed) return;
37
- const prev = (prevText ?? '').trim();
38
- if (prev === trimmed) return;
39
- store.templates = upsertTemplate(store.templates, trimmed);
40
- store.dirty = true;
41
- };
42
-
43
- module.exports = {
44
- TEMPLATE_SHOW,
45
- rankedTemplates,
46
- prefixTemplates,
47
- upsertTemplate,
48
- rememberTemplate,
49
- };
@@ -1,7 +0,0 @@
1
- 'use strict';
2
-
3
- const READ_ONLY_ORIGINS = ['commit', 'pr'];
4
-
5
- const isReadOnlyOrigin = (origin) => READ_ONLY_ORIGINS.includes(origin);
6
-
7
- module.exports = { READ_ONLY_ORIGINS, isReadOnlyOrigin };
package/lib/sys.js DELETED
@@ -1,84 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
-
6
- const IS_WIN = process.platform === 'win32';
7
-
8
- const UNIX_CLIP = [
9
- { cmd: 'wl-copy', args: [] },
10
- { cmd: 'xclip', args: ['-selection', 'clipboard'] },
11
- { cmd: 'xsel', args: ['--clipboard', '--input'] },
12
- ];
13
-
14
- const npmBin = (platform = process.platform) =>
15
- platform === 'win32' ? 'npm.cmd' : 'npm';
16
-
17
- const spawnBase = (extra = {}) => ({ windowsHide: true, ...extra });
18
-
19
- const npmOpts = (extra = {}, platform = process.platform) =>
20
- spawnBase({ shell: platform === 'win32', ...extra });
21
-
22
- const clipTools = (platform = process.platform) => {
23
- if (platform === 'win32') return [{ cmd: 'clip', args: [] }];
24
- if (platform === 'darwin') return [{ cmd: 'pbcopy', args: [] }];
25
- return UNIX_CLIP;
26
- };
27
-
28
- const listen = (emitter, event, handler) => {
29
- if (!emitter || typeof emitter.on !== 'function') return () => {};
30
- emitter.on(event, handler);
31
- return () => {
32
- if (typeof emitter.removeListener === 'function') {
33
- emitter.removeListener(event, handler);
34
- return;
35
- }
36
- if (typeof emitter.off === 'function') emitter.off(event, handler);
37
- };
38
- };
39
-
40
- const watchResize = (stdout, proc, onResize, signal) => {
41
- const stopStdout = listen(stdout, 'resize', onResize);
42
- let stopProc = () => {};
43
- try {
44
- stopProc = listen(proc, 'SIGWINCH', onResize);
45
- } catch {
46
- // SIGWINCH is not available on Windows
47
- }
48
- const stop = () => {
49
- stopStdout();
50
- stopProc();
51
- };
52
- if (signal) {
53
- if (signal.aborted) stop();
54
- else signal.addEventListener('abort', stop, { once: true });
55
- }
56
- return stop;
57
- };
58
-
59
- const canonPath = (value) => {
60
- try {
61
- return fs.realpathSync.native(value);
62
- } catch {
63
- return path.resolve(value);
64
- }
65
- };
66
-
67
- const samePath = (left, right) => {
68
- if (left === right) return true;
69
- const a = canonPath(left);
70
- const b = canonPath(right);
71
- if (a === b) return true;
72
- return IS_WIN && a.toLowerCase() === b.toLowerCase();
73
- };
74
-
75
- module.exports = {
76
- IS_WIN,
77
- npmBin,
78
- spawnBase,
79
- npmOpts,
80
- clipTools,
81
- listen,
82
- watchResize,
83
- samePath,
84
- };