diff --git a/lib/formatter.js b/lib/formatter.js
index 7358cc6..300efad 100644
--- a/lib/formatter.js
+++ b/lib/formatter.js
@@ -3,12 +3,6 @@ var path = require('path');
var firstBy = require('thenby');
var util = require('./util');
-var supportsLargeCharset =
- process.platform !== 'win32' ||
- process.env.CI ||
- process.env.TERM === 'xterm-256color';
-var warningSymbol = supportsLargeCharset ? '⚠' : '!!';
-
function createSortFunction(positionless, sortByPosition) {
var positionValue = 0
@@ -76,8 +70,12 @@ module.exports = function (opts) {
str += '\t';
}
- if (!options.noIcon && message.type === 'warning') {
- str += pico.yellow(warningSymbol + ' ');
+ if (!options.noIcon) {
+ if (message.type === 'warning') {
+ str += pico.yellow(util.warningSymbol + ' ');
+ } else if (message.type === 'error') {
+ str += pico.red(util.errorSymbol + ' ');
+ }
}
str += message.text;
diff --git a/lib/reporter.js b/lib/reporter.js
index 71872a9..ae709c7 100644
--- a/lib/reporter.js
+++ b/lib/reporter.js
@@ -32,7 +32,7 @@ module.exports = function (opts = {}) {
};
}
- var messageFilter = opts.filter || ((message) => message.type === 'warning');
+ var messageFilter = opts.filter || ((message) => message.type === 'warning' || message.type === 'error');
return {
postcssPlugin: 'postcss-reporter',
@@ -45,6 +45,9 @@ module.exports = function (opts = {}) {
? ''
: result.root.source.input.file || result.root.source.input.id;
+ let errorCount = 0;
+ let warningCount = 0;
+
var sourceGroupedMessages = messagesToLog.reduce((grouped, message) => {
const key = util.getLocation(message).file || resultSource;
@@ -52,6 +55,12 @@ module.exports = function (opts = {}) {
grouped[key] = [];
}
+ if (message.type === 'error') {
+ errorCount++;
+ } else if (message.type === 'warning') {
+ warningCount++;
+ }
+
grouped[key].push(message);
return grouped;
@@ -78,9 +87,15 @@ module.exports = function (opts = {}) {
if (!report) return;
+ const summaryColor = errorCount > 0 ? 'red' : 'yellow';
+ const summarySymbol = errorCount > 0 ? util.errorSymbol : util.warningSymbol;
+ const summary = `${summarySymbol} ${messagesToLog.length} ${util.plur('problem', messagesToLog.length)} (${errorCount} ${util.plur('error')}, ${warningCount} ${util.plur('warning')})`
+
+ report += `\n ${pico[summaryColor](pico.bold(summary))}\n`;
+
console.log(report);
- if (opts.throwError && shouldThrowError()) {
+ if (shouldThrowError()) {
throw new Error(
pico.red(
pico.bold('\n** postcss-reporter: warnings or errors were found **')
@@ -89,12 +104,7 @@ module.exports = function (opts = {}) {
}
function shouldThrowError() {
- return (
- messagesToLog.length &&
- messagesToLog.some((message) => {
- return message.type === 'warning' || message.type === 'error';
- })
- );
+ return opts.throwError || errorCount > 0;
}
},
};
diff --git a/lib/util.js b/lib/util.js
index 094b3ac..5433491 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -1,3 +1,8 @@
+var supportsLargeCharset =
+ process.platform !== 'win32' ||
+ process.env.CI ||
+ process.env.TERM === 'xterm-256color';
+
exports.getLocation = function (message) {
var messageNode = message.node;
@@ -17,3 +22,10 @@ exports.getLocation = function (message) {
location.file = messageInput.file || messageInput.id;
return location;
};
+
+exports.plur = function plur(word, count) {
+ return (count === 1 ? word : `${word}s`);
+}
+
+exports.warningSymbol = supportsLargeCharset ? '⚠' : '!!';
+exports.errorSymbol = supportsLargeCharset ? '✖' : 'xx';
diff --git a/test/formatter.js b/test/formatter.js
index c3447dc..2282401 100644
--- a/test/formatter.js
+++ b/test/formatter.js
@@ -8,6 +8,7 @@ var stripColor = require('strip-color');
var defaultFormatter = formatter();
var colorlessWarning = '⚠';
+var colorlessError = '✖';
var basicMessages = [
{
@@ -36,7 +37,7 @@ var basicOutput = '\n' +
'\n' + colorlessWarning + ' foo warning [foo]' +
'\n' + colorlessWarning + ' bar warning [bar]' +
'\n' + colorlessWarning + ' baz warning [baz]' +
- '\nbaz error [baz]' +
+ '\n' + colorlessError + ' baz error [baz]' +
'\n';
var basicOutputMinimal = '\n' +
@@ -104,14 +105,14 @@ var complexMessages = [
];
var complexOutput = '\nstyle/rainbows/horses.css' +
- '\nbaz error [baz]' +
+ '\n' + colorlessError + ' baz error [baz]' +
'\n1:99\t' + colorlessWarning + ' bar warning [bar]' +
'\n3:5\t' + colorlessWarning + ' foo warning [foo]' +
'\n8:13\t' + colorlessWarning + ' ha warning [foo]' +
'\n';
var noPositionSortOutput = '\nstyle/rainbows/horses.css' +
- '\nbaz error [baz]' +
+ '\n' + colorlessError + ' baz error [baz]' +
'\n3:5\t' + colorlessWarning + ' foo warning [foo]' +
'\n1:99\t' + colorlessWarning + ' bar warning [bar]' +
'\n8:13\t' + colorlessWarning + ' ha warning [foo]' +
@@ -121,12 +122,12 @@ var positionlessLastOutput = '\nstyle/rainbows/horses.css' +
'\n1:99\t' + colorlessWarning + ' bar warning [bar]' +
'\n3:5\t' + colorlessWarning + ' foo warning [foo]' +
'\n8:13\t' + colorlessWarning + ' ha warning [foo]' +
- '\nbaz error [baz]' +
+ '\n' + colorlessError + ' baz error [baz]' +
'\n';
var noSortOutput = '\nstyle/rainbows/horses.css' +
'\n3:5\t' + colorlessWarning + ' foo warning [foo]' +
- '\nbaz error [baz]' +
+ '\n' + colorlessError + ' baz error [baz]' +
'\n1:99\t' + colorlessWarning + ' bar warning [bar]' +
'\n8:13\t' + colorlessWarning + ' ha warning [foo]' +
'\n';
diff --git a/test/reporter.js b/test/reporter.js
index 2a069cf..1359a6a 100644
--- a/test/reporter.js
+++ b/test/reporter.js
@@ -84,11 +84,16 @@ test('reporter with simple mock result containing non warning typed message', fu
plugin: 'foo',
text: 'foo warning',
},
+ {
+ type: 'error',
+ plugin: 'foo',
+ text: 'foo error',
+ },
];
var testReporter = reporter({
formatter: mockFormatter(tracker),
});
- t.doesNotThrow(function() {
+ t.throws(function() {
testReporter.OnceExit(null, {
result: mockResultContainingNonWarningMessage,
});
@@ -158,7 +163,11 @@ test('reporter with simple mock result and function-filtered plugins', function(
formatter: mockFormatter(tracker),
filter: function(message) { return message.type === 'error'; },
});
- testReporter.OnceExit(null, { result: cloneResult });
+ t.throws(function() {
+ testReporter.OnceExit(null, {
+ result: cloneResult,
+ });
+ });
t.deepEqual(
tracker.messages,
[
@@ -422,7 +431,11 @@ test('reporter with warnings that messages that each have nodes', function(t) {
var testReporter = reporter({
formatter: mockMultiSourceFormatter(tracker),
});
- testReporter.OnceExit(null, { result: mockWarningNodeResult });
+ t.throws(function() {
+ testReporter.OnceExit(null, {
+ result: mockWarningNodeResult,
+ });
+ });
t.deepEqual(tracker, [
{
source: 'foo.css',
@@ -470,6 +483,45 @@ test('reporter with warnings that messages that each have nodes', function(t) {
},
],
},
+ {
+ source: '',
+ messages: [
+ {
+ type: 'error',
+ plugin: 'pat',
+ text: 'pat error',
+ node: {
+ source: {
+ input: {
+ id: '',
+ },
+ },
+ },
+ },
+ {
+ type: 'error',
+ plugin: 'hoo',
+ text: 'hoo error',
+ node: {
+ source: {
+ input: {
+ id: '',
+ },
+ },
+ },
+ },
+ ],
+ },
+ {
+ source: '',
+ messages: [
+ {
+ type: 'error',
+ plugin: 'hah',
+ text: 'hah error',
+ },
+ ],
+ },
]);
t.end();
});