1 | const chalk = require('chalk');
|
2 | const plur = require('plur');
|
3 | const prettyBytes = require('pretty-bytes');
|
4 | const strip = require('strip-ansi');
|
5 | const symbols = require('log-symbols');
|
6 | const table = require('text-table');
|
7 | const wrap = require('wordwrap')(72);
|
8 |
|
9 |
|
10 |
|
11 | module.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 |
|
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 |
|
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 | };
|