Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed .csslintrc file support to use CSSLint specification #6

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion Gruntfile.js
Expand Up @@ -33,6 +33,12 @@ module.exports = function(grunt) {
'ids': 0
},
files: ['test/fixtures/invalid.css']
},
external: {
options: {
csslintrc: 'test/fixtures/.csslintrc'
},
src: ['test/fixtures/*.css']
}
}
});
Expand All @@ -45,7 +51,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-internal');

// plugin's task(s), manually check the output, then run `grunt csslint:all` and `grunt csslint:custom` to look at lint errors
grunt.registerTask('test', ['csslint:valid', 'csslint:empty']);
grunt.registerTask('test', ['csslint:valid', 'csslint:empty', 'csslint:external']);

// By default, lint and run all tests.
grunt.registerTask('default', ['jshint', 'test', 'build-contrib']);
Expand Down
14 changes: 7 additions & 7 deletions docs/csslint-options.md
Expand Up @@ -53,15 +53,15 @@ A few additional options are supported:
Type: `String`
Default value: `null`

If this filename is specified, options and globals defined therein will be used. Task and target options override the options within the `csslintrc` file. The `csslint` file must be valid JSON and looks something like this:
If this filename is specified the options defined therein will be used. Task and target options override the options within the `csslintrc` file. The `csslintrc` file must be a series of [CSSLint command line arguments](https://github.com/stubbornella/csslint/wiki/Command-line-interface) separated by whitespace or linefeeds.

```json
{
"qualified-headings": true,
"unique-headings": true,
"known-properties": false
}
```
--ignore=box-model,ids,important
--exclude-list=invalid.css,empty.css
```

This task only processes the `--ignore`, ` --exclude`, `--errors`, and `--warnings` declarations.

#### formatters
Type: `array`
Default value: `null`
Expand Down
23 changes: 19 additions & 4 deletions tasks/csslint.js
Expand Up @@ -11,15 +11,29 @@
module.exports = function(grunt) {
grunt.registerMultiTask( "csslint", "Lint CSS files with csslint", function() {
var csslint = require( "csslint" ).CSSLint;
var rcparser = require( "./lib/rcparser" ).init( grunt );
var ruleset = {};
var verbose = grunt.verbose;
var externalOptions = {};
var combinedResult = {};
var options = this.options();
var filesList = this.filesSrc;

// Read JSHint options from a specified jshintrc file.
// Read CSSLint options from a specified csslintrc file.
if (options.csslintrc) {
externalOptions = grunt.file.readJSON( options.csslintrc );
rcparser.parse( options.csslintrc );

externalOptions = rcparser.getOptionsObject();

// filter out excluded files
filesList = filesList.filter(function( file ) {
if ( rcparser.isFileExcluded( file ) ) {
verbose.writeln( "Skipping file excluded by CSSLint config " + file );
return false;
}
return true;
});

// delete csslintrc option to not confuse csslint if a future release
// implements a rule or options on its own
delete options.csslintrc;
Expand All @@ -39,8 +53,9 @@ module.exports = function(grunt) {
ruleset[ rule ] = options[ rule ];
}
}

var hadErrors = 0;
this.filesSrc.forEach(function( filepath ) {
filesList.forEach(function( filepath ) {
var file = grunt.file.read( filepath ),
message = "Linting " + filepath + "...",
result;
Expand Down Expand Up @@ -92,6 +107,6 @@ module.exports = function(grunt) {
if ( hadErrors ) {
return false;
}
grunt.log.ok( this.filesSrc.length + " files lint free." );
grunt.log.ok( filesList.length + " files lint free." );
});
};
98 changes: 98 additions & 0 deletions tasks/lib/rcparser.js
@@ -0,0 +1,98 @@
'use strict';

var path = require('path');

exports.init = function(grunt) {

var exports = {},
statements = {},
basePath = '',
excludeList = [];

// parses a .csslintrc file into an object
exports.parse = function(filePath) {
var data = grunt.file.read(filePath);
basePath = path.dirname(filePath);

grunt.verbose.write('Parsing CSSLint config ' + filePath + '...');

// walk through the individual statements
data.split(/[\s\n\r]+/m).forEach(function(statement) {

// ignore empty lines
if (!statement) {
return;
}

// if a statement begins with '--' then it is an option
if (statement.indexOf('--') === 0) {
// the options are key/value pairs
// and the value is optional with a default of true
var pair = statement.substring(2).split('=');
if (pair.length === 1) {
statements[pair[0]] = true;
} else {
statements[pair[0]] = pair[1].split(',');
}
}

});

// build the path-based file exclude list for easy lookups
excludeList = exports.getExcludeList().map(function(file) {
return path.join(basePath, file);
});

grunt.verbose.ok();
return statements;
};

// returns a options object, ready to be merged into the task options
exports.getOptionsObject = function() {
var options = {};

// 2 = error, 1 = warning, 0 = ignore
exports.getErrorsList().forEach(function(rule) {
options[rule] = 2;
});
exports.getWarningsList().forEach(function(rule) {
options[rule] = 1;
});
exports.getIgnoreList().forEach(function(rule) {
options[rule] = 0;
});

return options;
};

// checks if a file is in the exclude list
exports.isFileExcluded = function(filePath) {
if (grunt.util._.indexOf(excludeList, path.normalize(filePath)) !== -1) {
return true;
}
return false;
};

// gets the list of error level rules
exports.getErrorsList = function() {
return statements['errors'] || [];
};

// gets the list of warning level rules
exports.getWarningsList = function() {
return statements['warnings'] || [];
};

// gets the list of ignored rules
exports.getIgnoreList = function() {
return statements['ignore'] || [];
};

// gets the list of excluded files
exports.getExcludeList = function() {
return statements['exclude-list'] || [];
};

return exports;

};
4 changes: 4 additions & 0 deletions test/fixtures/.csslintrc
@@ -0,0 +1,4 @@
--ignore=box-model,ids,important
--errors=import,box-sizing
--warnings=star-property-hack
--exclude-list=invalid.css,empty.css
21 changes: 21 additions & 0 deletions test/fixtures/warning.css
@@ -0,0 +1,21 @@
/* warning: "Don't use IDs in selectors" */
#idInSelector {
font-size: 12pt;
}

/* warning: "Don't use width or height when using padding or border" */
.boxModel {
border: 1px solid black;
padding: 5px;
width: 100px;
}

/* warning: "Be careful when using !important declaration" */
.important {
color: red !important;
}

/* this will not cause any warnings */
.perfectlyValid {
background-color: #eee;
}