Skip to content

Commit 16f810f

Browse files
committed
Allow registering custom formatter
1 parent 17d99d6 commit 16f810f

File tree

5 files changed

+248
-54
lines changed

5 files changed

+248
-54
lines changed

README.md

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ 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

6967
## Using formatters
@@ -81,27 +79,45 @@ gulp.task('lint', function() {
8179
8280
### Custom formatters
8381
84-
Custom formatter functions can be passed as `csslint.formatter(formatterFunc)`. The formatter 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 customFormatter = 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.formatter(customFormatter));
104+
.pipe(csslint.formatter(require('csslint-stylish')))
102105
});
103106
```
104107
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+
105121
### Formatter options
106122
You can also pass options to the built-in formatter, by passing a second option to `formatter`.
107123
@@ -153,7 +169,7 @@ gulp.task('lint', function(cb) {
153169
});
154170
```
155171
156-
This functionality is only available when not using custom formatters.
172+
This functionality is only available when not using a custom formatting function.
157173
158174
## Custom rules
159175

index.js

Lines changed: 34 additions & 39 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,7 +44,7 @@ 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
});
@@ -79,21 +59,29 @@ cssLintPlugin.formatter = function(customFormatter, options) {
7959
options = options || {};
8060

8161
var logger = options.logger || process.stdout.write.bind(process.stdout);
82-
83-
if (typeof customFormatter === 'function') {
84-
formatter = customFormatter;
85-
builtInFormatter = false;
86-
}
87-
else if (typeof customFormatter === 'string') {
88-
if (customFormatter === 'fail') {
89-
return cssLintPlugin.failFormatter();
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-
formatter = csslint.getFormatter(customFormatter);
93-
}
72+
formatter = csslint.getFormatter(customFormatter);
9473

95-
if (typeof formatter === 'undefined') {
96-
throw new Error('Invalid formatter');
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

9987
if (builtInFormatter) {
@@ -105,10 +93,10 @@ cssLintPlugin.formatter = function(customFormatter, options) {
10593
// Only report if CSSLint was ran and errors were found
10694
if (file.csslint && !file.csslint.success) {
10795
if (builtInFormatter) {
108-
output.push(formatter.formatResults(file.csslint.originalReport, file.path, options));
96+
output.push(formatter.formatResults(file.csslint.report, file.path, options));
10997
}
11098
else {
111-
formatter(file);
99+
formatter(file.csslint.report, file.path, options);
112100
}
113101
}
114102

@@ -137,6 +125,13 @@ cssLintPlugin.addRule = function(rule) {
137125
csslint.addRule(rule);
138126
};
139127

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

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)