Skip to content

Commit

Permalink
Errors: Support a filter to control which errors are reported
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Kemp authored and mrjoelkemp committed Nov 11, 2014
1 parent 573ef5a commit 7556fdc
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 5 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ jscs path[ path[...]] --reporter=./some-dir/my-reporter.js
### `--esnext`
Attempts to parse your code as ES6 using the harmony version of the esprima parser. Please note that this is currently experimental, and will improve over time.

### `--error-filter`
The path to a module that determines whether or not an error should be reported.
```
jscs path[ path[...]] --error-filter=path/to/my/module.js
```

### `--no-colors`
Clean output without colors.

Expand Down Expand Up @@ -216,6 +222,21 @@ Value: `true`
"esnext": true
```

### errorFilter

A filter function that determines whether or not to report an error.
This will be called for every found error.

Type: `String`

#### Example

```js
"errorFilter": "path/to/my/filter.js"
```

See [how to define an error filter](https://github.com/jscs-dev/node-jscs/wiki/Error-Filters).

## Error Suppression

### Inline Comments
Expand Down
1 change: 1 addition & 0 deletions bin/jscs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ program
.option('-p, --preset <preset>', 'preset config')
.option('-v, --verbose', 'adds rule names to the error output')
.option('-m, --max-errors <number>', 'maximum number of errors to report')
.option('-f, --error-filter <path>', 'a module to filter errors')
.option('-r, --reporter <reporter>', 'error reporter, console - default, text, checkstyle, junit, inline')
.option('', 'Also accepts relative or absolute path to custom reporter')
.option('', 'For instance:')
Expand Down
3 changes: 2 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ module.exports = function(program) {
var promise = defer.promise();
var checker = new Checker({
verbose: program.verbose,
esnext: program.esnext
esnext: program.esnext,
errorFilter: program.errorFilter
});
var args = program.args;
var returnArgs = {
Expand Down
35 changes: 34 additions & 1 deletion lib/config/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var BUILTIN_OPTIONS = {
fileExtensions: true,
maxErrors: true,
configPath: true,
esnext: true
esnext: true,
errorFilter: true
};

/**
Expand All @@ -33,6 +34,7 @@ function Configuration() {
this._overrides = {};
this._presetName = null;
this._esnextEnabled = false;
this._errorFilter = null;
}

/**
Expand Down Expand Up @@ -87,6 +89,7 @@ Configuration.prototype.getProcessedConfig = function() {
result.maxErrors = this._maxErrors;
result.preset = this._presetName;
result.esnext = this._esnextEnabled;
result.errorFilter = this._errorFilter;
return result;
};

Expand Down Expand Up @@ -157,6 +160,15 @@ Configuration.prototype.isESNextEnabled = function() {
return this._esnextEnabled;
};

/**
* Returns the loaded error filter.
*
* @returns {Function|null}
*/
Configuration.prototype.getErrorFilter = function() {
return this._errorFilter;
};

/**
* Returns base path.
*
Expand Down Expand Up @@ -258,6 +270,16 @@ Configuration.prototype._processConfig = function(config) {
this._esnextEnabled = Boolean(config.esnext);
}

if (config.errorFilter) {
assert(
typeof config.errorFilter === 'function' ||
typeof config.errorFilter === 'string' ||
config.errorFilter === null,
'`errorFilter` option requires a function, string or null value'
);
this._loadErrorFilter(config.errorFilter);
}

// Apply config options
Object.keys(config).forEach(function(key) {
if (!BUILTIN_OPTIONS[key]) {
Expand All @@ -279,6 +301,17 @@ Configuration.prototype._loadPlugin = function(plugin) {
plugin(this);
};

/**
* Loads an error filter.
*
* @param {Function} errorFilter
* @protected
*/
Configuration.prototype._loadErrorFilter = function(errorFilter) {
assert(typeof errorFilter === 'function', '`errorFilter` should be a function');
this._errorFilter = errorFilter;
};

/**
* Includes plugin in the configuration environment.
*
Expand Down
11 changes: 11 additions & 0 deletions lib/config/node-configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ NodeConfiguration.prototype._loadPlugin = function(plugin) {
Configuration.prototype._loadPlugin.call(this, plugin);
};

/**
* Loads an error filter module
*
* @param {String} errorFilter
* @protected
*/
NodeConfiguration.prototype._loadErrorFilter = function(errorFilter) {
errorFilter = require(errorFilter.replace('.js', ''));
Configuration.prototype._loadErrorFilter.call(this, errorFilter);
};

/**
* Loads additional rule.
*
Expand Down
12 changes: 12 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Errors.prototype = {
* @param {Number} [column] optional if line is an object
*/
add: function(message, line, column) {
var error;

if (typeof line === 'object') {
column = line.column;
line = line.line;
Expand All @@ -40,6 +42,7 @@ Errors.prototype = {
}

this._errorList.push({
filename: this._file.getFilename(),
rule: this._currentRule,
message: this._verbose ? this._currentRule + ': ' + message : message,
line: line,
Expand Down Expand Up @@ -92,6 +95,15 @@ Errors.prototype = {
this._errorList.splice(length);
},

/**
* Filters out errors based on the supplied filter function
*
* @param {Function} filter
*/
filterErrorList: function(filter) {
this._errorList = this._errorList.filter(filter);
},

/**
* Formats error for further output.
*
Expand Down
5 changes: 5 additions & 0 deletions lib/string-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ StringChecker.prototype = {
}
var file = new JsFile(filename, str, tree);
var errors = new Errors(file, this._verbose);
var errorFilter = this._configuration.getErrorFilter();

if (!this._maxErrorsExceeded) {
if (parseError) {
Expand All @@ -116,6 +117,10 @@ StringChecker.prototype = {
return (a.line - b.line) || (a.column - b.column);
});

if (errorFilter) {
errors.filterErrorList(errorFilter);
}

if (this._maxErrors !== null && !isNaN(this._maxErrors)) {
if (!this._maxErrorsExceeded) {
this._maxErrorsExceeded = this._errorsFound + errors.getErrorCount() > this._maxErrors;
Expand Down
21 changes: 21 additions & 0 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -567,4 +567,25 @@ describe('modules/cli', function() {
});
});
});

describe('errorFilter option', function() {
beforeEach(function() {
sinon.spy(console, 'log');
});

afterEach(function() {
console.log.restore();
});

it('should accept a path to a filter module', function() {
return cli({
errorFilter: __dirname + '/data/error-filter.js',
args: ['test/data/cli/error.js']
})
.promise.always(function() {
assert(console.log.getCall(0).args[0] === 'No code style errors found.');
rAfter();
});
});
});
});
8 changes: 8 additions & 0 deletions test/config/configuration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var assert = require('assert');
var sinon = require('sinon');
var Configuration = require('../../lib/config/configuration');
var path = require('path');

describe('modules/config/configuration', function() {

Expand Down Expand Up @@ -118,6 +119,13 @@ describe('modules/config/configuration', function() {
});
});

describe('getErrorFilter', function() {
it('should return the supplied error filter', function() {
configuration.load({errorFilter: function() {}});
assert(typeof configuration.getErrorFilter() === 'function');
});
});

describe('hasPreset', function() {
it('should return true if preset presents in collection', function() {
var preset = {maxErrors: 5};
Expand Down
8 changes: 8 additions & 0 deletions test/config/node-configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,13 @@ describe('modules/config/node-configuration', function() {
assert(examplePluginSpy.getCall(0).args[0] === configuration);
examplePluginSpy.reset();
});

it('should accept `errorFilter` to register an error filter', function() {
configuration.load({
errorFilter: path.resolve(__dirname, '../data/error-filter.js')
});

assert(typeof configuration.getErrorFilter() === 'function');
});
});
});
4 changes: 4 additions & 0 deletions test/data/error-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = function(error) {
// Blocks all errors from being added
return false;
};
20 changes: 17 additions & 3 deletions test/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ var Checker = require('../lib/checker');
var assert = require('assert');

describe('modules/errors', function() {
var checker = new Checker();
var checker;

checker.registerDefaultRules();
checker.configure({ disallowQuotedKeysInObjects: true });
beforeEach(function() {
checker = new Checker();

checker.registerDefaultRules();
checker.configure({ disallowQuotedKeysInObjects: true });
});

it('should provide correct indent for tabbed lines', function() {
var errors = checker.checkString('\tvar x = { "a": 1 }');
Expand Down Expand Up @@ -118,4 +122,14 @@ describe('modules/errors', function() {
assert.equal(error.column, 0);
});
});

describe('filterErrorList', function() {
it('filters the errorlist by the given function', function() {
var errors = checker.checkString('var');
errors.filterErrorList(function(error) {
return false;
});
assert(errors.isEmpty());
});
});
});
18 changes: 18 additions & 0 deletions test/string-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,22 @@ describe('modules/string-checker', function() {
assert(error.message !== customDescription);
});
});

describe('error filter', function() {
beforeEach(function() {
checker = new Checker();
checker.registerDefaultRules();
});

it('should accept a filter function to filter out errors', function() {
checker.configure({
disallowQuotedKeysInObjects: true,
errorFilter: __dirname + '/data/error-filter.js'
});

var errors = checker.checkString('var x = { "a": 1 }');

assert.ok(errors.isEmpty());
});
});
});

0 comments on commit 7556fdc

Please sign in to comment.