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.
Files changed (105) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/LICENSE +1 -1
  3. package/README.md +11 -11
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -8
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +39 -47
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +197 -402
  14. package/lib/deps.js +113 -240
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +76 -144
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +79 -178
  25. package/lib/editor.js +52 -69
  26. package/lib/files.js +71 -89
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +147 -272
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +155 -141
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +14 -14
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +19 -25
  44. package/lib/highlight/txt.js +7 -10
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +49 -82
  47. package/lib/manifest.js +67 -126
  48. package/lib/npm-commands.js +120 -169
  49. package/lib/remote.js +140 -190
  50. package/lib/render/branches.js +63 -61
  51. package/lib/render/chrome.js +220 -333
  52. package/lib/render/commits.js +160 -361
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -258
  58. package/lib/render/files.js +40 -85
  59. package/lib/render/frame.js +78 -117
  60. package/lib/render/notes.js +139 -210
  61. package/lib/render/npm.js +213 -177
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +72 -174
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -31
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -37
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -77
  72. package/lib/report-test.js +221 -99
  73. package/lib/report-tools.js +96 -154
  74. package/lib/review-merge.js +33 -41
  75. package/lib/review.js +68 -129
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +53 -91
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +61 -43
  80. package/lib/session/branches.js +166 -222
  81. package/lib/session/change-actions.js +49 -119
  82. package/lib/session/commit.js +274 -355
  83. package/lib/session/compose.js +556 -714
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +162 -170
  86. package/lib/session/files-pane.js +76 -44
  87. package/lib/session/items.js +6 -17
  88. package/lib/session/lifecycle.js +393 -466
  89. package/lib/session/load.js +1 -14
  90. package/lib/session/navigation.js +2 -2
  91. package/lib/session/npm.js +403 -420
  92. package/lib/session/ops.js +5 -13
  93. package/lib/session/pointer.js +16 -14
  94. package/lib/session/progress.js +39 -30
  95. package/lib/session/review.js +1 -3
  96. package/lib/session/tasks.js +276 -235
  97. package/lib/session/templates.js +51 -59
  98. package/lib/session/terminal.js +85 -132
  99. package/lib/session/view.js +47 -81
  100. package/lib/session/watch.js +196 -212
  101. package/lib/session.js +81 -161
  102. package/lib/update.js +44 -111
  103. package/lib/utilities.js +46 -88
  104. package/lib/wrap.js +29 -55
  105. package/package.json +1 -1
package/lib/report-run.js CHANGED
@@ -7,20 +7,16 @@ const { spawn } = childProcess;
7
7
  const utilities = require('./utilities.js');
8
8
  const { spawnBase } = utilities;
9
9
  const npmCommands = require('./npm-commands.js');
10
- const { writeLog } = npmCommands;
10
+ const { nextLogFile, saveLogs } = npmCommands;
11
11
  const reportParse = require('./report-parse.js');
12
12
  const { toolHint, buildDocument } = reportParse;
13
13
  const reportRender = require('./report-render.js');
14
14
  const { renderDocument } = reportRender;
15
+ const runs = require('./runs.js');
16
+ const { RunRecorder, commandLabel, summarizeDocument } = runs;
15
17
 
16
- const OUTPUTS = new Set(['md', 'raw']);
17
-
18
- const outputMode = (env) => {
19
- const value = env.RESLOP_OUTPUT;
20
- if (value) return OUTPUTS.has(value) ? value : '';
21
- return 'md';
22
- };
23
-
18
+ const OUTPUTS = ['md', 'raw'];
19
+ const PIPE = ['ignore', 'pipe', 'pipe'];
24
20
  const CMD_SAFE = /^[\w./:=@+-]+$/;
25
21
 
