Skip to content

Commit

Permalink
Errors: ability to suppress errors via inline comments.
Browse files Browse the repository at this point in the history
Fixes jscs-dev#335 and Fixes jscs-dev#486
  • Loading branch information
mikesherov committed Jul 29, 2014
1 parent 94870e3 commit f81fc73
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,51 @@ Values: A single file extension or an Array of file extensions, beginning with a
"fileExtensions": [".js"]
```

## Error Suppression

### Inline Comments

You can disable and reenable rules inline with two special comments: `//jscs:disable` and `//jscs:enable`. You can use them to disable rules in 3 ways.

#### Disabling All Rules

Simply using `//jscs:disable` or `//jscs:enable` will disable all rules.
```
var a = b;
//jscs:disable
var c = d; // all errors on this line will be ignored
//jscs:enable
var e = f; // all errors on this line will be reported
```

#### Disabling Specific Rules

Including a comma separated list of rules to modify after `//jscs:disable` or `//jscs:enable` will modify only those rules.
```
//jscs:disable requireCurlyBraces
if (x) y(); // all errors from requireCurlyBraces on this line will be ignored
//jscs:enable requireCurlyBraces
if (z) a(); // all errors, including from requireCurlyBraces, on this line will be reported
```

You can enable all rules after disabling a specific rule, and that rule becomes reenabled as well.
```
//jscs:disable requireCurlyBraces
if (x) y(); // all errors from requireCurlyBraces on this line will be ignored
//jscs:enable
if (z) a(); // all errors, even from requireCurlyBraces, will be reported
```

You can disable multiple rules at once and progressively reeanble them.
```
//jscs:disable requireCurlyBraces, requireDotNotation
if (x['a']) y(); // all errors from requireCurlyBraces OR requireDotNotation on this line will be ignored
//jscs:enable requireCurlyBraces
if (z['a']) a(); // all errors from requireDotNotation, but not requireCurlyBraces, will be ignored
//jscs:enable requireDotNotation
if (z['a']) a(); // all errors will be reported
```

## Rules

### requireCurlyBraces
Expand Down
5 changes: 5 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Errors.prototype = {
column = line.column;
line = line.line;
}

if (!this._file.isEnabledRule(this._currentRule, line)) {
return;
}

this._errorList.push({
rule: this._currentRule,
message: this._verbose ? this._currentRule + ': ' + message : message,
Expand Down
73 changes: 73 additions & 0 deletions lib/js-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ var JsFile = function(filename, source, tree) {
}
});

this._buildDisabledRuleIndex();

// Part of temporary esprima fix.
function convertKeywordToIdentifierIfRequired(node) {
var tokenPos = _this.getTokenPosByRangeStart(node.range[0]);
Expand All @@ -49,6 +51,77 @@ var JsFile = function(filename, source, tree) {
};

JsFile.prototype = {
/**
* Builds an index of disabled rules by starting line for error suppression.
*/
_buildDisabledRuleIndex: function() {
this._disabledRuleIndex = [];

var comments = this.getComments() || [];
var commentRe = /(jscs:(en|dis)able)(.*)/;

comments.forEach(function(comment) {
var enabled;
var parsed = commentRe.exec(comment.value.trim());

if (!parsed || parsed.index !== 0) {
return;
}

enabled = parsed[2] === 'en';
this._addToDisabledRuleIndex(enabled, parsed[3], comment.loc.start.line);
}, this);
},

/**
* returns whether a specific rule is disabled on the given line.
*
* @param {String} rule the rule name being tested
* @param {Number} line the line number being tested
* @returns {Boolean} true if the rule is enabled
*/
isEnabledRule: function(rule, line) {
var enabled = true;
this._disabledRuleIndex.some(function(region) {
if (region.line > line) {
return true;
}

if (region.rule === rule || region.rule === '*') {
enabled = region.enabled;
}
}, this);

return enabled;
},

/**
* Adds rules to the disabled index given a string containing rules (or '' for all).
*
* @param {Boolean} enabled whether the rule is disabled or enabled on this line
* @param {String} rulesStr the string containing specific rules to en/disable
* @param {Number} line the line the comment appears on
*/
_addToDisabledRuleIndex: function(enabled, rulesStr, line) {
rulesStr = rulesStr || '*';

rulesStr.split(',').forEach(function(rule) {
var ruleLength;

rule = rule.trim();

if (!rule) {
return;
}

this._disabledRuleIndex.push({
rule: rule,
enabled: enabled,
line: line
});
}, this);
},

/**
* Builds token index by starting pos for futher navigation.
*/
Expand Down
46 changes: 46 additions & 0 deletions test/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,50 @@ describe('modules/errors', function() {

assert.ok(error.rule === 'disallowQuotedKeysInObjects');
});

it('should suppress errors with disable comment', function() {
var errors = checker.checkString('//jscs:disable\n\tvar x = { "a": 1 }');
assert.ok(errors.isEmpty());
});

it('should not suppress errors with disable followed by enable comment', function() {
var errors = checker.checkString('//jscs:disable\n//jscs:enable\n\tvar x = { "a": 1 }');
assert.ok(!errors.isEmpty());
});

it('should suppress errors with disable comment followed by enable comment after error location', function() {
var errors = checker.checkString('//jscs:disable\n\tvar x = { "a": 1 };\n//jscs:enable');
assert.ok(errors.isEmpty());
});

it('should suppress errors when specific rule is disabled', function() {
var errors = checker.checkString('//jscs:disable disallowQuotedKeysInObjects\n\tvar x = { "a": 1 }');
assert.ok(errors.isEmpty());
});

it('should not suppress errors when other rule is disabled', function() {
var errors = checker.checkString('//jscs:disable someRuleName\n\tvar x = { "a": 1 }');
assert.ok(!errors.isEmpty());
});

it('should not suppress errors with disable followed by specific enable comment', function() {
var errors = checker.checkString('//jscs:disable\n ' +
'//jscs:enable disallowQuotedKeysInObjects\n\tvar x = { "a": 1 }');

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

it('should suppress errors with disable followed by specific enable other comment', function() {
var errors = checker.checkString('//jscs:disable\n ' +
'//jscs:enable someRuleName\n\tvar x = { "a": 1 }');

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

it('should not suppress errors with disable followed by specific enable other comment', function() {
var errors = checker.checkString('//jscs:disable\n ' +
'//jscs:enable someRuleName, disallowQuotedKeysInObjects\n\tvar x = { "a": 1 }');

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

0 comments on commit f81fc73

Please sign in to comment.