jscs
Version:
JavaScript Style Checker
1,603 lines (1,327 loc) • 240 kB
JavaScript
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JscsStringChecker=e():"undefined"!=typeof global?global.JscsStringChecker=e():"undefined"!=typeof self&&(self.JscsStringChecker=e())}(function(){var define,module,exports;
return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var colors = require('colors');
/**
* Set of errors for specified file.
*
* @name Errors
*/
var Errors = function(file) {
this._errorList = [];
this._file = file;
};
Errors.prototype = {
/**
* Adds style error to the list
*
* @param {String} message
* @param {Number|Object} line
* @param {Number} [column]
*/
add: function(message, line, column) {
if (typeof line === 'object') {
column = line.column;
line = line.line;
}
this._errorList.push({
message: message,
line: line,
column: column
});
},
/**
* Returns style error list.
*
* @returns {Object[]}
*/
getErrorList: function() {
return this._errorList;
},
/**
* Returns filename of file this error list is for.
*
* @returns {String}
*/
getFilename: function() {
return this._file.getFilename();
},
/**
* Returns true if no errors are added.
*
* @returns {Boolean}
*/
isEmpty: function() {
return this._errorList.length === 0;
},
/**
* Returns amount of errors added by the rules.
*
* @returns {Number}
*/
getErrorCount: function () {
return this._errorList.length;
},
/**
* Formats error for futher output.
*
* @param {Object} error
* @param {Boolean} colorize
* @returns {String}
*/
explainError: function(error, colorize) {
var lineNumber = error.line - 1;
var lines = this._file.getLines();
var result = [
renderLine(lineNumber, lines[lineNumber], colorize),
renderPointer(error.column, colorize)
];
var i = lineNumber - 1;
var linesAround = 2;
while (i >= 0 && i >= (lineNumber - linesAround)) {
result.unshift(renderLine(i, lines[i], colorize));
i--;
}
i = lineNumber + 1;
while (i < lines.length && i <= (lineNumber + linesAround)) {
result.push(renderLine(i, lines[i], colorize));
i++;
}
result.unshift(formatErrorMessage(error.message, this.getFilename(), colorize));
return result.join('\n');
}
};
/**
* Formats error message header.
*
* @param {String} message
* @param {String} filename
* @param {Boolean} colorize
* @returns {String}
*/
function formatErrorMessage(message, filename, colorize) {
return (colorize ? colors.bold(message) : message) +
' at ' +
(colorize ? colors.green(filename) : filename) + ' :';
}
/**
* Simple util for prepending spaces to the string until it fits specified size.
*
* @param {String} s
* @param {Number} len
* @returns {String}
*/
function prependSpaces(s, len) {
while (s.length < len) {
s = ' ' + s;
}
return s;
}
/**
* Renders single line of code in style error formatted output.
*
* @param {Number} n line number
* @param {String} line
* @param {Boolean} colorize
* @returns {String}
*/
function renderLine(n, line, colorize) {
// Convert tabs to spaces, so errors in code lines with tabs as indention symbol
// could be correctly rendered, plus it will provide less verbose output
line = line.replace(/\t/g, ' ');
// "n + 1" to print lines in human way (counted from 1)
var lineNumber = prependSpaces((n + 1).toString(), 5) + ' |';
return ' ' + (colorize ? colors.grey(lineNumber) : lineNumber) + line;
}
/**
* Renders pointer:
* ---------------^
*
* @param {Number} column
* @param {Boolean} colorize
* @returns {String}
*/
function renderPointer(column, colorize) {
var res = (new Array(column + 9)).join('-') + '^';
return colorize ? colors.grey(res) : res;
}
module.exports = Errors;
},{"colors":46}],2:[function(require,module,exports){
var treeIterator = require('./tree-iterator');
/**
* File representation for JSCS.
*
* @name JsFile
*/
var JsFile = function(filename, source, tree) {
this._filename = filename;
this._source = source;
this._tree = tree;
this._lines = source.split(/\r\n|\r|\n/);
this._tokenIndex = null;
var index = this._index = {};
this.iterate(function(node, parentNode, parentCollection) {
if (node) {
var type = node.type;
if (type) {
node.parentNode = parentNode;
node.parentCollection = parentCollection;
(index[type] || (index[type] = [])).push(node);
}
}
});
};
JsFile.prototype = {
/**
* Builds token index by starting pos for futher navigation.
*/
_buildTokenIndex: function() {
var tokens = this._tree.tokens;
var tokenIndex = {};
for (var i = 0, l = tokens.length; i < l; i++) {
tokenIndex[tokens[i].range[0]] = i;
}
this._tokenIndex = tokenIndex;
},
/**
* Returns token position using range start from the index.
*
* @returns {Object}
*/
getTokenPosByRangeStart: function(start) {
if (!this._tokenIndex) {
this._buildTokenIndex();
}
return this._tokenIndex[start];
},
/**
* Iterates through the token tree using tree iterator.
* Calls passed function for every token.
*
* @param {Function} cb
*/
iterate: function(cb) {
return treeIterator.iterate(this._tree, cb);
},
/**
* Returns tokens by type(s) from earlier built index.
*
* @param {String|String[]} type
* @returns {Object[]}
*/
getNodesByType: function(type) {
if (typeof type === 'string') {
return this._index[type] || [];
} else {
var result = [];
for (var i = 0, l = type.length; i < l; i++) {
var nodes = this._index[type[i]];
if (nodes) {
result = result.concat(nodes);
}
}
return result;
}
},
/**
* Iterates tokens by type(s) from earlier built index.
* Calls passed function for every matched token.
*
* @param {String|String[]} type
* @param {Function} cb
*/
iterateNodesByType: function(type, cb) {
return this.getNodesByType(type).forEach(cb);
},
/**
* Returns string representing contents of the file.
*
* @returns {String}
*/
getSource: function() {
return this._source;
},
/**
* Returns token tree, built using esprima.
*
* @returns {Object}
*/
getTree: function() {
return this._tree;
},
/**
* Returns token list, built using esprima.
*
* @returns {Object[]}
*/
getTokens: function() {
return this._tree.tokens;
},
/**
* Returns comment token list, built using esprima.
*/
getComments: function() {
return this._tree.comments;
},
/**
* Returns source filename for this object representation.
*
* @returns {String}
*/
getFilename: function() {
return this._filename;
},
/**
* Returns array of source lines for the file.
*
* @returns {String[]}
*/
getLines: function() {
return this._lines;
}
};
module.exports = JsFile;
},{"./tree-iterator":42}],3:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(types) {
assert(Array.isArray(types), 'disallowImplicitTypeConversion option requires array value');
this._typeIndex = {};
for (var i = 0, l = types.length; i < l; i++) {
this._typeIndex[types[i]] = true;
}
},
getOptionName: function () {
return 'disallowImplicitTypeConversion';
},
check: function(file, errors) {
var types = this._typeIndex;
if (types.numeric || types.boolean || types.binary) {
file.iterateNodesByType('UnaryExpression', function (node) {
if (types.numeric && node.operator === '+') {
errors.add('Implicit numeric conversion', node.loc.start);
}
if (types.binary && node.operator === '~') {
errors.add('Implicit binary conversion', node.loc.start);
}
if (types.boolean &&
node.operator === '!' &&
node.argument.type === 'UnaryExpression' &&
node.argument.operator === '!'
) {
errors.add('Implicit boolean conversion', node.loc.start);
}
});
}
if (types.string) {
file.iterateNodesByType('BinaryExpression', function (node) {
if (node.operator === '+' && (
(node.left.type === 'Literal' && node.left.value === '') ||
(node.right.type === 'Literal' && node.right.value === '')
)
) {
errors.add('Implicit string conversion', node.loc.start);
}
});
}
}
};
},{"assert":44}],4:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(keywords) {
assert(Array.isArray(keywords), 'disallowKeywordsOnNewLine option requires array value');
this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true;
}
},
getOptionName: function () {
return 'disallowKeywordsOnNewLine';
},
check: function(file, errors) {
var keywordIndex = this._keywordIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Keyword' && keywordIndex[token.value]) {
var prevToken = tokens[i - 1];
if (prevToken && prevToken.loc.end.line !== token.loc.start.line) {
errors.add(
'Keyword `' + token.value + '` should not be placed on new line',
token.loc.start.line,
token.loc.start.column
);
}
}
}
}
};
},{"assert":44}],5:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(keywords) {
assert(Array.isArray(keywords), 'disallowKeywords option requires array value');
this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true;
}
},
getOptionName: function () {
return 'disallowKeywords';
},
check: function(file, errors) {
var keywordIndex = this._keywordIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Keyword' && keywordIndex[token.value]) {
errors.add(
'Illegal keyword: ' + token.value,
token.loc.start
);
}
}
}
};
},{"assert":44}],6:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'disallowLeftStickedOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'disallowLeftStickedOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Punctuator' && operators[token.value]) {
var prevToken = tokens[i - 1];
if (prevToken && prevToken.range[1] === token.range[0]) {
errors.add(
'Operator ' + token.value + ' should not stick to preceding expression',
token.loc.start
);
}
}
}
}
};
},{"assert":44}],7:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowMultipleLineBreaks) {
assert(
typeof disallowMultipleLineBreaks === 'boolean',
'disallowMultipleLineBreaks option requires boolean value'
);
assert(
disallowMultipleLineBreaks === true,
'disallowMultipleLineBreaks option requires true value or should be removed'
);
},
getOptionName: function () {
return 'disallowMultipleLineBreaks';
},
check: function(file, errors) {
var lines = file.getLines();
for (var i = 1, l = lines.length; i < l; i++) {
var line = lines[i];
if (line === '' && lines[i - 1] === '') {
while (++i < l && lines[i] === '') {}
errors.add('Multiple line break', i - 1, 0);
}
}
}
};
},{"assert":44}],8:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowMultipleVarDecl) {
assert(
typeof disallowMultipleVarDecl === 'boolean',
'disallowMultipleVarDecl option requires boolean value'
);
assert(
disallowMultipleVarDecl === true,
'disallowMultipleVarDecl option requires true value or should be removed'
);
},
getOptionName: function () {
return 'disallowMultipleVarDecl';
},
check: function(file, errors) {
file.iterateNodesByType('VariableDeclaration', function (node) {
// allow multiple var declarations in for statement
// for (var i = 0, j = myArray.length; i < j; i++) {}
if (node.declarations.length > 1 && node.parentNode.type !== 'ForStatement') {
errors.add('Multiple var declaration', node.loc.start);
}
});
}
};
},{"assert":44}],9:[function(require,module,exports){
var assert = require('assert');
var OPTION_NAME = 'disallowQuotedKeysInObjects';
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowQuotedKeysInObjects) {
assert(
typeof disallowQuotedKeysInObjects === 'boolean',
OPTION_NAME + ' options requires boolean value'
);
assert(
disallowQuotedKeysInObjects === true,
'disallowQuotedKeysInObjects option requires true value or should be removed'
);
},
getOptionName: function() {
return OPTION_NAME;
},
check: function(file, errors) {
var KEY_NAME_RE = /^(0|[1-9][0-9]*|[a-zA-Z_$]+[\w$]*)$/; // number or identifier
file.iterateNodesByType('ObjectExpression', function(node) {
node.properties.forEach(function(prop) {
var key = prop.key;
if (key.type === 'Literal' &&
typeof key.value === 'string' &&
KEY_NAME_RE.test(key.value)
) {
errors.add('Extra qoutes for key', prop.loc.start);
}
});
});
}
};
},{"assert":44}],10:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'disallowRightStickedOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'disallowRightStickedOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Punctuator' && operators[token.value]) {
var nextToken = tokens[i + 1];
if (nextToken && nextToken.range[0] === token.range[1]) {
errors.add(
'Operator ' + token.value + ' should not stick to following expression',
token.loc.start
);
}
}
}
}
};
},{"assert":44}],11:[function(require,module,exports){
var assert = require('assert');
var tokenHelper = require('../token-helper');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'disallowSpaceAfterBinaryOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'disallowSpaceAfterBinaryOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
// 2 + 2, 2 == 2
file.iterateNodesByType(['BinaryExpression'], function (node) {
if (operators[node.operator]) {
// get token before right part of expression
var tokenBeforeRightPart = tokenHelper.getTokenByRangeStart(file, node.right.range[0] - 1, true);
if (!tokenHelper.tokenIsPunctuator(tokenBeforeRightPart, node.operator)) {
errors.add(
'Operator ' + node.operator + ' should stick to following expression',
node.right.loc.start
);
}
}
});
}
};
},{"../token-helper":41,"assert":44}],12:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(keywords) {
assert(Array.isArray(keywords), 'disallowSpaceAfterKeywords option requires array value');
this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true;
}
},
getOptionName: function () {
return 'disallowSpaceAfterKeywords';
},
check: function(file, errors) {
var keywordIndex = this._keywordIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Keyword' && 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
);
}
}
}
}
};
},{"assert":44}],13:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallow) {
assert(
typeof disallow === 'boolean',
this.getOptionName() + ' option requires boolean value'
);
assert(
disallow === true,
this.getOptionName() + ' option requires true value or should be removed'
);
},
getOptionName: function() {
return 'disallowSpaceAfterObjectKeys';
},
check: function(file, errors) {
var tokens = file.getTokens();
file.iterateNodesByType('ObjectExpression', function(node) {
node.properties.forEach(function(property) {
var key = property.key;
var keyPos = file.getTokenPosByRangeStart(key.range[0]);
var colon = tokens[keyPos + 1];
if (colon.range[0] !== key.range[1]) {
errors.add('Illegal space after key', key.loc.end);
}
});
});
}
};
},{"assert":44}],14:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), this.getOptionName() + ' option requires array value');
this._operators = operators.slice(0);
},
getOptionName: function () {
return 'disallowSpaceAfterPrefixUnaryOperators';
},
check: function(file, errors) {
var operators = this._operators;
file.iterateNodesByType(['UnaryExpression', 'UpdateExpression'], function (node) {
// Check "node.prefix" for prefix type of (inc|dec)rement
if (node.prefix && operators.indexOf(node.operator) !== -1) {
if ((node.range[0] + node.operator.length) < node.argument.range[0]) {
errors.add('Operator ' + node.operator + ' should stick to operand', node.loc.start);
}
}
});
}
};
},{"assert":44}],15:[function(require,module,exports){
var assert = require('assert');
var tokenHelper = require('../token-helper');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'disallowSpaceBeforeBinaryOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'disallowSpaceBeforeBinaryOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
// 2 + 2, 2 == 2
file.iterateNodesByType(['BinaryExpression'], function (node) {
if (operators[node.operator]) {
// get token after left part of expression
var tokenAfterLeftPart = tokenHelper.getTokenByRangeStart(file, node.left.range[1]);
if (!tokenHelper.tokenIsPunctuator(tokenAfterLeftPart, node.operator)) {
errors.add(
'Operator ' + node.operator + ' should stick to following expression',
node.left.loc.start
);
}
}
});
}
};
},{"../token-helper":41,"assert":44}],16:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), this.getOptionName() + ' option requires array value');
this._operators = operators.slice(0);
},
getOptionName: function () {
return 'disallowSpaceBeforePostfixUnaryOperators';
},
check: function(file, errors) {
var operators = this._operators;
// 'UpdateExpression' involve only ++ and -- operators
file.iterateNodesByType('UpdateExpression', function (node) {
// "!node.prefix" means postfix type of (inc|dec)rement
if (!node.prefix && operators.indexOf(node.operator) !== -1) {
// Length of operator is always 2
if (node.argument.range[1] < (node.range[1] - 2)) {
errors.add('Operator ' + node.operator + ' should stick to operand', node.loc.start);
}
}
});
}
};
},{"assert":44}],17:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(options) {
assert(
typeof options === 'object',
'disallowSpacesInFunctionExpression option must be the object'
);
if ('beforeOpeningRoundBrace' in options) {
assert(
options.beforeOpeningRoundBrace === true,
'disallowSpacesInFunctionExpression.beforeOpeningRoundBrace ' +
'property requires true value or should be removed'
);
}
if ('beforeOpeningCurlyBrace' in options) {
assert(
options.beforeOpeningCurlyBrace === true,
'disallowSpacesInFunctionExpression.beforeOpeningCurlyBrace ' +
'property requires true value or should be removed'
);
}
assert(
options.beforeOpeningCurlyBrace || options.beforeOpeningRoundBrace,
'disallowSpacesInFunctionExpression must have beforeOpeningCurlyBrace or beforeOpeningRoundBrace property'
);
this._beforeOpeningRoundBrace = Boolean(options.beforeOpeningRoundBrace);
this._beforeOpeningCurlyBrace = Boolean(options.beforeOpeningCurlyBrace);
},
getOptionName: function () {
return 'disallowSpacesInFunctionExpression';
},
check: function(file, errors) {
var beforeOpeningRoundBrace = this._beforeOpeningRoundBrace;
var beforeOpeningCurlyBrace = this._beforeOpeningCurlyBrace;
var tokens = file.getTokens();
file.iterateNodesByType([ 'FunctionDeclaration', 'FunctionExpression' ], function (node) {
if (beforeOpeningRoundBrace) {
var nodeBeforeRoundBrace = node;
// named function
if (node.id) {
nodeBeforeRoundBrace = node.id;
}
var functionTokenPos = file.getTokenPosByRangeStart(nodeBeforeRoundBrace.range[0]);
var functionToken = tokens[functionTokenPos];
var nextTokenPos = file.getTokenPosByRangeStart(functionToken.range[1]);
var nextToken = tokens[nextTokenPos];
if (!nextToken) {
errors.add(
'Illegal space before opening round brace',
functionToken.loc.start
);
}
}
if (beforeOpeningCurlyBrace) {
var tokenBeforeBodyPos = file.getTokenPosByRangeStart(node.body.range[0] - 1);
var tokenBeforeBody = tokens[tokenBeforeBodyPos];
if (!tokenBeforeBody) {
errors.add(
'Illegal space before opening curly brace',
node.body.loc.start
);
}
}
});
}
};
},{"assert":44}],18:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallow) {
assert(
typeof disallow === 'boolean',
this.getOptionName() + ' option requires boolean value'
);
assert(
disallow === true,
this.getOptionName() + ' option requires true value or should be removed'
);
},
getOptionName: function() {
return 'disallowSpacesInsideArrayBrackets';
},
check: function(file, errors) {
file.iterateNodesByType('ArrayExpression', function(node) {
var tokens = file.getTokens();
var openingBracketPos = file.getTokenPosByRangeStart(node.range[0]);
var openingBracket = tokens[openingBracketPos];
var nextToken = tokens[openingBracketPos + 1];
if (openingBracket.loc.start.line === nextToken.loc.start.line &&
openingBracket.range[1] !== nextToken.range[0]
) {
errors.add('Illegal space after opening square brace', openingBracket.loc.end);
}
var closingBracketPos = file.getTokenPosByRangeStart(node.range[1] - 1);
var closingBracket = tokens[closingBracketPos];
var prevToken = tokens[closingBracketPos - 1];
if (closingBracket.loc.start.line === prevToken.loc.start.line &&
closingBracket.range[0] !== prevToken.range[1]
) {
errors.add('Illegal space before closing square brace', prevToken.loc.end);
}
});
}
};
},{"assert":44}],19:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowSpacesInsideObjectBrackets) {
assert(
typeof disallowSpacesInsideObjectBrackets === 'boolean',
'disallowSpacesInsideObjectBrackets option requires boolean value'
);
assert(
disallowSpacesInsideObjectBrackets === true,
'disallowSpacesInsideObjectBrackets option requires true value or should be removed'
);
},
getOptionName: function() {
return 'disallowSpacesInsideObjectBrackets';
},
check: function(file, errors) {
file.iterateNodesByType('ObjectExpression', function(node) {
var tokens = file.getTokens();
var openingBracketPos = file.getTokenPosByRangeStart(node.range[0]);
var openingBracket = tokens[openingBracketPos];
var nextToken = tokens[openingBracketPos + 1];
if (openingBracket.loc.start.line === nextToken.loc.start.line &&
openingBracket.range[1] !== nextToken.range[0]
) {
errors.add('Illegal space after opening curly brace', openingBracket.loc.end);
}
var closingBracketPos = file.getTokenPosByRangeStart(node.range[1] - 1);
var closingBracket = tokens[closingBracketPos];
var prevToken = tokens[closingBracketPos - 1];
if (closingBracket.loc.start.line === prevToken.loc.start.line &&
closingBracket.range[0] !== prevToken.range[1]
) {
errors.add('Illegal space before closing curly brace', prevToken.loc.end);
}
});
}
};
},{"assert":44}],20:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowSpacesInsideParentheses) {
assert(
typeof disallowSpacesInsideParentheses === 'boolean',
'disallowSpacesInsideParentheses option requires boolean value'
);
assert(
disallowSpacesInsideParentheses === true,
'disallowSpacesInsideParentheses option requires true value or should be removed'
);
},
getOptionName: function() {
return 'disallowSpacesInsideParentheses';
},
check: function(file, errors) {
var tokens = file.getTokens();
tokens.forEach(function(token, index) {
if (token.type === 'Punctuator') {
if (token.value === '(') {
var nextToken = tokens[index + 1];
if (token.range[1] !== nextToken.range[0] &&
token.loc.end.line === nextToken.loc.start.line) {
errors.add('Illegal space after opening round bracket', token.loc.end);
}
}
if (token.value === ')') {
var prevToken = tokens[index - 1];
if (prevToken.range[1] !== token.range[0] &&
prevToken.loc.end.line === token.loc.start.line) {
errors.add('Illegal space before closing round bracket', prevToken.loc.end);
}
}
}
});
}
};
},{"assert":44}],21:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(disallowYodaConditions) {
assert(
typeof disallowYodaConditions === 'boolean',
'disallowYodaConditions option requires boolean value'
);
assert(
disallowYodaConditions === true,
'disallowYodaConditions option requires true value or should be removed'
);
this._operatorIndex = {
'==': true,
'===': true,
'!=': true,
'!==': true,
'>': true,
'<': true,
'>=': true,
'<=': true
};
},
getOptionName: function () {
return 'disallowYodaConditions';
},
check: function(file, errors) {
var operators = this._operatorIndex;
file.iterateNodesByType('BinaryExpression', function (node) {
if (operators[node.operator]) {
if (node.left.type === 'Literal' ||
(node.left.type === 'Identifier' && node.left.name === 'undefined')
) {
errors.add('Yoda condition', node.left.loc.start);
}
}
});
}
};
},{"assert":44}],22:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(mode) {
var modes = {
'all': true,
'skipWithFunction': true,
'skipWithLineBreak': true
};
assert(
typeof mode === 'string' && modes[mode],
this.getOptionName() + ' option requires string value \'skipWithFunction\' or \'skipWithLineBreak\''
);
this._mode = mode;
},
getOptionName: function() {
return 'requireAlignedObjectValues';
},
check: function(file, errors) {
var tokens = file.getTokens();
var mode = this._mode;
file.iterateNodesByType('ObjectExpression', function(node) {
if (node.loc.start.line === node.loc.end.line || node.properties < 2) {
return;
}
var skip = false;
var maxKeyEndPos = 0;
node.properties.forEach(function(property, index) {
var keyEndPos = property.key.loc.end.column;
if (keyEndPos > maxKeyEndPos) {
maxKeyEndPos = keyEndPos;
}
skip = skip || (mode === 'skipWithFunction' && property.value.type === 'FunctionExpression') ||
(mode === 'skipWithLineBreak' && index > 0 &&
node.properties[index - 1].loc.end.line !== property.loc.start.line - 1);
});
if (skip) {
return;
}
node.properties.forEach(function(property) {
var keyPos = file.getTokenPosByRangeStart(property.key.range[0]);
var colon = tokens[keyPos + 1];
if (colon.loc.start.column !== maxKeyEndPos + 1) {
errors.add('Alignment required', colon.loc.start);
}
});
});
}
};
},{"assert":44}],23:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(statementTypes) {
assert(Array.isArray(statementTypes), 'requireCurlyBraces option requires array value');
this._typeIndex = {};
for (var i = 0, l = statementTypes.length; i < l; i++) {
this._typeIndex[statementTypes[i]] = true;
}
},
getOptionName: function () {
return 'requireCurlyBraces';
},
check: function(file, errors) {
var typeIndex = this._typeIndex;
if (typeIndex['if'] || typeIndex['else']) {
file.iterateNodesByType('IfStatement', function (node) {
if (typeIndex.if && node.consequent && node.consequent.type !== 'BlockStatement') {
errors.add('If statement without curly braces', node.loc.start.line, node.loc.start.column);
}
if (typeIndex['else'] && node.alternate &&
node.alternate.type !== 'BlockStatement' &&
node.alternate.type !== 'IfStatement'
) {
errors.add(
'Else statement without curly braces',
node.alternate.loc.start.line,
node.alternate.loc.start.column
);
}
});
}
if (typeIndex['while']) {
file.iterateNodesByType('WhileStatement', function (node) {
if (node.body && node.body.type !== 'BlockStatement') {
errors.add('While statement without curly braces', node.loc.start.line, node.loc.start.column);
}
});
}
if (typeIndex['for']) {
file.iterateNodesByType('ForStatement', function (node) {
if (node.body && node.body.type !== 'BlockStatement') {
errors.add('For statement without curly braces', node.loc.start.line, node.loc.start.column);
}
});
file.iterateNodesByType('ForInStatement', function (node) {
if (node.body && node.body.type !== 'BlockStatement') {
errors.add('For in statement without curly braces', node.loc.start.line, node.loc.start.column);
}
});
}
if (typeIndex['do']) {
file.iterateNodesByType('DoWhileStatement', function (node) {
if (node.body && node.body.type !== 'BlockStatement') {
errors.add('Do while statement without curly braces', node.loc.start.line, node.loc.start.column);
}
});
}
}
};
},{"assert":44}],24:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(keywords) {
assert(Array.isArray(keywords), 'requireKeywordsOnNewLine option requires array value');
this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true;
}
},
getOptionName: function () {
return 'requireKeywordsOnNewLine';
},
check: function(file, errors) {
var keywordIndex = this._keywordIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Keyword' && keywordIndex[token.value]) {
var prevToken = tokens[i - 1];
if (prevToken && prevToken.loc.end.line === token.loc.start.line) {
errors.add(
'Keyword `' + token.value + '` should be placed on new line',
token.loc.start.line,
token.loc.start.column
);
}
}
}
}
};
},{"assert":44}],25:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'requireLeftStickedOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'requireLeftStickedOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Punctuator' && operators[token.value]) {
var prevToken = tokens[i - 1];
if (prevToken && prevToken.range[1] !== token.range[0]) {
errors.add(
'Operator ' + token.value + ' should stick to preceding expression',
token.loc.start
);
}
}
}
}
};
},{"assert":44}],26:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(requireLineFeedAtFileEnd) {
assert(
typeof requireLineFeedAtFileEnd === 'boolean',
'requireLineFeedAtFileEnd option requires boolean value'
);
assert(
requireLineFeedAtFileEnd === true,
'requireLineFeedAtFileEnd option requires true value or should be removed'
);
},
getOptionName: function () {
return 'requireLineFeedAtFileEnd';
},
check: function(file, errors) {
var lines = file.getLines();
if (lines[lines.length - 1] !== '') {
errors.add('Missing line feed at file end', lines.length, 0);
}
}
};
},{"assert":44}],27:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(requireMultipleVarDecl) {
assert(
typeof requireMultipleVarDecl === 'boolean',
'requireMultipleVarDecl option requires boolean value'
);
assert(
requireMultipleVarDecl === true,
'requireMultipleVarDecl option requires true value or should be removed'
);
},
getOptionName: function () {
return 'requireMultipleVarDecl';
},
check: function(file, errors) {
file.iterateNodesByType('VariableDeclaration', function (node) {
var pos = node.parentCollection.indexOf(node);
if (pos < node.parentCollection.length - 1) {
var sibling = node.parentCollection[pos + 1];
if (sibling.type === 'VariableDeclaration') {
errors.add(
'Var declarations should be joined',
sibling.loc.start
);
}
}
});
}
};
},{"assert":44}],28:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'requireRightStickedOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'requireRightStickedOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Punctuator' && operators[token.value]) {
var nextToken = tokens[i + 1];
if (nextToken && nextToken.range[0] !== token.range[1]) {
errors.add(
'Operator ' + token.value + ' should stick to following expression',
token.loc.start
);
}
}
}
}
};
},{"assert":44}],29:[function(require,module,exports){
var assert = require('assert');
var tokenHelper = require('../token-helper');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'requireSpaceAfterBinaryOperators option requires array value');
this._operatorIndex = {};
for (var i = 0, l = operators.length; i < l; i++) {
this._operatorIndex[operators[i]] = true;
}
},
getOptionName: function () {
return 'requireSpaceAfterBinaryOperators';
},
check: function(file, errors) {
var operators = this._operatorIndex;
// 2 + 2, 2 == 2
file.iterateNodesByType(['BinaryExpression'], function (node) {
if (operators[node.operator]) {
// get token before right part of expression
var tokenBeforeRightPart = tokenHelper.getTokenByRangeStart(file, node.right.range[0] - 1, true);
if (tokenHelper.tokenIsPunctuator(tokenBeforeRightPart, node.operator)) {
errors.add(
'Operator ' + node.operator + ' should not stick to following expression',
tokenBeforeRightPart.loc.start
);
}
}
});
}
};
},{"../token-helper":41,"assert":44}],30:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(keywords) {
assert(Array.isArray(keywords), 'requireSpaceAfterKeywords option requires array value');
this._keywordIndex = {};
for (var i = 0, l = keywords.length; i < l; i++) {
this._keywordIndex[keywords[i]] = true;
}
},
getOptionName: function () {
return 'requireSpaceAfterKeywords';
},
check: function(file, errors) {
var keywordIndex = this._keywordIndex;
var tokens = file.getTokens();
for (var i = 0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if (token.type === 'Keyword' && 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
);
}
}
}
}
}
};
},{"assert":44}],31:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(requireSpaceAfterObjectKeys) {
assert(
typeof requireSpaceAfterObjectKeys === 'boolean',
this.getOptionName() + ' option requires boolean value'
);
assert(
requireSpaceAfterObjectKeys === true,
this.getOptionName() + ' option requires true value or should be removed'
);
},
getOptionName: function() {
return 'requireSpaceAfterObjectKeys';
},
check: function(file, errors) {
var tokens = file.getTokens();
file.iterateNodesByType('ObjectExpression', function(node) {
node.properties.forEach(function(property) {
var key = property.key;
var keyPos = file.getTokenPosByRangeStart(key.range[0]);
var colon = tokens[keyPos + 1];
if (colon.range[0] === key.range[1]) {
errors.add('Missing space after key', key.loc.end);
}
});
});
}
};
},{"assert":44}],32:[function(require,module,exports){
var assert = require('assert');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), this.getOptionName() + ' option requires array value');
this._operators = operators.slice(0);
},
getOptionName: function () {
return 'requireSpaceAfterPrefixUnaryOperators';
},
check: function(file, errors) {
var operators = this._operators;
file.iterateNodesByType(['UnaryExpression', 'UpdateExpression'], function (node) {
// Check "node.prefix" for prefix type of (inc|dec)rement
if (node.prefix && operators.indexOf(node.operator) !== -1) {
if ((node.range[0] + node.operator.length) === node.argument.range[0]) {
errors.add('Operator ' + node.operator + ' should not stick to operand', node.loc.start);
}
}
});
}
};
},{"assert":44}],33:[function(require,module,exports){
var assert = require('assert');
var tokenHelper = require('../token-helper');
module.exports = function() {};
module.exports.prototype = {
configure: function(operators) {
assert(Array.isArray(operators), 'requireSpaceBeforeBinaryOperators option requires array value');
this._operatorIndex = {};