eslint
Advanced tools
Comparing version 0.5.1 to 0.6.0
@@ -34,4 +34,23 @@ { | ||
"ArrayBuffer": false, | ||
"Float32Array": false, | ||
"Float64Array": false, | ||
"Int16Array": false, | ||
"Int32Array": false, | ||
"Int8Array": false, | ||
"Uint16Array": false, | ||
"Uint32Array": false, | ||
"Uint8Array": false, | ||
"Uint8ClampedArray": false, | ||
"Math": false, | ||
"JSON": false | ||
"JSON": false, | ||
"toString": false, | ||
"hasOwnProperty": false, | ||
"valueOf": false, | ||
"propertyIsEnumerable": false, | ||
"constructor": false, | ||
"isPrototypeOf": false, | ||
"toLocaleString": false | ||
}, | ||
@@ -43,3 +62,2 @@ | ||
"applicationCache": false, | ||
"ArrayBuffer": false, | ||
"atob": false, | ||
@@ -65,4 +83,2 @@ "Audio": false, | ||
"find": false, | ||
"Float32Array": false, | ||
"Float64Array": false, | ||
"focus": false, | ||
@@ -130,5 +146,2 @@ "FormData": false, | ||
"innerWidth": false, | ||
"Int16Array": false, | ||
"Int32Array": false, | ||
"Int8Array": false, | ||
"Intl": false, | ||
@@ -327,6 +340,2 @@ "length": false, | ||
"top": false, | ||
"Uint16Array": false, | ||
"Uint32Array": false, | ||
"Uint8Array": false, | ||
"Uint8ClampedArray": false, | ||
"WebSocket": false, | ||
@@ -369,2 +378,3 @@ "window": false, | ||
"no-mixed-requires": 2, | ||
"no-new-require": 2, | ||
"no-path-concat": 2, | ||
@@ -371,0 +381,0 @@ "handle-callback-err": [2, "err"], |
@@ -40,2 +40,3 @@ { | ||
"no-implied-eval": 2, | ||
"no-inner-declarations": [2, "functions"], | ||
"no-invalid-regexp": 2, | ||
@@ -46,2 +47,3 @@ "no-iterator": 2, | ||
"no-lone-blocks": 2, | ||
"no-lonely-if": 0, | ||
"no-loop-func": 2, | ||
@@ -56,2 +58,3 @@ "no-mixed-requires": [0, false], | ||
"no-new-object": 2, | ||
"no-new-require": 0, | ||
"no-new-wrappers": 2, | ||
@@ -67,2 +70,3 @@ "no-obj-calls": 2, | ||
"no-regex-spaces": 2, | ||
"no-restricted-modules": 0, | ||
"no-return-assign": 2, | ||
@@ -98,2 +102,3 @@ "no-script-url": 2, | ||
"curly": [2, "all"], | ||
"default-case": 0, | ||
"dot-notation": 2, | ||
@@ -118,2 +123,3 @@ "eqeqeq": 2, | ||
"sort-vars": 0, | ||
"space-after-keywords": [0, "always"], | ||
"space-in-brackets": [0, "never"], | ||
@@ -120,0 +126,0 @@ "space-infix-ops": 2, |
@@ -99,3 +99,2 @@ /** | ||
output; | ||
if (existsSync(path.resolve(process.cwd(), config.format))) { | ||
@@ -106,10 +105,4 @@ formatterPath = path.resolve(process.cwd(), config.format); | ||
} | ||
try { | ||
formatter = require(formatterPath); | ||
output = formatter(results, config); | ||
if (output) { | ||
console.log(output); | ||
} | ||
return true; | ||
} catch (ex) { | ||
@@ -119,2 +112,7 @@ console.error("Could not find formatter '%s'.", config.format); | ||
} | ||
output = formatter(results, config); | ||
if (output) { | ||
console.log(output); | ||
} | ||
return true; | ||
@@ -184,6 +182,15 @@ } | ||
files.forEach(function(file) { | ||
if (isDirectory(file)) { | ||
fullFileList = fullFileList.concat(getFiles(file, configHelper)); | ||
} else { | ||
if (!configHelper.options.force) { | ||
configHelper.cacheExclusions(path.dirname(file)); | ||
if (configHelper.checkForExclusion(path.resolve(file))) { | ||
storeResults(file, [{ | ||
fatal: false, | ||
message: "File ignored because of your .eslintignore file. Use --force to override." | ||
}]); | ||
return; | ||
} | ||
} | ||
fullFileList.push(file); | ||
@@ -226,6 +233,6 @@ } | ||
try { | ||
currentOptions = options.parse(args); | ||
currentOptions = options.parse(args); | ||
} catch (error) { | ||
console.error(error.message); | ||
return 1; | ||
console.error(error.message); | ||
return 1; | ||
} | ||
@@ -253,3 +260,5 @@ | ||
if (currentOptions.rulesdir) { | ||
rules.load(currentOptions.rulesdir); | ||
currentOptions.rulesdir.forEach(function(rulesdir) { | ||
rules.load(rulesdir); | ||
}); | ||
} | ||
@@ -256,0 +265,0 @@ |
@@ -213,2 +213,6 @@ /** | ||
if (this.options.rule) { | ||
config = this.mergeConfigs(config, { rules: this.options.rule }); | ||
} | ||
this.cache[directory] = config; | ||
@@ -248,3 +252,5 @@ | ||
if (matches) { | ||
cache = cache.concat(matches.map(function(match) { return path.resolve(directory, match); })); | ||
cache = cache.concat(matches.map(function(match) { | ||
return path.resolve(directory, match); | ||
})); | ||
} | ||
@@ -265,5 +271,3 @@ } | ||
return Object.keys(this.exclusionsCache).some(function(directory) { | ||
return this.exclusionsCache[directory].some(function(file) { | ||
return file === filePath; | ||
}); | ||
return this.exclusionsCache[directory].indexOf(filePath) > -1; | ||
}, this); | ||
@@ -270,0 +274,0 @@ }; |
@@ -154,9 +154,73 @@ /** | ||
/** | ||
* Add data to reporting configuration to disable reporting for list of rules | ||
* starting from start location | ||
* @param {Object[]} reportingConfig Current reporting configuration | ||
* @param {Object} start Position to start | ||
* @param {string[]} rules List of rules | ||
* @returns {void} | ||
*/ | ||
function disableReporting(reportingConfig, start, rules) { | ||
if (rules.length) { | ||
rules.forEach(function(rule){ | ||
reportingConfig.push({ | ||
start: start, | ||
end: null, | ||
rule: rule | ||
}); | ||
}); | ||
} else { | ||
reportingConfig.push({ | ||
start: start, | ||
end: null, | ||
rule: null | ||
}); | ||
} | ||
} | ||
/** | ||
* Add data to reporting configuration to enable reporting for list of rules | ||
* starting from start location | ||
* @param {Object[]} reportingConfig Current reporting configuration | ||
* @param {Object} start Position to start | ||
* @param {string[]} rules List of rules | ||
* @returns {void} | ||
*/ | ||
function enableReporting(reportingConfig, start, rules) { | ||
if (rules.length) { | ||
rules.forEach(function(rule){ | ||
for (var i = reportingConfig.length - 1; i >= 0; i--) { | ||
if (!reportingConfig[i].end && reportingConfig[i].rule === rule ) { | ||
reportingConfig[i].end = start; | ||
break; | ||
} | ||
} | ||
}); | ||
} else { | ||
// find all previous disabled locations if they was started as list of rules | ||
var prevStart; | ||
for (var i = reportingConfig.length - 1; i >= 0; i--) { | ||
if (prevStart && prevStart !== reportingConfig[i].start) { | ||
break; | ||
} | ||
if (!reportingConfig[i].end) { | ||
reportingConfig[i].end = start; | ||
prevStart = reportingConfig[i].start; | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* Parses comments in file to extract file-specific config of rules, globals | ||
* and environments and merges them with global config. | ||
* and environments and merges them with global config; also code blocks | ||
* where reporting is disabled or enabled and merges them with reporting config. | ||
* @param {ASTNode} ast The top node of the AST. | ||
* @param {Object} config The existing configuration data. | ||
* @returns {Object} Merged config | ||
* @param {Object[]} reportingConfig The existing reporting configuration data. | ||
* @returns {void} | ||
*/ | ||
function modifyConfigFromComments(ast, config) { | ||
function modifyConfigsFromComments(ast, config, reportingConfig) { | ||
@@ -174,3 +238,3 @@ var commentConfig = { | ||
var value = comment.value.trim(); | ||
var match = /^(eslint-env|eslint|globals?)\s/.exec(value); | ||
var match = /^(eslint-\w+|eslint|globals?)(\s|$)/.exec(value); | ||
@@ -190,2 +254,10 @@ if (match) { | ||
case "eslint-disable": | ||
disableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value))); | ||
break; | ||
case "eslint-enable": | ||
enableReporting(reportingConfig, comment.loc.start, Object.keys(parseListConfig(value))); | ||
break; | ||
case "eslint": | ||
@@ -216,6 +288,28 @@ var items = parseJsonConfig(value); | ||
return util.mergeConfigs(config, commentConfig); | ||
util.mergeConfigs(config, commentConfig); | ||
} | ||
/** | ||
* Check if message of rule with ruleId should be ignored in location | ||
* @param {Object[]} reportingConfig Collection of ignore records | ||
* @param {string} ruleId Id of rule | ||
* @param {Object} location Location of message | ||
* @returns {boolean} True if message should be ignored, false otherwise | ||
*/ | ||
function isDisabledByReportingConfig(reportingConfig, ruleId, location) { | ||
for (var i = 0, c = reportingConfig.length; i < c; i++) { | ||
var ignore = reportingConfig[i]; | ||
if ((!ignore.rule || ignore.rule === ruleId) && | ||
(location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) && | ||
(!ignore.end || (location.line < ignore.end.line || (location.line === ignore.end.line && location.column <= ignore.end.column)))) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
/** | ||
* Process initial config to make it safe to extend by file comment config | ||
@@ -230,4 +324,16 @@ * @param {Object} config Initial config | ||
var copiedRules = {}; | ||
if (typeof config.rules === "object") { | ||
Object.keys(config.rules).forEach(function(k){ | ||
var rule = config.rules[k]; | ||
if (Array.isArray(rule)) { | ||
copiedRules[k] = rule.slice(); | ||
} else { | ||
copiedRules[k] = rule; | ||
} | ||
}); | ||
} | ||
return { | ||
rules: util.mergeConfigs({}, config.rules || {}), | ||
rules: copiedRules, | ||
globals: util.mergeConfigs({}, config.globals), | ||
@@ -250,3 +356,2 @@ env: util.mergeConfigs({}, config.env || {}) | ||
messages = [], | ||
commentsAttached = false, | ||
currentText = null, | ||
@@ -257,5 +362,5 @@ currentConfig = null, | ||
currentFilename = null, | ||
controller = null; | ||
controller = null, | ||
reportingConfig = []; | ||
/** | ||
@@ -277,3 +382,10 @@ * Parses text into an AST. Moved out here because the try-catch prevents | ||
try { | ||
return esprima.parse(text, { loc: true, range: true, raw: true, tokens: true, comment: true }); | ||
return esprima.parse(text, { | ||
loc: true, | ||
range: true, | ||
raw: true, | ||
tokens: true, | ||
comment: true, | ||
attachComment: true | ||
}); | ||
} catch (ex) { | ||
@@ -305,3 +417,2 @@ | ||
messages = []; | ||
commentsAttached = false; | ||
currentConfig = null; | ||
@@ -312,2 +423,3 @@ currentText = null; | ||
controller = null; | ||
reportingConfig = []; | ||
}; | ||
@@ -344,3 +456,3 @@ | ||
// parse global comments and modify config | ||
config = modifyConfigFromComments(ast, config); | ||
modifyConfigsFromComments(ast, config, reportingConfig); | ||
@@ -413,2 +525,3 @@ // enable appropriate rules | ||
enter: function(node, parent) { | ||
var comments = api.getComments(node), | ||
@@ -487,2 +600,6 @@ leadingComments = comments.leading, | ||
if (isDisabledByReportingConfig(reportingConfig, ruleId, location)) { | ||
return; | ||
} | ||
messages.push({ | ||
@@ -521,13 +638,20 @@ ruleId: ruleId, | ||
api.getComments = function(node) { | ||
var ast = controller.root; | ||
if (!commentsAttached) { | ||
// Attaching comments is a potentially expensive operation, so we do this lazily. | ||
estraverse.attachComments(ast, ast.comments, ast.tokens); | ||
commentsAttached = true; | ||
var leadingComments = node.leadingComments || [], | ||
trailingComments = node.trailingComments || []; | ||
/* | ||
* Esprima adds a "comments" array on Program nodes rather than | ||
* leadingComments/trailingComments. Comments are only left in the | ||
* Program node comments array if there is no executable code. | ||
*/ | ||
if (node.type === "Program") { | ||
if (node.body.length === 0) { | ||
leadingComments = node.comments; | ||
} | ||
} | ||
return { | ||
leading: node.leadingComments || [], | ||
trailing: node.trailingComments || [] | ||
leading: leadingComments, | ||
trailing: trailingComments | ||
}; | ||
@@ -573,7 +697,4 @@ }; | ||
case "FunctionDeclaration": | ||
return findJSDocComment(node.leadingComments); | ||
// first global function has its comments stolen by Program | ||
var nodeToCheck = (node.leadingComments ? node : parent); | ||
return findJSDocComment(nodeToCheck.leadingComments); | ||
case "FunctionExpression": | ||
@@ -586,3 +707,3 @@ | ||
return parent ? findJSDocComment(parent.leadingComments) : null; | ||
return parent && (parent.type !== "FunctionDeclaration") ? findJSDocComment(parent.leadingComments) : null; | ||
} | ||
@@ -589,0 +710,0 @@ |
@@ -12,6 +12,2 @@ /** | ||
function getMessageType(message, rules) { | ||
// TODO: Get rule severity in a better way | ||
var severity = null; | ||
if (message.fatal) { | ||
@@ -21,3 +17,4 @@ return "error"; | ||
severity = rules[message.ruleId][0] || rules[message.ruleId]; | ||
var rule = rules[message.ruleId], | ||
severity = rule && (rule[0] || rule); | ||
@@ -24,0 +21,0 @@ if (severity === 2) { |
@@ -12,6 +12,2 @@ /** | ||
function getMessageType(message, rules) { | ||
// TODO: Get rule severity in a better way | ||
var severity = null; | ||
if (message.fatal) { | ||
@@ -21,3 +17,4 @@ return "Error"; | ||
severity = rules[message.ruleId][0] || rules[message.ruleId]; | ||
var rule = rules[message.ruleId], | ||
severity = rule && (rule[0] || rule); | ||
@@ -24,0 +21,0 @@ if (severity === 2) { |
@@ -14,6 +14,2 @@ /** | ||
function getMessageType(message, rules) { | ||
// TODO: Get rule severity in a better way | ||
var severity = null; | ||
if (message.fatal) { | ||
@@ -23,3 +19,4 @@ return "Error"; | ||
severity = rules[message.ruleId][0] || rules[message.ruleId]; | ||
var rule = rules[message.ruleId], | ||
severity = rule && (rule[0] || rule); | ||
@@ -26,0 +23,0 @@ if (severity === 2) { |
@@ -19,3 +19,4 @@ /** | ||
var severity = rules[message.ruleId][0] || rules[message.ruleId]; | ||
var rule = rules[message.ruleId], | ||
severity = rule && (rule[0] || rule); | ||
@@ -22,0 +23,0 @@ if (severity === 2) { |
@@ -23,6 +23,2 @@ /** | ||
function getMessageType(message, rules) { | ||
// TODO: Get rule severity in a better way | ||
var severity = null; | ||
if (message.fatal) { | ||
@@ -32,3 +28,4 @@ return "error"; | ||
severity = rules[message.ruleId][0] || rules[message.ruleId]; | ||
var rule = rules[message.ruleId], | ||
severity = rule && (rule[0] || rule); | ||
@@ -99,3 +96,3 @@ if (severity === 2) { | ||
// If we have an error include diagnostics | ||
// If we have an error include diagnostics | ||
if (messages.length > 0) { | ||
@@ -102,0 +99,0 @@ output += outputDiagnostics(diagnostics); |
@@ -33,3 +33,5 @@ /** | ||
fs.readdirSync(rulesDir).forEach(function(file) { | ||
if (path.extname(file) !== ".js") { return; } | ||
if (path.extname(file) !== ".js") { | ||
return; | ||
} | ||
rules[file.slice(0, -3)] = require(path.join(rulesDir, file)); | ||
@@ -36,0 +38,0 @@ }); |
@@ -19,49 +19,58 @@ /** | ||
module.exports = optionator({ | ||
prepend: "eslint [options] file.js [file.js] [dir]", | ||
concatRepeatedArrays: true, | ||
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." | ||
}, { | ||
option: "reset", | ||
type: "Boolean", | ||
description: "Set all default rules to off." | ||
}, { | ||
option: "eslintrc", | ||
type: "Boolean", | ||
default: "true", | ||
description: "Enable loading .eslintrc configuration." | ||
}, { | ||
option: "env", | ||
type: "[String]", | ||
description: "Specify environments." | ||
}, { | ||
option: "global", | ||
type: "[String]", | ||
description: "Define global variables." | ||
}] | ||
prepend: "eslint [options] file.js [file.js] [dir]", | ||
concatRepeatedArrays: true, | ||
mergeRepeatedObjects: true, | ||
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." | ||
}, { | ||
option: "reset", | ||
type: "Boolean", | ||
description: "Set all default rules to off." | ||
}, { | ||
option: "eslintrc", | ||
type: "Boolean", | ||
default: "true", | ||
description: "Enable loading .eslintrc configuration." | ||
}, { | ||
option: "env", | ||
type: "[String]", | ||
description: "Specify environments." | ||
}, { | ||
option: "force", | ||
type: "Boolean", | ||
description: "Allow linting of otherwise ignored files." | ||
}, { | ||
option: "global", | ||
type: "[String]", | ||
description: "Define global variables." | ||
},{ | ||
option: "rule", | ||
type: "Object", | ||
description: "Specify rules." | ||
}] | ||
}); |
@@ -96,2 +96,3 @@ /** | ||
declare(node.id ? [node.id.name] : []); | ||
declare(["arguments"]); | ||
} | ||
@@ -130,2 +131,5 @@ | ||
"FunctionDeclaration:exit": popScope, | ||
"FunctionExpression:exit": popScope, | ||
"Identifier": function(node) { | ||
@@ -132,0 +136,0 @@ var ancestor = context.getAncestors().pop(); |
@@ -16,2 +16,3 @@ /** | ||
var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", | ||
BODY_MESSAGE = "Statement inside of curly braces should be on next line.", | ||
CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.", | ||
@@ -40,4 +41,7 @@ CLOSE_MESSAGE_STROUSTRUP = "Closing curly brace appears on the same line as the subsequent block."; | ||
curlyToken = context.getFirstToken(block); | ||
if (previousToken.loc.start.line !== curlyToken.loc.start.line) { | ||
context.report(node, OPEN_MESSAGE); | ||
} else if (block.body.length && curlyToken.loc.start.line === block.body[0].loc.start.line) { | ||
context.report(block.body[0], BODY_MESSAGE); | ||
} | ||
@@ -44,0 +48,0 @@ } |
@@ -18,3 +18,3 @@ /** | ||
if (node.operator === "delete" && node.argument.type === "Identifier") { | ||
context.report(node, "Variables should not be deleted."); | ||
context.report(node, "Variables should not be deleted."); | ||
} | ||
@@ -21,0 +21,0 @@ } |
@@ -20,3 +20,3 @@ /** | ||
if (node.type === "ReturnStatement") { | ||
context.report(alternate, "Unexpected 'else' after 'return'."); | ||
context.report(alternate, "Unexpected 'else' after 'return'."); | ||
} | ||
@@ -23,0 +23,0 @@ } |
@@ -30,3 +30,5 @@ /** | ||
if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") { return; } | ||
if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") { | ||
return; | ||
} | ||
@@ -37,3 +39,5 @@ affectsProto = lhs.object.computed ? | ||
if (!affectsProto) { return; } | ||
if (!affectsProto) { | ||
return; | ||
} | ||
@@ -40,0 +44,0 @@ BUILTINS.forEach(function(builtin) { |
@@ -90,2 +90,6 @@ /** | ||
case "CallExpression": | ||
// IIFE is allowed to have parens in any position (#655) | ||
if (node.callee.type === "FunctionExpression") { | ||
return -1; | ||
} | ||
return 16; | ||
@@ -162,3 +166,5 @@ case "NewExpression": | ||
"DoWhileStatement": function(node) { | ||
if(isParenthesisedTwice(node.test)) { report(node.test); } | ||
if(isParenthesisedTwice(node.test)) { | ||
report(node.test); | ||
} | ||
}, | ||
@@ -175,11 +181,23 @@ "ExpressionStatement": function(node) { | ||
"ForInStatement": function(node) { | ||
if(isParenthesised(node.right)) { report(node.right); } | ||
if(isParenthesised(node.right)) { | ||
report(node.right); | ||
} | ||
}, | ||
"ForStatement": function(node) { | ||
if(node.init && isParenthesised(node.init)) { report(node.init); } | ||
if(node.test && isParenthesised(node.test)) { report(node.test); } | ||
if(node.update && isParenthesised(node.update)) { report(node.update); } | ||
if(node.init && isParenthesised(node.init)) { | ||
report(node.init); | ||
} | ||
if(node.test && isParenthesised(node.test)) { | ||
report(node.test); | ||
} | ||
if(node.update && isParenthesised(node.update)) { | ||
report(node.update); | ||
} | ||
}, | ||
"IfStatement": function(node) { | ||
if(isParenthesisedTwice(node.test)) { report(node.test); } | ||
if(isParenthesisedTwice(node.test)) { | ||
report(node.test); | ||
} | ||
}, | ||
@@ -213,17 +231,27 @@ "LogicalExpression": dryBinaryLogical, | ||
"ReturnStatement": function(node) { | ||
if(node.argument && isParenthesised(node.argument)) { report(node.argument); } | ||
if(node.argument && isParenthesised(node.argument)) { | ||
report(node.argument); | ||
} | ||
}, | ||
"SequenceExpression": function(node) { | ||
[].forEach.call(node.expressions, function(e) { | ||
if(isParenthesised(e)) { report(e); } | ||
if(isParenthesised(e) && precedence(e) >= precedence(node)) { | ||
report(e); | ||
} | ||
}); | ||
}, | ||
"SwitchCase": function(node) { | ||
if(node.test && isParenthesised(node.test)) { report(node.test); } | ||
if(node.test && isParenthesised(node.test)) { | ||
report(node.test); | ||
} | ||
}, | ||
"SwitchStatement": function(node) { | ||
if(isParenthesisedTwice(node.discriminant)) { report(node.discriminant); } | ||
if(isParenthesisedTwice(node.discriminant)) { | ||
report(node.discriminant); | ||
} | ||
}, | ||
"ThrowStatement": function(node) { | ||
if(isParenthesised(node.argument)) { report(node.argument); } | ||
if(isParenthesised(node.argument)) { | ||
report(node.argument); | ||
} | ||
}, | ||
@@ -238,6 +266,10 @@ "UnaryExpression": dryUnaryUpdate, | ||
"WhileStatement": function(node) { | ||
if(isParenthesisedTwice(node.test)) { report(node.test); } | ||
if(isParenthesisedTwice(node.test)) { | ||
report(node.test); | ||
} | ||
}, | ||
"WithStatement": function(node) { | ||
if(isParenthesisedTwice(node.object)) { report(node.object); } | ||
if(isParenthesisedTwice(node.object)) { | ||
report(node.object); | ||
} | ||
} | ||
@@ -244,0 +276,0 @@ }; |
@@ -19,3 +19,6 @@ /** | ||
if (variable.identifiers && variable.identifiers.length > 1) { | ||
variable.identifiers.sort(function(a, b) { return a.range[1] - b.range[1];}); | ||
variable.identifiers.sort(function(a, b) { | ||
return a.range[1] - b.range[1]; | ||
}); | ||
for (var i = 1, l = variable.identifiers.length; i < l; i++) { | ||
@@ -22,0 +25,0 @@ context.report(variable.identifiers[i], "{{a}} is already defined", {a: variable.name}); |
@@ -26,3 +26,5 @@ /** | ||
"FunctionExpression": function(node) { | ||
if(node.id) { checkForViolation(node.id); } | ||
if(node.id) { | ||
checkForViolation(node.id); | ||
} | ||
[].map.call(node.params, checkForViolation); | ||
@@ -29,0 +31,0 @@ }, |
@@ -39,3 +39,5 @@ /** | ||
// openParenIndex will be undefined for a NewExpression with no argument list | ||
if (!openParenIndex) { return; } | ||
if (!openParenIndex) { | ||
return; | ||
} | ||
@@ -42,0 +44,0 @@ // look for a space between the callee and the open paren |
@@ -22,5 +22,3 @@ /** | ||
var emptySpot = node.elements.some(function(value) { | ||
return value === null; | ||
}); | ||
var emptySpot = node.elements.indexOf(null) > -1; | ||
@@ -27,0 +25,0 @@ if (emptySpot) { |
@@ -15,5 +15,6 @@ /** | ||
var config = { | ||
vars: "local", | ||
vars: "all", | ||
args: "after-used" | ||
}; | ||
if (context.options[0]) { | ||
@@ -31,2 +32,3 @@ if (typeof(context.options[0]) === "string") { | ||
function lookupVariableName(name) { | ||
@@ -45,5 +47,3 @@ | ||
return candidates.filter(function (candidate) { | ||
return variable.identifiers.some(function (identifier) { | ||
return candidate.node === identifier; | ||
}); | ||
return variable.identifiers.indexOf(candidate.node) > -1; | ||
})[0]; | ||
@@ -107,2 +107,8 @@ } | ||
/** | ||
* Determines if the given node represents a function. | ||
* @param {ASTNode} node The node to check. | ||
* @returns {boolean} True if the node represents a function, false if not. | ||
* @private | ||
*/ | ||
function isFunction(node) { | ||
@@ -109,0 +115,0 @@ return node && node.type && (node.type === "FunctionDeclaration" || node.type === "FunctionExpression"); |
@@ -7,2 +7,8 @@ /** | ||
//------------------------------------------------------------------------------ | ||
// Constants | ||
//------------------------------------------------------------------------------ | ||
var NO_FUNC = "nofunc"; | ||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
@@ -30,6 +36,9 @@ //------------------------------------------------------------------------------ | ||
var scope = context.getScope(); | ||
var typeOption = context.options[0]; | ||
function checkLocationAndReport(reference, declaration) { | ||
if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) { | ||
context.report(reference.identifier, "{{a}} was used before it was defined", {a: reference.identifier.name}); | ||
if (typeOption !== NO_FUNC || declaration.defs[0].type !== "FunctionName") { | ||
if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) { | ||
context.report(reference.identifier, "{{a}} was used before it was defined", {a: reference.identifier.name}); | ||
} | ||
} | ||
@@ -36,0 +45,0 @@ } |
@@ -12,2 +12,4 @@ /** | ||
var OPT_OUT_PATTERN = /[\[\(\/\+\-]/; | ||
var always = context.options[0] !== "never"; | ||
@@ -25,3 +27,4 @@ | ||
function checkForSemicolon(node) { | ||
var lastToken = context.getLastToken(node); | ||
var lastToken = context.getLastToken(node), | ||
nextToken = context.getTokenAfter(node); | ||
@@ -34,3 +37,7 @@ if (always) { | ||
if (lastToken.type === "Punctuator" && lastToken.value === ";") { | ||
context.report(node, node.loc.end, "Extra semicolon."); | ||
if (!nextToken || !(OPT_OUT_PATTERN.test(nextToken.value))) { | ||
context.report(node, node.loc.end, "Extra semicolon."); | ||
} | ||
} | ||
@@ -75,3 +82,4 @@ } | ||
nextToken = context.getTokenAfter(node) || context.getLastToken(node); | ||
if (!(/[\[\(\/\+\-]/.test(nextToken.value))) { | ||
if (!(OPT_OUT_PATTERN.test(nextToken.value))) { | ||
context.report(node, "Extra semicolon."); | ||
@@ -78,0 +86,0 @@ } |
@@ -55,3 +55,5 @@ /** | ||
function checkBinary(node) { | ||
if(!isSpaced(node.left, node.right)) { report(node); } | ||
if(!isSpaced(node.left, node.right)) { | ||
report(node); | ||
} | ||
} | ||
@@ -58,0 +60,0 @@ |
@@ -23,4 +23,12 @@ /** | ||
return { | ||
"ReturnStatement": function(node) { if(node.argument) { check(node); } }, | ||
"SwitchCase": function(node) { if(node.test) { check(node); } }, | ||
"ReturnStatement": function(node) { | ||
if(node.argument) { | ||
check(node); | ||
} | ||
}, | ||
"SwitchCase": function(node) { | ||
if(node.test) { | ||
check(node); | ||
} | ||
}, | ||
"ThrowStatement": check | ||
@@ -27,0 +35,0 @@ }; |
@@ -21,4 +21,7 @@ /** | ||
prefer = options.prefer || {}, | ||
requireReturn = options.requireReturn === false ? false : true; | ||
// these both default to true, so you have to explicitly make them false | ||
requireReturn = options.requireReturn === false ? false : true, | ||
requireParamDescription = options.requireParamDescription === false ? false : true; | ||
//-------------------------------------------------------------------------- | ||
@@ -31,3 +34,7 @@ // Helpers | ||
// When parsing a new function, store it in our function stack | ||
/** | ||
* When parsing a new function, store it in our function stack. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function startFunction() { | ||
@@ -37,2 +44,8 @@ fns.push({returnPresent: false}); | ||
/** | ||
* Indicate that return has been found in the current function. | ||
* @param {ASTNode} node The return node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function addReturn(node) { | ||
@@ -50,2 +63,3 @@ var functionState = fns[fns.length - 1]; | ||
* @returns {void} | ||
* @private | ||
*/ | ||
@@ -89,3 +103,3 @@ function checkJSDoc(node) { | ||
if (!tag.description) { | ||
if (!tag.description && requireParamDescription) { | ||
context.report(jsdocNode, "Missing JSDoc parameter description for '{{name}}'.", { name: tag.name }); | ||
@@ -92,0 +106,0 @@ } |
{ | ||
"name": "eslint", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -37,3 +37,3 @@ "description": "An Esprima-based pattern checker for JavaScript.", | ||
"estraverse": "~1.3.0", | ||
"esprima": "~1.1.1", | ||
"esprima": "^1.2.0", | ||
"escope": "~1.0.0", | ||
@@ -72,3 +72,6 @@ "glob": "~3.2.7", | ||
"preferGlobal": true, | ||
"license": "MIT" | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=0.10" | ||
} | ||
} |
@@ -12,8 +12,2 @@ [![Build Status](https://travis-ci.org/eslint/eslint.svg?branch=master)](http://travis-ci.org/eslint/eslint) | ||
## Alpha Version | ||
ESLint, as of v0.1.0, is in alpha, meaning that there is some stability but you shouldn't be depending on it as your only means of code verification at this time. The alpha version is intended to gather feedback from the community, catch bugs, and determine general direction for the project. | ||
When ESLint v0.5.0 is released, it will be in beta and will have more stability in terms of interface and API. | ||
## Installation | ||
@@ -20,0 +14,0 @@ |
288405
141
7436
42
+ Addedesprima@1.2.5(transitive)
- Removedesprima@1.1.1(transitive)
Updatedesprima@^1.2.0