├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example.png
├── index.js
├── lib
└── processResult.js
├── package.json
└── test
├── forVisual.css
├── index.js
├── processResult.js
└── visual.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | charset = utf-8
11 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true
4 | },
5 | "rules": {
6 | "curly": 0,
7 | "radix": 2,
8 | "wrap-iife": 2,
9 | "brace-style": 0,
10 | "comma-style": 2,
11 | "consistent-this": [2, "_that"],
12 | "no-lonely-if": 2,
13 | "no-nested-ternary": 2,
14 | "no-process-exit": 0,
15 | "no-spaced-func": 2,
16 | "no-use-before-define": [2, "nofunc"],
17 | "quotes": [2, "single"],
18 | "space-after-keywords": [2, "always"],
19 | "space-before-blocks": [2, "always"],
20 | "space-in-parens": [2, "never"],
21 | "space-unary-ops": 2
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | tmp
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.12"
4 | - "iojs"
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v0.3.1
4 | - Fix bug causing error if warning is on root node.
5 |
6 | ## v0.3.0
7 | - Throw error instead of exiting process when `throwError: true`.
8 |
9 | ## v0.2.3
10 | - Remove async.
11 |
12 | ## v0.2.0
13 | - Change the print format slightly.
14 | - Clear warnings from postcssResult.messages after logging them (configurable with option `keepWarnings`).
15 |
16 | ## v0.1.3
17 | - Add message when exiting process with code 1 to clarify reason.
18 |
19 | ## v0.1.2
20 | - Only log if there is something to log (don't log undefined).
21 |
22 | ## v0.1.1
23 | - Only exit process if code is non-zero.
24 |
25 | ## v0.1.0
26 | - First release.
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 David Clark
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # postcss-log-warnings [](https://travis-ci.org/davidtheclark/postcss-log-warnings)
2 |
3 | ---
4 |
5 | **DEPRECATED** -- **DEPRECATED** -- **DEPRECATED**
6 |
7 | This plugin has grown up and become [postcss-reporter](https://github.com/postcss/postcss-reporter)!
8 |
9 | Please switch to the new official PostCSS plugin!
10 |
11 | **DEPRECATED** -- **DEPRECATED** -- **DEPRECATED**
12 |
13 | ---
14 |
15 | Log PostCSS warnings in the console.
16 |
17 | ## Purpose
18 |
19 | As of PostCSS 4.1, a single PostCSS process can accumulate warnings from all of the plugins it uses.
20 | Presumably, plugin authors want you to see those warnings.
21 | So this plugin exists to read the accumulated warnings (or warnings from only the plugins you've specified), format them for human legibility, and print them to the console.
22 |
23 | ## Example Output
24 |
25 | 
26 |
27 | ## Installation
28 |
29 | ```
30 | npm install postcss-log-warnings
31 | ```
32 |
33 | ## Usage
34 |
35 | Add it to your plugin list *after any plugins whose warnings you want to log*, and pass it an object of options.
36 |
37 | For example, using [gulp-postcss](https://github.com/w0rm/gulp-postcss):
38 |
39 | ```js
40 | gulp.task('css', function() {
41 | return gulp.src('./src/*.css')
42 | .pipe(postcss([
43 | bemLinter(),
44 | customProperties(),
45 | calc(),
46 | rejectAllColors(),
47 | logWarnings(myOptions) // <------ ding
48 | ]))
49 | .pipe(gulp.dest('./dist'));
50 | });
51 | ```
52 |
53 | *By default, this plugin will clear the warnings after it logs them*. Otherwise, your other plugins or your PostCSS runner might re-print the same warnings, causing some confusion. This can be changed by setting the option `{ keepWarnings: true }`.
54 |
55 | You can also use this module as a library:
56 |
57 | ```js
58 | var processResult = require('postcss-log-warnings/lib/processResult');
59 | var warningLog = processResult(postcssResult, options);
60 | ```
61 |
62 | ### Options
63 |
64 | - **keepWarnings** (boolean, default = `false`)
65 |
66 | If true, the plugin will *not* clear the warnings after it logs them (by default, it will clear them). Other plugins will then have access to these warnings and might re-print them.
67 |
68 | - **plugins** (array of strings, default = `[]`)
69 |
70 | If empty, the plugin will log every warning, regardless of which plugin registered it.
71 | To limit output, name the plugins whose warnings you would like to see.
72 | For example, `{ plugins: ['postcss-bem-linter'] }` will only log warnings from the `postcss-bem-linter` plugin.
73 |
74 | - **throwError** (boolean, default = `false`)
75 |
76 | If `true`, after the plugin logs your warnings it will throw an error if it found any warnings.
77 | (Not part of the library options.)
78 |
--------------------------------------------------------------------------------
/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtheclark/postcss-log-warnings/c8bf820fb1c0031e6e30390ddbbb914e805d4b38/example.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var postcss = require('postcss');
4 | var chalk = require('chalk');
5 | var processResult = require('./lib/processResult');
6 |
7 | module.exports = postcss.plugin('postcss-log-warnings', function(options) {
8 | options = options || {};
9 |
10 | return function(css, result) {
11 | var warningLog = processResult(result, options);
12 |
13 | if (!warningLog) return;
14 |
15 | console.log(warningLog);
16 |
17 | if (options.throwError) {
18 | throw new Error(chalk.red.bold('\n** postcss-log-warnings: warnings were found **'));
19 | }
20 | };
21 | });
22 |
--------------------------------------------------------------------------------
/lib/processResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var chalk = require('chalk');
4 | var path = require('path');
5 |
6 | module.exports = function(postcssResult, options) {
7 | options = options || {};
8 | options.plugins = options.plugins || [];
9 |
10 | var warnings = postcssResult.warnings();
11 |
12 | if (!warnings.length) return undefined;
13 |
14 | var output = '\n# postcss-log-warnings\n\n';
15 |
16 | output += chalk.bold.underline(logFrom(postcssResult.root.source.input.from)) + '\n';
17 |
18 | var filteredWarnings = warnings.filter(shouldLog);
19 | filteredWarnings.forEach(function(w) {
20 | output += warningToString(w) + '\n';
21 | });
22 |
23 | // Unless user has set `keepWarnings` option,
24 | // clear all these warnings that were just stringified
25 | if (!options.keepWarnings) {
26 | postcssResult.messages = postcssResult.messages.filter(function(message) {
27 | return message.type !== 'warning';
28 | });
29 | }
30 |
31 | return output;
32 |
33 | function shouldLog(warning) {
34 | if (options.plugins.length && options.plugins.indexOf(warning.plugin) === -1) {
35 | return false;
36 | }
37 | return true;
38 | }
39 |
40 | function warningToString(warning) {
41 | var str = '';
42 | if (warning.node && warning.node.type !== 'root') {
43 | str += chalk.bold(
44 | warning.node.source.start.line + ':' +
45 | warning.node.source.start.column + '\t'
46 | );
47 | }
48 | str += warning.text;
49 | if (options.plugins.length !== 1) {
50 | str += chalk.yellow(' [' + warning.plugin + ']');
51 | }
52 | return str;
53 | }
54 |
55 | function logFrom(f) {
56 | if (f.charAt(0) === '<') return f;
57 | return path.relative(process.cwd(), f);
58 | }
59 | };
60 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss-log-warnings",
3 | "version": "0.3.1",
4 | "description": "Log PostCSS warnings in the console",
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "eslint .",
8 | "test": "npm run lint && tape test",
9 | "visual": "node test/visual.js"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/davidtheclark/postcss-log-warnings.git"
14 | },
15 | "author": {
16 | "name": "David Clark",
17 | "email": "david.dave.clark@gmail.com",
18 | "url": "http://davidtheclark.com"
19 | },
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/davidtheclark/postcss-log-warnings/issues"
23 | },
24 | "homepage": "https://github.com/davidtheclark/postcss-log-warnings",
25 | "devDependencies": {
26 | "eslint": "0.20.0",
27 | "lodash": "3.8.0",
28 | "tape": "4.0.0"
29 | },
30 | "dependencies": {
31 | "chalk": "^1.0.0",
32 | "postcss": "^4.1.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/forVisual.css:
--------------------------------------------------------------------------------
1 | /** @define HamSandwich */
2 | .Ham.Sandwich {
3 | color: pink;
4 | }
5 |
6 | :root a {
7 | font-weight: bold;
8 | }
9 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./processResult');
4 |
--------------------------------------------------------------------------------
/test/processResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var test = require('tape');
4 | var processResult = require('../lib/processResult');
5 | var chalk = require('chalk');
6 | var _ = require('lodash');
7 | var path = require('path');
8 |
9 | var mockSimpleResult = {
10 | messages: [{
11 | type: 'warning',
12 | plugin: 'foo',
13 | text: 'foo warning'
14 | }, {
15 | type: 'warning',
16 | plugin: 'bar',
17 | text: 'bar warning'
18 | }, {
19 | type: 'warning',
20 | plugin: 'baz',
21 | text: 'baz warning'
22 | }, {
23 | type: 'error',
24 | plugin: 'baz',
25 | text: 'baz error'
26 | }],
27 | root: {
28 | source: {
29 | input: {
30 | from: ''
31 | }
32 | }
33 | }
34 | };
35 |
36 | mockSimpleResult.warnings = function() {
37 | return this.messages.filter(function(m) {
38 | return m.type === 'warning';
39 | });
40 | };
41 |
42 | var simpleOutput = '\n# postcss-log-warnings\n' +
43 | '\n' +
44 | '\nfoo warning [foo]' +
45 | '\nbar warning [bar]' +
46 | '\nbaz warning [baz]\n';
47 |
48 | var simpleOutputNoBar = '\n# postcss-log-warnings\n' +
49 | '\n' +
50 | '\nfoo warning [foo]' +
51 | '\nbaz warning [baz]\n';
52 |
53 | test('processResult with simple mock', function(t) {
54 | t.equal(
55 | chalk.stripColor(processResult(_.cloneDeep(mockSimpleResult))),
56 | simpleOutput,
57 | 'basic'
58 | );
59 |
60 | t.equal(
61 | chalk.stripColor(
62 | processResult(_.cloneDeep(mockSimpleResult), { plugins: ['foo', 'baz']})
63 | ),
64 | simpleOutputNoBar,
65 | 'excluding bar'
66 | );
67 |
68 | t.end();
69 | });
70 |
71 | test('clearing warnings from result.messages', function(t) {
72 | var resultA = _.cloneDeep(mockSimpleResult);
73 | var resultB = _.cloneDeep(mockSimpleResult);
74 |
75 | t.equal(resultA.warnings().length, 3, 'initial length accurate');
76 |
77 | processResult(resultA);
78 |
79 | t.equal(resultA.warnings().length, 0, 'warnings are cleared');
80 |
81 | processResult(resultB, { keepWarnings: true });
82 |
83 | t.deepEqual(mockSimpleResult.messages, resultB.messages,
84 | 'keepWarnings option preserves messages exactly');
85 |
86 | t.end();
87 | });
88 |
89 | var mockComplexResult = {
90 | messages: [{
91 | type: 'warning',
92 | plugin: 'foo',
93 | text: 'foo warning',
94 | node: {
95 | source: {
96 | start: {
97 | line: 3,
98 | column: 5
99 | }
100 | }
101 | }
102 | }, {
103 | type: 'warning',
104 | plugin: 'bar',
105 | text: 'bar warning',
106 | node: {
107 | source: {
108 | start: {
109 | line: 1,
110 | column: 99
111 | }
112 | }
113 | }
114 | }, {
115 | type: 'error',
116 | plugin: 'baz',
117 | text: 'baz error'
118 | }],
119 | root: {
120 | source: {
121 | input: {
122 | from: path.resolve(process.cwd(), 'style/rainbows/horses.css')
123 | }
124 | }
125 | }
126 | };
127 |
128 | mockComplexResult.warnings = function() {
129 | return this.messages.filter(function(m) {
130 | return m.type === 'warning';
131 | });
132 | };
133 |
134 | var complexOutput = '\n# postcss-log-warnings\n' +
135 | '\nstyle/rainbows/horses.css' +
136 | '\n3:5\tfoo warning [foo]' +
137 | '\n1:99\tbar warning [bar]\n';
138 |
139 | var complexOutputNoBar = '\n# postcss-log-warnings\n' +
140 | '\nstyle/rainbows/horses.css' +
141 | '\n3:5\tfoo warning\n';
142 |
143 |
144 | test('processResult with complex mock', function(t) {
145 | t.equal(
146 | chalk.stripColor(processResult(_.cloneDeep(mockComplexResult))),
147 | complexOutput,
148 | 'basic'
149 | );
150 |
151 | t.equal(
152 | chalk.stripColor(processResult(_.cloneDeep(mockComplexResult), { plugins: ['foo'] })),
153 | complexOutputNoBar,
154 | 'excluding bar'
155 | );
156 |
157 | t.end();
158 | });
159 |
160 | var mockWarningOnRootResult = {
161 | messages: [{
162 | type: 'warning',
163 | text: 'blergh',
164 | node: {
165 | type: 'root',
166 | // warnings on root do not have start position
167 | source: {}
168 | },
169 | plugin: 'reject-root'
170 | }],
171 | root: {
172 | source: {
173 | input: {
174 | from: ''
175 | }
176 | }
177 | }
178 | };
179 |
180 | mockWarningOnRootResult.warnings = function() {
181 | return this.messages.filter(function(m) {
182 | return m.type === 'warning';
183 | });
184 | };
185 |
186 | var warningOnRootResultOutput = '\n# postcss-log-warnings\n' +
187 | '\n' +
188 | '\nblergh [reject-root]\n';
189 |
190 | test('processResult with mocked warning on root', function(t) {
191 | console.log(chalk.stripColor(processResult(_.cloneDeep(mockWarningOnRootResult))));
192 | t.equal(
193 | chalk.stripColor(processResult(_.cloneDeep(mockWarningOnRootResult))),
194 | warningOnRootResultOutput
195 | );
196 | t.end();
197 | });
198 |
--------------------------------------------------------------------------------
/test/visual.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var postcss = require('postcss');
4 | var logWarnings = require('..');
5 | var fs = require('fs');
6 |
7 | var rejectColors = postcss.plugin('reject-colors', function() {
8 | return function(css, result) {
9 | css.eachDecl(function(decl) {
10 | if (decl.prop === 'color') {
11 | result.warn('no colors allowed', { node: decl });
12 | }
13 | });
14 | };
15 | });
16 |
17 | var rejectBackgrounds = postcss.plugin('reject-backgrounds', function() {
18 | return function(css, result) {
19 | css.eachDecl(function(decl) {
20 | if (decl.prop === 'background') {
21 | result.warn('no backgrounds allowed', { node: decl });
22 | }
23 | });
24 | };
25 | });
26 |
27 | var rejectRoot = postcss.plugin('reject-root', function() {
28 | return function(css, result) {
29 | result.warn('blergh', { node: css });
30 | };
31 | });
32 |
33 | fs.readFile('test/forVisual.css', { encoding: 'utf8' }, function(err, data) {
34 | if (err) throw err;
35 | postcss()
36 | .use(rejectColors())
37 | .use(rejectBackgrounds())
38 | .use(rejectRoot())
39 | .use(logWarnings({ throwError: true }))
40 | .process(data, { from: 'test/forVisual.css' })
41 | .then(function() {
42 | console.error('`throwError: true` failed!');
43 | })
44 | .catch(function(ourErr) {
45 | console.log(ourErr);
46 | console.log('There\'s your visual confirmation that it works.');
47 | })
48 | .catch(function(error) {
49 | console.log(error.stack);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------