Socket
Socket
Sign inDemoInstall

eslint

Package Overview
Dependencies
Maintainers
1
Versions
367
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint - npm Package Compare versions

Comparing version 0.10.0-alpha.2 to 0.10.0

lib/token-store.js

2

conf/environments.json

@@ -83,2 +83,3 @@ {

"Element": false,
"Event": false,
"FileReader": false,

@@ -421,2 +422,3 @@ "find": false,

"pending": false,
"runs": false,
"spyOn": false,

@@ -423,0 +425,0 @@ "waits": false,

24

lib/cli-engine.js
/**
* @fileoverview Main CLI object.
* @author Nicholas C. Zakas
* @copyright 2014 Nicholas C. Zakas. All rights reserved.
*/

@@ -45,2 +46,3 @@

* @property {string[]} globals An array of global variables to declare.
* @property {string[]} extensions An array of file extensions to check.
* @property {Object<string,*>} rules An object of rules to use.

@@ -76,2 +78,3 @@ * @property {string} ignorePath The ignore file to use instead of .eslintignore.

rules: {},
extensions: [".js"],
ignore: true,

@@ -215,4 +218,5 @@ ignorePath: null

processed = [],
configHelper = new Config(this.options),
ignoredPaths = IgnoredPaths.load(this.options),
options = this.options,
configHelper = new Config(options),
ignoredPaths = IgnoredPaths.load(options),
exclude = ignoredPaths.contains.bind(ignoredPaths);

@@ -222,3 +226,4 @@

files: files,
exclude: this.options.ignore ? exclude : false
extensions: options.extensions,
exclude: options.ignore ? exclude : false
}, function(filename) {

@@ -228,13 +233,10 @@

if (path.extname(filename) === ".js") {
processed.push(filename);
results.push(processFile(filename, configHelper));
}
processed.push(filename);
results.push(processFile(filename, configHelper));
});
// only warn for files explicitly passes on the command line
if (this.options.ignore) {
// only warn for files explicitly passed on the command line
if (options.ignore) {
files.forEach(function(file) {
if (path.extname(file) === ".js" && processed.indexOf(file) === -1) {
if (fs.statSync(path.resolve(file)).isFile() && processed.indexOf(file) === -1) {
results.push({

@@ -241,0 +243,0 @@ filePath: file,

@@ -42,2 +42,3 @@ /**

envs: cliOptions.env,
extensions: cliOptions.ext,
rules: cliOptions.rule,

@@ -44,0 +45,0 @@ plugins: cliOptions.plugin,

/**
* @fileoverview Main ESLint object.
* @author Nicholas C. Zakas
* @copyright 2013 Nicholas C. Zakas. All rights reserved.
*/

@@ -12,4 +11,4 @@ "use strict";

var esprima = require("esprima-fb"),
estraverse = require("estraverse-fb"),
var esprima = require("esprima"),
estraverse = require("estraverse"),
escope = require("escope"),

@@ -20,8 +19,6 @@ environments = require("../conf/environments.json"),

util = require("./util"),
attachComments = require("./util/attach-comments"),
Validator = require("./util/validator"),
RuleContext = require("./rule-context"),
timing = require("./timing"),
EventEmitter = require("events").EventEmitter,
createDebug = require("debug");
createTokenStore = require("./token-store.js"),
EventEmitter = require("events").EventEmitter;

@@ -32,4 +29,2 @@ //------------------------------------------------------------------------------

var debug = createDebug("eslint:linter");
function escapeRegExp(rx) {

@@ -381,4 +376,3 @@ return rx.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");

commentLocsEnter = [],
commentLocsExit = [],
validator;
commentLocsExit = [];

@@ -401,4 +395,3 @@ /**

try {
debug("Parsing text");
var ast = esprima.parse(text, {
return esprima.parse(text, {
loc: true,

@@ -408,10 +401,7 @@ range: true,

tokens: true,
comment: true
comment: true,
attachComment: true
});
} catch (ex) {
attachComments(ast, ast.comments, ast.tokens);
return ast;
} catch (ex) {
debug("Parse failed: " + ex.message);
messages.push({

@@ -521,3 +511,2 @@ fatal: true,

commentLocsExit = [];
validator = null;
};

@@ -538,4 +527,3 @@

var ast,
shebang,
validatorOptions = {};
shebang;

@@ -559,10 +547,2 @@ // set the current parsed filename

// get settings information for ECMAScript version and JSX
if (typeof config.settings.ecmascript === "number" && config.settings.ecmascript > 5) {
validatorOptions.ecmascript = config.settings.ecmascript;
}
validatorOptions.jsx = !!config.settings.jsx;
validator = new Validator(validatorOptions);
// parse global comments and modify config

@@ -635,9 +615,5 @@ modifyConfigsFromComments(ast, config, reportingConfig);

/* get all tokens from the ast and store them as a hashtable to
* improve traversal speed when wanting to find tokens for a given
* node
*/
currentTokens = [];
ast.tokens.forEach(function(token) {
currentTokens[token.range[0]] = token;
currentTokens = createTokenStore(ast.tokens);
Object.keys(currentTokens).forEach(function(method) {
api[method] = currentTokens[method];
});

@@ -665,26 +641,6 @@

var comments = api.getComments(node),
validation;
var comments = api.getComments(node);
debug("Starting traversal");
emitCommentsEnter(comments.leading);
node.parent = parent;
validation = validator.validate(node);
if (!validation.valid) {
messages.push({
fatal: true,
severity: 2,
message: validation.message,
node: node,
line: validation.line,
column: validation.column
});
// no further parsing should happen
this.break();
}
api.emit(node.type, node);

@@ -869,173 +825,2 @@ emitCommentsEnter(comments.trailing);

/**
* Gets a number of tokens that precede a given node's tokens in the token stream.
* @param {ASTNode} node The AST node.
* @param {int} [beforeCount=0] The number of tokens before the node to retrieve.
* @returns {[Token]} Array of objects representing tokens.
*/
api.getTokensBefore = function(node, beforeCount) {
var beforeTokens = [], cursor = node.range[0] - 1;
while (beforeCount > 0 && cursor >= 0) {
if (currentTokens[cursor]) {
beforeTokens.unshift(currentTokens[cursor]);
--beforeCount;
}
--cursor;
}
return beforeTokens;
};
/**
* Gets the token that precedes a given node's tokens in the token stream.
* @param {ASTNode} node The AST node.
* @param {int} [skip=0] A number of tokens to skip before the given node.
* @returns {Token} An object representing the token.
*/
api.getTokenBefore = function(node, skip) {
for (var cursor = node.range[0] - 1; cursor >= 0; --cursor) {
if (currentTokens[cursor]) {
if (skip > 0) {
--skip;
} else {
return currentTokens[cursor];
}
}
}
};
/**
* Gets a number of tokens that precede a given node's tokens in the token stream.
* @param {ASTNode} node The AST node.
* @param {int} [afterCount=0] The number of tokens after the node to retrieve.
* @returns {[Token]} Array of objects representing tokens.
*/
api.getTokensAfter = function(node, afterCount) {
var afterTokens = [], cursor = node.range[1];
while (afterCount > 0 && cursor < currentTokens.length) {
if (currentTokens[cursor]) {
afterTokens.push(currentTokens[cursor]);
--afterCount;
cursor = currentTokens[cursor].range[1];
} else {
++cursor;
}
}
return afterTokens;
};
/**
* Gets the token that follows a given node's tokens in the token stream.
* @param {ASTNode} node The AST node.
* @param {int} [skip=0] A number of tokens to skip after the given node.
* @returns {Token} An object representing the token.
*/
api.getTokenAfter = function(node, skip) {
for (var cursor = node.range[1]; cursor < currentTokens.length; ++cursor) {
if (currentTokens[cursor]) {
if (skip > 0) {
--skip;
} else {
return currentTokens[cursor];
}
}
}
};
/**
* Gets all tokens that are related to the given node.
* @param {ASTNode} node The AST node.
* @param {int} [beforeCount=0] The number of tokens before the node to retrieve.
* @param {int} [afterCount=0] The number of tokens after the node to retrieve.
* @returns {[Token]} Array of objects representing tokens.
*/
api.getTokens = function(node, beforeCount, afterCount) {
var beforeTokens = api.getTokensBefore(node, beforeCount),
afterTokens = api.getTokensAfter(node, afterCount),
tokens = [],
cursor = node.range[0];
while (cursor < node.range[1]) {
if (currentTokens[cursor]) {
tokens.push(currentTokens[cursor]);
cursor = currentTokens[cursor].range[1];
} else {
++cursor;
}
}
return beforeTokens.concat(tokens, afterTokens);
};
/**
* Gets the first `count` tokens of the given node's token stream.
* @param {ASTNode} node The AST node.
* @param {int} [count=0] The number of tokens of the node to retrieve.
* @returns {[Token]} Array of objects representing tokens.
*/
api.getFirstTokens = function(node, count) {
var tokens = [], cursor = node.range[0];
while (count > 0 && cursor < node.range[1]) {
if (currentTokens[cursor]) {
tokens.push(currentTokens[cursor]);
--count;
cursor = currentTokens[cursor].range[1];
} else {
++cursor;
}
}
return tokens;
};
/**
* Gets the first token of the given node's token stream.
* @param {ASTNode} node The AST node.
* @param {int} [skip=0] A number of tokens to skip.
* @returns {Token} An object representing the token.
*/
api.getFirstToken = function(node, skip) {
for (var cursor = node.range[0]; cursor < node.range[1]; ++cursor) {
if (currentTokens[cursor]) {
if (skip > 0) {
--skip;
} else {
return currentTokens[cursor];
}
}
}
};
/**
* Gets the last `count` tokens of the given node.
* @param {ASTNode} node The AST node.
* @param {int} [count=0] The number of tokens of the node to retrieve.
* @returns {[Token]} Array of objects representing tokens.
*/
api.getLastTokens = function(node, count) {
var tokens = [], cursor = node.range[1] - 1;
while (count > 0 && cursor >= node.range[0]) {
if (currentTokens[cursor]) {
tokens.unshift(currentTokens[cursor]);
--count;
}
--cursor;
}
return tokens;
};
/**
* Gets the last token of the given node's token stream.
* @param {ASTNode} node The AST node.
* @param {int} [skip=0] A number of tokens to skip.
* @returns {Token} An object representing the token.
*/
api.getLastToken = function(node, skip) {
for (var cursor = node.range[1] - 1; cursor >= node.range[0]; --cursor) {
if (currentTokens[cursor]) {
if (skip > 0) {
--skip;
} else {
return currentTokens[cursor];
}
}
}
};
/**
* Gets nodes that are ancestors of current node.

@@ -1042,0 +827,0 @@ * @returns {ASTNode[]} Array of objects representing ancestors.

@@ -15,2 +15,23 @@ /**

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Returns an array of entries for a directory. If there's an error, then an
* empty array is returned instead. The try-catch is moved out here to avoid
* performance penalty of having it in the findInDirectory() method.
* @param {string} directory The directory to search in.
* @returns {string[]} The filenames in the directory or an empty array on error.
* @private
*/
function getDirectoryEntries(directory) {
try {
return fs.readdirSync(directory);
} catch (ex) {
return [];
}
}
//------------------------------------------------------------------------------
// API

@@ -54,4 +75,5 @@ //------------------------------------------------------------------------------

files = fs.readdirSync(lookInDirectory);
files = getDirectoryEntries(lookInDirectory);
if (files.indexOf(lookFor) !== -1) {

@@ -58,0 +80,0 @@ isFound = true;

@@ -63,2 +63,7 @@ /**

}, {
option: "ext",
type: "[String]",
default: ".js",
description: "Specify JavaScript file extensions."
}, {
option: "plugin",

@@ -65,0 +70,0 @@ type: "[String]",

@@ -23,2 +23,3 @@ /**

"getLastToken",
"getTokensBetween",
"getComments",

@@ -25,0 +26,0 @@ "getAncestors",

@@ -142,2 +142,8 @@ /**

validateCommaSpacing(node, "params");
},
"CallExpression": function(node) {
validateCommaSpacing(node, "arguments");
},
"NewExpression": function(node) {
validateCommaSpacing(node, "arguments");
}

@@ -144,0 +150,0 @@ };

@@ -56,3 +56,3 @@ /**

function getOperatorLocation(node) {
var opToken = context.getTokens(node)[context.getTokens(node.left).length];
var opToken = context.getTokenAfter(node.left);
return {line: opToken.loc.start.line, column: opToken.loc.start.column};

@@ -59,0 +59,0 @@ }

@@ -10,2 +10,4 @@ /**

var CAPS_ALLOWED = [
"Object",
"Function",
"Number",

@@ -12,0 +14,0 @@ "String",

@@ -19,10 +19,14 @@ /**

function checkForTrailingComma(node) {
var secondToLastToken = context.getLastTokens(node, 2)[0];
var items = node.properties || node.elements,
length = items.length,
lastItem, penultimateToken;
var items = node.properties || node.elements,
lastItem = items[items.length - 1];
// The last token in an object/array literal will always be a closing
// curly, so we check the second to last token for a comma.
if (secondToLastToken.value === "," && items.length && lastItem) {
context.report(lastItem, secondToLastToken.loc.start, "Trailing comma.");
if (length) {
lastItem = items[length - 1];
if (lastItem) {
penultimateToken = context.getLastToken(node, 1);
if (penultimateToken.value === ",") {
context.report(lastItem, penultimateToken.loc.start, "Trailing comma.");
}
}
}

@@ -29,0 +33,0 @@ }

/**
* @fileoverview Rule to flag assignment in a conditional expression
* @fileoverview Rule to flag assignment in a conditional statement's test expression
* @author Stephen Murray <spmurrayzzz>

@@ -7,2 +7,9 @@ */

var NODE_DESCRIPTIONS = {
"DoWhileStatement": "a 'do...while' statement",
"ForStatement": "a 'for' statement",
"IfStatement": "an 'if' statement",
"WhileStatement": "a 'while' statement"
};
//------------------------------------------------------------------------------

@@ -14,2 +21,37 @@ // Rule Definition

var prohibitAssign = (context.options[0] || "except-parens");
/**
* Check whether an AST node is the test expression for a conditional statement.
* @param {!Object} node The node to test.
* @returns {boolean} `true` if the node is the text expression for a conditional statement; otherwise, `false`.
*/
function isConditionalTestExpression(node) {
return node.parent &&
node.parent.test &&
node === node.parent.test;
}
/**
* Given an AST node, perform a bottom-up search for the first ancestor that represents a conditional statement.
* @param {!Object} node The node to use at the start of the search.
* @returns {?Object} The closest ancestor node that represents a conditional statement.
*/
function findConditionalAncestor(node) {
var currentAncestor = node;
while ((currentAncestor = currentAncestor.parent)) {
if (isConditionalTestExpression(currentAncestor)) {
return currentAncestor.parent;
}
}
return null;
}
/**
* Check whether the code represented by an AST node is enclosed in parentheses.
* @param {!Object} node The node to test.
* @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`.
*/
function isParenthesised(node) {

@@ -23,2 +65,7 @@ var previousToken = context.getTokenBefore(node),

/**
* Check whether the code represented by an AST node is enclosed in two sets of parentheses.
* @param {!Object} node The node to test.
* @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`.
*/
function isParenthesisedTwice(node) {

@@ -33,4 +80,10 @@ var previousToken = context.getTokenBefore(node, 1),

/**
* Check a conditional statement's test expression for top-level assignments that are not enclosed in parentheses.
* @param {!Object} node The node for the conditional statement.
* @returns {void}
*/
function testForAssign(node) {
if (node.test && (node.test.type === "AssignmentExpression") && !isParenthesisedTwice(node.test)) {
// must match JSHint's error message
context.report(node, "Expected a conditional expression and instead saw an assignment.");

@@ -40,9 +93,30 @@ }

/**
* Check whether an assignment expression is descended from a conditional statement's test expression.
* @param {!Object} node The node for the assignment expression.
* @returns {void}
*/
function testForConditionalAncestor(node) {
var ancestor = findConditionalAncestor(node);
if (ancestor) {
context.report(ancestor, "Unexpected assignment within {{type}}.", {
type: NODE_DESCRIPTIONS[ancestor.type] || ancestor.type
});
}
}
if (prohibitAssign === "always") {
return {
"AssignmentExpression": testForConditionalAncestor
};
}
return {
"DoWhileStatement": testForAssign,
"ForStatement": testForAssign,
"IfStatement": testForAssign,
"WhileStatement": testForAssign,
"DoWhileStatement": testForAssign,
"ForStatement": testForAssign
"WhileStatement": testForAssign
};
};

@@ -27,17 +27,17 @@ /**

switch (node.type) {
case "Literal":
case "FunctionExpression":
case "ObjectExpression":
case "ArrayExpression":
return true;
case "UnaryExpression":
return isConstant(node.argument);
case "BinaryExpression":
case "LogicalExpression":
return isConstant(node.left) && isConstant(node.right);
case "AssignmentExpression":
return isConstant(node.right);
case "SequenceExpression":
return isConstant(node.expressions[node.expressions.length - 1]);
// no default
case "Literal":
case "FunctionExpression":
case "ObjectExpression":
case "ArrayExpression":
return true;
case "UnaryExpression":
return isConstant(node.argument);
case "BinaryExpression":
case "LogicalExpression":
return isConstant(node.left) && isConstant(node.right);
case "AssignmentExpression":
return isConstant(node.right);
case "SequenceExpression":
return isConstant(node.expressions[node.expressions.length - 1]);
// no default
}

@@ -44,0 +44,0 @@ return false;

@@ -17,12 +17,6 @@ /**

"Literal": function(node) {
var token = context.getFirstTokens(node, 1)[0],
nodeType = token.type,
source;
var token = context.getFirstToken(node);
if (nodeType === "RegularExpression") {
source = context.getFirstTokens(node, 1)[0].value;
if (source[1] === "=") {
context.report(node, "A regular expression literal can be confused with '/='.");
}
if (token.type === "RegularExpression" && token.value[1] === "=") {
context.report(node, "A regular expression literal can be confused with '/='.");
}

@@ -29,0 +23,0 @@ }

@@ -7,2 +7,20 @@ /**

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/*
plain-English description of the following regexp:
0. `^` fix the match at the beginning of the string
1. `\/`: the `/` that begins the regexp
2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
2.1. `\\.`: an escape sequence
2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
3. `\/` the `/` that ends the regexp
4. `[gimy]*`: optional regexp flags
5. `$`: fix the match at the end of the string
*/
var regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimy]*$/;
//------------------------------------------------------------------------------
// Rule Definition

@@ -18,21 +36,6 @@ //------------------------------------------------------------------------------

"Literal": function(node) {
var tokens = context.getTokens(node);
tokens.forEach(function (token) {
/*
plain-English description of the following regexp:
0. `^` fix the match at the beginning of the string
1. `\/`: the `/` that begins the regexp
2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
2.1. `\\.`: an escape sequence
2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
3. `\/` the `/` that ends the regexp
4. `[gimy]*`: optional regexp flags
5. `$`: fix the match at the end of the string
*/
if (token.type === "RegularExpression" &&
!/^\/([^\\[]|\\.|\[([^\\\]]|\\.)+\])*\/[gimy]*$/.test(token.value)) {
context.report(node, "Empty class.");
}
});
var token = context.getFirstToken(node);
if (token.type === "RegularExpression" && !regex.test(token.value)) {
context.report(node, "Empty class.");
}
}

@@ -39,0 +42,0 @@

@@ -43,4 +43,11 @@ /**

// unless the user doesn't like semicolons, in which case it's first leading comment of this case
if (!comment) {
comments = context.getComments(node).leading;
comment = comments[comments.length - 1];
}
// check for comment
if (!comment || !FALLTHROUGH_COMMENT.test(comment.value)) {
context.report(switchData.lastCase,

@@ -47,0 +54,0 @@ "Expected a \"break\" statement before \"{{code}}\".",

@@ -26,3 +26,3 @@ /**

var preamble = startLine.slice(0,node.loc.start.column).trim();
var preamble = startLine.slice(0, node.loc.start.column).trim();

@@ -29,0 +29,0 @@ // Also check after the comment

@@ -5,2 +5,3 @@ /**

* @copyright 2014 Vignesh Anand. All rights reserved.
* @copyright 2014 Brandon Mills. All rights reserved.
*/

@@ -10,2 +11,50 @@ "use strict";

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
var OPERATORS = {
"Punctuator": {
"*": true, "/": true, "%": true, "+": true, "-": true, "<<": true,
">>": true, ">>>": true, "<": true, "<=": true, ">": true, ">=": true,
"==": true, "!=": true, "===": true, "!==": true, "&": true, "^": true,
"|": true, "&&": true, "||": true, "=": true, "+=": true, "-=": true,
"*=": true, "/=": true, "%=": true, "<<=": true, ">>=": true,
">>>=": true, "&=": true, "^=": true, "|=": true, "?": true, ":": true,
",": true
},
"Keyword": {
"in": true,
"instanceof": true
}
};
/**
* Determines whether a token is a binary operator.
* @param {Token} token The token.
* @returns {Boolean} Whether the token is a binary operator.
*/
function isOperator(token) {
var type = OPERATORS[token.type];
return (type && type[token.value]) || false;
}
/**
* Gets the index of the first element of an array that satisfies a predicate.
* Like Array.prototype.indexOf(), but with a predicate instead of equality.
* @param {Array} array An array to search.
* @param {Function} predicate A function returning true if its argument
* satisfies a condition.
* @returns {Number} The index of the first element that satisifies
* the predicate, or -1 if no elements match.
*/
function findIndex(array, predicate) {
for (var i = 0, l = array.length; i < l; i++) {
if (predicate(array[i])) {
return i;
}
}
return -1;
}
//------------------------------------------------------------------------------
// Rule Definition

@@ -16,76 +65,38 @@ //------------------------------------------------------------------------------

var OPERATORS = [
"*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", "<=", ">", ">=", "in",
"instanceof", "==", "!=", "===", "!==", "&", "^", "|", "&&", "||", "=",
"+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "^=", "|=",
"?", ":", ","
], errOps = [];
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
/**
* Reports an AST node as a rule violation.
* @param {ASTNode} node The node to report.
* Validates that two adjacent tokens are separated by less than two spaces.
* @param {Token} left Token on the left side.
* @param {Token} right Token on the right side.
* @returns {void}
* @private
*/
function report(node) {
context.report(node, "Multiple spaces found around '" + errOps.shift() + "'.");
}
function validate(left, right) {
var op;
/**
* Checks whether the operator is in same line as two adjacent tokens.
* @param {ASTNode} left The token left to the operator.
* @param {ASTNode} right The token right to the operator.
* @param {ASTNode} operator The operator.
* @returns {boolean} Whether the operator is in same line as two adjacent tokens.
* @private
*/
function isSameLine(left, right, operator) {
return operator.loc.end.line === left.loc.end.line &&
operator.loc.end.line === right.loc.start.line;
if (
left.loc.end.line === right.loc.start.line &&
right.range[0] - left.range[1] > 1
) {
op = isOperator(left) ? left : right;
context.report(op, "Multiple spaces found {{side}} '{{op}}'.", {
side: op === right ? "before" : "after",
op: op.value
});
}
}
/**
* Check whether there are multiple spaces around the operator.
* @param {ASTNode} left The token left to the operator.
* @param {ASTNode} right The token right to the operator.
* @param {ASTNode} operator The operator.
* @returns {boolean} Whether there are multiple spaces.
* @private
* Validates the spacing of two nodes with an operator between them.
* @param {ASTNode} left Node left of the operator.
* @param {ASTNode} right Node right of the operator.
* @returns {void}
*/
function isMultiSpaced(left, right, operator) {
return operator.range[0] - left.range[1] > 1 ||
right.range[0] - operator.range[1] > 1;
}
function validateBetween(left, right) {
var tokens = context.getTokensBetween(left, right, 1),
operatorIndex = findIndex(tokens, isOperator),
op = tokens[operatorIndex];
/**
* Get tokens and validate the spacing.
* @param {ASTNode} left The token left to the operator.
* @param {ASTNode} right The token right to the operator.
* @returns {boolean} Whether multiple spaces were found.
* @private
*/
function validateSpacing(left, right) {
var tokens = context.getTokens({range: [left.range[1], right.range[0]]}, 1, 1),
operator;
for (var i = 1, l = tokens.length - 1; i < l; ++i) {
left = tokens[i - 1];
operator = tokens[i];
right = tokens[i + 1];
if (operator && operator.type === "Punctuator" && OPERATORS.indexOf(operator.value) >= 0 &&
isSameLine(left, right, operator) && isMultiSpaced(left, right, operator)) {
errOps.push(operator.value);
return true;
}
}
return false;
validate(tokens[operatorIndex - 1], op);
validate(op, tokens[operatorIndex + 1]);
}
/**

@@ -98,5 +109,3 @@ * Report if there are multiple spaces on the expression.

function checkExpression(node) {
if (validateSpacing(node.left, node.right)) {
report(node);
}
validateBetween(node.left, node.right);
}

@@ -111,8 +120,4 @@

function checkConditional(node) {
if (validateSpacing(node.test, node.consequent)) {
report(node);
}
if (validateSpacing(node.consequent, node.alternate)) {
report(node);
}
validateBetween(node.test, node.consequent);
validateBetween(node.consequent, node.alternate);
}

@@ -127,4 +132,4 @@

function checkVar(node) {
if (node.init && validateSpacing(node.id, node.init)) {
report(node);
if (node.init) {
validateBetween(node.id, node.init);
}

@@ -134,22 +139,62 @@ }

/**
* Report if there are multiple spaces around list of items in objects, arrays,
* function parameters, sequences and declarations.
* @param {ASTNode} node The node to check.
* @param {string} property The property of node.
* Generates a function to check object literals and other list-like nodes.
* @param {String} property Name of the node's collection property.
* @returns {Function} A function that checks spacing within list-like node.
* @private
*/
function checkList(property) {
/**
* Report if there are multiple spaces around list of items in objects,
* function parameters, sequences and declarations.
* @param {ASTNode} node The node to check.
* @returns {void}
* @private
*/
return function(node) {
var items = node[property];
for (var i = 0, l = items.length; i < l - 1; i++) {
validateBetween(items[i], items[i + 1]);
}
};
}
/**
* Checks arrays literals, allowing that some elements may be empty.
* @param {ASTNode} node An ArrayExpression.
* @returns {void}
* @private
*/
function checkList(node, property) {
var items = node[property];
function checkArray(node) {
var elements = node.elements,
elementIndex = 0,
tokens = context.getTokens(node),
tokenIndex = 0,
length = tokens.length,
dest;
for (var i = 0, l = items.length; i < l; i++) {
var left = items[i - 1],
right = items[i],
operator = context.getTokenBefore(right);
// Check spacing at the beginning, around commas, and at the end
while (tokenIndex < length - 1) {
validate(tokens[tokenIndex], tokens[++tokenIndex]);
if (operator && operator.type === "Punctuator" && operator.value === ",") {
if (isSameLine(left, right, operator) && isMultiSpaced(left, right, operator)) {
errOps.push(operator.value);
report(right);
// Don't advance to the next element until both sides of the comma
// have been checked
if (tokens[tokenIndex].value !== ",") {
// Skip to just before the end of the array or the next comma
if (elements[elementIndex]) {
dest = elements[elementIndex].range[1];
// Move to the end of the element
while (tokens[tokenIndex].range[1] < dest) {
++tokenIndex;
}
// Move past anything (like closing parens) between the end
// of the node and the following comma or end brace.
while (
tokenIndex + 1 < tokens.length &&
tokens[tokenIndex + 1].value !== ","
) {
++tokenIndex;
}
}
++elementIndex;
}

@@ -169,22 +214,10 @@ }

"VariableDeclarator": checkVar,
"ArrayExpression": function(node) {
checkList(node, "elements");
},
"ObjectExpression": function(node) {
checkList(node, "properties");
},
"SequenceExpression": function(node) {
checkList(node, "expressions");
},
"FunctionExpression": function(node) {
checkList(node, "params");
},
"FunctionDeclaration": function(node) {
checkList(node, "params");
},
"VariableDeclaration": function(node) {
checkList(node, "declarations");
}
"ArrayExpression": checkArray,
"ObjectExpression": checkList("properties"),
"SequenceExpression": checkList("expressions"),
"FunctionExpression": checkList("params"),
"FunctionDeclaration": checkList("params"),
"VariableDeclaration": checkList("declarations")
};
};

@@ -41,3 +41,3 @@ /**

lastLocation = currentLocation;
currentLocation = trimmedLines.indexOf("",currentLocation + 1);
currentLocation = trimmedLines.indexOf("", currentLocation + 1);
if (lastLocation === currentLocation - 1) {

@@ -44,0 +44,0 @@ blankCounter++;

@@ -17,3 +17,3 @@ /**

"Literal": function(node) {
var token = context.getFirstTokens(node, 1)[0],
var token = context.getFirstToken(node),
nodeType = token.type,

@@ -20,0 +20,0 @@ nodeValue = token.value,

@@ -38,2 +38,12 @@ /**

/**
* Checks if the given node is the argument of a typeof operator.
* @param {ASTNode} node The AST node being checked.
* @returns {boolean} Whether or not the node is the argument of a typeof operator.
*/
function hasTypeOfOperator(node) {
var parent = node.parent;
return parent.type === "UnaryExpression" && parent.operator === "typeof";
}
//------------------------------------------------------------------------------

@@ -47,3 +57,3 @@ // Rule Definition

"Program": function(/*node*/) {
"Program:exit": function(/*node*/) {

@@ -55,2 +65,7 @@ var globalScope = context.getScope();

name = ref.identifier.name;
if (hasTypeOfOperator(ref.identifier)) {
return;
}
if (!variable) {

@@ -57,0 +72,0 @@ context.report(ref.identifier, "'{{name}}' is not defined.", { name: name });

/**
* @fileoverview Rule to flag wrapping none-iffe in parens
* @fileoverview Rule to flag wrapping non-iife in parens
* @author Ilya Volodin

@@ -4,0 +4,0 @@ */

@@ -65,8 +65,8 @@ /**

* @param {ASTNode} node - The node to report in the event of an error.
* @param {Object[]} tokens - The tokens to be checked for spacing.
* @param {Token} token - The token to use for the report.
* @returns {void}
*/
function reportNoBeginningSpace(node, tokens) {
context.report(node, tokens[0].loc.start,
"There should be no space after '" + tokens[0].value + "'");
function reportNoBeginningSpace(node, token) {
context.report(node, token.loc.start,
"There should be no space after '" + token.value + "'");
}

@@ -77,8 +77,8 @@

* @param {ASTNode} node - The node to report in the event of an error.
* @param {Object[]} tokens - The tokens to be checked for spacing.
* @param {Token} token - The token to use for the report.
* @returns {void}
*/
function reportNoEndingSpace(node, tokens) {
context.report(node, tokens[tokens.length - 1].loc.start,
"There should be no space before '" + tokens[tokens.length - 1].value + "'");
function reportNoEndingSpace(node, token) {
context.report(node, token.loc.start,
"There should be no space before '" + token.value + "'");
}

@@ -89,8 +89,8 @@

* @param {ASTNode} node - The node to report in the event of an error.
* @param {Object[]} tokens - The tokens to be checked for spacing.
* @param {Token} token - The token to use for the report.
* @returns {void}
*/
function reportRequiredBeginningSpace(node, tokens) {
context.report(node, tokens[0].loc.start,
"A space is required after '" + tokens[0].value + "'");
function reportRequiredBeginningSpace(node, token) {
context.report(node, token.loc.start,
"A space is required after '" + token.value + "'");
}

@@ -101,8 +101,8 @@

* @param {ASTNode} node - The node to report in the event of an error.
* @param {Object[]} tokens - The tokens to be checked for spacing.
* @param {Token} token - The token to use for the report.
* @returns {void}
*/
function reportRequiredEndingSpace(node, tokens) {
context.report(node, tokens[tokens.length - 1].loc.start,
"A space is required before '" + tokens[tokens.length - 1].value + "'");
function reportRequiredEndingSpace(node, token) {
context.report(node, token.loc.start,
"A space is required before '" + token.value + "'");
}

@@ -117,27 +117,30 @@

MemberExpression: function checkMember(node) {
MemberExpression: function(node) {
if (!node.computed) {
return;
}
var tokens = context.getTokens(node.property, 1, 1);
var tokenA = tokens[0], tokenB = tokens[1],
tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
var property = node.property,
before = context.getTokenBefore(property),
first = context.getFirstToken(property),
last = context.getLastToken(property),
after = context.getTokenAfter(property);
var propertyNameMustBeSpaced = options.propertyNameException ?
!options.spaced : options.spaced;
if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
if (isSameLine(before, first) || isSameLine(last, after)) {
if (propertyNameMustBeSpaced) {
if (!isSpaced(tokenA, tokenB) && isSameLine(tokenA, tokenB)) {
reportRequiredBeginningSpace(node, tokens);
if (!isSpaced(before, first) && isSameLine(before, first)) {
reportRequiredBeginningSpace(node, before);
}
if (!isSpaced(tokenC, tokenD) && isSameLine(tokenC, tokenD)) {
reportRequiredEndingSpace(node, tokens);
if (!isSpaced(last, after) && isSameLine(last, after)) {
reportRequiredEndingSpace(node, after);
}
} else {
if (isSpaced(tokenA, tokenB)) {
reportNoBeginningSpace(node, tokens);
if (isSpaced(before, first)) {
reportNoBeginningSpace(node, before);
}
if (isSpaced(tokenC, tokenD)) {
reportNoEndingSpace(node, tokens);
if (isSpaced(last, after)) {
reportNoEndingSpace(node, after);
}

@@ -147,2 +150,3 @@ }

},
ArrayExpression: function(node) {

@@ -152,9 +156,11 @@ if (node.elements.length === 0) {

}
var tokens = context.getTokens(node);
var tokenA = tokens[0], tokenB = tokens[1],
tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
var first = context.getFirstToken(node),
second = context.getFirstToken(node, 1),
penultimate = context.getLastToken(node, 1),
last = context.getLastToken(node);
var openingBracketMustBeSpaced =
options.objectsInArraysException && tokenB.value === "{" ||
options.arraysInArraysException && tokenB.value === "[" ||
options.objectsInArraysException && second.value === "{" ||
options.arraysInArraysException && second.value === "[" ||
options.singleElementException && node.elements.length === 1

@@ -164,19 +170,19 @@ ? !options.spaced : options.spaced;

var closingBracketMustBeSpaced =
options.objectsInArraysException && tokenC.value === "}" ||
options.arraysInArraysException && tokenC.value === "]" ||
options.objectsInArraysException && penultimate.value === "}" ||
options.arraysInArraysException && penultimate.value === "]" ||
options.singleElementException && node.elements.length === 1
? !options.spaced : options.spaced;
if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
if (openingBracketMustBeSpaced && !isSpaced(tokenA, tokenB)) {
reportRequiredBeginningSpace(node, tokens);
if (isSameLine(first, second) || isSameLine(penultimate, last)) {
if (openingBracketMustBeSpaced && !isSpaced(first, second)) {
reportRequiredBeginningSpace(node, first);
}
if (!openingBracketMustBeSpaced && isSpaced(tokenA, tokenB)) {
reportNoBeginningSpace(node, tokens);
if (!openingBracketMustBeSpaced && isSpaced(first, second)) {
reportNoBeginningSpace(node, first);
}
if (closingBracketMustBeSpaced && !isSpaced(tokenC, tokenD)) {
reportRequiredEndingSpace(node, tokens);
if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) {
reportRequiredEndingSpace(node, last);
}
if (!closingBracketMustBeSpaced && isSpaced(tokenC, tokenD)) {
reportNoEndingSpace(node, tokens);
if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) {
reportNoEndingSpace(node, last);
}

@@ -190,23 +196,25 @@ }

}
var tokens = context.getTokens(node);
var tokenA = tokens[0], tokenB = tokens[1],
tokenC = tokens[tokens.length - 2], tokenD = tokens[tokens.length - 1];
var first = context.getFirstToken(node),
second = context.getFirstToken(node, 1),
penultimate = context.getLastToken(node, 1),
last = context.getLastToken(node);
var closingCurlyBraceMustBeSpaced =
options.arraysInObjectsException && tokenC.value === "]" ||
options.objectsInObjectsException && tokenC.value === "}"
options.arraysInObjectsException && penultimate.value === "]" ||
options.objectsInObjectsException && penultimate.value === "}"
? !options.spaced : options.spaced;
if (isSameLine(tokenA, tokenB) || isSameLine(tokenC, tokenD)) {
if (options.spaced && !isSpaced(tokenA, tokenB)) {
reportRequiredBeginningSpace(node, tokens);
if (isSameLine(first, second) || isSameLine(penultimate, last)) {
if (options.spaced && !isSpaced(first, second)) {
reportRequiredBeginningSpace(node, first);
}
if (!options.spaced && isSpaced(tokenA, tokenB)) {
reportNoBeginningSpace(node, tokens);
if (!options.spaced && isSpaced(first, second)) {
reportNoBeginningSpace(node, first);
}
if (closingCurlyBraceMustBeSpaced && !isSpaced(tokenC, tokenD)) {
reportRequiredEndingSpace(node, tokens);
if (closingCurlyBraceMustBeSpaced && !isSpaced(penultimate, last)) {
reportRequiredEndingSpace(node, last);
}
if (!closingCurlyBraceMustBeSpaced && isSpaced(tokenC, tokenD)) {
reportNoEndingSpace(node, tokens);
if (!closingCurlyBraceMustBeSpaced && isSpaced(penultimate, last)) {
reportNoEndingSpace(node, last);
}

@@ -213,0 +221,0 @@ }

@@ -21,3 +21,3 @@ /**

function isSpaced(left, right) {
var op, tokens = context.getTokens({range: [left.range[1], right.range[0]]}, 1, 1);
var op, tokens = context.getTokensBetween(left, right, 1);
for (var i = 1, l = tokens.length - 1; i < l; ++i) {

@@ -24,0 +24,0 @@ op = tokens[i];

@@ -43,2 +43,7 @@ /**

// If length is zero, ignore it
if (node.value.length === 0) {
return;
}
// Space expected and not found

@@ -45,0 +50,0 @@ if (node.value.indexOf(" ") !== 0) {

@@ -25,2 +25,4 @@ /**

* @param {string} name The file or directory path.
* @param {string[]} extensions The file extensions that should cause the callback
* to be called.
* @param {Function} exclude The function to check if file/path should be excluded.

@@ -31,3 +33,3 @@ * @param {Function} callback The function to call on each file.

*/
function walk(name, exclude, callback) {
function walk(name, extensions, exclude, callback) {

@@ -59,3 +61,4 @@ var stat, basename;

if (fileStat.isFile()) {
// only call callback for files with correct extensions
if (fileStat.isFile() && extensions.indexOf(path.extname(filePath)) > -1) {
callback(filePath);

@@ -79,2 +82,3 @@ } else if (fileStat.isDirectory()) {

// always call callback for any files that are passed on the command line
if (stat.isFile()) {

@@ -98,8 +102,9 @@ callback(name);

var files = options.files,
exclude = options.exclude;
exclude = options.exclude,
extensions = options.extensions;
files.forEach(function(file) {
walk(file, exclude, callback);
walk(file, extensions, exclude, callback);
});
};
{
"name": "eslint",
"version": "0.10.0-alpha.2",
"version": "0.10.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",

@@ -39,9 +39,6 @@ "description": "An Esprima-based pattern checker for JavaScript.",

"debug": "^2.0.0",
"deepcopy": "^0.3.3",
"doctrine": "^0.5.2",
"doctrine": "^0.6.2",
"escope": "~1.0.0",
"esprima": "^1.2.2",
"esprima-fb": "^8001.1.0-dev-harmony-fb",
"estraverse": "~1.5.1",
"estraverse-fb": "^1.0.0",
"js-yaml": "~3.2.2",

@@ -67,3 +64,2 @@ "minimatch": "^1.0.0",

"jsonlint": "^1.6.2",
"leche": "^1.0.1",
"mocha": "~1.13.0",

@@ -70,0 +66,0 @@ "mocha-phantomjs": "^3.5.0",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc