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](`${problems} ${plur('problem', problems)}`),
|
64 | warnings: plur('warning', counts.warnings)
|
65 | };
|
66 | const errors = chalk[style.errors](`${counts.errors} ${labels.errors}`);
|
67 | const warnings = chalk[style.warnings](`${counts.warnings} ${labels.warnings}`);
|
68 |
|
69 | if (counts.errors > 0) {
|
70 | labels.problems = chalk[style.errors](labels.problems);
|
71 | } else if (counts.warnings) {
|
72 | labels.problems = ` ${chalk[style.warnings](labels.problems)}`;
|
73 | }
|
74 |
|
75 | result.push(chalk`${symbol} ${labels.problems} {dim (}${errors}, ${warnings}{dim )}`);
|
76 | }
|
77 |
|
78 | return result.join('\n');
|
79 | },
|
80 |
|
81 | hash(json, files, hidden) {
|
82 | const { hash } = json;
|
83 | const time = module.exports.time(json.time);
|
84 | const result = [];
|
85 |
|
86 | result.push(chalk.underline(hash));
|
87 | result.push(files);
|
88 | result.push(chalk`\n {gray Δ{italic t}} ${time} ${hidden}`);
|
89 |
|
90 | return result.join('\n');
|
91 | },
|
92 |
|
93 | header(row) {
|
94 | return row.map((h) => chalk.gray(h));
|
95 | },
|
96 |
|
97 | hidden(text) {
|
98 | return chalk.dim(text);
|
99 | },
|
100 |
|
101 | problems(problems) {
|
102 | const result = [];
|
103 | const { dim } = chalk;
|
104 | const types = { errors: 'red', warnings: 'yellow' };
|
105 |
|
106 |
|
107 | for (const key of Object.keys(problems)) {
|
108 | const problem = problems[key];
|
109 | const rows = [];
|
110 | const options = {
|
111 | align: ['', 'l', 'l', 'l', 'l'],
|
112 | stringLength(str) {
|
113 | return strip(str).length;
|
114 | }
|
115 | };
|
116 |
|
117 | result.push('', chalk.underline(key));
|
118 |
|
119 | for (const type of Object.keys(types)) {
|
120 | const color = types[type];
|
121 |
|
122 | for (const item of problem[type]) {
|
123 | const message = wrap(item.message);
|
124 | const lines = message.split('\n').map((l) => chalk.blue(l.replace(/░/g, ' ')));
|
125 | const probType = chalk[color](type.substring(0, type.length - 1));
|
126 |
|
127 | rows.push(['', dim(`${item.line}:${item.column}`), probType, lines[0]]);
|
128 |
|
129 | for (const line of lines.slice(1)) {
|
130 | rows.push(['', '', '', line]);
|
131 | }
|
132 | }
|
133 | }
|
134 |
|
135 | result.push(table(rows, options));
|
136 | }
|
137 |
|
138 | if (result.length) {
|
139 | result.unshift('');
|
140 | result.push('');
|
141 | }
|
142 |
|
143 | return result.join('\n');
|
144 | },
|
145 |
|
146 | status(statuses) {
|
147 | return statuses
|
148 | .map((status) => {
|
149 | if (status === 'emitted' || status === 'built') {
|
150 | return chalk.green(status);
|
151 | } else if (status === 'error') {
|
152 | status = chalk.bold(symbols.error);
|
153 | } else if (status === 'failed') {
|
154 | status = chalk.red.bold(status);
|
155 | } else if (status === 'warning') {
|
156 | status = chalk.bold(symbols.warning);
|
157 | } else if (status === 'optional' || status === 'no-cache') {
|
158 | return chalk.yellow(status);
|
159 | } else if (status === 'prefetch') {
|
160 | return chalk.cyan(status);
|
161 | }
|
162 |
|
163 | return status;
|
164 | })
|
165 | .join(' ');
|
166 | },
|
167 |
|
168 | time(ms) {
|
169 | const out = `${ms.toString()}ms`;
|
170 | const ubound = 1600;
|
171 | const lbound = 200;
|
172 |
|
173 | if (ms > ubound) {
|
174 | return chalk.bgRed(out);
|
175 | } else if (ms <= lbound) {
|
176 | return chalk.green.bold(out);
|
177 | }
|
178 |
|
179 | const styles = [chalk.red.bold, chalk.red, chalk.yellow, chalk.green];
|
180 | const values = [ubound, ubound / 2, lbound * 2, lbound];
|
181 | const closest = Math.max.apply(null, values.filter((v) => v <= ms));
|
182 | const style = styles[values.indexOf(closest)];
|
183 |
|
184 | return style(out);
|
185 | }
|
186 | };
|