Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Space after keywords superset rule (nested required/allowed) #181

Closed
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
39 changes: 37 additions & 2 deletions README.md
Expand Up @@ -67,9 +67,44 @@ if (x) {
if (x) x++; if (x) x++;
``` ```


### spaceAfterKeywords

Requires or disallows space after particualr keywords.

Type: `Object`
Values: Valid child properties are `"required"` and `"disallowed"`. Each child property is an Array of quoted keywords

#### Example

```js
"spaceAfterKeywords": {
"required": [
"switch",
"return"
],
"disallowed": [
"if"
]
}
```

##### Valid `"required"`

```js
return true;
```

##### Valid `"disallowed"`

```js
if(x) {
x++;
}
```

### requireSpaceAfterKeywords ### requireSpaceAfterKeywords


Requires space after keyword. DEPRECIATED: Replaced by [spaceAfterKeywords](spaceAfterKeywords). Requires space after keyword.


Type: `Array` Type: `Array`


Expand Down Expand Up @@ -107,7 +142,7 @@ if(x) {


### disallowSpaceAfterKeywords ### disallowSpaceAfterKeywords


Disallows space after keyword. DEPRECIATED: Replaced by [spaceAfterKeywords](spaceAfterKeywords). Disallows space after keyword.


Type: `Array` Type: `Array`


Expand Down
19 changes: 4 additions & 15 deletions lib/rules/disallow-space-after-keywords.js
@@ -1,4 +1,5 @@
var assert = require('assert'); var assert = require('assert');
var spaceAfterKeywords = require('./space-after-keywords');


module.exports = function() {}; module.exports = function() {};


Expand All @@ -8,7 +9,7 @@ module.exports.prototype = {
assert(Array.isArray(keywords), 'disallowSpaceAfterKeywords option requires array value'); assert(Array.isArray(keywords), 'disallowSpaceAfterKeywords option requires array value');
this._keywordIndex = {}; this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) { for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true; this._keywordIndex[keywords[i]] = false;
} }
}, },


Expand All @@ -17,20 +18,8 @@ module.exports.prototype = {
}, },


check: function(file, errors) { check: function(file, errors) {
var keywordIndex = this._keywordIndex; /* jshint unused: false */

spaceAfterKeywords.prototype.check.apply(this, arguments);
file.iterateTokensByType('Keyword', function(token, i, tokens) {
if (keywordIndex[token.value]) {
var nextToken = tokens[i + 1];
if (nextToken && nextToken.range[0] !== token.range[1]) {
errors.add(
'Illegal space after `' + token.value + '` keyword',
nextToken.loc.start.line,
nextToken.loc.start.column
);
}
}
});
} }


}; };
19 changes: 3 additions & 16 deletions lib/rules/require-space-after-keywords.js
@@ -1,4 +1,5 @@
var assert = require('assert'); var assert = require('assert');
var spaceAfterKeywords = require('./space-after-keywords');


module.exports = function() {}; module.exports = function() {};


Expand All @@ -17,22 +18,8 @@ module.exports.prototype = {
}, },


check: function(file, errors) { check: function(file, errors) {
var keywordIndex = this._keywordIndex; /* jshint unused: false */

spaceAfterKeywords.prototype.check.apply(this, arguments);
file.iterateTokensByType('Keyword', function(token, i, tokens) {
if (keywordIndex[token.value]) {
var nextToken = tokens[i + 1];
if (nextToken && nextToken.range[0] === token.range[1]) {
if (nextToken.type !== 'Punctuator' || nextToken.value !== ';') {
errors.add(
'Missing space after `' + token.value + '` keyword',
nextToken.loc.start.line,
nextToken.loc.start.column
);
}
}
}
});
} }


}; };
66 changes: 66 additions & 0 deletions lib/rules/space-after-keywords.js
@@ -0,0 +1,66 @@
var assert = require('assert');

module.exports = function() {};

module.exports.prototype = {

configure: function(options) {
var i, l;

assert(
typeof options === 'object',
'spaceAfterKeywords option must be an object'
);

this._keywordIndex = {};

if ('required' in options) {
var requried = options.required;
assert(Array.isArray(requried), 'spaceAfterKeywords.required option requires array value');
for (i = 0, l = requried.length; i < l; i++) {
this._keywordIndex[requried[i]] = true;
}
}
if ('disallowed' in options) {
var disallowed = options.disallowed;
assert(Array.isArray(disallowed), 'spaceAfterKeywords.allowed option requires array value');
for (i = 0, l = disallowed.length; i < l; i++) {
this._keywordIndex[disallowed[i]] = false;
}
}

},

getOptionName: function () {
return 'spaceAfterKeywords';
},

check: function(file, errors) {
var keywordIndex = this._keywordIndex;

file.iterateTokensByType('Keyword', function(token, i, tokens) {
var nextToken = tokens[i + 1];
var keyword = typeof keywordIndex[token.value] === 'undefined' ? null : keywordIndex[token.value];
if (keyword === true) {
if (nextToken && nextToken.range[0] === token.range[1]) {
if (nextToken.type !== 'Punctuator' || nextToken.value !== ';') {
errors.add(
'Missing space after `' + token.value + '` keyword',
nextToken.loc.start.line,
nextToken.loc.start.column
);
}
}
} else if (keyword === false) {
if (nextToken && nextToken.range[0] !== token.range[1]) {
errors.add(
'Illegal space after `' + token.value + '` keyword',
nextToken.loc.start.line,
nextToken.loc.start.column
);
}
}
});
}

};
2 changes: 2 additions & 0 deletions lib/string-checker.js
Expand Up @@ -96,6 +96,8 @@ StringChecker.prototype = {
this.registerRule(new (require('./rules/safe-context-keyword'))()); this.registerRule(new (require('./rules/safe-context-keyword'))());


this.registerRule(new (require('./rules/require-dot-notation'))()); this.registerRule(new (require('./rules/require-dot-notation'))());

this.registerRule(new (require('./rules/space-after-keywords'))());
}, },


/** /**
Expand Down
31 changes: 31 additions & 0 deletions test/test.space-after-keywords.js
@@ -0,0 +1,31 @@
var Checker = require('../lib/checker');
var assert = require('assert');

describe('rules/space-after-keywords', function() {
var checker;
beforeEach(function() {
checker = new Checker();
checker.registerDefaultRules();
});
it('should report illegal space after keyword', function() {
checker.configure({ spaceAfterKeywords: { 'disallowed': ['if'] }});
assert(checker.checkString('if (x) { x++; }').getErrorCount() === 1);
});
it('should not report space after keyword', function() {
checker.configure({ spaceAfterKeywords: { 'disallowed': ['if'] }});
assert(checker.checkString('if(x) { x++; }').isEmpty());
});

it('should report missing space after keyword', function() {
checker.configure({ spaceAfterKeywords: { 'required': ['if'] }});
assert(checker.checkString('if(x) { x++; }').getErrorCount() === 1);
});
it('should not report space after keyword', function() {
checker.configure({ spaceAfterKeywords: { 'required': ['if'] }});
assert(checker.checkString('if (x) { x++; }').isEmpty());
});
it('should not report semicolon after keyword', function() {
checker.configure({ spaceAfterKeywords: { 'required': ['return'] }});
assert(checker.checkString('var x = function () { return; }').isEmpty());
});
});