UNPKG

5.51 kBJavaScriptView Raw
1const chalk = require('chalk');
2const plur = require('plur');
3const prettyBytes = require('pretty-bytes');
4const strip = require('strip-ansi');
5const symbols = require('log-symbols');
6const table = require('text-table');
7const wrap = require('wordwrap')(72);
8
9/* eslint-disable no-param-reassign */
10
11module.exports = {
12 files(rows, opts) {
13 const max = opts.performance.maxAssetSize;
14 const options = {
15 align: ['', 'l', 'l', 'l', 'l'],
16 stringLength(str) {
17 return strip(str).length;
18 },
19 };
20
21 rows = rows.map((row) => {
22 row.unshift('');
23
24 const [, size, name, file, status] = row;
25 const filePath = file.substring(0, file.lastIndexOf('/') + 1);
26 const namePath = name.substring(0, name.lastIndexOf('/') + 1);
27 const sizeStyle = size > max ? chalk.yellow : chalk.green;
28
29 if (size === 'size') {
30 row = module.exports.header(row);
31 } else if (size && name) {
32 // ignore empty rows, only render rows with data
33 row[1] = sizeStyle(prettyBytes(size));
34 row[2] = chalk.blue(name.replace(namePath, '').trim());
35 row[3] = chalk.dim(filePath) + file.replace(filePath, '');
36 row[4] = module.exports.status(status);
37 }
38
39 return row;
40 });
41
42 return table(rows, options);
43 },
44
45 footer(counts) {
46 const problems = counts.errors + counts.warnings;
47 const result = [];
48
49 if (counts.time) {
50 const time = module.exports.time(counts.time);
51 result.push(chalk`{gray {bold {italic total}} Δ{italic t}} ${time}`);
52 }
53
54 if (problems > 0) {
55 const symbol = counts.errors > 0 ? symbols.error : symbols.warning;
56 const style = {
57 errors: counts.errors > 0 ? 'red' : 'dim',
58 problems: problems > 0 ? 'bold' : 'dim',
59 warnings: counts.warnings > 0 ? 'yellow' : 'dim',
60 };
61 const labels = {
62 errors: plur('error', counts.errors),
63 problems: chalk[style.problems](
64 `${problems} ${plur('problem', problems)}`
65 ),
66 warnings: plur('warning', counts.warnings),
67 };
68 const errors = chalk[style.errors](`${counts.errors} ${labels.errors}`);
69 const warnings = chalk[style.warnings](
70 `${counts.warnings} ${labels.warnings}`
71 );
72
73 if (counts.errors > 0) {
74 labels.problems = chalk[style.errors](labels.problems);
75 } else if (counts.warnings) {
76 labels.problems = ` ${chalk[style.warnings](labels.problems)}`;
77 }
78
79 result.push(
80 chalk`${symbol} ${labels.problems} {dim (}${errors}, ${warnings}{dim )}`
81 );
82 }
83
84 return result.join('\n');
85 },
86
87 hash(json, files, hidden) {
88 const { hash } = json;
89 const time = module.exports.time(json.time);
90 const result = [];
91
92 result.push(chalk.underline(hash));
93 result.push(files);
94 result.push(chalk`\n {gray Δ{italic t}} ${time} ${hidden}`);
95
96 return result.join('\n');
97 },
98
99 header(row) {
100 return row.map((h) => chalk.gray(h));
101 },
102
103 hidden(text) {
104 return chalk.dim(text);
105 },
106
107 problems(problems) {
108 const result = [];
109 const { dim } = chalk;
110 const types = { errors: 'red', warnings: 'yellow' };
111
112 // render problem table per-file
113 for (const key of Object.keys(problems)) {
114 const problem = problems[key];
115 const rows = [];
116 const options = {
117 align: ['', 'l', 'l', 'l', 'l'],
118 stringLength(str) {
119 return strip(str).length;
120 },
121 };
122
123 result.push('', chalk.underline(key));
124
125 for (const type of Object.keys(types)) {
126 const color = types[type];
127
128 for (const item of problem[type]) {
129 const message = wrap(item.message);
130 const lines = message
131 .split('\n')
132 .map((l) => chalk.blue(l.replace(/░/g, ' ')));
133 const probType = chalk[color](type.substring(0, type.length - 1));
134
135 rows.push([
136 '',
137 dim(`${item.line}:${item.column}`),
138 probType,
139 lines[0],
140 ]);
141
142 for (const line of lines.slice(1)) {
143 rows.push(['', '', '', line]);
144 }
145 }
146 }
147
148 result.push(table(rows, options));
149 }
150
151 if (result.length) {
152 result.unshift('');
153 result.push('');
154 }
155
156 return result.join('\n');
157 },
158
159 status(statuses) {
160 return statuses
161 .map((status) => {
162 if (status === 'emitted' || status === 'built') {
163 return chalk.green(status);
164 } else if (status === 'error') {
165 status = chalk.bold(symbols.error);
166 } else if (status === 'failed') {
167 status = chalk.red.bold(status);
168 } else if (status === 'warning') {
169 status = chalk.bold(symbols.warning);
170 } else if (status === 'optional' || status === 'no-cache') {
171 return chalk.yellow(status);
172 } else if (status === 'prefetch') {
173 return chalk.cyan(status);
174 }
175
176 return status;
177 })
178 .join(' ');
179 },
180
181 time(ms) {
182 const out = `${ms.toString()}ms`;
183 const ubound = 1600;
184 const lbound = 200;
185
186 if (ms > ubound) {
187 return chalk.bgRed(out);
188 } else if (ms <= lbound) {
189 return chalk.green.bold(out);
190 }
191
192 const styles = [chalk.red.bold, chalk.red, chalk.yellow, chalk.green];
193 const values = [ubound, ubound / 2, lbound * 2, lbound];
194 const closest = Math.max.apply(null, values.filter((v) => v <= ms));
195 const style = styles[values.indexOf(closest)];
196
197 return style(out);
198 },
199};