jscs
Version:
JavaScript Code Style
176 lines (147 loc) • 4.29 kB
JavaScript
/**
* Requires multiple `var` declaration.
*
* Types: `Boolean` or `String` or `Object`
*
* Values: `true` or `"onevar"` or `allExcept: ['require']`
*
* If `requireMultipleVarDecl` defined as a `true` value, it will report only consecutive vars, if, on the other hand,
* value equals to `"onevar"` string, `requireMultipleVarDecl` will allow only one `var` per function scope.
*
* If the value is `allExcept: ['require']`, then require statements are allowed to have a var declaration per variable.
*
* JSHint: [`onevar`](http://jshint.com/docs/options/#onevar)
*
* #### Example
*
* ```js
* "requireMultipleVarDecl": true
* ```
*
* ##### Valid
*
* ```js
* var x = 1,
* y = 2;
* ```
*
* ##### Valid for `allExcept: ['require']`
*
* ```js
* var a = require("a");
* var b = require("b");
* var c = 1,
* d = 2;
* ```
*
* ##### Invalid
*
* ```js
* var x = 1;
* var y = 2;
* ```
*/
var assert = require('assert');
function consecutive(file, errors) {
var isExceptRequire = this._isExceptRequire;
file.iterateNodesByType('VariableDeclaration', function(node) {
if (isExceptRequire && hasRequireStatements(node)) {
return;
}
var sibling = node.nextSibling;
if (!sibling) {
return;
}
while (sibling.nextSibling) {
sibling = sibling.nextSibling;
if (sibling.type !== node.type) {
break;
}
if (isExceptRequire && hasRequireStatements(sibling)) {
break;
}
if (sibling.kind === node.kind) {
errors.add(
node.kind[0].toUpperCase() + node.kind.slice(1) + ' declarations should be joined',
sibling
);
}
}
});
}
function _onevar(file, errors, node) {
var firstVar = true;
var firstConst = true;
var firstParent = true;
file.iterate(function(node) {
var type = node.type;
var kind = node.kind;
// Don't go in nested scopes
if (!firstParent && ['FunctionDeclaration', 'FunctionExpression'].indexOf(type) > -1) {
return false;
}
if (firstParent) {
firstParent = false;
}
if (type === 'VariableDeclaration') {
if (kind === 'var') {
if (!firstVar) {
errors.add('Var declarations should be joined', node);
} else {
firstVar = false;
}
}
if (kind === 'const') {
if (!firstConst) {
errors.add('Const declarations should be joined', node);
} else {
firstConst = false;
}
}
}
}, node);
}
function onevar(file, errors) {
_onevar(file, errors, file.getProgram());
file.iterateNodesByType(
['FunctionDeclaration', 'FunctionExpression'],
_onevar.bind(this, file, errors)
);
}
function hasRequireStatements(node) {
if (!Array.isArray(node.declarations)) {
return false;
}
return node.declarations.some(function(declaration) {
var init = declaration.init;
return init &&
init.callee &&
init.callee.name === 'require';
});
}
module.exports = function() {};
module.exports.prototype = {
configure: function(options) {
var isExceptRequire = typeof options === 'object' &&
options.allExcept.length &&
options.allExcept.indexOf('require') !== -1;
assert(
options === true ||
options === 'onevar' ||
isExceptRequire,
this.getOptionName() + ' option requires a true value, `onevar` or {allExcept: [\'require\']}'
);
var checkers = {
'true': consecutive,
onevar: onevar
};
this._isExceptRequire = isExceptRequire;
this._check = isExceptRequire ? consecutive : checkers[options];
},
getOptionName: function() {
return 'requireMultipleVarDecl';
},
check: function() {
return this._check.apply(this, arguments);
}
};