reslop 0.2.5 → 0.2.6
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 +12 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +332 -0
- package/lib/dashboard/npm.js +193 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +197 -402
- package/lib/deps.js +113 -240
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +76 -144
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +71 -89
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +147 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +141 -212
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +155 -141
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +14 -14
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +49 -82
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +220 -333
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +245 -0
- package/lib/render/dash-table.js +290 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +40 -85
- package/lib/render/frame.js +78 -117
- package/lib/render/notes.js +139 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +72 -174
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/tiles.js +260 -0
- package/lib/render/unit.js +15 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +68 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +61 -43
- package/lib/session/branches.js +166 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +274 -355
- package/lib/session/compose.js +556 -714
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +162 -170
- package/lib/session/files-pane.js +76 -44
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +393 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +2 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/pointer.js +16 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +276 -235
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +47 -81
- package/lib/session/watch.js +196 -212
- package/lib/session.js +81 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
package/lib/files.js
CHANGED
|
@@ -8,7 +8,37 @@ const ORIGIN_ORDER = ['staged', 'unstaged', 'untracked', 'commit', 'pr'];
|
|
|
8
8
|
const TASKS_FILE = 'TODOs';
|
|
9
9
|
const REPO_TASKS_LABEL =
|
|
10
10
|
'Project Tasks: Backlog, Issues, Bug Reports, Feature Requests';
|
|
11
|
+
const TASK_KINDS = [
|
|
12
|
+
{ id: 'backlog', title: 'Backlog' },
|
|
13
|
+
{ id: 'issues', title: 'Issues' },
|
|
14
|
+
{ id: 'bugs', title: 'Bug Reports' },
|
|
15
|
+
{ id: 'features', title: 'Feature Requests' },
|
|
16
|
+
];
|
|
17
|
+
const TASK_KIND_IDS = new Set(TASK_KINDS.map((kind) => kind.id));
|
|
18
|
+
|
|
19
|
+
const taskKind = (todo) => {
|
|
20
|
+
const kind = todo && todo.kind;
|
|
21
|
+
return TASK_KIND_IDS.has(kind) ? kind : 'backlog';
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const taskTitle = (id) => {
|
|
25
|
+
for (const kind of TASK_KINDS) {
|
|
26
|
+
if (kind.id === id) return kind.title;
|
|
27
|
+
}
|
|
28
|
+
return TASK_KINDS[0].title;
|
|
29
|
+
};
|
|
11
30
|
const TOTAL_LABEL = 'total';
|
|
31
|
+
const AGE_UNIT = {
|
|
32
|
+
second: 's',
|
|
33
|
+
minute: 'm',
|
|
34
|
+
hour: 'h',
|
|
35
|
+
day: 'd',
|
|
36
|
+
week: 'w',
|
|
37
|
+
month: 'mo',
|
|
38
|
+
year: 'y',
|
|
39
|
+
};
|
|
40
|
+
const AGE_AGO = /^(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago$/i;
|
|
41
|
+
const AGE_SHORT = /^(\d+)(mo|[smhdwy])(?: ago)?$/i;
|
|
12
42
|
|
|
13
43
|
const isPathInScope = (rel, paths) => {
|
|
14
44
|
if (!paths.length) return true;
|
|
@@ -20,20 +50,17 @@ const isPathInScope = (rel, paths) => {
|
|
|
20
50
|
return false;
|
|
21
51
|
};
|
|
22
52
|
|
|
23
|
-
const itemPath = (item) =>
|
|
24
|
-
if (!item || !item.file) return '';
|
|
25
|
-
return item.file.newPath || item.file.oldPath || '';
|
|
26
|
-
};
|
|
53
|
+
const itemPath = (item) => item?.file?.newPath || item?.file?.oldPath || '';
|
|
27
54
|
|
|
28
55
|
const listPath = (item) => listFilePath(itemPath(item));
|
|
29
56
|
|
|
30
|
-
const isTaskItem = (item) =>
|
|
57
|
+
const isTaskItem = (item) => item?.origin === 'task';
|
|
31
58
|
|
|
32
59
|
const isReadOnlyOrigin = (origin) => origin === 'commit' || origin === 'pr';
|
|
33
60
|
|
|
34
|
-
const isTasksEntry = (entry) =>
|
|
61
|
+
const isTasksEntry = (entry) => entry?.kind === 'tasks';
|
|
35
62
|
|
|
36
|
-
const isTotalEntry = (entry) =>
|
|
63
|
+
const isTotalEntry = (entry) => entry?.kind === 'total';
|
|
37
64
|
|
|
38
65
|
const makeTaskItem = () => ({
|
|
39
66
|
origin: 'task',
|
|
@@ -53,52 +80,30 @@ const makeTaskItem = () => ({
|
|
|
53
80
|
});
|
|
54
81
|
|
|
55
82
|
const fileStatus = (origins) => {
|
|
56
|
-
const
|
|
57
|
-
const seen = ORIGIN_ORDER.filter((origin) => present.has(origin));
|
|
83
|
+
const seen = ORIGIN_ORDER.filter((origin) => origins.includes(origin));
|
|
58
84
|
const key = seen.join('+');
|
|
59
|
-
|
|
60
|
-
if (key === 'staged+unstaged') return 'partial';
|
|
61
|
-
return key;
|
|
85
|
+
return key === 'staged+unstaged' ? 'partial' : key;
|
|
62
86
|
};
|
|
63
87
|
|
|
64
88
|
const lineDelta = ({ hunk, blockId }) => {
|
|
65
89
|
const delta = { added: 0, removed: 0 };
|
|
66
|
-
if (!hunk) return delta;
|
|
67
|
-
const { lines } = hunk;
|
|
68
|
-
if (!lines) return delta;
|
|
90
|
+
if (!hunk || !hunk.lines) return delta;
|
|
69
91
|
const scoped = typeof blockId === 'number';
|
|
70
|
-
for (const
|
|
71
|
-
if (scoped &&
|
|
72
|
-
if (type === 'add') delta.added += 1;
|
|
73
|
-
else if (type === 'del') delta.removed += 1;
|
|
92
|
+
for (const line of hunk.lines) {
|
|
93
|
+
if (scoped && line.blockId !== blockId) continue;
|
|
94
|
+
if (line.type === 'add') delta.added += 1;
|
|
95
|
+
else if (line.type === 'del') delta.removed += 1;
|
|
74
96
|
}
|
|
75
97
|
return delta;
|
|
76
98
|
};
|
|
77
99
|
|
|
78
|
-
const AGE_UNIT = {
|
|
79
|
-
second: 's',
|
|
80
|
-
minute: 'm',
|
|
81
|
-
hour: 'h',
|
|
82
|
-
day: 'd',
|
|
83
|
-
week: 'w',
|
|
84
|
-
month: 'mo',
|
|
85
|
-
year: 'y',
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const AGE_AGO = /^(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago$/i;
|
|
89
|
-
const AGE_SHORT = /^(\d+)(mo|[smhdwy])(?: ago)?$/i;
|
|
90
|
-
|
|
91
100
|
const shortUnit = (n, unit) => `${n}${AGE_UNIT[unit]} ago`;
|
|
92
101
|
|
|
93
102
|
const shortAge = (text) => {
|
|
94
103
|
const raw = `${text ?? ''}`.trim();
|
|
95
|
-
if (!raw) return '';
|
|
96
104
|
if (/^yesterday$/i.test(raw)) return '1d ago';
|
|
97
105
|
const match = AGE_AGO.exec(raw);
|
|
98
|
-
if (match)
|
|
99
|
-
const unit = AGE_UNIT[match[2].toLowerCase()];
|
|
100
|
-
if (unit) return `${match[1]}${unit} ago`;
|
|
101
|
-
}
|
|
106
|
+
if (match) return shortUnit(match[1], match[2].toLowerCase());
|
|
102
107
|
const brief = AGE_SHORT.exec(raw);
|
|
103
108
|
if (brief) return `${brief[1]}${brief[2].toLowerCase()} ago`;
|
|
104
109
|
return raw;
|
|
@@ -118,6 +123,18 @@ const relativeAge = (thenMs, nowMs = Date.now()) => {
|
|
|
118
123
|
return shortUnit(Math.round(days / 365), 'year');
|
|
119
124
|
};
|
|
120
125
|
|
|
126
|
+
const emptyCounts = () => ({
|
|
127
|
+
remaining: 0,
|
|
128
|
+
added: 0,
|
|
129
|
+
removed: 0,
|
|
130
|
+
stagedAdded: 0,
|
|
131
|
+
stagedRemoved: 0,
|
|
132
|
+
unstagedAdded: 0,
|
|
133
|
+
unstagedRemoved: 0,
|
|
134
|
+
staged: 0,
|
|
135
|
+
unstaged: 0,
|
|
136
|
+
});
|
|
137
|
+
|
|
121
138
|
const addLineDelta = (group, origin, delta) => {
|
|
122
139
|
group.added += delta.added;
|
|
123
140
|
group.removed += delta.removed;
|
|
@@ -141,19 +158,12 @@ const originLineDelta = (entry) => {
|
|
|
141
158
|
}
|
|
142
159
|
const added = entry.added ?? 0;
|
|
143
160
|
const removed = entry.removed ?? 0;
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
stagedAdded: added,
|
|
147
|
-
stagedRemoved: removed,
|
|
148
|
-
unstagedAdded: 0,
|
|
149
|
-
unstagedRemoved: 0,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
161
|
+
const staged = entry.status === 'staged';
|
|
152
162
|
return {
|
|
153
|
-
stagedAdded: 0,
|
|
154
|
-
stagedRemoved: 0,
|
|
155
|
-
unstagedAdded: added,
|
|
156
|
-
unstagedRemoved: removed,
|
|
163
|
+
stagedAdded: staged ? added : 0,
|
|
164
|
+
stagedRemoved: staged ? removed : 0,
|
|
165
|
+
unstagedAdded: staged ? 0 : added,
|
|
166
|
+
unstagedRemoved: staged ? 0 : removed,
|
|
157
167
|
};
|
|
158
168
|
};
|
|
159
169
|
|
|
@@ -165,22 +175,8 @@ const fileEntries = (items) => {
|
|
|
165
175
|
const rel = listPath(item);
|
|
166
176
|
if (!rel) continue;
|
|
167
177
|
if (!groups.has(rel)) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
origins: [],
|
|
171
|
-
firstIndex: i,
|
|
172
|
-
openIndex: i,
|
|
173
|
-
remaining: 0,
|
|
174
|
-
added: 0,
|
|
175
|
-
removed: 0,
|
|
176
|
-
stagedAdded: 0,
|
|
177
|
-
stagedRemoved: 0,
|
|
178
|
-
unstagedAdded: 0,
|
|
179
|
-
unstagedRemoved: 0,
|
|
180
|
-
staged: 0,
|
|
181
|
-
unstaged: 0,
|
|
182
|
-
date: '',
|
|
183
|
-
});
|
|
178
|
+
const fields = { origins: [], firstIndex: i, openIndex: i };
|
|
179
|
+
groups.set(rel, { path: rel, ...fields, ...emptyCounts(), date: '' });
|
|
184
180
|
}
|
|
185
181
|
const group = groups.get(rel);
|
|
186
182
|
const { origin } = item;
|
|
@@ -195,47 +191,30 @@ const fileEntries = (items) => {
|
|
|
195
191
|
}
|
|
196
192
|
}
|
|
197
193
|
const entries = [...groups.values()];
|
|
198
|
-
for (const group of entries)
|
|
199
|
-
group.status = fileStatus(group.origins);
|
|
200
|
-
}
|
|
194
|
+
for (const group of entries) group.status = fileStatus(group.origins);
|
|
201
195
|
entries.sort((left, right) => left.path.localeCompare(right.path, 'en'));
|
|
202
196
|
return entries;
|
|
203
197
|
};
|
|
204
198
|
|
|
205
199
|
const fileTotals = (files) => {
|
|
206
|
-
const total = {
|
|
207
|
-
|
|
208
|
-
kind: 'total',
|
|
209
|
-
status: '',
|
|
210
|
-
remaining: 0,
|
|
211
|
-
added: 0,
|
|
212
|
-
removed: 0,
|
|
213
|
-
stagedAdded: 0,
|
|
214
|
-
stagedRemoved: 0,
|
|
215
|
-
unstagedAdded: 0,
|
|
216
|
-
unstagedRemoved: 0,
|
|
217
|
-
staged: 0,
|
|
218
|
-
unstaged: 0,
|
|
219
|
-
};
|
|
200
|
+
const total = { path: TOTAL_LABEL, kind: 'total', status: '' };
|
|
201
|
+
Object.assign(total, emptyCounts());
|
|
220
202
|
for (const entry of files) {
|
|
221
203
|
if (isTasksEntry(entry) || isTotalEntry(entry)) continue;
|
|
222
204
|
const remaining = entry.remaining ?? 0;
|
|
223
205
|
const staged = entry.staged ?? 0;
|
|
224
|
-
const added = entry.added ?? 0;
|
|
225
|
-
const removed = entry.removed ?? 0;
|
|
226
206
|
const lines = originLineDelta(entry);
|
|
227
207
|
const listed = entry.unstaged ?? Math.max(0, remaining - staged);
|
|
228
|
-
const untracked =
|
|
229
|
-
const unstaged = untracked && listed === 0 ? remaining : listed;
|
|
208
|
+
const untracked = entry.status === 'untracked';
|
|
230
209
|
total.remaining += remaining;
|
|
231
|
-
total.added += added;
|
|
232
|
-
total.removed += removed;
|
|
210
|
+
total.added += entry.added ?? 0;
|
|
211
|
+
total.removed += entry.removed ?? 0;
|
|
233
212
|
total.stagedAdded += lines.stagedAdded;
|
|
234
213
|
total.stagedRemoved += lines.stagedRemoved;
|
|
235
214
|
total.unstagedAdded += lines.unstagedAdded;
|
|
236
215
|
total.unstagedRemoved += lines.unstagedRemoved;
|
|
237
216
|
total.staged += staged;
|
|
238
|
-
total.unstaged +=
|
|
217
|
+
total.unstaged += untracked && listed === 0 ? remaining : listed;
|
|
239
218
|
}
|
|
240
219
|
return total;
|
|
241
220
|
};
|
|
@@ -244,6 +223,9 @@ module.exports = {
|
|
|
244
223
|
REVIEW_DIR,
|
|
245
224
|
TASKS_FILE,
|
|
246
225
|
REPO_TASKS_LABEL,
|
|
226
|
+
TASK_KINDS,
|
|
227
|
+
taskKind,
|
|
228
|
+
taskTitle,
|
|
247
229
|
TOTAL_LABEL,
|
|
248
230
|
isPathInScope,
|
|
249
231
|
itemPath,
|