reslop 0.2.6 → 0.3.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.
- package/CHANGELOG.md +27 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +504 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +16 -0
- package/lib/agents/models.js +460 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +61 -66
- package/lib/{files.js → common/files.js} +51 -52
- package/lib/common/find.js +61 -0
- package/lib/common/format.js +101 -0
- package/lib/{utilities.js → common/process.js} +7 -95
- package/lib/common/tasks.json +27 -0
- package/lib/common/utilities.js +112 -0
- package/lib/dashboard/git.js +9 -16
- package/lib/dashboard/model.js +117 -51
- package/lib/dashboard/npm.js +133 -32
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +41 -31
- package/lib/dashboard/workspace.js +151 -0
- package/lib/{deps.js → deps/deps.js} +31 -45
- package/lib/{deps-diff.js → deps/diff.js} +35 -25
- package/lib/{manifest.js → deps/manifest.js} +47 -30
- package/lib/diff/align.js +1 -2
- package/lib/diff/diff.js +2 -2
- package/lib/diff/display.js +29 -5
- package/lib/diff/inline.js +10 -14
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +39 -3
- package/lib/diff/unit.js +45 -16
- package/lib/{git-branches.js → git/branches.js} +53 -48
- package/lib/{git-deps.js → git/deps.js} +123 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +475 -0
- package/lib/highlight/bash.js +1 -2
- package/lib/highlight/csv.js +1 -2
- package/lib/highlight/dot.js +1 -2
- package/lib/{highlight.js → highlight/highlight.js} +42 -11
- package/lib/highlight/html.js +20 -18
- package/lib/highlight/json.js +1 -2
- package/lib/highlight/log.js +1 -2
- package/lib/highlight/txt.js +1 -2
- package/lib/{session → input}/actions.js +240 -71
- package/lib/{editor.js → input/editor.js} +7 -8
- package/lib/{keys.js → input/keys.js} +36 -39
- package/lib/input/line-edit.js +77 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +640 -0
- package/lib/render/branches.js +4 -5
- package/lib/render/commits.js +54 -64
- package/lib/render/{dash-activity.js → dashboard/activity.js} +25 -40
- package/lib/render/dashboard/blocks.js +490 -0
- package/lib/render/{dashboard.js → dashboard/dashboard.js} +25 -22
- package/lib/render/diff.js +166 -45
- package/lib/render/field.js +131 -0
- package/lib/render/files.js +22 -8
- package/lib/render/footer.js +383 -0
- package/lib/render/frame.js +127 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +319 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +29 -13
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +89 -0
- package/lib/render/primitives.js +109 -16
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +214 -0
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +19 -61
- package/lib/render/tiles.js +203 -47
- package/lib/render/unit.js +32 -13
- package/lib/{report-model.js → report/model.js} +4 -6
- package/lib/{report-parse.js → report/parse.js} +9 -14
- package/lib/{report-render.js → report/render.js} +46 -14
- package/lib/{report-run.js → report/run.js} +42 -30
- package/lib/{report-test.js → report/test.js} +56 -55
- package/lib/{report-tools.js → report/tools.js} +24 -33
- package/lib/review/agent-instructions.md +9 -0
- package/lib/review/format.js +426 -0
- package/lib/{review-merge.js → review/merge.js} +9 -8
- package/lib/review/review.js +190 -0
- package/lib/review/store.js +281 -0
- package/lib/review/templates.js +83 -0
- package/lib/runs/commands.js +14 -0
- package/lib/runs/logs.js +299 -0
- package/lib/runs/output.js +174 -0
- package/lib/runs/process.js +113 -0
- package/lib/{runs.js → runs/runs.js} +84 -36
- package/lib/runs/scripts.js +150 -0
- package/lib/session/agents/agents.js +958 -0
- package/lib/session/agents/job.js +320 -0
- package/lib/session/agents/jobs.js +355 -0
- package/lib/session/agents/options.js +153 -0
- package/lib/session/agents/plans.js +83 -0
- package/lib/session/branches.js +36 -44
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +122 -56
- package/lib/session/compose.js +197 -146
- package/lib/session/dashboard.js +183 -37
- package/lib/session/dispatch.js +120 -22
- package/lib/session/files-pane.js +60 -24
- package/lib/session/find.js +81 -0
- package/lib/session/import.js +82 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +96 -66
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +8 -3
- package/lib/session/npm/history.js +249 -0
- package/lib/session/npm/npm.js +815 -0
- package/lib/session/npm/packages.js +150 -0
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +216 -10
- package/lib/session/prefs.js +112 -0
- package/lib/session/reads.js +109 -0
- package/lib/session/review.js +28 -10
- package/lib/session/run-panel.js +40 -0
- package/lib/{session.js → session/session.js} +166 -59
- package/lib/session/tasks.js +321 -66
- package/lib/session/templates.js +1 -1
- package/lib/session/terminal.js +94 -12
- package/lib/session/unit.js +35 -30
- package/lib/session/update.js +194 -6
- package/lib/session/view.js +72 -59
- package/lib/session/workspace.js +416 -0
- package/lib/{capabilities.js → source/capabilities.js} +3 -12
- package/lib/{github.js → source/github.js} +102 -32
- package/lib/{gitlab.js → source/gitlab.js} +87 -10
- package/lib/{remote.js → source/remote.js} +144 -40
- package/lib/source/review-threads.graphql +20 -0
- package/lib/source/source.js +74 -0
- package/lib/term/ansi.js +396 -0
- package/lib/{clipboard.js → term/clipboard.js} +3 -6
- package/lib/{select.js → term/select.js} +2 -2
- package/lib/term/themes/dark.json +122 -0
- package/lib/term/themes/light.json +122 -0
- package/lib/term/wide.txt +21 -0
- package/lib/{wrap.js → term/wrap.js} +4 -4
- package/package.json +2 -2
- package/lib/ansi.js +0 -505
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -437
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -628
- package/lib/render/dash-blocks.js +0 -245
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/review.js +0 -744
- package/lib/session/accessors.js +0 -26
- package/lib/session/edit-click.js +0 -57
- package/lib/session/npm.js +0 -452
- package/lib/session/progress.js +0 -41
- package/lib/source.js +0 -36
- package/lib/update.js +0 -192
- /package/lib/{git-reword-todo.js → git/reword-todo.js} +0 -0
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const files = require('../files.js');
|
|
4
|
-
const { shortAge } = files;
|
|
5
|
-
const tiles = require('./tiles.js');
|
|
6
|
-
const { seg, barSegments, sparkline, spinner } = tiles;
|
|
7
|
-
const table = require('./dash-table.js');
|
|
8
|
-
const { num, size, delta, waiting, cell, cellSegs, flexCell } = table;
|
|
9
|
-
const { tableLines, pickGroups, labelOf, stat, pairRows } = table;
|
|
10
|
-
const { titleAside, captionOver } = table;
|
|
11
|
-
|
|
12
|
-
const BAR_W = 6;
|
|
13
|
-
const FOLDER = '📁';
|
|
14
|
-
const MARK_GAP = 1;
|
|
15
|
-
const TREND_LABEL = 'trend ';
|
|
16
|
-
const UNKNOWN = '…';
|
|
17
|
-
|
|
18
|
-
const share = (value, total) => (total > 0 ? value / total : 0);
|
|
19
|
-
|
|
20
|
-
const markCell = (isDir) => cell(isDir ? FOLDER : '');
|
|
21
|
-
|
|
22
|
-
const nameCell = (key, isDir, hot = false) => {
|
|
23
|
-
const name = cell(labelOf(key, isDir), hot ? 'warn' : 'sha', 'l', hot);
|
|
24
|
-
name.gap = MARK_GAP;
|
|
25
|
-
return name;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const fileName = (key, isDir, hot) => {
|
|
29
|
-
const name = nameCell(key, isDir, hot);
|
|
30
|
-
name.flex = true;
|
|
31
|
-
name.keep = true;
|
|
32
|
-
return name;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const fileRow = (group, isDir, data) => {
|
|
36
|
-
const hot = (isDir ? data.hot.dirs : data.hot.exts).has(group.key);
|
|
37
|
-
const ratio = share(group.bytes, data.total.bytes);
|
|
38
|
-
return [
|
|
39
|
-
markCell(isDir),
|
|
40
|
-
fileName(group.key, isDir, hot),
|
|
41
|
-
cell(`${group.files}`, 'muted', 'r'),
|
|
42
|
-
cell(size(group.bytes), 'text', 'r'),
|
|
43
|
-
cell(num(group.lines), 'muted', 'r'),
|
|
44
|
-
cellSegs(barSegments(ratio, BAR_W, 'sha')),
|
|
45
|
-
];
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const filesTotal = (data, ctx) => {
|
|
49
|
-
const { total } = data;
|
|
50
|
-
const name = cell('');
|
|
51
|
-
name.flex = true;
|
|
52
|
-
name.gap = MARK_GAP;
|
|
53
|
-
const row = [
|
|
54
|
-
cell(''),
|
|
55
|
-
name,
|
|
56
|
-
cell(`${total.files}`, 'text', 'r', true),
|
|
57
|
-
cell(size(total.bytes), 'text', 'r', true),
|
|
58
|
-
cell(num(total.lines), 'text', 'r', true),
|
|
59
|
-
cell(''),
|
|
60
|
-
];
|
|
61
|
-
const moved = data.delta ? data.delta.lines : 0;
|
|
62
|
-
const change = delta(moved, ctx.now, data.delta?.at);
|
|
63
|
-
if (change) row.push(cellSegs([change]));
|
|
64
|
-
return row;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const filesBlock = (model, width, height, ctx, tile) => {
|
|
68
|
-
const data = model.files;
|
|
69
|
-
if (!data.ready) return waiting('scanning…');
|
|
70
|
-
const picked = pickGroups(data.dirs, data.exts, height - 1);
|
|
71
|
-
const labels = [
|
|
72
|
-
cell(''),
|
|
73
|
-
cell(''),
|
|
74
|
-
cell('files', 'muted', 'r'),
|
|
75
|
-
cell('size', 'muted', 'r'),
|
|
76
|
-
cell('lines', 'muted', 'r'),
|
|
77
|
-
cell(''),
|
|
78
|
-
];
|
|
79
|
-
const rows = [labels];
|
|
80
|
-
for (const group of picked.dirs) rows.push(fileRow(group, true, data));
|
|
81
|
-
for (const group of picked.exts) rows.push(fileRow(group, false, data));
|
|
82
|
-
rows.push(filesTotal(data, ctx));
|
|
83
|
-
const lines = tableLines(rows, width);
|
|
84
|
-
return {
|
|
85
|
-
titleLine: captionOver(tile, lines[0]),
|
|
86
|
-
lines: lines.slice(1, -1),
|
|
87
|
-
footer: lines.at(-1),
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const ratio = (sign, part, total) => `${sign}${part}/${total}`;
|
|
92
|
-
|
|
93
|
-
const changeCells = (group, bold = false) => [
|
|
94
|
-
cell(ratio('+', group.stagedAdded, group.added), 'add', 'r', bold),
|
|
95
|
-
cell(ratio('-', group.stagedRemoved, group.removed), 'del', 'r', bold),
|
|
96
|
-
cell(`${group.staged}/${group.remaining}`, 'text', 'r', bold),
|
|
97
|
-
cell(shortAge(group.date), 'muted', 'r'),
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
const diffRow = (group, isDir) => [
|
|
101
|
-
markCell(isDir),
|
|
102
|
-
nameCell(group.key, isDir),
|
|
103
|
-
...changeCells(group),
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
const diffsHeader = (data, ctx) => {
|
|
107
|
-
const name = cell('');
|
|
108
|
-
name.gap = MARK_GAP;
|
|
109
|
-
const row = [cell(''), name, ...changeCells(data.totals, true)];
|
|
110
|
-
const moved = data.delta ? data.delta.added + data.delta.removed : 0;
|
|
111
|
-
const change = delta(moved, ctx.now, data.delta?.at);
|
|
112
|
-
if (change) row[row.length - 1] = cellSegs([change], 'r');
|
|
113
|
-
return row;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const trendFooter = (data, width) => {
|
|
117
|
-
const room = width - TREND_LABEL.length;
|
|
118
|
-
if (data.samples.length < 2 || room < 2) return null;
|
|
119
|
-
const trend = sparkline(data.samples, room);
|
|
120
|
-
return [seg(TREND_LABEL, 'muted'), seg(trend, 'trend')];
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const diffsBlock = (model, width, height, ctx, tile) => {
|
|
124
|
-
const data = model.diffs;
|
|
125
|
-
if (!data.files) {
|
|
126
|
-
const rows = pairRows([stat('changes', 'working tree clean', 'muted')], 1);
|
|
127
|
-
return { badge: [], lines: tableLines(rows, width) };
|
|
128
|
-
}
|
|
129
|
-
const footer = trendFooter(data, width);
|
|
130
|
-
const room = footer ? height - 1 : height;
|
|
131
|
-
const picked = pickGroups(data.dirs, data.exts, room);
|
|
132
|
-
const rows = [diffsHeader(data, ctx)];
|
|
133
|
-
for (const group of picked.dirs) rows.push(diffRow(group, true));
|
|
134
|
-
for (const group of picked.exts) rows.push(diffRow(group, false));
|
|
135
|
-
const lines = tableLines(rows, width, 2, true);
|
|
136
|
-
return {
|
|
137
|
-
titleLine: captionOver(tile, lines[0]),
|
|
138
|
-
lines: lines.slice(1),
|
|
139
|
-
footer,
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const countSegs = (label, value) => [
|
|
144
|
-
seg(`${label}: `, 'muted'),
|
|
145
|
-
seg(`${value}`, 'text'),
|
|
146
|
-
];
|
|
147
|
-
|
|
148
|
-
const markSegs = (value, tone, mark) => {
|
|
149
|
-
if (!value) return [];
|
|
150
|
-
return [seg(' '), seg(mark), seg(`${value}`, tone, true)];
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const npmAside = (data) => {
|
|
154
|
-
const modules = data.modules;
|
|
155
|
-
return [
|
|
156
|
-
...countSegs('deps', data.deps),
|
|
157
|
-
seg(' '),
|
|
158
|
-
...countSegs('dev', data.dev),
|
|
159
|
-
seg(' '),
|
|
160
|
-
...countSegs('all', modules.count),
|
|
161
|
-
seg(' (', 'muted'),
|
|
162
|
-
seg(size(modules.bytes), 'text'),
|
|
163
|
-
seg(')', 'muted'),
|
|
164
|
-
...markSegs(data.audit, 'error', '🚨 '),
|
|
165
|
-
...markSegs(data.outdated, 'warn', '⚠️ '),
|
|
166
|
-
];
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const differs = (left, right) =>
|
|
170
|
-
left !== UNKNOWN && right !== UNKNOWN && left !== right;
|
|
171
|
-
|
|
172
|
-
const versionCell = (text, changed, audited) => {
|
|
173
|
-
const base = changed ? 'warn' : 'muted';
|
|
174
|
-
const tone = audited && text !== UNKNOWN ? 'error' : base;
|
|
175
|
-
return cell(text, tone, 'r');
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const packageHead = () => {
|
|
179
|
-
const title = flexCell('');
|
|
180
|
-
title.keep = true;
|
|
181
|
-
return [
|
|
182
|
-
title,
|
|
183
|
-
cell('current', 'muted', 'r'),
|
|
184
|
-
cell('wanted', 'muted', 'r'),
|
|
185
|
-
cell('latest', 'muted', 'r'),
|
|
186
|
-
cell('size', 'muted', 'r'),
|
|
187
|
-
];
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const packageRow = (pkg) => {
|
|
191
|
-
const name = flexCell(pkg.name, pkg.dev ? 'sha' : 'add');
|
|
192
|
-
name.keep = true;
|
|
193
|
-
const current = pkg.current || UNKNOWN;
|
|
194
|
-
const wanted = pkg.wanted || UNKNOWN;
|
|
195
|
-
const latest = pkg.latest || UNKNOWN;
|
|
196
|
-
return [
|
|
197
|
-
name,
|
|
198
|
-
versionCell(current, differs(current, wanted), pkg.audit),
|
|
199
|
-
versionCell(wanted, differs(wanted, current), pkg.audit),
|
|
200
|
-
versionCell(latest, differs(latest, wanted), pkg.audit),
|
|
201
|
-
cell(size(pkg.bytes), 'muted', 'r'),
|
|
202
|
-
];
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const npmBlock = (model, width, height, ctx, tile) => {
|
|
206
|
-
const data = model.npm;
|
|
207
|
-
if (!data.ready) return waiting('reading package.json…');
|
|
208
|
-
if (!data.hasManifest) return waiting('no package.json');
|
|
209
|
-
const badge = data.running ? [seg(spinner(ctx.frame), 'warn', true)] : [];
|
|
210
|
-
const titleLine = titleAside(tile, npmAside(data), width, badge);
|
|
211
|
-
const packages = data.modules.packages;
|
|
212
|
-
const headed = packages.length > 0 && height > 1;
|
|
213
|
-
const shown = packages.slice(0, Math.max(0, height - (headed ? 1 : 0)));
|
|
214
|
-
const rows = shown.map(packageRow);
|
|
215
|
-
if (headed) rows.unshift(packageHead());
|
|
216
|
-
return { titleLine, lines: tableLines(rows, width) };
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const taskName = (title) => {
|
|
220
|
-
const name = flexCell(title, 'text');
|
|
221
|
-
name.keep = true;
|
|
222
|
-
return name;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const taskLine = (title, done, total, bold = false) => [
|
|
226
|
-
taskName(title),
|
|
227
|
-
cell(`${done}/${total}`, bold ? 'text' : 'muted', 'r', bold),
|
|
228
|
-
cellSegs(barSegments(share(done, total), BAR_W)),
|
|
229
|
-
];
|
|
230
|
-
|
|
231
|
-
const tasksBlock = (model, width, height, ctx, tile) => {
|
|
232
|
-
const data = model.tasks;
|
|
233
|
-
const rows = [taskLine('', data.done, data.total, true)];
|
|
234
|
-
for (const kind of data.kinds) {
|
|
235
|
-
rows.push(taskLine(kind.title, kind.done, kind.total));
|
|
236
|
-
}
|
|
237
|
-
const lines = tableLines(rows, width);
|
|
238
|
-
const shown = Math.max(0, height);
|
|
239
|
-
return {
|
|
240
|
-
titleLine: captionOver(tile, lines[0]),
|
|
241
|
-
lines: lines.slice(1, 1 + shown),
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
module.exports = { filesBlock, diffsBlock, npmBlock, tasksBlock };
|
package/lib/render/present.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const ansi = require('../ansi.js');
|
|
4
|
-
const { ESC } = ansi;
|
|
5
|
-
|
|
6
|
-
const presentCursor = (cursor) => {
|
|
7
|
-
if (!cursor || cursor.x <= 0 || cursor.y <= 0) return `${ESC}[?25l`;
|
|
8
|
-
const pos = `${ESC}[${cursor.y};${cursor.x}H`;
|
|
9
|
-
return `${pos}${ESC}[1 q${ESC}[?12h${ESC}[?25h`;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const presentRows = (rows, options = {}) => {
|
|
13
|
-
let out = `${ESC}[?25l${ESC}[?2026h`;
|
|
14
|
-
if (options.clear === true) out += `${ESC}[H${ESC}[2J`;
|
|
15
|
-
for (let i = 0; i < rows.length; i++) out += `${ESC}[${i + 1};1H${rows[i]}`;
|
|
16
|
-
return `${out}${ESC}[?2026l${presentCursor(options.cursor)}`;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
module.exports = { presentCursor, presentRows };
|
package/lib/render/report.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
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 };
|