Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint

Package Overview
Dependencies
Maintainers
1
Versions
372
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.3.0 to 0.4.0

lib/rules/consistent-return.js

2

bin/eslint.js
#!/usr/bin/env node
var cli = require("../lib/cli");
var exitCode = cli.execute(Array.prototype.slice.call(process.argv, 2));
var exitCode = cli.execute(process.argv);
process.exit(exitCode);

@@ -360,5 +360,7 @@ {

"rules": {
"no-console": 0,
"no-global-strict": 0,
"no-mixed-requires": 2,
"no-console": 0
"no-path-concat": 2,
"no-process-exit": 2
}

@@ -365,0 +367,0 @@ },

@@ -10,10 +10,12 @@ {

"no-alert": 2,
"no-array-constructor": 2,
"no-bitwise": 0,
"no-caller": 2,
"no-bitwise": 0,
"no-catch-shadow": 2,
"no-console": 2,
"no-comma-dangle": 2,
"no-cond-assign": 2,
"no-console": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-div-regex": 0,

@@ -24,62 +26,70 @@ "no-dupe-keys": 2,

"no-empty-class": 2,
"no-empty-label": 2,
"no-eq-null": 0,
"no-eval": 2,
"no-ex-assign": 2,
"no-extend-native": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": 0,
"no-extra-semi": 2,
"no-extra-strict": 2,
"no-fallthrough": 2,
"no-floating-decimal": 0,
"no-func-assign": 2,
"no-floating-decimal": 0,
"no-global-strict": 2,
"no-implied-eval": 2,
"no-invalid-regexp": 2,
"no-with": 2,
"no-fallthrough": 2,
"no-global-strict": 2,
"no-unreachable": 2,
"no-undef": 2,
"no-undef-init": 2,
"no-unused-expressions": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-obj-calls": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": 2,
"no-lone-blocks": 2,
"no-loop-func": 2,
"no-mixed-requires": [0, false],
"no-multi-str": 2,
"no-new-wrappers": 2,
"no-native-reassign": 2,
"no-negated-in-lhs": 2,
"no-nested-ternary": 0,
"no-new": 2,
"no-new-func": 2,
"no-native-reassign": 2,
"no-new-object": 2,
"no-new-wrappers": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-path-concat": 0,
"no-plusplus": 0,
"no-delete-var": 2,
"no-process-exit": 2,
"no-proto": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-return-assign": 2,
"no-nested-ternary": 0,
"no-new-array": 2,
"no-new-object": 2,
"no-label-var": 2,
"no-ternary": 0,
"no-script-url": 2,
"no-self-compare": 0,
"no-spaced-func": 1,
"no-shadow": 2,
"no-shadow-restricted-names": 2,
"no-spaced-func": 2,
"no-sparse-arrays": 2,
"no-sync": 0,
"no-ternary": 0,
"no-undef": 2,
"no-undef-init": 2,
"no-underscore-dangle": 2,
"no-loop-func": 2,
"no-empty-label": 2,
"no-unreachable": 2,
"no-unused-expressions": 2,
"no-unused-vars": [2, "local"],
"no-script-url": 2,
"no-proto": 2,
"no-iterator": 2,
"no-mixed-requires": [0, false],
"no-use-before-define": 2,
"no-with": 2,
"no-wrap-func": 2,
"no-shadow": 2,
"no-shadow-restricted-names": 2,
"no-use-before-define": 2,
"no-redeclare": 2,
"no-negated-in-lhs": 2,
"no-extend-native": 2,
"no-yoda": 2,
"block-scoped-var": 0,
"brace-style": 0,
"block-scoped-var": 0,
"camelcase": 2,
"complexity": [0, 11],
"consistent-return": 2,
"consistent-this": [0, "that"],
"curly": 2,
"curly": [2, "all"],
"dot-notation": 2,
"eqeqeq": 2,
"func-names": 0,
"func-style": [0, "declaration"],

@@ -95,13 +105,13 @@ "guard-for-in": 0,

"one-var": 0,
"quote-props": 0,
"quotes": [2, "double"],
"quote-props": 0,
"radix": 0,
"regex-spaces": 2,
"semi": 2,
"sort-vars": 0,
"space-infix-ops": 2,
"space-return-throw-case": 2,
"space-infix-ops": 2,
"space-unary-word-ops": 0,
"strict": 2,
"use-isnan": 2,
"valid-jsdoc": 0,
"wrap-iife": 0,

@@ -108,0 +118,0 @@ "wrap-regex": 0

@@ -89,5 +89,12 @@ /**

/**
* Outputs the results of the linting.
* @param {Config} config The configuration options for the results.
* @returns {boolean} True if the printing succeeds, false if not.
* @private
*/
function printResults(config) {
var formatter,
formatterPath;
formatterPath,
output;

@@ -102,6 +109,9 @@ if (existsSync(path.resolve(process.cwd(), config.format))) {

formatter = require(formatterPath);
console.log(formatter(results, config));
output = formatter(results, config);
if (output) {
console.log(output);
}
return true;
} catch (ex) {
console.log("Could not find formatter '%s'.", config.format);
console.error("Could not find formatter '%s'.", config.format);
return false;

@@ -203,22 +213,31 @@ }

* Executes the CLI based on an array of arguments that is passed in.
* @param {String[]} argv The array of arguments to process.
* @param {string|Array|Object} args The arguments to process.
* @returns {int} The exit code for the operation.
*/
execute: function(argv) {
execute: function(args) {
var currentOptions = options.parse(argv),
files = currentOptions._,
var currentOptions,
files,
configHelper,
result;
try {
currentOptions = options.parse(args);
} catch (error) {
console.error(error.message);
return 1;
}
files = currentOptions._;
// Ensure results from previous execution are not printed.
results = [];
if (currentOptions.v) { // version from package.json
if (currentOptions.version) { // version from package.json
console.log("v" + require("../package.json").version);
} else if (currentOptions.h || !files.length) {
} else if (currentOptions.help || !files.length) {
options.help();
console.log(options.generateHelp());

@@ -225,0 +244,0 @@ } else {

@@ -16,3 +16,4 @@ /**

glob = require("glob"),
stripComments = require("strip-json-comments");
stripComments = require("strip-json-comments"),
yaml = require("js-yaml");

@@ -37,3 +38,4 @@ var existsSync = fs.existsSync || path.existsSync;

* files and if so, load and parse them
* @param {string} directory path
* @param {string} directory The path to load from.
* @returns {string[]} An array of paths to exclude or an empty array.
*/

@@ -58,3 +60,3 @@ function loadIgnoreFile(directory) {

* @param {string} filePath the path to the JSON config file
* @return {object} the parsed config object (empty object if there was a parse error)
* @returns {Object} the parsed config object (empty object if there was a parse error)
*/

@@ -66,3 +68,3 @@ function loadConfig(filePath) {

try {
config = JSON.parse(stripComments(fs.readFileSync(filePath, "utf8")));
config = yaml.safeLoad(stripComments(fs.readFileSync(filePath, "utf8")));
} catch (e) {

@@ -80,3 +82,3 @@ console.error("Cannot read config file:", filePath);

* @param {string} directory the directory to start looking for a local config
* @return {object} the local config object (empty object if there is no local config)
* @returns {Object} the local config object (empty object if there is no local config)
*/

@@ -102,4 +104,4 @@ function getLocalConfig(helper, directory) {

* @constructor
* @class Confi
* @param {Object} options
* @class Config
* @param {Object} options Options to be passed in
* @param {string} [cwd] current working directory. Defaults to process.cwd()

@@ -115,3 +117,3 @@ */

this.baseConfig.format = options.format;
useConfig = options.c || options.config;
useConfig = options.config;

@@ -127,3 +129,3 @@ if (useConfig) {

* @param {string} filePath a file in whose directory we start looking for a local config
* @return {object} config object
* @returns {Object} config object
*/

@@ -172,5 +174,5 @@ Config.prototype.getConfig = function (filePath) {

* specify all options in a custom config.
* @param {object} base the base config
* @param {object} custom the custom config
* @return {object} the merged config
* @param {Object} base the base config
* @param {Object} custom the custom config
* @returns {Object} the merged config
*/

@@ -183,3 +185,4 @@ Config.prototype.mergeConfigs = function (base, custom) {

* Process given directory or file and cache ignore file if there's any
* @param {string} path to file or directory
* @param {string} directory The path to file or directory
* @returns {void}
*/

@@ -209,4 +212,4 @@ Config.prototype.cacheExclusions = function(directory) {

* Check if the current file should not be processed
* @param {string} resolved file path
* return {boolean} if the file should be excluded
* @param {string} filePath file path
* @returns {boolean} if the file should be excluded
*/

@@ -224,3 +227,3 @@ Config.prototype.checkForExclusion = function(filePath) {

* @param {string} directory the directory to start searching from
* @return {string|boolean} returns path of config file if found, or false if no config is found
* @returns {string|boolean} returns path of config file if found, or false if no config is found
*/

@@ -227,0 +230,0 @@ Config.prototype.findLocalConfigFile = function (directory) {

@@ -60,9 +60,9 @@ /**

* Parses info about globals from a special block comment and adds them to the `declaredGlobals` map.
* @param {ASTNode} comment
* @param {object} declaredGlobals
* @returns {void}
* @param {ASTNode} comment The comment node to parse.
* @param {Object} declaredGlobals The already-declared globals.
* @returns {boolean} True if globals were added, false if not.
*/
function parseComment(comment, declaredGlobals) {
if (comment.type !== "Block") {
return;
return false;
}

@@ -185,2 +185,4 @@ var text = comment.value;

//------------------------------------------------------------------------------

@@ -205,2 +207,36 @@ // Public Interface

/**
* Parses text into an AST. Moved out here because the try-catch prevents
* optimization of functions, so it's best to keep the try-catch as isolated
* as possible
* @param {string} text The text to parse.
* @returns {ASTNode} The AST if successful or null if not.
* @private
*/
function parse(text) {
/*
* Check for parsing errors first. If there's a parsing error, nothing
* else can happen. However, a parsing error does not throw an error
* from this method - it's just considered a fatal error message, a
* problem that ESLint identified just like any other.
*/
try {
return esprima.parse(text, { loc: true, range: true, raw: true, tokens: true, comment: true });
} catch (ex) {
messages.push({
fatal: true,
// messages come as "Line X: Unexpected token foo", so strip off leading part
message: ex.message.substring(ex.message.indexOf(":") + 1).trim(),
line: ex.lineNumber,
column: ex.column
});
return null;
}
}
// set unlimited listeners (see https://github.com/eslint/eslint/issues/524)

@@ -228,2 +264,4 @@ api.setMaxListeners(0);

* @param {Object} config An object whose keys specify the rules to use.
* @param {boolean=} saveState Indicates if the state from the last run should be saved.
* Mostly useful for testing purposes.
* @returns {Object[]} The results as an array of messages or null if no messages.

@@ -233,4 +271,3 @@ */

var parseError = false,
ast;
var ast;

@@ -241,27 +278,6 @@ if (!saveState) {

/*
* Check for parsing errors first. If there's a parsing error, nothing
* else can happen. However, a parsing error does not throw an error
* from this method - it's just considered a fatal error message, a
* problem that ESLint identified just like any other.
*/
try {
ast = esprima.parse(text, { loc: true, range: true, raw: true, tokens: true, comment: true });
} catch (ex) {
ast = parse(text);
parseError = true;
messages.push({
fatal: true,
// messages come as "Line X: Unexpected token foo", so strip off leading part
message: ex.message.substring(ex.message.indexOf(":") + 1).trim(),
line: ex.lineNumber,
column: ex.column
});
}
//if Esprima failed to parse the file, there's no sense in setting up rules
if (!parseError) {
if (ast) {
// parse global comments and modify config rules

@@ -333,3 +349,3 @@ config.rules = modifyRulesFromComments(ast, config);

controller.traverse(ast, {
enter: function(node) {
enter: function(node, parent) {
var comments = api.getComments(node),

@@ -345,2 +361,4 @@ leadingComments = comments.leading,

node.parent = parent;
api.emit(node.type, node);

@@ -363,11 +381,11 @@

trailingComments.forEach(function(node) {
api.emit(node.type + "Comment:after", node);
api.emit(node.type + "Comment:exit", node);
});
}
api.emit(node.type + ":after", node);
api.emit(node.type + ":exit", node);
if (leadingComments) {
leadingComments.forEach(function(node) {
api.emit(node.type + "Comment:after", node);
api.emit(node.type + "Comment:exit", node);
});

@@ -387,3 +405,3 @@ }

* @param {ASTNode} node The AST node that the message relates to.
* @param {Object} [location] An object containing the error line and column
* @param {Object=} location An object containing the error line and column
* numbers. If location is not provided the node's start location will

@@ -421,5 +439,5 @@ * be used.

* Gets the source code for the given node.
* @param {ASTNode} [node] The AST node to get the text for.
* @param {int} [beforeCount] The number of characters before the node to retrieve.
* @param {int} [afterCount] The number of characters after the node to retrieve.
* @param {ASTNode=} node The AST node to get the text for.
* @param {int=} beforeCount The number of characters before the node to retrieve.
* @param {int=} afterCount The number of characters after the node to retrieve.
* @returns {string} The text representing the AST node.

@@ -429,6 +447,6 @@ */

if (node) {
return currentText ? currentText.slice(node.range[0] - (beforeCount || 0),
return (currentText !== null) ? currentText.slice(node.range[0] - (beforeCount || 0),
node.range[1] + (afterCount || 0)) : null;
} else {
return currentText || null;
return currentText;
}

@@ -439,10 +457,2 @@

/**
* Returns all comments.
* @returns {Object[]}
*/
api.getAllComments = function () {
return controller.root.comments || [];
};
/**
* Gets all comments for the given node.

@@ -452,3 +462,3 @@ * @param {ASTNode} node The AST node to get the comments for.

*/
api.getComments = function (node) {
api.getComments = function(node) {
var ast = controller.root;

@@ -469,6 +479,64 @@

/**
* Retrieves the JSDoc comment for a given node.
* @param {ASTNode} node The AST node to get the comment for.
* @returns {ASTNode} The BlockComment node containing the JSDoc for the
* given node or null if not found.
*/
api.getJSDocComment = function(node) {
var parent = node.parent,
line = node.loc.start.line;
/**
* Finds a JSDoc comment node in an array of comment nodes.
* @param {ASTNode[]} comments The array of comment nodes to search.
* @returns {ASTNode} The node if found, null if not.
* @private
*/
function findJSDocComment(comments) {
if (comments) {
for (var i = comments.length - 1; i >= 0; i--) {
if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") {
if (line - comments[i].loc.end.line <= 1) {
return comments[i];
} else {
break;
}
}
}
}
return null;
}
switch(node.type) {
case "FunctionDeclaration":
// first global function has its comments stolen by Program
return findJSDocComment(((parent.type === "Program") ? parent : node).leadingComments);
case "FunctionExpression":
if (parent.type !== "CallExpression" || parent.callee !== node) {
while (parent && !parent.leadingComments) {
parent = parent.parent;
}
return parent ? findJSDocComment(parent.leadingComments) : null;
}
// falls through
default:
return null;
}
};
/**
* Gets all tokens that are related to the given node.
* @param {ASTNode} [node] The AST node to get the text for.
* @param {int} [beforeCount] The number of tokens before the node to retrieve.
* @param {int} [afterCount] The number of tokens after the node to retrieve.
* @param {ASTNode=} node The AST node to get the text for.
* @param {int=} beforeCount The number of tokens before the node to retrieve.
* @param {int=} afterCount The number of tokens after the node to retrieve.
* @returns {Object[]} Array of objects representing tokens.

@@ -562,4 +630,4 @@ */

* Defines a new linting rule.
* @param {string} unique rule identifier
* @param {function} function from context to object mapping AST node types to event handlers
* @param {string} ruleId A unique rule identifier
* @param {Function} ruleModule Function from context to object mapping AST node types to event handlers
* @returns {void}

@@ -573,3 +641,3 @@ */

* Defines many new linting rules.
* @param {object} map from unique rule identifier to rule
* @param {object} rules map from unique rule identifier to rule
* @returns {void}

@@ -576,0 +644,0 @@ */

/**
* @fileoverview Wrapper around Optimist to preconfigure CLI options output.
* @author Nicholas C. Zakas
* @fileoverview Options configuration for optionator.
* @author George Zahariev
*/

@@ -11,41 +11,39 @@ "use strict";

var optimist = require("optimist");
var optionator = require("optionator");
//------------------------------------------------------------------------------
// Initialization
// Initialization and Public Interface
//------------------------------------------------------------------------------
optimist.usage("eslint [options] file.js [file.js] [dir]");
// Help
optimist.boolean("h");
optimist.alias("h", "help");
optimist.describe("h", "Show help.");
// Config
optimist.alias("c", "config");
optimist.describe("c", "Load configuration data from this file.");
// RulesDir
optimist.describe("rulesdir", "Load additional rules from this directory.");
// Format
optimist.alias("f", "format");
optimist.default("f", "stylish");
optimist.describe("f", "Use a specific output format.");
// Version
optimist.alias("v", "version");
optimist.describe("v", "Outputs the version number.");
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
exports.help = function() {
console.log(optimist.help());
};
exports.parse = function(argv) {
return optimist.parse(argv);
};
// exports "parse(args)", "generateHelp()", and "generateHelpForOption(optionName)"
module.exports = optionator({
prepend: "eslint [options] file.js [file.js] [dir]",
options: [{
heading: "Options"
}, {
option: "help",
alias: "h",
type: "Boolean",
description: "Show help."
}, {
option: "config",
alias: "c",
type: "path::String",
description: "Load configuration data from this file."
}, {
option: "rulesdir",
type: "path::String",
description: "Load additional rules from this directory."
}, {
option: "format",
alias: "f",
type: "String",
default: "stylish",
description: "Use a specific output format."
}, {
option: "version",
alias: "v",
type: "Boolean",
description: "Outputs the version number."
}]
});

@@ -15,5 +15,5 @@ /**

"getComments",
"getAllComments",
"getAncestors",
"getScope"
"getScope",
"getJSDocComment"
];

@@ -20,0 +20,0 @@

@@ -88,3 +88,3 @@ /**

"BlockStatement": pushBlock,
"BlockStatement:after": popBlock,
"BlockStatement:exit": popBlock,
"CatchClause": addCommonDeclaration,

@@ -91,0 +91,0 @@ "VariableDeclaration": addCommonDeclaration,

@@ -67,4 +67,4 @@ /**

"FunctionExpression": startFunction,
"FunctionDeclaration:after": endFunction,
"FunctionExpression:after": endFunction,
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,

@@ -71,0 +71,0 @@ "CatchClause": increaseComplexity,

@@ -5,17 +5,53 @@ /**

*/
"use strict";
//------------------------------------------------------------------------------
// Helpers
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function(context) {
var multiOnly = (context.options[0] === "multi");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
module.exports = function(context) {
/**
* Checks the body of a node to see if it's a block statement. Depending on
* the rule options, reports the appropriate problems.
* @param {ASTNode} node The node to report if there's a problem.
* @param {ASTNode} body The body node to check for blocks.
* @param {string} name The name to report if there's a problem.
* @param {string} suffix Additional string to add to the end of a report.
* @returns {void}
*/
function checkBody(node, body, name, suffix) {
var hasBlock = (body.type === "BlockStatement");
"use strict";
if (multiOnly) {
if (hasBlock && body.body.length === 1) {
context.report(node, "Unnecessary { after '{{name}}'{{suffix}}.",
{
name: name,
suffix: (suffix ? " " + suffix : "")
}
);
}
} else {
if (!hasBlock) {
context.report(node, "Expected { after '{{name}}'{{suffix}}.",
{
name: name,
suffix: (suffix ? " " + suffix : "")
}
);
}
}
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {

@@ -25,34 +61,20 @@

if (node.consequent.type !== "BlockStatement") {
context.report(node, "Expected { after 'if' condition.");
checkBody(node, node.consequent, "if", "condition");
if (node.alternate && node.alternate.type !== "IfStatement") {
checkBody(node, node.alternate, "else");
}
if (node.alternate && node.alternate.type !== "BlockStatement" &&
node.alternate.type !== "IfStatement") {
context.report(node, "Expected { after 'else'.");
}
},
"WhileStatement": function(node) {
if (node.body.type !== "BlockStatement") {
context.report(node, "Expected { after 'while' condition.");
}
checkBody(node, node.body, "while", "condition");
},
"DoWhileStatement": function (node) {
if (node.body.type !== "BlockStatement") {
context.report(node, "Expected { after 'do'.");
}
checkBody(node, node.body, "do");
},
"ForStatement": function(node) {
if (node.body.type !== "BlockStatement") {
context.report(node, "Expected { after 'for' condition.");
}
checkBody(node, node.body, "for", "condition");
}

@@ -59,0 +81,0 @@ };

@@ -60,16 +60,16 @@ /**

"IfStatement:after": popBlock,
"SwitchStatement:after": popBlock,
"TryStatement:after": popBlock,
"DoWhileStatement:after": popBlock,
"WhileStatement:after": popBlock,
"WithStatement:after": popBlock,
"ForStatement:after": popBlock,
"ForInStatement:after": popBlock,
"IfStatement:exit": popBlock,
"SwitchStatement:exit": popBlock,
"TryStatement:exit": popBlock,
"DoWhileStatement:exit": popBlock,
"WhileStatement:exit": popBlock,
"WithStatement:exit": popBlock,
"ForStatement:exit": popBlock,
"ForInStatement:exit": popBlock,
"FunctionDeclaration:after": endFunction,
"FunctionExpression:after": endFunction,
"Program:after": endFunction
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction,
"Program:exit": endFunction
};
};

@@ -46,7 +46,3 @@ /**

node.range[0] = 0;
var lines = context.getSource(node);
// getSource might return null if fed an empty string
if(!lines) {
return;
}
var lines = context.getSource(node) || ""; // necessary for backwards compat

@@ -53,0 +49,0 @@ // Replace the tabs

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

"FunctionExpression:after": function() {
"FunctionExpression:exit": function() {
callbackStack.pop();

@@ -49,2 +49,2 @@ }

};
};

@@ -48,6 +48,6 @@ /**

"FunctionDeclaration:after": endFunction,
"FunctionExpression:after": endFunction
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction
};
};

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

*/
"use strict";

@@ -13,4 +14,2 @@ //------------------------------------------------------------------------------

"use strict";
function isParenthesised(node) {

@@ -20,2 +19,3 @@ var tokens = context.getTokens(node, 1, 1),

lastToken = tokens[tokens.length - 1];
return firstToken.value === "(" && firstToken.range[1] <= node.range[0] &&

@@ -29,2 +29,3 @@ lastToken.value === ")" && lastToken.range[0] >= node.range[1];

lastToken = tokens[tokens.length - 1];
return isParenthesised(node) &&

@@ -36,3 +37,3 @@ firstToken.value === "(" && firstToken.range[1] <= node.range[0] &&

function testForAssign(node) {
if ("AssignmentExpression" === node.test.type && !isParenthesisedTwice(node.test)) {
if (node.test && (node.test.type === "AssignmentExpression") && !isParenthesisedTwice(node.test)) {
context.report(node, "Expected a conditional expression and instead saw an assignment.");

@@ -39,0 +40,0 @@ }

@@ -24,3 +24,3 @@ /**

"CatchClause:after": function() {
"CatchClause:exit": function() {
inCatch = false;

@@ -27,0 +27,0 @@ exceptionName = null;

@@ -75,3 +75,3 @@ /**

"SwitchStatement:after": function() {
"SwitchStatement:exit": function() {
switches.pop();

@@ -78,0 +78,0 @@ }

@@ -16,3 +16,3 @@ /**

*
* @returns {string[]}
* @returns {string[]} An array of built-in Node.js modules.
*/

@@ -45,3 +45,3 @@ function getBuiltinModules() {

* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string}
* @returns {string} The type of declaration represented by the expression.
*/

@@ -72,3 +72,3 @@ function getDeclarationType(initExpression) {

* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string}
* @returns {string} The module type.
*/

@@ -107,3 +107,3 @@ function inferModuleType(initExpression) {

* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean}
* @returns {boolean} True if the declarations are mixed, false if not.
*/

@@ -128,3 +128,3 @@ function isMixed(declarations) {

* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean}
* @returns {boolean} True if the declarations are grouped, false if not.
*/

@@ -131,0 +131,0 @@ function isGrouped(declarations) {

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

"Literal": function(node) {
if (typeof node.value !== "string") {
return;
}
var match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7])/),

@@ -19,0 +22,0 @@ octalDigit;

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

*/
"use strict";

@@ -13,4 +14,2 @@ //------------------------------------------------------------------------------

"use strict";
return {

@@ -20,3 +19,3 @@

if (node.argument && node.argument.type === "AssignmentExpression") {
context.report(node, "Return statement should not contain assigment.");
context.report(node, "Return statement should not contain assignment.");
}

@@ -23,0 +22,0 @@ }

@@ -38,21 +38,40 @@ /**

/**
* Checks if a node is an exception for no-unreachable because of variable/function hoisting
* @param {ASTNode} node The AST node to check.
* @returns {boolean} if the node doesn't trigger unreachable
* @private
*/
function isUnreachableAllowed(node) {
return node.type === "FunctionDeclaration" ||
node.type === "VariableDeclaration" &&
node.declarations.every(function(declaration){
return declaration.type === "VariableDeclarator" && declaration.init === null;
});
}
/**
* Loops through a field of a node and checks if its children fulfill conditions to trigger the unreachable report.
* @param {ASTNode} node The AST node to check.
* @param {string} field The field that represents the children of the node.
* @returns {void}
* @private
*/
function checkNodeFieldForUnreachable(node, field) {
var i, unreachableType = false;
for (i = 1; i < node[field].length; i++) {
unreachableType = unreachableType || checkForUnreachable(node[field][i - 1]);
if (unreachableType && !isUnreachableAllowed(node[field][i])) {
report(context, node[field][i], unreachableType);
}
}
}
return {
"BlockStatement": function(node) {
var i, unreachableType = false;
for (i = 1; i < node.body.length; i++) {
unreachableType = unreachableType || checkForUnreachable(node.body[i - 1]);
if (unreachableType) {
report(context, node.body[i], unreachableType);
}
}
checkNodeFieldForUnreachable(node, "body");
},
"SwitchCase": function(node) {
var i, unreachableType = false;
for (i = 1; i < node.consequent.length; i++) {
unreachableType = unreachableType || checkForUnreachable(node.consequent[i - 1]);
if (unreachableType) {
report(context, node.consequent[i], unreachableType);
}
}
checkNodeFieldForUnreachable(node, "consequent");
}

@@ -59,0 +78,0 @@ };

@@ -31,3 +31,3 @@ /**

!/^(?:Assignment|Call|New|Update)Expression$/.test(type) &&
("UnaryExpression" !== type || ["delete", "void"].indexOf(node.expression.operator) < 0) &&
(type !== "UnaryExpression" || ["delete", "void"].indexOf(node.expression.operator) < 0) &&
!isPragma(node.expression, parent)

@@ -34,0 +34,0 @@ ) {

@@ -14,6 +14,26 @@ /**

var allowUnusedGlobals = context.options[0] === "all" ? false : true;
var allowUnusedGlobals = (context.options[0] !== "all"),
variables = {};
var variables = [];
function lookupVariableName(name) {
// Convoluted check in case name is "hasOwnProperty"
if (!Object.prototype.hasOwnProperty.call(variables, name)) {
return null;
}
return variables[name];
}
function lookupVariable(variable) {
var candidates = lookupVariableName(variable.name);
if (candidates) {
return candidates.filter(function (candidate) {
return variable.identifiers.some(function (identifier) {
return candidate.node === identifier;
});
})[0];
}
return candidates;
}
function populateVariables(node) {

@@ -33,7 +53,8 @@ var scope = context.getScope(),

//make sure that this variable is not already in the array
if (!variables.some(function(storedVariable) {
return storedVariable.name === variable.name && storedVariable.node === variable.identifiers[0];
})) {
if (!lookupVariable(variable)) {
variables.push({
if (!lookupVariableName(variable.name)) {
variables[variable.name] = [];
}
variables[variable.name].push({
name: variable.name,

@@ -71,7 +92,4 @@ node: variable.identifiers[0],

}
return variables.filter(function(variable) {
return variable.name === scopeVariable[0].name && scopeVariable[0].identifiers.some(function(identifier) {
return variable.node === identifier;
});
})[0];
return lookupVariable(scopeVariable[0]);
}

@@ -83,11 +101,4 @@

function findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors) {
var currentAncestor;
while (ancestors.length !== 0 && !isFunction(currentAncestor)) {
currentAncestor = ancestors.pop();
}
return isFunction(currentAncestor) ? currentAncestor : undefined;
}
function markIgnorableUnusedVariables(usedVariable) {
function markIgnorableUnusedVariables(usedVariable, ancestors) {
/* When variables are declared as parameters in a FunctionExpression or

@@ -100,6 +111,6 @@ * FunctionDeclaration, they can go unused so long as at least one

// may be a parameter
var ancestorFunctionNode = findFirstAncestorThatIsFunctionExpressionOrDeclaration(ancestors);
if (ancestorFunctionNode) {
var parent = usedVariable.node.parent;
if (isFunction(parent)) {
// Get a list of the param names used in the ancestor Function
var fnParamNames = ancestorFunctionNode.params.map(function(param){
var fnParamNames = parent.params.map(function(param){
return param.name;

@@ -116,6 +127,5 @@ });

ignorableVariables.forEach(function(ignorableVariable){
variables.forEach(function(variable){
if (variable.name === ignorableVariable) {
variable.ignorable = true;
}
(lookupVariableName(ignorableVariable) || []).forEach(function(variable){
variable.ignorable = true;
});

@@ -145,2 +155,3 @@ });

var variable = findVariable(node.name);
if (variable) {

@@ -154,9 +165,12 @@ variable.used = true;

"Program:after": function() {
var unused = variables.filter(function(variable) {
return !variable.used && !variable.ignorable;
});
unused.forEach(function(variable) {
context.report(variable.node, "{{var}} is defined but never used", {"var": variable.name});
});
"Program:exit": function() {
Object.keys(variables)
.forEach(function (name) {
variables[name].forEach(function (variable) {
if (variable.used || variable.ignorable) {
return;
}
context.report(variable.node, "{{var}} is defined but never used", {"var": variable.name});
});
});
}

@@ -163,0 +177,0 @@ };

@@ -47,7 +47,7 @@ /**

"Program:after": endFunction,
"FunctionDeclaration:after": endFunction,
"FunctionExpression:after": endFunction
"Program:exit": endFunction,
"FunctionDeclaration:exit": endFunction,
"FunctionExpression:exit": endFunction
};
};

@@ -35,7 +35,7 @@ /**

* Validate that a string passed in is surrounded by the specified character
* @param {string} val
* @param {string} character
* @return {bool}
* @param {string} val The text to check.
* @param {string} character The character to see if it's surrounded by.
* @returns {boolean} True if the text is surrounded by the character, false if not.
*/
function surroundedBy(val, character) {
function isSurroundedBy(val, character) {
return val[0] === character && val[val.length - 1] === character;

@@ -55,6 +55,6 @@ }

if (settings && typeof val === "string") {
isValid = surroundedBy(rawVal, settings.quote);
isValid = isSurroundedBy(rawVal, settings.quote);
if (!isValid && avoidEscape) {
isValid = surroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0;
isValid = isSurroundedBy(rawVal, settings.alternateQuote) && rawVal.indexOf(settings.quote) >= 0;
}

@@ -61,0 +61,0 @@

@@ -17,4 +17,20 @@ /**

if (node.callee.name === "parseInt" && node.arguments.length === 1) {
context.report(node, "Missing radix parameter.");
var radix;
if (node.callee.name === "parseInt") {
if (node.arguments.length === 1) {
context.report(node, "Missing radix parameter.");
} else {
radix = node.arguments[1];
// don't allow non-numeric literals or undefined
if ((radix.type === "Literal" && typeof radix.value !== "number") ||
(radix.type === "Identifier" && radix.name === "undefined")
) {
context.report(node, "Invalid radix parameter.");
}
}
}

@@ -21,0 +37,0 @@ }

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

* onto the stack.
* @returns {void}
* @private

@@ -46,5 +47,5 @@ */

"Program:after": exitScope,
"FunctionDeclaration:after": exitScope,
"FunctionExpression:after": exitScope,
"Program:exit": exitScope,
"FunctionDeclaration:exit": exitScope,
"FunctionExpression:exit": exitScope,

@@ -51,0 +52,0 @@ "ExpressionStatement": function(node) {

@@ -23,4 +23,4 @@ /**

* Merges two config objects. This will not only add missing keys, but will also modify values to match.
* @param {Object} initial config object
* @param {Object} second config object. Overrides in this config object will take priority over base.
* @param {Object} base config object
* @param {Object} custom config object. Overrides in this config object will take priority over base.
* @returns {Object} merged config object.

@@ -27,0 +27,0 @@ */

{
"name": "eslint",
"version": "0.3.0",
"version": "0.4.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",

@@ -17,3 +17,4 @@ "description": "An Esprima-based pattern checker for JavaScript.",

"gensite": "node Makefile.js gensite",
"browserify": "node Makefile.js browserify"
"browserify": "node Makefile.js browserify",
"profile": "beefy tests/bench/bench.js --open -- -t brfs -t ./tests/bench/xform-rules.js"
},

@@ -32,3 +33,3 @@ "files": [

"dependencies": {
"optimist": "*",
"optionator": "~0.1.1",
"estraverse": "~1.3.0",

@@ -40,3 +41,5 @@ "esprima": "*",

"chalk": "~0.4.0",
"strip-json-comments": "~0.1.1"
"strip-json-comments": "~0.1.1",
"js-yaml": "~3.0.1",
"doctrine": "~0.3.0"
},

@@ -53,3 +56,7 @@ "devDependencies": {

"mocha-phantomjs": "~3.3.1",
"phantomjs": "~1.9.2-6"
"phantomjs": "~1.9.2-6",
"eslint-tester": "latest",
"brfs": "0.0.9",
"through": "~2.3.4",
"beefy": "~1.0.0"
},

@@ -56,0 +63,0 @@ "keywords": [

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