@atlaspack/reporter-cli 2.12.1-canary.3354
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/LICENSE +201 -0
- package/lib/CLIReporter.js +7750 -0
- package/lib/CLIReporter.js.map +1 -0
- package/package.json +45 -0
- package/src/CLIReporter.js +298 -0
- package/src/bundleReport.js +99 -0
- package/src/emoji.js +29 -0
- package/src/logLevels.js +13 -0
- package/src/phaseReport.js +33 -0
- package/src/render.js +149 -0
- package/src/utils.js +48 -0
- package/test/CLIReporter.test.js +257 -0
package/src/utils.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import stringWidth from 'string-width';
|
|
5
|
+
import termSize from 'term-size';
|
|
6
|
+
import {stripAnsi} from '@atlaspack/utils';
|
|
7
|
+
|
|
8
|
+
export type PadAlign = 'left' | 'right';
|
|
9
|
+
let terminalSize = termSize();
|
|
10
|
+
process.stdout.on('resize', function () {
|
|
11
|
+
terminalSize = termSize();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export function getTerminalWidth(): any {
|
|
15
|
+
return terminalSize;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Pad a string with spaces on either side
|
|
19
|
+
export function pad(
|
|
20
|
+
text: string,
|
|
21
|
+
length: number,
|
|
22
|
+
align: PadAlign = 'left',
|
|
23
|
+
): string {
|
|
24
|
+
let pad = ' '.repeat(length - stringWidth(text));
|
|
25
|
+
if (align === 'right') {
|
|
26
|
+
return pad + text;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return text + pad;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatFilename(
|
|
33
|
+
filename: string,
|
|
34
|
+
color: (s: string) => string = chalk.reset,
|
|
35
|
+
): string {
|
|
36
|
+
let dir = path.relative(process.cwd(), path.dirname(filename));
|
|
37
|
+
return (
|
|
38
|
+
chalk.dim(dir + (dir ? path.sep : '')) + color(path.basename(filename))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function countLines(message: string): number {
|
|
43
|
+
let {columns} = terminalSize;
|
|
44
|
+
|
|
45
|
+
return stripAnsi(message)
|
|
46
|
+
.split('\n')
|
|
47
|
+
.reduce((p, line) => p + Math.ceil((stringWidth(line) || 1) / columns), 0);
|
|
48
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import assert from 'assert';
|
|
4
|
+
import sinon from 'sinon';
|
|
5
|
+
import {PassThrough} from 'stream';
|
|
6
|
+
import {_report} from '../src/CLIReporter';
|
|
7
|
+
import * as render from '../src/render';
|
|
8
|
+
import {_setStdio} from '../src/render';
|
|
9
|
+
import {inputFS, outputFS} from '@atlaspack/test-utils';
|
|
10
|
+
import {NodePackageManager} from '@atlaspack/package-manager';
|
|
11
|
+
import stripAnsi from 'strip-ansi';
|
|
12
|
+
import * as bundleReport from '../src/bundleReport';
|
|
13
|
+
import {DEFAULT_FEATURE_FLAGS} from '@atlaspack/feature-flags';
|
|
14
|
+
|
|
15
|
+
const EMPTY_OPTIONS = {
|
|
16
|
+
cacheDir: '.atlaspack-cache',
|
|
17
|
+
atlaspackVersion: '',
|
|
18
|
+
entries: [],
|
|
19
|
+
logLevel: 'info',
|
|
20
|
+
targets: [],
|
|
21
|
+
projectRoot: '',
|
|
22
|
+
distDir: 'dist',
|
|
23
|
+
lockFile: undefined,
|
|
24
|
+
shouldAutoInstall: false,
|
|
25
|
+
shouldBuildLazily: false,
|
|
26
|
+
hmrOptions: undefined,
|
|
27
|
+
serveOptions: false,
|
|
28
|
+
mode: 'development',
|
|
29
|
+
shouldScopeHoist: false,
|
|
30
|
+
shouldOptimize: false,
|
|
31
|
+
env: {},
|
|
32
|
+
shouldDisableCache: false,
|
|
33
|
+
sourceMaps: false,
|
|
34
|
+
inputFS,
|
|
35
|
+
outputFS,
|
|
36
|
+
instanceId: 'test',
|
|
37
|
+
packageManager: new NodePackageManager(inputFS, '/'),
|
|
38
|
+
detailedReport: {
|
|
39
|
+
assetsPerBundle: 10,
|
|
40
|
+
},
|
|
41
|
+
featureFlags: DEFAULT_FEATURE_FLAGS,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('CLIReporter', () => {
|
|
45
|
+
let originalStdout;
|
|
46
|
+
let originalStderr;
|
|
47
|
+
let stdoutOutput;
|
|
48
|
+
let stderrOutput;
|
|
49
|
+
|
|
50
|
+
beforeEach(async () => {
|
|
51
|
+
// Stub these out to avoid writing noise to real stdio and to read from these
|
|
52
|
+
// otherwise only writable streams
|
|
53
|
+
originalStdout = process.stdout;
|
|
54
|
+
originalStderr = process.stderr;
|
|
55
|
+
|
|
56
|
+
stdoutOutput = '';
|
|
57
|
+
stderrOutput = '';
|
|
58
|
+
|
|
59
|
+
let mockStdout = new PassThrough();
|
|
60
|
+
mockStdout.on('data', d => (stdoutOutput += stripAnsi(d.toString())));
|
|
61
|
+
let mockStderr = new PassThrough();
|
|
62
|
+
mockStderr.on('data', d => (stderrOutput += stripAnsi(d.toString())));
|
|
63
|
+
_setStdio(mockStdout, mockStderr);
|
|
64
|
+
|
|
65
|
+
await _report(
|
|
66
|
+
{
|
|
67
|
+
type: 'buildStart',
|
|
68
|
+
},
|
|
69
|
+
EMPTY_OPTIONS,
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
_setStdio(originalStdout, originalStderr);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('writes log, info, success, and verbose log messages to stdout', async () => {
|
|
78
|
+
let options = {
|
|
79
|
+
...EMPTY_OPTIONS,
|
|
80
|
+
logLevel: 'verbose',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
await _report(
|
|
84
|
+
{
|
|
85
|
+
type: 'log',
|
|
86
|
+
level: 'info',
|
|
87
|
+
diagnostics: [
|
|
88
|
+
{
|
|
89
|
+
origin: 'test',
|
|
90
|
+
message: 'info',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
options,
|
|
95
|
+
);
|
|
96
|
+
await _report({type: 'log', level: 'success', message: 'success'}, options);
|
|
97
|
+
await _report(
|
|
98
|
+
{
|
|
99
|
+
type: 'log',
|
|
100
|
+
level: 'verbose',
|
|
101
|
+
diagnostics: [
|
|
102
|
+
{
|
|
103
|
+
origin: 'test',
|
|
104
|
+
message: 'verbose',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
options,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
assert.equal(stdoutOutput, 'test: info\nsuccess\ntest: verbose\n');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('writes errors and warnings to stderr', async () => {
|
|
115
|
+
await _report(
|
|
116
|
+
{
|
|
117
|
+
type: 'log',
|
|
118
|
+
level: 'error',
|
|
119
|
+
diagnostics: [
|
|
120
|
+
{
|
|
121
|
+
origin: 'test',
|
|
122
|
+
message: 'error',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
EMPTY_OPTIONS,
|
|
127
|
+
);
|
|
128
|
+
await _report(
|
|
129
|
+
{
|
|
130
|
+
type: 'log',
|
|
131
|
+
level: 'warn',
|
|
132
|
+
diagnostics: [
|
|
133
|
+
{
|
|
134
|
+
origin: 'test',
|
|
135
|
+
message: 'warn',
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
EMPTY_OPTIONS,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
assert.equal(stdoutOutput, '\n\n');
|
|
143
|
+
assert.equal(stderrOutput, 'test: error\ntest: warn\n');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('prints errors nicely', async () => {
|
|
147
|
+
await _report(
|
|
148
|
+
{
|
|
149
|
+
type: 'log',
|
|
150
|
+
level: 'error',
|
|
151
|
+
diagnostics: [
|
|
152
|
+
{
|
|
153
|
+
origin: 'test',
|
|
154
|
+
message: 'error',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
EMPTY_OPTIONS,
|
|
159
|
+
);
|
|
160
|
+
await _report(
|
|
161
|
+
{
|
|
162
|
+
type: 'log',
|
|
163
|
+
level: 'warn',
|
|
164
|
+
diagnostics: [
|
|
165
|
+
{
|
|
166
|
+
origin: 'test',
|
|
167
|
+
message: 'warn',
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
EMPTY_OPTIONS,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
assert.equal(stdoutOutput, '\n\n');
|
|
175
|
+
assert(stderrOutput.includes('test: error\n'));
|
|
176
|
+
assert(stderrOutput.includes('test: warn\n'));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('writes buildProgress messages to stdout on the default loglevel', async () => {
|
|
180
|
+
await _report({type: 'buildProgress', phase: 'bundling'}, EMPTY_OPTIONS);
|
|
181
|
+
assert.equal(stdoutOutput, 'Bundling...\n');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('writes buildSuccess messages to stdout on the default loglevel', async () => {
|
|
185
|
+
await _report({type: 'buildProgress', phase: 'bundling'}, EMPTY_OPTIONS);
|
|
186
|
+
assert.equal(stdoutOutput, 'Bundling...\n');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('writes phase timings to stdout when ATLASPACK_SHOW_PHASE_TIMES is set', async () => {
|
|
190
|
+
let oldPhaseTimings = process.env['ATLASPACK_SHOW_PHASE_TIMES'];
|
|
191
|
+
const bundleReportStub = sinon.stub(bundleReport, 'default');
|
|
192
|
+
const persistSpinnerStub = sinon.stub(render, 'persistSpinner');
|
|
193
|
+
|
|
194
|
+
after(() => {
|
|
195
|
+
bundleReportStub.restore();
|
|
196
|
+
persistSpinnerStub.restore();
|
|
197
|
+
process.env['ATLASPACK_SHOW_PHASE_TIMES'] = oldPhaseTimings;
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// emit a buildSuccess event to reset the timings and seen phases
|
|
201
|
+
// from the previous test
|
|
202
|
+
process.env['ATLASPACK_SHOW_PHASE_TIMES'] = undefined;
|
|
203
|
+
// $FlowFixMe
|
|
204
|
+
await _report({type: 'buildSuccess'}, EMPTY_OPTIONS);
|
|
205
|
+
|
|
206
|
+
process.env['ATLASPACK_SHOW_PHASE_TIMES'] = 'true';
|
|
207
|
+
await _report(
|
|
208
|
+
{type: 'buildProgress', phase: 'transforming', filePath: 'foo.js'},
|
|
209
|
+
EMPTY_OPTIONS,
|
|
210
|
+
);
|
|
211
|
+
await _report({type: 'buildProgress', phase: 'bundling'}, EMPTY_OPTIONS);
|
|
212
|
+
await _report(
|
|
213
|
+
// $FlowFixMe
|
|
214
|
+
{
|
|
215
|
+
type: 'buildProgress',
|
|
216
|
+
phase: 'packaging',
|
|
217
|
+
bundle: {
|
|
218
|
+
displayName: 'test',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
EMPTY_OPTIONS,
|
|
222
|
+
);
|
|
223
|
+
// $FlowFixMe
|
|
224
|
+
await _report({type: 'buildSuccess'}, EMPTY_OPTIONS);
|
|
225
|
+
const expected =
|
|
226
|
+
/Building...\nBundling...\nPackaging & Optimizing...\nTransforming finished in [0-9]ms\nBundling finished in [0-9]ms\nPackaging & Optimizing finished in [0-9]ms/;
|
|
227
|
+
|
|
228
|
+
assert.equal(expected.test(stdoutOutput), true);
|
|
229
|
+
|
|
230
|
+
stdoutOutput = '';
|
|
231
|
+
|
|
232
|
+
await _report(
|
|
233
|
+
{type: 'buildProgress', phase: 'transforming', filePath: 'foo.js'},
|
|
234
|
+
EMPTY_OPTIONS,
|
|
235
|
+
);
|
|
236
|
+
await _report({type: 'buildProgress', phase: 'bundling'}, EMPTY_OPTIONS);
|
|
237
|
+
await _report(
|
|
238
|
+
// $FlowFixMe
|
|
239
|
+
{
|
|
240
|
+
type: 'buildProgress',
|
|
241
|
+
phase: 'packaging',
|
|
242
|
+
bundle: {
|
|
243
|
+
displayName: 'test',
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
EMPTY_OPTIONS,
|
|
247
|
+
);
|
|
248
|
+
// $FlowFixMe
|
|
249
|
+
await _report({type: 'buildSuccess'}, EMPTY_OPTIONS);
|
|
250
|
+
|
|
251
|
+
assert.equal(
|
|
252
|
+
expected.test(stdoutOutput),
|
|
253
|
+
true,
|
|
254
|
+
'STDOUT output did not match',
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
});
|