reslop 0.1.9 → 0.2.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +3 -1
  3. package/bin/reslop.js +2 -2
  4. package/lib/ansi.js +148 -5
  5. package/lib/api.js +4 -2
  6. package/lib/capabilities.js +13 -14
  7. package/lib/cli.js +38 -49
  8. package/lib/clipboard.js +1 -1
  9. package/lib/{deps/changes.js → deps-diff.js} +309 -19
  10. package/lib/deps.js +498 -29
  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 +5 -8
  20. package/lib/{git/branches.js → git-branches.js} +191 -11
  21. package/lib/{git/dependencies.js → git-deps.js} +111 -38
  22. package/lib/git-reword-todo.js +20 -0
  23. package/lib/git.js +606 -68
  24. package/lib/github.js +28 -197
  25. package/lib/gitlab.js +24 -195
  26. package/lib/highlight/bash.js +1 -3
  27. package/lib/highlight/css.js +1 -3
  28. package/lib/highlight/js.js +11 -14
  29. package/lib/highlight.js +6 -9
  30. package/lib/keys.js +14 -8
  31. package/lib/manifest.js +330 -0
  32. package/lib/remote.js +374 -0
  33. package/lib/render/branches.js +18 -100
  34. package/lib/render/chrome.js +71 -14
  35. package/lib/render/commits.js +69 -60
  36. package/lib/render/diff.js +20 -20
  37. package/lib/render/files.js +6 -34
  38. package/lib/render/frame.js +36 -13
  39. package/lib/render/notes.js +26 -8
  40. package/lib/render/primitives.js +99 -11
  41. package/lib/{render.js → render/render.js} +8 -8
  42. package/lib/render/unit.js +41 -0
  43. package/lib/review-merge.js +270 -0
  44. package/lib/review.js +782 -14
  45. package/lib/select.js +5 -10
  46. package/lib/session/accessors.js +9 -1
  47. package/lib/session/actions.js +61 -18
  48. package/lib/session/branches.js +116 -128
  49. package/lib/session/change-actions.js +202 -123
  50. package/lib/session/commit.js +201 -115
  51. package/lib/session/compose.js +181 -15
  52. package/lib/session/dispatch.js +110 -60
  53. package/lib/session/files-pane.js +156 -148
  54. package/lib/session/items.js +22 -30
  55. package/lib/session/lifecycle.js +151 -54
  56. package/lib/session/load.js +19 -33
  57. package/lib/session/navigation.js +12 -1
  58. package/lib/session/ops.js +28 -41
  59. package/lib/session/pointer.js +57 -57
  60. package/lib/session/review.js +23 -37
  61. package/lib/session/terminal.js +6 -12
  62. package/lib/session/todos.js +37 -13
  63. package/lib/session/unit.js +208 -0
  64. package/lib/session/update.js +33 -46
  65. package/lib/session/view.js +78 -9
  66. package/lib/session/watch.js +128 -24
  67. package/lib/session.js +22 -246
  68. package/lib/source.js +3 -3
  69. package/lib/update.js +40 -75
  70. package/lib/{git/proc.js → utilities.js} +75 -11
  71. package/lib/wrap.js +1 -3
  72. package/package.json +2 -2
  73. package/lib/deps/items.js +0 -134
  74. package/lib/deps/manifest.js +0 -152
  75. package/lib/deps/merge.js +0 -120
  76. package/lib/deps/proposals.js +0 -164
  77. package/lib/deps/reports.js +0 -180
  78. package/lib/deps/rows.js +0 -176
  79. package/lib/deps/scan.js +0 -138
  80. package/lib/deps/usage.js +0 -68
  81. package/lib/deps/versions.js +0 -119
  82. package/lib/diff.js +0 -33
  83. package/lib/git/changes.js +0 -164
  84. package/lib/git/read.js +0 -253
  85. package/lib/git/run.js +0 -100
  86. package/lib/npm/commands.js +0 -100
  87. package/lib/remote/changes.js +0 -37
  88. package/lib/remote/headers.js +0 -36
  89. package/lib/remote/http.js +0 -122
  90. package/lib/remote/notes.js +0 -94
  91. package/lib/review/format.js +0 -434
  92. package/lib/review/storage.js +0 -150
  93. package/lib/review/store.js +0 -178
  94. package/lib/review/templates.js +0 -49
  95. package/lib/session/origins.js +0 -7
  96. 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
- };