Skip to content

Commit 3cfacb3

Browse files
authored
Merge pull request #29 from SimenB/custom-formatter
Custom formatter
2 parents 15e16e0 + 16f810f commit 3cfacb3

File tree

5 files changed

+294
-100
lines changed

5 files changed

+294
-100
lines changed

README.md

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var csslint = require('gulp-csslint');
1717
gulp.task('css', function() {
1818
gulp.src('client/css/*.css')
1919
.pipe(csslint())
20-
.pipe(csslint.reporter());
20+
.pipe(csslint.formatter());
2121
});
2222
```
2323

@@ -39,7 +39,7 @@ gulp.src('client/css/*.css')
3939
.pipe(csslint({
4040
'shorthand': false
4141
}))
42-
.pipe(csslint.reporter());
42+
.pipe(csslint.formatter());
4343
```
4444

4545
### csslint(csslintrc)
@@ -52,7 +52,7 @@ You can also pass the path to your csslintrc file instead of a rule configuratio
5252
```js
5353
gulp.src('client/css/*.css')
5454
.pipe(csslint('csslintrc.json'))
55-
.pipe(csslint.reporter());
55+
.pipe(csslint.formatter());
5656
```
5757

5858
## Results
@@ -61,55 +61,71 @@ Adds the following properties to the file object:
6161

6262
```js
6363
file.csslint.success = true; // or false
64-
file.csslint.errorCount = 0; // number of errors returned by CSSLint
65-
file.csslint.results = []; // CSSLint errors
66-
file.csslint.opt = {}; // The options you passed to CSSLint
64+
file.csslint.report = {}; // The report from CSSLint after linting the file
6765
```
6866

69-
## Using reporters
67+
## Using formatters
7068

71-
Several reporters come built-in to css-lint. To use one of these reporters, pass the name to `csslint.reporter`.
69+
Several formatters come built-in to CSSLint. To use one of these formatters, pass the name to `csslint.formatter`.
7270