26
22
  const quoteCmdArg = (arg) => {
@@ -35,34 +31,18 @@ const winCommand = (program, args) => {
35
31
  return `"${parts.join(' ')}"`;
36
32
  };
37
33
 
38
- const spawnCommand = (program, args, options) => {
39
- const { cwd, env, stdio } = options;
40
- const base = { cwd, env, stdio };
34
+ const spawnCommand = (command, options) => {
35
+ const { program, args } = command;
41
36
  if (process.platform !== 'win32') {
42
- return spawn(program, args, spawnBase(base));
37
+ return spawn(program, args, spawnBase(options));
43
38
  }
44
- const command = winCommand(program, args);
45
39
  const shell = process.env.comspec || 'cmd.exe';
46
- return spawn(
47
- shell,
48
- ['/d', '/s', '/c', command],
49
- spawnBase({ ...base, windowsVerbatimArguments: true }),
50
- );
40
+ const line = winCommand(program, args);
41
+ const opts = spawnBase({ ...options, windowsVerbatimArguments: true });
42
+ return spawn(shell, ['/d', '/s', '/c', line], opts);
51
43
  };
52
44
 
53
- const waitStatus = (child) =>
54
- new Promise((resolve) => {
55
- let settled = false;
56
- const finish = (status) => {
57
- if (settled) return;
58
- settled = true;
59
- resolve(status);
60
- };
61
- child.on('error', () => finish(1));
62
- child.on('close', (status) => finish(status === null ? 1 : status));
63
- });
64
-
65
- const collect = (child) =>
45
+ const collect = (child, onOut, onErr) =>
66
46
  new Promise((resolve) => {
67
47
  let out = '';
68
48
  let err = '';
@@ -76,89 +56,119 @@ const collect = (child) =>
76
56
  child.stdout.setEncoding('utf8');
77
57
  child.stdout.on('data', (chunk) => {
78
58
  out += chunk;
59
+ if (onOut) onOut(chunk);
79
60
  });
80
61
  }
81
62
  if (child.stderr) {
82
63
  child.stderr.setEncoding('utf8');
83
64
  child.stderr.on('data', (chunk) => {
84
65
  err += chunk;
66
+ if (onErr) onErr(chunk);
85
67
  });
86
68
  }
87
69
  child.on('error', (error) => {
88
70
  err += `${error.message}\n`;
89
71
  finish(1);
90
72
  });
91
- child.on('close', (status) => finish(status === null ? 1 : status));
73
+ child.on('close', (status) => finish(status ?? 1));
92
74
  });
93
75
 
94
- const commandArgs = (argv) => {
95
- if (argv[0] !== 't' || argv[1] !== '--' || !argv[2]) return null;
96
- return { program: argv[2], args: argv.slice(3) };
76
+ const beginRun = (cwd, command) =>
77
+ new RunRecorder(cwd, commandLabel(command.program, command.args));
78
+
79
+ const documentOf = (command, result, cwd) => {
80
+ const hint = toolHint(command.program, command.args);
81
+ const { stdout, stderr, status } = result;
82
+ return buildDocument(stdout, stderr, cwd, status, hint);
97
83
  };
98
84
 
99
- const usage = (stderr) => {
100
- stderr.write('reslop: missing command\n');
101
- stderr.write('Usage: reslop t -- <program> [args]\n');
102
- return 1;
85
+ const rawStreams = (stdout, stderr) => {
86
+ if (!stderr.trim()) return stdout;
87
+ const lead = stdout.endsWith('\n') || !stdout ? stdout : `${stdout}\n`;
88
+ return `${lead}# stderr\n${stderr}`;
103
89
  };
104
90
 
105
- const runInherit = async (spawnFn, program, args, options) => {
106
- let child;
91
+ const runInherit = async (command, cwd, env) => {
107
92
  try {
108
- child = spawnFn(program, args, { ...options, stdio: 'inherit' });
93
+ const child = spawnCommand(command, { cwd, env, stdio: 'inherit' });
94
+ return (await collect(child)).status;
109
95
  } catch {
110
96
  return 1;
111
97
  }
112
- return waitStatus(child);
113
98
  };
114
99
 
115
- const runCapture = async (proc, deps = {}) => {
116
- const env = proc.env || {};
117
- const argv = proc.argv.slice(2);
118
- const command = commandArgs(argv);
119
- if (!command) return usage(proc.stderr);
120
- const mode = outputMode(env);
121
- if (!mode) {
122
- proc.stderr.write(`reslop: unknown RESLOP_OUTPUT ${env.RESLOP_OUTPUT}\n`);
100
+ const runRaw = async (proc, command, cwd, env) => {
101
+ const recorder = beginRun(cwd, command);
102
+ let child;
103
+ try {
104
+ child = spawnCommand(command, { cwd, env, stdio: PIPE });
105
+ } catch {
106
+ recorder.finish(1);
123
107
  return 1;
124
108
  }
125
- const cwd = deps.cwd ? deps.cwd : proc.cwd();
126
- const spawnFn = deps.spawn || spawnCommand;
127
- const capture = env.RESLOP_CAPTURE === '1';
128
- if (mode === 'raw' || capture) {
129
- return runInherit(spawnFn, command.program, command.args, { cwd, env });
130
- }
131
- const childEnv = { ...env, RESLOP_CAPTURE: '1' };
109
+ const onOut = (chunk) => {
110
+ proc.stdout.write(chunk);
111
+ recorder.feed(chunk);
112
+ };
113
+ const onErr = (chunk) => proc.stderr.write(chunk);
114
+ const result = await collect(child, onOut, onErr);
115
+ const doc = documentOf(command, result, cwd);
116
+ recorder.finish(result.status, summarizeDocument(doc));
117
+ return result.status;
118
+ };
119
+
120
+ const runReport = async (proc, command, cwd, env) => {
121
+ const recorder = beginRun(cwd, command);
122
+ const fail = (error) => proc.stderr.write(`reslop: ${error.message}\n`);
132
123
  let child;
133
124
  try {
134
- child = spawnFn(command.program, command.args, {
135
- cwd,
136
- env: childEnv,
137
- stdio: ['ignore', 'pipe', 'pipe'],
138
- });
125
+ const childEnv = { ...env, RESLOP_CAPTURE: '1' };
126
+ child = spawnCommand(command, { cwd, env: childEnv, stdio: PIPE });
139
127
  } catch (error) {
140
- proc.stderr.write(`reslop: ${error.message}\n`);
128
+ fail(error);
129
+ recorder.finish(1);
141
130
  return 1;
142
131
  }
143
- const result = await collect(child);
144
- const hint = toolHint(command.program, command.args);
145
- const doc = buildDocument(
146
- result.stdout,
147
- result.stderr,
148
- cwd,
149
- result.status,
150
- hint,
151
- );
152
- const text = renderDocument(doc);
132
+ const result = await collect(child, (chunk) => recorder.feed(chunk));
133
+ const doc = documentOf(command, result, cwd);
134
+ let slot = null;
135
+ try {
136
+ slot = nextLogFile(cwd, path.basename(command.program));
137
+ } catch (error) {
138
+ fail(error);
139
+ }
140
+ const text = renderDocument(doc, slot ? slot.rawName : '');
141
+ recorder.finish(result.status, summarizeDocument(doc));
153
142
  proc.stdout.write(text);
143
+ if (!slot) return result.status;
154
144
  try {
155
- writeLog(cwd, path.basename(command.program), text);
145
+ await saveLogs(slot, text, rawStreams(result.stdout, result.stderr));
156
146
  } catch (error) {
157
- proc.stderr.write(`reslop: ${error.message}\n`);
147
+ fail(error);
158
148
  }
159
149
  return result.status;
160
150
  };
161
151
 
152
+ const runCapture = async (proc, deps = {}) => {
153
+ const argv = proc.argv.slice(2);
154
+ if (argv[1] !== '--' || !argv[2]) {
155
+ proc.stderr.write('reslop: missing command\n');
156
+ proc.stderr.write('Usage: reslop t -- <program> [args]\n');
157
+ return 1;
158
+ }
159
+ const command = { program: argv[2], args: argv.slice(3) };
160
+ const env = proc.env ?? {};
161
+ const mode = env.RESLOP_OUTPUT || 'md';
162
+ if (!OUTPUTS.includes(mode)) {
163
+ proc.stderr.write(`reslop: unknown RESLOP_OUTPUT ${env.RESLOP_OUTPUT}\n`);
164
+ return 1;
165
+ }
166
+ const cwd = deps.cwd ?? proc.cwd();
167
+ if (env.RESLOP_CAPTURE === '1') return runInherit(command, cwd, env);
168
+ if (mode === 'raw') return runRaw(proc, command, cwd, env);
169
+ return runReport(proc, command, cwd, env);
170
+ };
171
+
162
172
  module.exports = {
163
173
  winCommand,
164
174
  runCapture,