UNPKG

5.36 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](`${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 // render problem table per-file
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};