73-
For a list of all reporters supported by `csslint`, see the [csslint wiki](https://github.com/CSSLint/csslint/wiki/Command-line-interface#--format).
71+
For a list of all formatters supported by `csslint`, see the [csslint wiki](https://github.com/CSSLint/csslint/wiki/Command-line-interface#--format).
7472

7573
```js
7674
gulp.task('lint', function() {
7775
gulp.src('lib/*.css')
7876
.pipe(csslint())
79-
.pipe(csslint.reporter('junit-xml'));
77+
.pipe(csslint.formatter('junit-xml'));
8078
```
8179
82-
### Custom reporters
80+
### Custom formatters
8381
84-
Custom reporter functions can be passed as `csslint.reporter(reporterFunc)`. The reporter function will be called for each linted file and passed the file object as described above.
82+
Custom formatters can be provided by first adding a valid CSSLint-formatter, such as `csslint-stylish`, then using it:
8583
8684
```js
8785
var csslint = require('gulp-csslint');
88-
var gutil = require('gulp-util');
8986

90-
var customReporter = function(file) {
91-
gutil.log(gutil.colors.cyan(file.csslint.errorCount)+' errors in '+gutil.colors.magenta(file.path));
87+
csslint.addFormatter('csslint-stylish');
9288

93-
file.csslint.results.forEach(function(result) {
94-
gutil.log(result.error.message+' on line '+result.error.line);
95-
});
96-
};
89+
gulp.task('lint', function() {
90+
gulp.src('lib/*.css')
91+
.pipe(csslint())
92+
.pipe(csslint.formatter('stylish'))
93+
});
94+
```
95+
96+
You can provide the formatter by requiring it directly as well:
97+
98+
```js
99+
var csslint = require('gulp-csslint');
97100

98101
gulp.task('lint', function() {
99102
gulp.src('lib/*.css')
100103
.pipe(csslint())
101-
.pipe(csslint.reporter(customReporter));
104+
.pipe(csslint.formatter(require('csslint-stylish')))
102105
});
103106
```
104107
105-
### Reporter options
106-
You can also pass options to the built-in formatter, by passing a second option to `reporter`.
108+
You can also provide an object with the following contract to implement your own formatter:
109+
110+
```js
111+
{
112+
id: 'string', // Name passed to csslint.formatter
113+
startFormat: function() {}, // Called before parsing any files, should return a string
114+
startFormat: function() {}, // Called after parsing all files, should return a string
115+
formatResult: function (results, filename, options) {} // Called with a results-object per file linted. Optionally called with a filename, and options passed to csslint.formatter(*formatter*, *options*)
116+
}
117+
```
118+
119+
You can also provide a function, which is called for each file linted with the same arguments as `formatResults`.
120+
121+
### Formatter options
122+
You can also pass options to the built-in formatter, by passing a second option to `formatter`.
107123
108124
```js
109125
gulp.task('lint', function() {
110126
gulp.src('lib/*.css')
111127
.pipe(csslint())
112-
.pipe(csslint.reporter('junit-xml', options));
128+
.pipe(csslint.formatter('junit-xml', options));
113129
});
114130
```
115131
@@ -122,19 +138,19 @@ Default is using `process.stdout.write`, but you can use e.g. `console.log`, or
122138
gulp.task('lint', function() {
123139
gulp.src('lib/*.css')
124140
.pipe(csslint())
125-
.pipe(csslint.reporter('junit-xml', {logger: console.log.bind(console)}));
141+
.pipe(csslint.formatter('junit-xml', {logger: console.log.bind(console)}));
126142
});
127143
```
128144
129145
```js
130146
gulp.task('lint', function() {
131147
gulp.src('lib/*.css')
132148
.pipe(csslint())
133-
.pipe(csslint.reporter('junit-xml', {logger: gutil.log.bind(null, 'gulp-csslint:')}));
149+
.pipe(csslint.formatter('junit-xml', {logger: gutil.log.bind(null, 'gulp-csslint:')}));
134150
});
135151
```
136152
137-
`logger` is called once for the starting format of the reporter, then once for each file containing violations, then
153+
`logger` is called once for the starting format of the formatter, then once for each file containing violations, then
138154
lastly once for the ending format. Instead of writing to `stdout`, you can write to file using this option.
139155
140156
```js
@@ -144,7 +160,7 @@ gulp.task('lint', function(cb) {
144160

145161
gulp.src('lib/*.css')
146162
.pipe(csslint())
147-
.pipe(csslint.reporter('junit-xml', {logger: function(str) { output += str; }}))
163+
.pipe(csslint.formatter('junit-xml', {logger: function(str) { output += str; }}))
148164
.on('end', function(err) {
149165
if (err) return cb(err);
150166

@@ -153,7 +169,7 @@ gulp.task('lint', function(cb) {
153169
});
154170
```
155171
156-
This functionality is only available when not using custom reporters.
172+
This functionality is only available when not using a custom formatting function.
157173
158174
## Custom rules
159175
@@ -169,22 +185,22 @@ csslint.addRule({
169185
gulp.task('lint', function() {
170186
gulp.src('lib/*.css')
171187
.pipe(csslint())
172-
.pipe(csslint.reporter())
188+
.pipe(csslint.formatter())
173189
});
174190
```
175191
176192
## Fail on errors
177193
178-
Pipe the file stream to `csslint.failReporter()` to fail on errors.
194+
Pipe the file stream to `csslint.failFormatter()` to fail on errors.
179195
180196
```js
181197
var csslint = require('gulp-csslint');
182198

183199
gulp.task('lint', function() {
184200
gulp.src('lib/*.css')
185201
.pipe(csslint())
186-
.pipe(csslint.reporter()) // Display errors
187-
.pipe(csslint.reporter('fail')); // Fail on error (or csslint.failReporter())
202+
.pipe(csslint.formatter()) // Display errors
203+
.pipe(csslint.formatter('fail')); // Fail on error (or csslint.failFormatter())
188204
});
189205
```
190206

index.js

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,11 @@ var through = require('through2');
55
var csslint = require('csslint').CSSLint;
66
var RcLoader = require('rcloader');
77

8-
var formatOutput = function(report, file, options) {
9-
if (!report.messages.length) {
10-
return {
11-
success: true
12-
};
8+
function validateFormatter(formatter) {
9+
if (typeof formatter !== 'object' || !formatter.id || !formatter.startFormat || !formatter.endFormat || !formatter.endFormat || !formatter.formatResults) {
10+
throw new Error('Invalid formatter: formatters need to be objects, and contain "id", "name", "startFormat", "endFormat" and "formatResults"');
1311
}
14-
15-
var filePath = (file.path || 'stdin');
16-
17-
// Handle errors
18-
var results = report.messages.map(function(err) {
19-
if (!err) return;
20-
return { file: filePath, error: err };
21-
}).filter(function(err) {
22-
return err;
23-
});
24-
25-
return {
26-
originalReport: report,
27-
errorCount: results.length,
28-
success: false,
29-
results: results,
30-
options: options
31-
};
32-
};
12+
}
3313

3414
var cssLintPlugin = function(options) {
3515
options = options || {};
@@ -64,59 +44,67 @@ var cssLintPlugin = function(options) {
6444
var report = csslint.verify(content, ruleset);
6545

6646
// send status down-stream
67-
file.csslint = formatOutput(report, file, ruleset);
47+
file.csslint = { report: report, success: !report.messages.length };
6848

6949
cb(null, file);
7050
});
7151
});
7252
};
7353

74-
cssLintPlugin.reporter = function(customReporter, options) {
75-
var reporter = csslint.getFormatter('text');
76-
var builtInReporter = true;
54+
cssLintPlugin.formatter = function(customFormatter, options) {
55+
var formatter = csslint.getFormatter('text');
56+
var builtInFormatter = true;
7757
var output;
7858

7959
options = options || {};
8060

8161
var logger = options.logger || process.stdout.write.bind(process.stdout);
82-
83-
if (typeof customReporter === 'function') {
84-
reporter = customReporter;
85-
builtInReporter = false;
86-
}
87-
else if (typeof customReporter === 'string') {
88-
if (customReporter === 'fail') {
89-
return cssLintPlugin.failReporter();
62+
if (customFormatter) {
63+
if (typeof customFormatter === 'function') {
64+
formatter = customFormatter;
65+
builtInFormatter = false;
9066
}
67+
else if (typeof customFormatter === 'string') {
68+
if (customFormatter === 'fail') {
69+
return cssLintPlugin.failFormatter();
70+
}
9171

92-
reporter = csslint.getFormatter(customReporter);
93-
}
72+
formatter = csslint.getFormatter(customFormatter);
9473

95-
if (typeof reporter === 'undefined') {
96-
throw new Error('Invalid reporter');
74+
if (typeof formatter === 'undefined') {
75+
throw new Error('Invalid reporter: ' + customFormatter);
76+
}
77+
}
78+
else if (typeof customFormatter === 'object') {
79+
validateFormatter(customFormatter);
80+
formatter = customFormatter;
81+
}
82+
else {
83+
throw new Error('Invalid custom formatter passed, please pass `null` or `undefined` if you want to pass options while using default formatter.');
84+
}
9785
}
9886

99-
if (builtInReporter) {
100-
output = [reporter.startFormat()];
87+
if (builtInFormatter) {
88+
output = [formatter.startFormat()];
10189
}
10290

10391
return through.obj(
10492
function(file, enc, cb) {
10593
// Only report if CSSLint was ran and errors were found
10694
if (file.csslint && !file.csslint.success) {
107-
if (builtInReporter) {
108-
output.push(reporter.formatResults(file.csslint.originalReport, file.path, options));
95+
if (builtInFormatter) {
96+
output.push(formatter.formatResults(file.csslint.report, file.path, options));
10997
}
11098
else {
111-
reporter(file);
99+
formatter(file.csslint.report, file.path, options);
112100
}
113101
}
114102

115103
return cb(null, file);
116104
},
117105
function(cb) {
118-
if (builtInReporter) {
119-
output.push(reporter.endFormat());
106+
if (builtInFormatter) {
107+
output.push(formatter.endFormat());
120108

121109
output
122110
.filter(function(str) {
@@ -137,7 +125,14 @@ cssLintPlugin.addRule = function(rule) {
137125
csslint.addRule(rule);
138126
};
139127

140-
cssLintPlugin.failReporter = function() {
128+
cssLintPlugin.addFormatter = function(formatter) {
129+
formatter = typeof formatter === 'string' ? require(formatter) : formatter;
130+
validateFormatter(formatter);
131+
132+
csslint.addFormatter(formatter);
133+
};
134+
135+
cssLintPlugin.failFormatter = function() {
141136
return through.obj(function(file, enc, cb) {
142137
// Nothing to report or no errors
143138
if (!file.csslint || file.csslint.success) {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
},
1515
"devDependencies": {
1616
"coveralls": "^2.11.2",
17+
"csslint-stylish": "0.0.4",
1718
"eslint": "^1.1.0",
1819
"eslint-config-semistandard": "^5.0.0",
1920
"eslint-config-standard": "^4.1.0",

test/expected/text.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
csslint: There are 2 problems in test/fixtures/usingImportant.css.
2+
3+
usingImportant.css
4+
1: warning at line 2, col 1
5+
Bad naming: .mybox
6+
.mybox {
7+
8+
usingImportant.css
9+
2: warning at line 3, col 3
10+
Use of !important
11+
border: 1px solid black !important;

0 commit comments

Comments
 (0)