reslop 0.2.4 → 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 +25 -1
- package/LICENSE +1 -1
- package/README.md +12 -13
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +32 -19
- package/lib/capabilities.js +8 -12
- package/lib/cli.js +40 -74
- package/lib/clipboard.js +48 -18
- 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 +196 -404
- package/lib/deps.js +240 -399
- 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 +138 -141
- 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 +90 -206
- package/lib/editor.js +98 -55
- package/lib/files.js +86 -103
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +182 -344
- 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 +157 -132
- 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 +16 -26
- 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 +22 -35
- package/lib/highlight/txt.js +9 -22
- package/lib/highlight.js +17 -46
- package/lib/keys.js +62 -85
- package/lib/manifest.js +67 -130
- package/lib/npm-commands.js +119 -189
- package/lib/remote.js +141 -197
- package/lib/render/branches.js +66 -73
- package/lib/render/chrome.js +264 -323
- package/lib/render/commits.js +187 -500
- 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 -228
- package/lib/render/files.js +45 -99
- package/lib/render/frame.js +129 -183
- package/lib/render/notes.js +144 -160
- package/lib/render/npm.js +234 -112
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +131 -170
- 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 -28
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -38
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -78
- package/lib/report-test.js +256 -141
- package/lib/report-tools.js +96 -161
- package/lib/review-merge.js +114 -152
- package/lib/review.js +115 -189
- package/lib/runs.js +225 -0
- package/lib/select.js +89 -75
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +82 -63
- package/lib/session/branches.js +193 -247
- package/lib/session/change-actions.js +171 -214
- package/lib/session/commit.js +280 -342
- package/lib/session/compose.js +559 -674
- package/lib/session/dashboard.js +385 -0
- package/lib/session/dispatch.js +164 -157
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +85 -53
- package/lib/session/items.js +73 -104
- package/lib/session/lifecycle.js +403 -541
- package/lib/session/load.js +48 -68
- package/lib/session/navigation.js +96 -87
- package/lib/session/npm.js +409 -345
- package/lib/session/ops.js +196 -63
- package/lib/session/pointer.js +23 -15
- package/lib/session/progress.js +33 -21
- package/lib/session/review.js +33 -54
- package/lib/session/tasks.js +333 -0
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -136
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -97
- package/lib/session/view.js +52 -83
- package/lib/session/watch.js +208 -204
- package/lib/session.js +112 -237
- package/lib/update.js +45 -116
- package/lib/utilities.js +67 -89
- package/lib/wrap.js +33 -44
- package/package.json +1 -1
- package/lib/session/todos.js +0 -293
package/lib/render/primitives.js
CHANGED
|
@@ -2,67 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
const ansi = require('../ansi.js');
|
|
4
4
|
const actions = require('../session/actions.js');
|
|
5
|
-
const { LIST_PANES } = actions;
|
|
6
5
|
|
|
7
|
-
const { THEME, paint, visibleWidth,
|
|
6
|
+
const { THEME, paint, visibleWidth, graphemes, graphemeWidth } = ansi;
|
|
7
|
+
const { LIST_PANES } = actions;
|
|
8
8
|
|
|
9
9
|
const GUTTER_W = 2;
|
|
10
10
|
const FILE_MARK = '▶';
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const CHECK_LEAD = /^\[[ xX]\] /;
|
|
11
|
+
const MARK_W = visibleWidth(` ${FILE_MARK} `);
|
|
12
|
+
const LIST_PAD = 1;
|
|
13
|
+
const NO_EDITS = [];
|
|
15
14
|
|
|
16
15
|
const fill = (width, fgRgb, bgRgb, color) =>
|
|
17
16
|
paint(' '.repeat(Math.max(0, width)), fgRgb, bgRgb, color);
|
|
18
17
|
|
|
19
|
-
const
|
|
20
|
-
const clipped = truncateVisible(text, width);
|
|
21
|
-
const pad = Math.max(0, width - visibleWidth(clipped));
|
|
22
|
-
const filled = clipped + ' '.repeat(pad);
|
|
23
|
-
if (!color) return filled;
|
|
24
|
-
return `${seq(fgRgb, bgRgb)}${EL}${filled}${RESET}`;
|
|
25
|
-
};
|
|
18
|
+
const markPrefix = (selected) => ` ${selected ? FILE_MARK : ' '} `;
|
|
26
19
|
|
|
27
|
-
const
|
|
28
|
-
const match = CHECK_TOKEN.exec(text);
|
|
29
|
-
if (!match) return null;
|
|
30
|
-
const start = match.index;
|
|
31
|
-
const token = match[0];
|
|
32
|
-
const before = text.slice(0, start);
|
|
33
|
-
const mark = match[1];
|
|
34
|
-
const after = text.slice(start + token.length);
|
|
35
|
-
return { before, mark, token, after };
|
|
36
|
-
};
|
|
20
|
+
const isListPane = (pane) => LIST_PANES.includes(pane) || pane === 'dashboard';
|
|
37
21
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!parts) return paintBar(text, width, fgRgb, bgRgb, color);
|
|
42
|
-
const pad = Math.max(0, width - visibleWidth(clipped));
|
|
43
|
-
const done = CHECK_DONE.includes(parts.mark);
|
|
44
|
-
let chipFg = THEME.checkFg;
|
|
45
|
-
let chipBg = THEME.checkBg;
|
|
46
|
-
if (plain) {
|
|
47
|
-
chipFg = fgRgb;
|
|
48
|
-
chipBg = bgRgb;
|
|
49
|
-
} else if (done) {
|
|
50
|
-
chipFg = THEME.checkDoneFg;
|
|
51
|
-
chipBg = THEME.checkDoneBg;
|
|
52
|
-
}
|
|
53
|
-
const after = `${parts.after}${' '.repeat(pad)}`;
|
|
54
|
-
let out = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
55
|
-
if (parts.before) out += paint(parts.before, fgRgb, bgRgb, color);
|
|
56
|
-
out += paint(parts.token, chipFg, chipBg, color);
|
|
57
|
-
if (after) out += paint(after, fgRgb, bgRgb, color);
|
|
58
|
-
return out;
|
|
59
|
-
};
|
|
22
|
+
const isTaskView = (view) => view.item?.origin === 'task';
|
|
23
|
+
|
|
24
|
+
const branchLabel = (name) => `${name ?? ''}`.trim();
|
|
60
25
|
|
|
61
26
|
const padVisible = (text, width, align) => {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
if (align === 'end') return `${text}${gap}`;
|
|
65
|
-
return `${gap}${text}`;
|
|
27
|
+
const gap = ' '.repeat(Math.max(0, width - visibleWidth(text)));
|
|
28
|
+
return align === 'end' ? `${text}${gap}` : `${gap}${text}`;
|
|
66
29
|
};
|
|
67
30
|
|
|
68
31
|
const splitWidths = (width) => {
|
|
@@ -74,136 +37,132 @@ const splitWidths = (width) => {
|
|
|
74
37
|
const paintSplitRule = (color) =>
|
|
75
38
|
fill(1, THEME.splitGutterFg, THEME.splitGutterBg, color);
|
|
76
39
|
|
|
77
|
-
const
|
|
40
|
+
const paintBodyFill = (width, color, kind) => {
|
|
41
|
+
const ctx = (n) => fill(n, THEME.ctxFg, THEME.ctxBg, color);
|
|
42
|
+
if (kind === 'files') return ctx(Math.max(1, width - 1)) + ctx(1);
|
|
43
|
+
if (kind !== 'split') return ctx(width);
|
|
78
44
|
const { leftW, rightW } = splitWidths(width);
|
|
79
|
-
return (
|
|
80
|
-
fill(leftW, THEME.ctxFg, THEME.ctxBg, color) +
|
|
81
|
-
paintSplitRule(color) +
|
|
82
|
-
fill(rightW, THEME.ctxFg, THEME.ctxBg, color)
|
|
83
|
-
);
|
|
45
|
+
return ctx(leftW) + paintSplitRule(color) + ctx(rightW);
|
|
84
46
|
};
|
|
85
47
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
};
|
|
48
|
+
const paneResult = (fields = {}) => ({
|
|
49
|
+
body: fields.body ?? [],
|
|
50
|
+
fileHits: fields.fileHits ?? [],
|
|
51
|
+
taskOwners: fields.taskOwners ?? [],
|
|
52
|
+
taskChecks: fields.taskChecks ?? [],
|
|
53
|
+
cursor: fields.cursor ?? null,
|
|
54
|
+
splitBody: fields.splitBody === true,
|
|
55
|
+
listScroll: fields.listScroll ?? 0,
|
|
56
|
+
editHits: fields.editHits ?? [],
|
|
57
|
+
});
|
|
96
58
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
59
|
+
const editSpan = (x0, textX, x1, start, text) => ({
|
|
60
|
+
x0,
|
|
61
|
+
textX,
|
|
62
|
+
x1,
|
|
63
|
+
start,
|
|
64
|
+
text,
|
|
65
|
+
limit: start + text.length,
|
|
66
|
+
live: true,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const listLine = (row, index, cursor = null, edits = NO_EDITS) => ({
|
|
70
|
+
row,
|
|
71
|
+
index,
|
|
72
|
+
hit: index >= 0,
|
|
73
|
+
cursor,
|
|
74
|
+
edits,
|
|
75
|
+
});
|
|
104
76
|
|
|
105
77
|
const listWindowStart = (focus, offset, listH, count) => {
|
|
106
78
|
let start = offset ?? 0;
|
|
107
79
|
if (focus < start) start = focus;
|
|
108
80
|
if (focus >= start + listH) start = focus - listH + 1;
|
|
109
|
-
|
|
110
|
-
if (start > maxStart) start = maxStart;
|
|
111
|
-
if (start < 0) start = 0;
|
|
112
|
-
return start;
|
|
81
|
+
return Math.max(0, Math.min(start, count - listH));
|
|
113
82
|
};
|
|
114
83
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
return count;
|
|
84
|
+
const rowCursor = (cursor, row) => {
|
|
85
|
+
const out = { x: cursor.x, row };
|
|
86
|
+
if (typeof cursor.scroll === 'number') out.scroll = cursor.scroll;
|
|
87
|
+
return out;
|
|
120
88
|
};
|
|
121
89
|
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
todoOwners: fields.todoOwners ?? [],
|
|
126
|
-
todoChecks: fields.todoChecks ?? [],
|
|
127
|
-
cursor: fields.cursor ?? null,
|
|
128
|
-
splitBody: fields.splitBody === true,
|
|
129
|
-
listScroll: fields.listScroll ?? 0,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const paintCursorList = (
|
|
133
|
-
items,
|
|
134
|
-
cursor,
|
|
135
|
-
width,
|
|
136
|
-
color,
|
|
137
|
-
bodyH,
|
|
138
|
-
headerLines,
|
|
139
|
-
paintRow,
|
|
140
|
-
extraRow,
|
|
141
|
-
offset = 0,
|
|
142
|
-
) => {
|
|
143
|
-
const pad = bodyH >= FILE_LIST_PAD * 2 + 1 ? FILE_LIST_PAD : 0;
|
|
90
|
+
const paintListWindow = (count, focus, pane, lineAt) => {
|
|
91
|
+
const { width, color, bodyH, headerLines, offset } = pane;
|
|
92
|
+
const pad = bodyH >= LIST_PAD * 2 + 1 ? LIST_PAD : 0;
|
|
144
93
|
const listH = bodyH - pad * 2;
|
|
145
|
-
const inserting = extraRow && extraRow.at === 'start';
|
|
146
|
-
const extra = extraRow && extraRow.at !== 'replace' ? 1 : 0;
|
|
147
|
-
const count = items.length + extra;
|
|
148
|
-
const extraAt = extraIdx(extraRow, cursor, items.length);
|
|
149
|
-
const focus = extraRow ? extraAt : cursor;
|
|
150
94
|
const start = listWindowStart(focus, offset, listH, count);
|
|
151
95
|
const blank = paintBodyFill(width, color, 'files');
|
|
152
|
-
const body = [];
|
|
96
|
+
const body = pad ? [blank] : [];
|
|
153
97
|
const fileHits = [];
|
|
154
|
-
|
|
155
|
-
|
|
98
|
+
const editHits = [];
|
|
99
|
+
let cursor = null;
|
|
156
100
|
for (let i = 0; i < listH; i++) {
|
|
157
|
-
const
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
101
|
+
const line = lineAt(start + i);
|
|
102
|
+
if (!line) break;
|
|
103
|
+
const row = body.push(line.row) - 1;
|
|
104
|
+
if (line.cursor) cursor = rowCursor(line.cursor, row);
|
|
105
|
+
for (const edit of line.edits) editHits.push({ ...edit, row });
|
|
106
|
+
if (line.hit) {
|
|
107
|
+
fileHits.push({ y: headerLines + pad + i + 1, cursor: line.index });
|
|
164
108
|
}
|
|
165
|
-
const itemIdx = inserting ? idx - 1 : idx;
|
|
166
|
-
const entry = items[itemIdx];
|
|
167
|
-
if (!entry) break;
|
|
168
|
-
const selected = extraRow ? false : itemIdx === cursor;
|
|
169
|
-
body.push(paintRow(entry, width, color, selected));
|
|
170
|
-
const y = headerLines + pad + i + 1;
|
|
171
|
-
fileHits.push({ y, cursor: itemIdx });
|
|
172
109
|
}
|
|
173
110
|
if (pad) body.push(blank);
|
|
174
|
-
return paneResult({
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
111
|
+
return paneResult({ body, fileHits, editHits, cursor, listScroll: start });
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const paintCursorList = (items, cursor, pane, paintRow, extra = null) => {
|
|
115
|
+
const lineAt = (index) => {
|
|
116
|
+
const entry = items[index];
|
|
117
|
+
if (!entry) return null;
|
|
118
|
+
return listLine(paintRow(entry, !extra && index === cursor), index);
|
|
119
|
+
};
|
|
120
|
+
if (!extra) return paintListWindow(items.length, cursor, pane, lineAt);
|
|
121
|
+
const edit = listLine(extra.row, -1, extra.cursor, extra.edits);
|
|
122
|
+
if (extra.at === 'replace') {
|
|
123
|
+
const at = extra.index;
|
|
124
|
+
const replaced = (i) => (i === at ? edit : lineAt(i));
|
|
125
|
+
return paintListWindow(items.length, at, pane, replaced);
|
|
126
|
+
}
|
|
127
|
+
const first = extra.at === 'start';
|
|
128
|
+
const at = first ? 0 : items.length;
|
|
129
|
+
const shift = first ? 1 : 0;
|
|
130
|
+
const inserted = (i) => (i === at ? edit : lineAt(i - shift));
|
|
131
|
+
return paintListWindow(items.length + 1, at, pane, inserted);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const sliceVisible = (text, skip, width) => {
|
|
135
|
+
if (width <= 0) return '';
|
|
136
|
+
const parts = graphemes(text);
|
|
137
|
+
let used = 0;
|
|
138
|
+
let i = 0;
|
|
139
|
+
const drop = Math.max(0, skip);
|
|
140
|
+
while (i < parts.length) {
|
|
141
|
+
const w = graphemeWidth(parts[i], used);
|
|
142
|
+
if (used + w > drop) break;
|
|
143
|
+
used += w;
|
|
144
|
+
i += 1;
|
|
145
|
+
}
|
|
146
|
+
let out = '';
|
|
147
|
+
let taken = 0;
|
|
148
|
+
for (; i < parts.length; i++) {
|
|
149
|
+
const w = graphemeWidth(parts[i], drop + taken);
|
|
150
|
+
if (taken + w > width) break;
|
|
151
|
+
out += parts[i];
|
|
152
|
+
taken += w;
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
180
155
|
};
|
|
181
156
|
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
const pad = Math.max(0, rest - visibleWidth(clipped));
|
|
192
|
-
const left = `${prefix}${clipped}${' '.repeat(pad)}`;
|
|
193
|
-
const fgRgb = THEME.chromeFg;
|
|
194
|
-
const bgRgb = THEME.buttonBg;
|
|
195
|
-
const edge = fill(edgeW, fgRgb, THEME.ctxBg, color);
|
|
196
|
-
let row = `${left}${edge}`;
|
|
197
|
-
if (color) {
|
|
198
|
-
const gap = ' '.repeat(pad);
|
|
199
|
-
row = `${seq(fgRgb, bgRgb)}${EL}`;
|
|
200
|
-
row += paint(prefix, fgRgb, bgRgb, color);
|
|
201
|
-
row += paint(clipped, THEME.buttonHotFg, bgRgb, color);
|
|
202
|
-
row += paint(gap, fgRgb, bgRgb, color);
|
|
203
|
-
row += edge;
|
|
204
|
-
}
|
|
205
|
-
const col = Math.min(compose.cursor ?? 0, visibleWidth(clipped));
|
|
206
|
-
return { row, cursor: { x: prefixW + col + 1 } };
|
|
157
|
+
const fieldWindow = (text, cursor, scroll, width) => {
|
|
158
|
+
if (width <= 0) return { text: '', col: 0, scroll: 0 };
|
|
159
|
+
const at = Math.max(0, Math.min(cursor ?? 0, text.length));
|
|
160
|
+
const col = visibleWidth(text.slice(0, at));
|
|
161
|
+
let next = Math.max(0, scroll ?? 0);
|
|
162
|
+
if (col < next) next = col;
|
|
163
|
+
if (col >= next + width) next = col - width + 1;
|
|
164
|
+
const shown = sliceVisible(text, next, width);
|
|
165
|
+
return { text: shown, col: col - next, scroll: next };
|
|
207
166
|
};
|
|
208
167
|
|
|
209
168
|
const measureColumns = (entries, rowFields, align) => {
|
|
@@ -221,7 +180,7 @@ const measureColumns = (entries, rowFields, align) => {
|
|
|
221
180
|
const padColumns = (fields, widths, align) => {
|
|
222
181
|
const parts = {};
|
|
223
182
|
for (const key of Object.keys(align)) {
|
|
224
|
-
const width = widths
|
|
183
|
+
const width = widths[key] ?? visibleWidth(fields[key]);
|
|
225
184
|
parts[key] = padVisible(fields[key], width, align[key]);
|
|
226
185
|
}
|
|
227
186
|
return parts;
|
|
@@ -248,25 +207,27 @@ const paintColumns = (parts, widths, fgRgb, bgRgb, color, tones) => {
|
|
|
248
207
|
};
|
|
249
208
|
|
|
250
209
|
module.exports = {
|
|
251
|
-
measureColumns,
|
|
252
|
-
padColumns,
|
|
253
|
-
joinColumns,
|
|
254
|
-
paintColumns,
|
|
255
210
|
GUTTER_W,
|
|
256
211
|
FILE_MARK,
|
|
257
|
-
|
|
258
|
-
CHECK_LEAD,
|
|
212
|
+
MARK_W,
|
|
259
213
|
fill,
|
|
260
|
-
|
|
261
|
-
|
|
214
|
+
markPrefix,
|
|
215
|
+
isListPane,
|
|
216
|
+
isTaskView,
|
|
217
|
+
branchLabel,
|
|
262
218
|
padVisible,
|
|
263
219
|
splitWidths,
|
|
264
220
|
paintSplitRule,
|
|
265
221
|
paintBodyFill,
|
|
266
|
-
windowRows,
|
|
267
|
-
listWindowStart,
|
|
268
|
-
paintCursorList,
|
|
269
|
-
paintListEdit,
|
|
270
|
-
branchLabel,
|
|
271
222
|
paneResult,
|
|
223
|
+
editSpan,
|
|
224
|
+
listLine,
|
|
225
|
+
paintListWindow,
|
|
226
|
+
paintCursorList,
|
|
227
|
+
sliceVisible,
|
|
228
|
+
fieldWindow,
|
|
229
|
+
measureColumns,
|
|
230
|
+
padColumns,
|
|
231
|
+
joinColumns,
|
|
232
|
+
paintColumns,
|
|
272
233
|
};
|
package/lib/render/render.js
CHANGED
|
@@ -5,30 +5,21 @@ const notes = require('./notes.js');
|
|
|
5
5
|
const diff = require('./diff.js');
|
|
6
6
|
const present = require('./present.js');
|
|
7
7
|
const frame = require('./frame.js');
|
|
8
|
-
const { renderFrame } = frame;
|
|
9
8
|
|
|
10
|
-
const { QUIT_PROMPT, PUSH_PROMPT } = chrome;
|
|
11
|
-
const { updatePrompt, dropPrompt } = chrome;
|
|
12
9
|
const { formatBusyStatus, headerText, layoutButtons } = chrome;
|
|
13
|
-
const {
|
|
14
|
-
const {
|
|
10
|
+
const { todoBodyWidth, noteInnerWidth } = notes;
|
|
11
|
+
const { paintDiffLine, codeInnerWidth } = diff;
|
|
15
12
|
const { presentCursor, presentRows } = present;
|
|
13
|
+
const { renderFrame } = frame;
|
|
16
14
|
|
|
17
15
|
module.exports = {
|
|
18
|
-
|
|
19
|
-
PUSH_PROMPT,
|
|
20
|
-
updatePrompt,
|
|
21
|
-
dropPrompt,
|
|
22
|
-
delCharBg,
|
|
23
|
-
addCharBg,
|
|
24
|
-
paintDiffLine,
|
|
16
|
+
formatBusyStatus,
|
|
25
17
|
headerText,
|
|
26
18
|
layoutButtons,
|
|
27
|
-
todoInnerWidth,
|
|
28
19
|
todoBodyWidth,
|
|
29
20
|
noteInnerWidth,
|
|
21
|
+
paintDiffLine,
|
|
30
22
|
codeInnerWidth,
|
|
31
|
-
formatBusyStatus,
|
|
32
23
|
renderFrame,
|
|
33
24
|
presentCursor,
|
|
34
25
|
presentRows,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const commands = require('../npm-commands.js');
|
|
4
|
+
const { formatTable } = commands;
|
|
5
|
+
const reportRender = require('../report-render.js');
|
|
6
|
+
const { summaryRows, problemRows, displayMessage, quoteLines } = reportRender;
|
|
7
|
+
|
|
8
|
+
const reportProblem = (item) => {
|
|
9
|
+
const title = item.name || item.message || item.code || 'problem';
|
|
10
|
+
const mark = item.severity === 'warning' ? '△' : '✖';
|
|
11
|
+
const count = item.count > 1 ? ` × ${item.count}` : '';
|
|
12
|
+
const lines = ['', `${mark} ${title.split('\n')[0]}${count}`, ''];
|
|
13
|
+
lines.push(...formatTable(problemRows(item)));
|
|
14
|
+
const message = displayMessage(item);
|
|
15
|
+
if (message) lines.push('', ...quoteLines(message));
|
|
16
|
+
if (item.trace) {
|
|
17
|
+
lines.push('', 'Stack');
|
|
18
|
+
for (const row of item.trace.split(/\r?\n/)) {
|
|
19
|
+
const frame = row.trim().replace(/^at\s+/, '');
|
|
20
|
+
if (frame) lines.push(` at ${frame}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (item.related.length) {
|
|
24
|
+
lines.push('', 'Related failures');
|
|
25
|
+
for (const row of item.related) lines.push(` ↳ ${row}`);
|
|
26
|
+
}
|
|
27
|
+
return lines;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const renderReport = (doc) => {
|
|
31
|
+
const lines = [];
|
|
32
|
+
for (const item of doc.reports) {
|
|
33
|
+
if (lines.length) lines.push('');
|
|
34
|
+
const mark = item.ok ? '✔' : '✖';
|
|
35
|
+
lines.push(`${mark} ${item.tool} · exit ${doc.exit}`, '');
|
|
36
|
+
lines.push(...formatTable(summaryRows(item.summary)));
|
|
37
|
+
for (const entry of item.problems) lines.push(...reportProblem(entry));
|
|
38
|
+
}
|
|
39
|
+
if (doc.stderr) lines.push('', 'Stderr', doc.stderr);
|
|
40
|
+
return `${lines.join('\n')}\n`;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = { renderReport };
|