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 7, 2014
1 parent 52dcc50 commit 4817187
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 8 deletions.
44 changes: 44 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,44 @@ 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` or `Function`

#### Example

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

You may also supply a function with that accepts an error object
and returns a boolean indicating whether or not to exclude an error:

```js
"errorFilter": function(error) {
// Analyze the error object...

// Return false to exclude this error
// Return true to report this error normally
return false;
}
```

The `error` is of the following format:

```js
{
filename: '',
rule: '',
message: '',
line: 0,
column: 0
}
```

## 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
4 changes: 4 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ module.exports = function(program) {
checker.getConfiguration().override({maxErrors: Number(program.maxErrors)});
}

if (program.errorFilter) {
config.errorFilter = program.errorFilter;
}

if (program.reporter) {
reporterPath = path.resolve(process.cwd(), program.reporter);
returnArgs.reporter = reporterPath;
Expand Down
20 changes: 19 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 @@ -32,6 +33,7 @@ function Configuration() {
this._overrides = {};
this._presetName = null;
this._esnextEnabled = false;
this._errorFilter = null;
}

/**
Expand Down Expand Up @@ -88,6 +90,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 @@ -149,6 +152,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 @@ -250,6 +262,12 @@ Configuration.prototype._processConfig = function(config) {
this._esnextEnabled = Boolean(config.esnext);
}

if (typeof config.errorFilter === 'string') {
this._errorFilter = require(config.errorFilter.replace('.js', ''));
} else if (typeof config.errorFilter === 'function') {
this._errorFilter = config.errorFilter;
}

// Apply config options
Object.keys(config).forEach(function(key) {
if (!BUILTIN_OPTIONS[key]) {
Expand Down
15 changes: 12 additions & 3 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ var colors = require('colors');
* @name Errors
* @param {JsFile} file
* @param {Boolean} verbose
* @param {Function} errorFilter
*/
var Errors = function(file, verbose) {
var Errors = function(file, verbose, errorFilter) {
this._errorList = [];
this._file = file;
this._currentRule = '';
this._verbose = verbose || false;
this._errorFilter = errorFilter;
};

Errors.prototype = {
Expand All @@ -24,6 +26,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 @@ -39,12 +43,17 @@ Errors.prototype = {
return;
}

this._errorList.push({
error = {
filename: this._file.getFilename(),
rule: this._currentRule,
message: this._verbose ? this._currentRule + ': ' + message : message,
line: line,
column: column
});
};

if (!this._errorFilter || this._errorFilter(error)) {
this._errorList.push(error);
}
},

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/string-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ StringChecker.prototype = {
parseError = e;
}
var file = new JsFile(filename, str, tree);
var errors = new Errors(file, this._verbose);
var errors = new Errors(file, this._verbose, this._configuration.getErrorFilter());

if (!this._maxErrorsExceeded) {
if (parseError) {
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
Expand Up @@ -111,6 +111,14 @@ describe('modules/config/configuration', function() {
});
});

describe('getErrorFilter', function() {
it('should return a list of the names of unsupported rules found', function() {
var errorFilter = function() {};
configuration.load({errorFilter: errorFilter});
assert(configuration.getErrorFilter() === errorFilter);
});
});

describe('hasPreset', function() {
it('should return true if preset presents in collection', function() {
var preset = {maxErrors: 5};
Expand Down
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;
};
41 changes: 38 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,35 @@ describe('modules/errors', function() {
assert.equal(error.column, 0);
});
});

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

it('should accept a path to a filter module 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());
});

it('should accept a function as a filter', function() {
checker.configure({
disallowQuotedKeysInObjects: true,
errorFilter: function() {
// Accept all errors
return true;
}
});

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

0 comments on commit 4817187

Please sign in to comment.