Browse Source

tools: update ESLint to 3.3.0 and enable rules

Update ESLint 3.3.0 and update .eslintrc:

* replace deprecated no-negated-in-lhs rule with no-unsafe-negation
  * http://eslint.org/docs/rules/no-negated-in-lhs
  * http://eslint.org/docs/rules/no-unsafe-negation
* enable no-template-curly-in-string
  * http://eslint.org/docs/rules/no-template-curly-in-string
* enable no-global-assign
  * http://eslint.org/docs/rules/no-global-assign
* enable func-call-spacing
  * http://eslint.org/docs/rules/func-call-spacing

PR-URL: https://github.com/nodejs/node/pull/8097
Reviewed-By: targos - Michaël Zasso <mic.besace@gmail.com>
Reviewed-By: jasnell - James M Snell <jasnell@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
v6.x
Rich Trott 9 years ago
committed by Evan Lucas
parent
commit
cdcf23ab7f
  1. 5
      .eslintrc
  2. 5
      tools/eslint/conf/category-list.json
  3. 2
      tools/eslint/conf/environments.js
  4. 11
      tools/eslint/conf/eslint-all.js
  5. 5
      tools/eslint/conf/eslint.json
  6. 165
      tools/eslint/lib/ast-utils.js
  7. 93
      tools/eslint/lib/cli-engine.js
  8. 40
      tools/eslint/lib/cli.js
  9. 34
      tools/eslint/lib/code-path-analysis/code-path-analyzer.js
  10. 14
      tools/eslint/lib/code-path-analysis/code-path-segment.js
  11. 200
      tools/eslint/lib/code-path-analysis/code-path-state.js
  12. 14
      tools/eslint/lib/code-path-analysis/code-path.js
  13. 24
      tools/eslint/lib/code-path-analysis/debug-helpers.js
  14. 18
      tools/eslint/lib/code-path-analysis/fork-context.js
  15. 47
      tools/eslint/lib/config.js
  16. 62
      tools/eslint/lib/config/autoconfig.js
  17. 51
      tools/eslint/lib/config/config-file.js
  18. 78
      tools/eslint/lib/config/config-initializer.js
  19. 24
      tools/eslint/lib/config/config-ops.js
  20. 31
      tools/eslint/lib/config/config-rule.js
  21. 13
      tools/eslint/lib/config/config-validator.js
  22. 2
      tools/eslint/lib/config/environments.js
  23. 17
      tools/eslint/lib/config/plugins.js
  24. 140
      tools/eslint/lib/eslint.js
  25. 31
      tools/eslint/lib/file-finder.js
  26. 4
      tools/eslint/lib/formatters/checkstyle.js
  27. 2
      tools/eslint/lib/formatters/compact.js
  28. 21
      tools/eslint/lib/formatters/html.js
  29. 4
      tools/eslint/lib/formatters/jslint-xml.js
  30. 6
      tools/eslint/lib/formatters/junit.js
  31. 4
      tools/eslint/lib/formatters/stylish.js
  32. 14
      tools/eslint/lib/formatters/table.js
  33. 8
      tools/eslint/lib/formatters/tap.js
  34. 2
      tools/eslint/lib/formatters/unix.js
  35. 2
      tools/eslint/lib/formatters/visualstudio.js
  36. 25
      tools/eslint/lib/ignored-paths.js
  37. 31
      tools/eslint/lib/internal-rules/internal-no-invalid-meta.js
  38. 4
      tools/eslint/lib/load-rules.js
  39. 2
      tools/eslint/lib/options.js
  40. 9
      tools/eslint/lib/rule-context.js
  41. 6
      tools/eslint/lib/rules.js
  42. 12
      tools/eslint/lib/rules/accessor-pairs.js
  43. 16
      tools/eslint/lib/rules/array-bracket-spacing.js
  44. 44
      tools/eslint/lib/rules/array-callback-return.js
  45. 14
      tools/eslint/lib/rules/arrow-body-style.js
  46. 72
      tools/eslint/lib/rules/arrow-parens.js
  47. 14
      tools/eslint/lib/rules/arrow-spacing.js
  48. 8
      tools/eslint/lib/rules/block-scoped-var.js
  49. 12
      tools/eslint/lib/rules/block-spacing.js
  50. 31
      tools/eslint/lib/rules/brace-style.js
  51. 9
      tools/eslint/lib/rules/callback-return.js
  52. 16
      tools/eslint/lib/rules/camelcase.js
  53. 26
      tools/eslint/lib/rules/comma-dangle.js
  54. 20
      tools/eslint/lib/rules/comma-spacing.js
  55. 19
      tools/eslint/lib/rules/comma-style.js
  56. 10
      tools/eslint/lib/rules/complexity.js
  57. 10
      tools/eslint/lib/rules/computed-property-spacing.js
  58. 8
      tools/eslint/lib/rules/consistent-return.js
  59. 12
      tools/eslint/lib/rules/consistent-this.js
  60. 36
      tools/eslint/lib/rules/constructor-super.js
  61. 22
      tools/eslint/lib/rules/curly.js
  62. 16
      tools/eslint/lib/rules/default-case.js
  63. 10
      tools/eslint/lib/rules/dot-location.js
  64. 8
      tools/eslint/lib/rules/dot-notation.js
  65. 2
      tools/eslint/lib/rules/eol-last.js
  66. 83
      tools/eslint/lib/rules/eqeqeq.js
  67. 153
      tools/eslint/lib/rules/func-call-spacing.js
  68. 8
      tools/eslint/lib/rules/func-names.js
  69. 10
      tools/eslint/lib/rules/func-style.js
  70. 22
      tools/eslint/lib/rules/generator-star-spacing.js
  71. 12
      tools/eslint/lib/rules/global-require.js
  72. 2
      tools/eslint/lib/rules/guard-for-in.js
  73. 8
      tools/eslint/lib/rules/handle-callback-err.js
  74. 4
      tools/eslint/lib/rules/id-blacklist.js
  75. 22
      tools/eslint/lib/rules/id-length.js
  76. 8
      tools/eslint/lib/rules/id-match.js
  77. 92
      tools/eslint/lib/rules/indent.js
  78. 14
      tools/eslint/lib/rules/init-declarations.js
  79. 8
      tools/eslint/lib/rules/jsx-quotes.js
  80. 56
      tools/eslint/lib/rules/key-spacing.js
  81. 60
      tools/eslint/lib/rules/keyword-spacing.js
  82. 17
      tools/eslint/lib/rules/linebreak-style.js
  83. 36
      tools/eslint/lib/rules/lines-around-comment.js
  84. 8
      tools/eslint/lib/rules/max-depth.js
  85. 30
      tools/eslint/lib/rules/max-len.js
  86. 24
      tools/eslint/lib/rules/max-lines.js
  87. 10
      tools/eslint/lib/rules/max-nested-callbacks.js
  88. 4
      tools/eslint/lib/rules/max-params.js
  89. 12
      tools/eslint/lib/rules/max-statements-per-line.js
  90. 10
      tools/eslint/lib/rules/max-statements.js
  91. 6
      tools/eslint/lib/rules/multiline-ternary.js
  92. 58
      tools/eslint/lib/rules/new-cap.js
  93. 6
      tools/eslint/lib/rules/new-parens.js
  94. 53
      tools/eslint/lib/rules/newline-after-var.js
  95. 19
      tools/eslint/lib/rules/newline-before-return.js
  96. 12
      tools/eslint/lib/rules/newline-per-chained-call.js
  97. 33
      tools/eslint/lib/rules/no-alert.js
  98. 8
      tools/eslint/lib/rules/no-bitwise.js
  99. 2
      tools/eslint/lib/rules/no-caller.js
  100. 2
      tools/eslint/lib/rules/no-case-declarations.js

5
.eslintrc

@ -19,17 +19,19 @@ rules:
no-func-assign: 2 no-func-assign: 2
no-invalid-regexp: 2 no-invalid-regexp: 2
no-irregular-whitespace: 2 no-irregular-whitespace: 2
no-negated-in-lhs: 2
no-obj-calls: 2 no-obj-calls: 2
no-proto: 2 no-proto: 2
no-template-curly-in-string: 2
no-unexpected-multiline: 2 no-unexpected-multiline: 2
no-unreachable: 2 no-unreachable: 2
no-unsafe-negation: 2
use-isnan: 2 use-isnan: 2
valid-typeof: 2 valid-typeof: 2
# Best Practices # Best Practices
# http://eslint.org/docs/rules/#best-practices # http://eslint.org/docs/rules/#best-practices
no-fallthrough: 2 no-fallthrough: 2
no-global-assign: 2
no-multi-spaces: 2 no-multi-spaces: 2
no-octal: 2 no-octal: 2
no-redeclare: 2 no-redeclare: 2
@ -58,6 +60,7 @@ rules:
brace-style: [2, 1tbs, {allowSingleLine: true}] brace-style: [2, 1tbs, {allowSingleLine: true}]
comma-spacing: 2 comma-spacing: 2
eol-last: 2 eol-last: 2
func-call-spacing: 2
indent: [2, 2, {SwitchCase: 1, MemberExpression: 1}] indent: [2, 2, {SwitchCase: 1, MemberExpression: 1}]
key-spacing: [2, {mode: minimum}] key-spacing: [2, {mode: minimum}]
keyword-spacing: 2 keyword-spacing: 2

5
tools/eslint/conf/category-list.json

@ -8,6 +8,11 @@
{ "name": "Stylistic Issues", "description": "These rules relate to style guidelines, and are therefore quite subjective:" }, { "name": "Stylistic Issues", "description": "These rules relate to style guidelines, and are therefore quite subjective:" },
{ "name": "ECMAScript 6", "description": "These rules relate to ES6, also known as ES2015:" } { "name": "ECMAScript 6", "description": "These rules relate to ES6, also known as ES2015:" }
], ],
"deprecated": {
"name": "Deprecated",
"description": "These rules have been deprecated and replaced by newer rules:",
"rules": []
},
"removed": { "removed": {
"name": "Removed", "name": "Removed",
"description": "These rules from older versions of ESLint have been replaced by newer rules:", "description": "These rules from older versions of ESLint have been replaced by newer rules:",

2
tools/eslint/conf/environments.js

@ -8,7 +8,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let globals = require("globals"); const globals = require("globals");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Public Interface // Public Interface

11
tools/eslint/conf/eslint-all.js

@ -9,17 +9,16 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let fs = require("fs"), const load = require("../lib/load-rules"),
path = require("path"); rules = require("../lib/rules");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let ruleFiles = fs.readdirSync(path.resolve(__dirname, "../lib/rules")); const enabledRules = Object.keys(load()).reduce((result, ruleId) => {
let enabledRules = ruleFiles.reduce(function(result, filename) { if (!rules.get(ruleId).meta.deprecated) {
if (path.extname(filename) === ".js") { result[ruleId] = "error";
result[path.basename(filename, ".js")] = "error";
} }
return result; return result;
}, {}); }, {});

5
tools/eslint/conf/eslint.json

@ -41,6 +41,7 @@
"no-fallthrough": "error", "no-fallthrough": "error",
"no-floating-decimal": "off", "no-floating-decimal": "off",
"no-func-assign": "error", "no-func-assign": "error",
"no-global-assign": "off",
"no-implicit-coercion": "off", "no-implicit-coercion": "off",
"no-implicit-globals": "off", "no-implicit-globals": "off",
"no-implied-eval": "off", "no-implied-eval": "off",
@ -113,6 +114,7 @@
"no-unneeded-ternary": "off", "no-unneeded-ternary": "off",
"no-unreachable": "error", "no-unreachable": "error",
"no-unsafe-finally": "error", "no-unsafe-finally": "error",
"no-unsafe-negation": "off",
"no-unused-expressions": "off", "no-unused-expressions": "off",
"no-unused-labels": "error", "no-unused-labels": "error",
"no-unused-vars": "error", "no-unused-vars": "error",
@ -152,6 +154,7 @@
"dot-notation": "off", "dot-notation": "off",
"eol-last": "off", "eol-last": "off",
"eqeqeq": "off", "eqeqeq": "off",
"func-call-spacing": "off",
"func-names": "off", "func-names": "off",
"func-style": "off", "func-style": "off",
"generator-star-spacing": "off", "generator-star-spacing": "off",
@ -204,6 +207,7 @@
"rest-spread-spacing": "off", "rest-spread-spacing": "off",
"semi": "off", "semi": "off",
"semi-spacing": "off", "semi-spacing": "off",
"sort-keys": "off",
"sort-imports": "off", "sort-imports": "off",
"sort-vars": "off", "sort-vars": "off",
"space-before-blocks": "off", "space-before-blocks": "off",
@ -221,6 +225,7 @@
"vars-on-top": "off", "vars-on-top": "off",
"wrap-iife": "off", "wrap-iife": "off",
"wrap-regex": "off", "wrap-regex": "off",
"no-template-curly-in-string": "off",
"yield-star-spacing": "off", "yield-star-spacing": "off",
"yoda": "off" "yoda": "off"
} }

165
tools/eslint/lib/ast-utils.js

@ -9,19 +9,19 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let esutils = require("esutils"); const esutils = require("esutils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/; const anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/;
let anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/; const anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/;
let arrayOrTypedArrayPattern = /Array$/; const arrayOrTypedArrayPattern = /Array$/;
let arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/; const arrayMethodPattern = /^(?:every|filter|find|findIndex|forEach|map|some)$/;
let bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/; const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/;
let breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/; const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/;
let thisTagPattern = /^[\s\*]*@this/m; const thisTagPattern = /^[\s\*]*@this/m;
/** /**
* Checks reference if is non initializer and writable. * Checks reference if is non initializer and writable.
@ -32,15 +32,14 @@ let thisTagPattern = /^[\s\*]*@this/m;
* @private * @private
*/ */
function isModifyingReference(reference, index, references) { function isModifyingReference(reference, index, references) {
let identifier = reference.identifier, const identifier = reference.identifier;
modifyingDifferentIdentifier;
/* /*
* Destructuring assignments can have multiple default value, so * Destructuring assignments can have multiple default value, so
* possibly there are multiple writeable references for the same * possibly there are multiple writeable references for the same
* identifier. * identifier.
*/ */
modifyingDifferentIdentifier = index === 0 || const modifyingDifferentIdentifier = index === 0 ||
references[index - 1].identifier !== identifier; references[index - 1].identifier !== identifier;
return (identifier && return (identifier &&
@ -50,16 +49,23 @@ function isModifyingReference(reference, index, references) {
); );
} }
/**
* Checks whether the given string starts with uppercase or not.
*
* @param {string} s - The string to check.
* @returns {boolean} `true` if the string starts with uppercase.
*/
function startsWithUpperCase(s) {
return s[0] !== s[0].toLocaleLowerCase();
}
/** /**
* Checks whether or not a node is a constructor. * Checks whether or not a node is a constructor.
* @param {ASTNode} node - A function node to check. * @param {ASTNode} node - A function node to check.
* @returns {boolean} Wehether or not a node is a constructor. * @returns {boolean} Wehether or not a node is a constructor.
*/ */
function isES5Constructor(node) { function isES5Constructor(node) {
return ( return (node.id && startsWithUpperCase(node.id.name));
node.id &&
node.id.name[0] !== node.id.name[0].toLocaleLowerCase()
);
} }
/** /**
@ -160,7 +166,7 @@ function isMethodWhichHasThisArg(node) {
* @returns {boolean} Whether or not the node has a `@this` tag in its comments. * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
*/ */
function hasJSDocThisTag(node, sourceCode) { function hasJSDocThisTag(node, sourceCode) {
let jsdocComment = sourceCode.getJSDocComment(node); const jsdocComment = sourceCode.getJSDocComment(node);
if (jsdocComment && thisTagPattern.test(jsdocComment.value)) { if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
return true; return true;
@ -183,7 +189,7 @@ function hasJSDocThisTag(node, sourceCode) {
* @private * @private
*/ */
function isParenthesised(sourceCode, node) { function isParenthesised(sourceCode, node) {
let previousToken = sourceCode.getTokenBefore(node), const previousToken = sourceCode.getTokenBefore(node),
nextToken = sourceCode.getTokenAfter(node); nextToken = sourceCode.getTokenAfter(node);
return Boolean(previousToken && nextToken) && return Boolean(previousToken && nextToken) &&
@ -285,7 +291,7 @@ module.exports = {
* @returns {boolean} `true` if the node is an ESLint directive comment * @returns {boolean} `true` if the node is an ESLint directive comment
*/ */
isDirectiveComment: function(node) { isDirectiveComment: function(node) {
let comment = node.value.trim(); const comment = node.value.trim();
return ( return (
node.type === "Line" && comment.indexOf("eslint-") === 0 || node.type === "Line" && comment.indexOf("eslint-") === 0 ||
@ -321,7 +327,7 @@ module.exports = {
let scope = initScope; let scope = initScope;
while (scope) { while (scope) {
let variable = scope.set.get(name); const variable = scope.set.get(name);
if (variable) { if (variable) {
return variable; return variable;
@ -345,9 +351,9 @@ module.exports = {
* If the location is below, this judges `this` is valid. * If the location is below, this judges `this` is valid.
* *
* - The location is not on an object literal. * - The location is not on an object literal.
* - The location does not assign to a property. * - The location is not assigned to a variable which starts with an uppercase letter.
* - The location is not on an ES2015 class. * - The location is not on an ES2015 class.
* - The location does not call its `bind`/`call`/`apply` method directly. * - Its `bind`/`call`/`apply` method is not called directly.
* - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given. * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
* *
* @param {ASTNode} node - A function node to check. * @param {ASTNode} node - A function node to check.
@ -358,9 +364,10 @@ module.exports = {
if (isES5Constructor(node) || hasJSDocThisTag(node, sourceCode)) { if (isES5Constructor(node) || hasJSDocThisTag(node, sourceCode)) {
return false; return false;
} }
const isAnonymous = node.id === null;
while (node) { while (node) {
let parent = node.parent; const parent = node.parent;
switch (parent.type) { switch (parent.type) {
@ -392,25 +399,44 @@ module.exports = {
// e.g. // e.g.
// var obj = { foo() { ... } }; // var obj = { foo() { ... } };
// var obj = { foo: function() { ... } }; // var obj = { foo: function() { ... } };
case "Property":
return false;
// e.g.
// obj.foo = foo() { ... };
case "AssignmentExpression":
return (
parent.right !== node ||
parent.left.type !== "MemberExpression"
);
// e.g.
// class A { constructor() { ... } } // class A { constructor() { ... } }
// class A { foo() { ... } } // class A { foo() { ... } }
// class A { get foo() { ... } } // class A { get foo() { ... } }
// class A { set foo() { ... } } // class A { set foo() { ... } }
// class A { static foo() { ... } } // class A { static foo() { ... } }
case "Property":
case "MethodDefinition": case "MethodDefinition":
return false; return parent.value !== node;
// e.g.
// obj.foo = function foo() { ... };
// Foo = function() { ... };
// [obj.foo = function foo() { ... }] = a;
// [Foo = function() { ... }] = a;
case "AssignmentExpression":
case "AssignmentPattern":
if (parent.right === node) {
if (parent.left.type === "MemberExpression") {
return false;
}
if (isAnonymous &&
parent.left.type === "Identifier" &&
startsWithUpperCase(parent.left.name)
) {
return false;
}
}
return true;
// e.g.
// var Foo = function() { ... };
case "VariableDeclarator":
return !(
isAnonymous &&
parent.init === node &&
parent.id.type === "Identifier" &&
startsWithUpperCase(parent.id.name)
);
// e.g. // e.g.
// var foo = function foo() { ... }.bind(obj); // var foo = function foo() { ... }.bind(obj);
@ -585,5 +611,74 @@ module.exports = {
*/ */
isFunction: function(node) { isFunction: function(node) {
return Boolean(node && anyFunctionPattern.test(node.type)); return Boolean(node && anyFunctionPattern.test(node.type));
},
/**
* Gets the property name of a given node.
* The node can be a MemberExpression, a Property, or a MethodDefinition.
*
* If the name is dynamic, this returns `null`.
*
* For examples:
*
* a.b // => "b"
* a["b"] // => "b"
* a['b'] // => "b"
* a[`b`] // => "b"
* a[100] // => "100"
* a[b] // => null
* a["a" + "b"] // => null
* a[tag`b`] // => null
* a[`${b}`] // => null
*
* let a = {b: 1} // => "b"
* let a = {["b"]: 1} // => "b"
* let a = {['b']: 1} // => "b"
* let a = {[`b`]: 1} // => "b"
* let a = {[100]: 1} // => "100"
* let a = {[b]: 1} // => null
* let a = {["a" + "b"]: 1} // => null
* let a = {[tag`b`]: 1} // => null
* let a = {[`${b}`]: 1} // => null
*
* @param {ASTNode} node - The node to get.
* @returns {string|null} The property name if static. Otherwise, null.
*/
getStaticPropertyName(node) {
let prop;
switch (node && node.type) {
case "Property":
case "MethodDefinition":
prop = node.key;
break;
case "MemberExpression":
prop = node.property;
break;
// no default
}
switch (prop && prop.type) {
case "Literal":
return String(prop.value);
case "TemplateLiteral":
if (prop.expressions.length === 0 && prop.quasis.length === 1) {
return prop.quasis[0].value.cooked;
}
break;
case "Identifier":
if (!node.computed) {
return prop.name;
}
break;
// no default
}
return null;
} }
}; };

93
tools/eslint/lib/cli-engine.js

@ -15,12 +15,8 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let fs = require("fs"), const fs = require("fs"),
path = require("path"), path = require("path"),
lodash = require("lodash"),
debug = require("debug"),
rules = require("./rules"), rules = require("./rules"),
eslint = require("./eslint"), eslint = require("./eslint"),
defaultOptions = require("../conf/cli-options"), defaultOptions = require("../conf/cli-options"),
@ -36,6 +32,7 @@ let fs = require("fs"),
pkg = require("../package.json"); pkg = require("../package.json");
const debug = require("debug")("eslint:cli-engine");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Typedefs // Typedefs
@ -84,8 +81,6 @@ let fs = require("fs"),
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:cli-engine");
/** /**
* It will calculate the error and warning count for collection of messages per file * It will calculate the error and warning count for collection of messages per file
* @param {Object[]} messages - Collection of messages * @param {Object[]} messages - Collection of messages
@ -137,12 +132,11 @@ function calculateStatsPerRun(results) {
* @private * @private
*/ */
function multipassFix(text, config, options) { function multipassFix(text, config, options) {
const MAX_PASSES = 10;
let messages = [], let messages = [],
fixedResult, fixedResult,
fixed = false, fixed = false,
passNumber = 0, passNumber = 0;
MAX_PASSES = 10;
/** /**
* This loop continues until one of the following is true: * This loop continues until one of the following is true:
@ -213,12 +207,9 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
eslint.reset(); eslint.reset();
let filePath, let filePath,
config,
messages, messages,
stats,
fileExtension, fileExtension,
processor, processor,
loadedPlugins,
fixedResult; fixedResult;
if (filename) { if (filename) {
@ -228,15 +219,15 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
filename = filename || "<text>"; filename = filename || "<text>";
debug("Linting " + filename); debug("Linting " + filename);
config = configHelper.getConfig(filePath); const config = configHelper.getConfig(filePath);
if (config.plugins) { if (config.plugins) {
Plugins.loadAll(config.plugins); Plugins.loadAll(config.plugins);
} }
loadedPlugins = Plugins.getAll(); const loadedPlugins = Plugins.getAll();
for (let plugin in loadedPlugins) { for (const plugin in loadedPlugins) {
if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) { if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) {
processor = loadedPlugins[plugin].processors[fileExtension]; processor = loadedPlugins[plugin].processors[fileExtension];
break; break;
@ -245,8 +236,8 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
if (processor) { if (processor) {
debug("Using processor"); debug("Using processor");
let parsedBlocks = processor.preprocess(text, filename); const parsedBlocks = processor.preprocess(text, filename);
let unprocessedMessages = []; const unprocessedMessages = [];
parsedBlocks.forEach(function(block) { parsedBlocks.forEach(function(block) {
unprocessedMessages.push(eslint.verify(block, config, { unprocessedMessages.push(eslint.verify(block, config, {
@ -275,9 +266,9 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
} }
} }
stats = calculateStatsPerFile(messages); const stats = calculateStatsPerFile(messages);
let result = { const result = {
filePath: filename, filePath: filename,
messages: messages, messages: messages,
errorCount: stats.errorCount, errorCount: stats.errorCount,
@ -302,7 +293,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig) {
*/ */
function processFile(filename, configHelper, options) { function processFile(filename, configHelper, options) {
let text = fs.readFileSync(path.resolve(filename), "utf8"), const text = fs.readFileSync(path.resolve(filename), "utf8"),
result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig); result = processText(text, configHelper, filename, options.fix, options.allowInlineConfig);
return result; return result;
@ -318,9 +309,9 @@ function processFile(filename, configHelper, options) {
*/ */
function createIgnoreResult(filePath, baseDir) { function createIgnoreResult(filePath, baseDir) {
let message; let message;
let isHidden = /^\./.test(path.basename(filePath)); const isHidden = /^\./.test(path.basename(filePath));
let isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath)); const isInNodeModules = baseDir && /^node_modules/.test(path.relative(baseDir, filePath));
let isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath)); const isInBowerComponents = baseDir && /^bower_components/.test(path.relative(baseDir, filePath));
if (isHidden) { if (isHidden) {
message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern \'!<relative/path/to/filename>\'\") to override."; message = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern \'!<relative/path/to/filename>\'\") to override.";
@ -377,8 +368,8 @@ function getCacheFile(cacheFile, cwd) {
*/ */
cacheFile = path.normalize(cacheFile); cacheFile = path.normalize(cacheFile);
let resolvedCacheFile = path.resolve(cwd, cacheFile); const resolvedCacheFile = path.resolve(cwd, cacheFile);
let looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep; const looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep;
/** /**
* return the name for the cache file in case the provided parameter is a directory * return the name for the cache file in case the provided parameter is a directory
@ -442,7 +433,7 @@ function getCacheFile(cacheFile, cwd) {
*/ */
function CLIEngine(options) { function CLIEngine(options) {
options = lodash.assign( options = Object.assign(
Object.create(null), Object.create(null),
defaultOptions, defaultOptions,
{cwd: process.cwd()}, {cwd: process.cwd()},
@ -455,7 +446,7 @@ function CLIEngine(options) {
*/ */
this.options = options; this.options = options;
let cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd); const cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile, this.options.cwd);
/** /**
* Cache used to avoid operating on files that haven't changed since the * Cache used to avoid operating on files that haven't changed since the
@ -467,7 +458,7 @@ function CLIEngine(options) {
// load in additional rules // load in additional rules
if (this.options.rulePaths) { if (this.options.rulePaths) {
let cwd = this.options.cwd; const cwd = this.options.cwd;
this.options.rulePaths.forEach(function(rulesdir) { this.options.rulePaths.forEach(function(rulesdir) {
debug("Loading rules from " + rulesdir); debug("Loading rules from " + rulesdir);
@ -502,7 +493,7 @@ CLIEngine.getFormatter = function(format) {
// if there's a slash, then it's a file // if there's a slash, then it's a file
if (format.indexOf("/") > -1) { if (format.indexOf("/") > -1) {
let cwd = this.options ? this.options.cwd : process.cwd(); const cwd = this.options ? this.options.cwd : process.cwd();
formatterPath = path.resolve(cwd, format); formatterPath = path.resolve(cwd, format);
} else { } else {
@ -527,10 +518,10 @@ CLIEngine.getFormatter = function(format) {
* @returns {LintResult[]} The filtered results. * @returns {LintResult[]} The filtered results.
*/ */
CLIEngine.getErrorResults = function(results) { CLIEngine.getErrorResults = function(results) {
let filtered = []; const filtered = [];
results.forEach(function(result) { results.forEach(function(result) {
let filteredMessages = result.messages.filter(isErrorMessage); const filteredMessages = result.messages.filter(isErrorMessage);
if (filteredMessages.length > 0) { if (filteredMessages.length > 0) {
filtered.push({ filtered.push({
@ -588,14 +579,11 @@ CLIEngine.prototype = {
* @returns {Object} The results for all files that were linted. * @returns {Object} The results for all files that were linted.
*/ */
executeOnFiles: function(patterns) { executeOnFiles: function(patterns) {
let results = [], const results = [],
options = this.options, options = this.options,
fileCache = this._fileCache, fileCache = this._fileCache,
configHelper = new Config(options), configHelper = new Config(options);
fileList, let prevConfig; // the previous configuration used
stats,
startTime,
prevConfig; // the previous configuration used
/** /**
* Calculates the hash of the config file used to validate a given file * Calculates the hash of the config file used to validate a given file
@ -603,7 +591,7 @@ CLIEngine.prototype = {
* @returns {string} the hash of the config * @returns {string} the hash of the config
*/ */
function hashOfConfigFor(filename) { function hashOfConfigFor(filename) {
let config = configHelper.getConfig(filename); const config = configHelper.getConfig(filename);
if (!prevConfig) { if (!prevConfig) {
prevConfig = {}; prevConfig = {};
@ -618,7 +606,7 @@ CLIEngine.prototype = {
*/ */
prevConfig.config = config; prevConfig.config = config;
let eslintVersion = pkg.version; const eslintVersion = pkg.version;
prevConfig.hash = hash(eslintVersion + "_" + stringify(config)); prevConfig.hash = hash(eslintVersion + "_" + stringify(config));
} }
@ -650,11 +638,11 @@ CLIEngine.prototype = {
* the file has changed * the file has changed
*/ */
descriptor = fileCache.getFileDescriptor(filename); descriptor = fileCache.getFileDescriptor(filename);
let meta = descriptor.meta || {}; const meta = descriptor.meta || {};
hashOfConfig = hashOfConfigFor(filename); hashOfConfig = hashOfConfigFor(filename);
let changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig; const changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig;
if (!changed) { if (!changed) {
debug("Skipping file since hasn't changed: " + filename); debug("Skipping file since hasn't changed: " + filename);
@ -676,7 +664,7 @@ CLIEngine.prototype = {
debug("Processing " + filename); debug("Processing " + filename);
let res = processFile(filename, configHelper, options); const res = processFile(filename, configHelper, options);
if (options.cache) { if (options.cache) {
@ -706,17 +694,18 @@ CLIEngine.prototype = {
results.push(res); results.push(res);
} }
startTime = Date.now(); const startTime = Date.now();
patterns = this.resolveFileGlobPatterns(patterns); patterns = this.resolveFileGlobPatterns(patterns);
fileList = globUtil.listFilesToProcess(patterns, options); const fileList = globUtil.listFilesToProcess(patterns, options);
fileList.forEach(function(fileInfo) { fileList.forEach(function(fileInfo) {
executeOnFile(fileInfo.filename, fileInfo.ignored); executeOnFile(fileInfo.filename, fileInfo.ignored);
}); });
stats = calculateStatsPerRun(results); const stats = calculateStatsPerRun(results);
if (options.cache) { if (options.cache) {
@ -742,8 +731,7 @@ CLIEngine.prototype = {
*/ */
executeOnText: function(text, filename, warnIgnored) { executeOnText: function(text, filename, warnIgnored) {
let results = [], const results = [],
stats,
options = this.options, options = this.options,
configHelper = new Config(options), configHelper = new Config(options),
ignoredPaths = new IgnoredPaths(options); ignoredPaths = new IgnoredPaths(options);
@ -761,7 +749,7 @@ CLIEngine.prototype = {
results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig)); results.push(processText(text, configHelper, filename, options.fix, options.allowInlineConfig));
} }
stats = calculateStatsPerRun(results); const stats = calculateStatsPerRun(results);
return { return {
results: results, results: results,
@ -778,7 +766,7 @@ CLIEngine.prototype = {
* @returns {Object} A configuration object for the file. * @returns {Object} A configuration object for the file.
*/ */
getConfigForFile: function(filePath) { getConfigForFile: function(filePath) {
let configHelper = new Config(this.options); const configHelper = new Config(this.options);
return configHelper.getConfig(filePath); return configHelper.getConfig(filePath);
}, },
@ -789,10 +777,9 @@ CLIEngine.prototype = {
* @returns {boolean} Whether or not the given path is ignored. * @returns {boolean} Whether or not the given path is ignored.
*/ */
isPathIgnored: function(filePath) { isPathIgnored: function(filePath) {
let ignoredPaths; const resolvedPath = path.resolve(this.options.cwd, filePath);
let resolvedPath = path.resolve(this.options.cwd, filePath); const ignoredPaths = new IgnoredPaths(this.options);
ignoredPaths = new IgnoredPaths(this.options);
return ignoredPaths.contains(resolvedPath); return ignoredPaths.contains(resolvedPath);
}, },

40
tools/eslint/lib/cli.js

@ -15,22 +15,20 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let fs = require("fs"), const fs = require("fs"),
path = require("path"), path = require("path"),
shell = require("shelljs"),
debug = require("debug"),
options = require("./options"), options = require("./options"),
CLIEngine = require("./cli-engine"), CLIEngine = require("./cli-engine"),
mkdirp = require("mkdirp"), mkdirp = require("mkdirp"),
log = require("./logging"); log = require("./logging");
const debug = require("debug")("eslint:cli");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:cli");
/** /**
* Translates the CLI options into the options expected by the CLIEngine. * Translates the CLI options into the options expected by the CLIEngine.
* @param {Object} cliOptions The CLI options to translate. * @param {Object} cliOptions The CLI options to translate.
@ -70,9 +68,7 @@ function translateOptions(cliOptions) {
* @private * @private
*/ */
function printResults(engine, results, format, outputFile) { function printResults(engine, results, format, outputFile) {
let formatter, let formatter;
output,
filePath;
try { try {
formatter = engine.getFormatter(format); formatter = engine.getFormatter(format);
@ -81,13 +77,13 @@ function printResults(engine, results, format, outputFile) {
return false; return false;
} }
output = formatter(results); const output = formatter(results);
if (output) { if (output) {
if (outputFile) { if (outputFile) {
filePath = path.resolve(process.cwd(), outputFile); const filePath = path.resolve(process.cwd(), outputFile);
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) { if (shell.test("-d", filePath)) {
log.error("Cannot write to output file path, it is a directory: %s", outputFile); log.error("Cannot write to output file path, it is a directory: %s", outputFile);
return false; return false;
} }
@ -116,7 +112,7 @@ function printResults(engine, results, format, outputFile) {
* Encapsulates all CLI behavior for eslint. Makes it easier to test as well as * Encapsulates all CLI behavior for eslint. Makes it easier to test as well as
* for other Node.js programs to effectively run the CLI. * for other Node.js programs to effectively run the CLI.
*/ */
let cli = { const cli = {
/** /**
* Executes the CLI based on an array of arguments that is passed in. * Executes the CLI based on an array of arguments that is passed in.
@ -126,11 +122,7 @@ let cli = {
*/ */
execute: function(args, text) { execute: function(args, text) {
let currentOptions, let currentOptions;
files,
report,
engine,
tooManyWarnings;
try { try {
currentOptions = options.parse(args); currentOptions = options.parse(args);
@ -139,7 +131,7 @@ let cli = {
return 1; return 1;
} }
files = currentOptions._; const files = currentOptions._;
if (currentOptions.version) { // version from package.json if (currentOptions.version) { // version from package.json
@ -159,7 +151,8 @@ let cli = {
return 1; return 1;
} }
engine = new CLIEngine(translateOptions(currentOptions)); const engine = new CLIEngine(translateOptions(currentOptions));
if (currentOptions.printConfig) { if (currentOptions.printConfig) {
if (files.length !== 1) { if (files.length !== 1) {
log.error("The --print-config option requires a " + log.error("The --print-config option requires a " +
@ -172,13 +165,14 @@ let cli = {
return 1; return 1;
} }
let fileConfig = engine.getConfigForFile(files[0]); const fileConfig = engine.getConfigForFile(files[0]);
log.info(JSON.stringify(fileConfig, null, " ")); log.info(JSON.stringify(fileConfig, null, " "));
return 0; return 0;
} }
report = text ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files); const report = text ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files);
if (currentOptions.fix) { if (currentOptions.fix) {
debug("Fix mode enabled - applying fixes"); debug("Fix mode enabled - applying fixes");
CLIEngine.outputFixes(report); CLIEngine.outputFixes(report);
@ -190,7 +184,7 @@ let cli = {
} }
if (printResults(engine, report.results, currentOptions.format, currentOptions.outputFile)) { if (printResults(engine, report.results, currentOptions.format, currentOptions.outputFile)) {
tooManyWarnings = currentOptions.maxWarnings >= 0 && report.warningCount > currentOptions.maxWarnings; const tooManyWarnings = currentOptions.maxWarnings >= 0 && report.warningCount > currentOptions.maxWarnings;
if (!report.errorCount && tooManyWarnings) { if (!report.errorCount && tooManyWarnings) {
log.error("ESLint found too many warnings (maximum: %s).", currentOptions.maxWarnings); log.error("ESLint found too many warnings (maximum: %s).", currentOptions.maxWarnings);

34
tools/eslint/lib/code-path-analysis/code-path-analyzer.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let assert = require("assert"), const assert = require("assert"),
CodePath = require("./code-path"), CodePath = require("./code-path"),
CodePathSegment = require("./code-path-segment"), CodePathSegment = require("./code-path-segment"),
IdGenerator = require("./id-generator"), IdGenerator = require("./id-generator"),
@ -38,7 +38,7 @@ function isCaseNode(node) {
* @returns {boolean} `true` if the node is a test of a choice statement. * @returns {boolean} `true` if the node is a test of a choice statement.
*/ */
function isForkingByTrueOrFalse(node) { function isForkingByTrueOrFalse(node) {
let parent = node.parent; const parent = node.parent;
switch (parent.type) { switch (parent.type) {
case "ConditionalExpression": case "ConditionalExpression":
@ -83,7 +83,7 @@ function getBooleanValueIfSimpleConstant(node) {
* @returns {boolean} `true` if the node is a reference. * @returns {boolean} `true` if the node is a reference.
*/ */
function isIdentifierReference(node) { function isIdentifierReference(node) {
let parent = node.parent; const parent = node.parent;
switch (parent.type) { switch (parent.type) {
case "LabeledStatement": case "LabeledStatement":
@ -135,11 +135,11 @@ function isIdentifierReference(node) {
* @returns {void} * @returns {void}
*/ */
function forwardCurrentToHead(analyzer, node) { function forwardCurrentToHead(analyzer, node) {
let codePath = analyzer.codePath; const codePath = analyzer.codePath;
let state = CodePath.getState(codePath); const state = CodePath.getState(codePath);
let currentSegments = state.currentSegments; const currentSegments = state.currentSegments;
let headSegments = state.headSegments; const headSegments = state.headSegments;
let end = Math.max(currentSegments.length, headSegments.length); const end = Math.max(currentSegments.length, headSegments.length);
let i, currentSegment, headSegment; let i, currentSegment, headSegment;
// Fires leaving events. // Fires leaving events.
@ -191,11 +191,11 @@ function forwardCurrentToHead(analyzer, node) {
* @returns {void} * @returns {void}
*/ */
function leaveFromCurrentSegment(analyzer, node) { function leaveFromCurrentSegment(analyzer, node) {
let state = CodePath.getState(analyzer.codePath); const state = CodePath.getState(analyzer.codePath);
let currentSegments = state.currentSegments; const currentSegments = state.currentSegments;
for (let i = 0; i < currentSegments.length; ++i) { for (let i = 0; i < currentSegments.length; ++i) {
let currentSegment = currentSegments[i]; const currentSegment = currentSegments[i];
debug.dump("onCodePathSegmentEnd " + currentSegment.id); debug.dump("onCodePathSegmentEnd " + currentSegment.id);
if (currentSegment.reachable) { if (currentSegment.reachable) {
@ -221,9 +221,9 @@ function leaveFromCurrentSegment(analyzer, node) {
* @returns {void} * @returns {void}
*/ */
function preprocess(analyzer, node) { function preprocess(analyzer, node) {
let codePath = analyzer.codePath; const codePath = analyzer.codePath;
let state = CodePath.getState(codePath); const state = CodePath.getState(codePath);
let parent = node.parent; const parent = node.parent;
switch (parent.type) { switch (parent.type) {
case "LogicalExpression": case "LogicalExpression":
@ -330,7 +330,7 @@ function preprocess(analyzer, node) {
function processCodePathToEnter(analyzer, node) { function processCodePathToEnter(analyzer, node) {
let codePath = analyzer.codePath; let codePath = analyzer.codePath;
let state = codePath && CodePath.getState(codePath); let state = codePath && CodePath.getState(codePath);
let parent = node.parent; const parent = node.parent;
switch (node.type) { switch (node.type) {
case "Program": case "Program":
@ -419,8 +419,8 @@ function processCodePathToEnter(analyzer, node) {
* @returns {void} * @returns {void}
*/ */
function processCodePathToExit(analyzer, node) { function processCodePathToExit(analyzer, node) {
let codePath = analyzer.codePath; const codePath = analyzer.codePath;
let state = CodePath.getState(codePath); const state = CodePath.getState(codePath);
let dontForward = false; let dontForward = false;
switch (node.type) { switch (node.type) {

14
tools/eslint/lib/code-path-analysis/code-path-segment.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let debug = require("./debug-helpers"); const debug = require("./debug-helpers");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
@ -22,11 +22,11 @@ let debug = require("./debug-helpers");
* @returns {CodePathSegment[]} The replaced array. * @returns {CodePathSegment[]} The replaced array.
*/ */
function flattenUnusedSegments(segments) { function flattenUnusedSegments(segments) {
let done = Object.create(null); const done = Object.create(null);
let retv = []; const retv = [];
for (let i = 0; i < segments.length; ++i) { for (let i = 0; i < segments.length; ++i) {
let segment = segments[i]; const segment = segments[i];
// Ignores duplicated. // Ignores duplicated.
if (done[segment.id]) { if (done[segment.id]) {
@ -36,7 +36,7 @@ function flattenUnusedSegments(segments) {
// Use previous segments if unused. // Use previous segments if unused.
if (!segment.internal.used) { if (!segment.internal.used) {
for (let j = 0; j < segment.allPrevSegments.length; ++j) { for (let j = 0; j < segment.allPrevSegments.length; ++j) {
let prevSegment = segment.allPrevSegments[j]; const prevSegment = segment.allPrevSegments[j];
if (!done[prevSegment.id]) { if (!done[prevSegment.id]) {
done[prevSegment.id] = true; done[prevSegment.id] = true;
@ -175,7 +175,7 @@ CodePathSegment.newNext = function(id, allPrevSegments) {
* @returns {CodePathSegment} The created segment. * @returns {CodePathSegment} The created segment.
*/ */
CodePathSegment.newUnreachable = function(id, allPrevSegments) { CodePathSegment.newUnreachable = function(id, allPrevSegments) {
let segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false); const segment = new CodePathSegment(id, flattenUnusedSegments(allPrevSegments), false);
// In `if (a) return a; foo();` case, the unreachable segment preceded by // In `if (a) return a; foo();` case, the unreachable segment preceded by
// the return statement is not used but must not be remove. // the return statement is not used but must not be remove.
@ -215,7 +215,7 @@ CodePathSegment.markUsed = function(segment) {
if (segment.reachable) { if (segment.reachable) {
for (i = 0; i < segment.allPrevSegments.length; ++i) { for (i = 0; i < segment.allPrevSegments.length; ++i) {
let prevSegment = segment.allPrevSegments[i]; const prevSegment = segment.allPrevSegments[i];
prevSegment.allNextSegments.push(segment); prevSegment.allNextSegments.push(segment);
prevSegment.nextSegments.push(segment); prevSegment.nextSegments.push(segment);

200
tools/eslint/lib/code-path-analysis/code-path-state.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let CodePathSegment = require("./code-path-segment"), const CodePathSegment = require("./code-path-segment"),
ForkContext = require("./fork-context"); ForkContext = require("./fork-context");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -31,7 +31,7 @@ let CodePathSegment = require("./code-path-segment"),
*/ */
function addToReturnedOrThrown(dest, others, all, segments) { function addToReturnedOrThrown(dest, others, all, segments) {
for (let i = 0; i < segments.length; ++i) { for (let i = 0; i < segments.length; ++i) {
let segment = segments[i]; const segment = segments[i];
dest.push(segment); dest.push(segment);
if (others.indexOf(segment) === -1) { if (others.indexOf(segment) === -1) {
@ -150,8 +150,8 @@ function remove(xs, x) {
*/ */
function removeConnection(prevSegments, nextSegments) { function removeConnection(prevSegments, nextSegments) {
for (let i = 0; i < prevSegments.length; ++i) { for (let i = 0; i < prevSegments.length; ++i) {
let prevSegment = prevSegments[i]; const prevSegment = prevSegments[i];
let nextSegment = nextSegments[i]; const nextSegment = nextSegments[i];
remove(prevSegment.nextSegments, nextSegment); remove(prevSegment.nextSegments, nextSegment);
remove(prevSegment.allNextSegments, nextSegment); remove(prevSegment.allNextSegments, nextSegment);
@ -169,11 +169,11 @@ function removeConnection(prevSegments, nextSegments) {
* @returns {void} * @returns {void}
*/ */
function makeLooped(state, fromSegments, toSegments) { function makeLooped(state, fromSegments, toSegments) {
let end = Math.min(fromSegments.length, toSegments.length); const end = Math.min(fromSegments.length, toSegments.length);
for (let i = 0; i < end; ++i) { for (let i = 0; i < end; ++i) {
let fromSegment = fromSegments[i]; const fromSegment = fromSegments[i];
let toSegment = toSegments[i]; const toSegment = toSegments[i];
if (toSegment.reachable) { if (toSegment.reachable) {
fromSegment.nextSegments.push(toSegment); fromSegment.nextSegments.push(toSegment);
@ -241,9 +241,9 @@ function CodePathState(idGenerator, onLooped) {
this.initialSegment = this.forkContext.head[0]; this.initialSegment = this.forkContext.head[0];
// returnedSegments and thrownSegments push elements into finalSegments also. // returnedSegments and thrownSegments push elements into finalSegments also.
let final = this.finalSegments = []; const final = this.finalSegments = [];
let returned = this.returnedForkContext = []; const returned = this.returnedForkContext = [];
let thrown = this.thrownForkContext = []; const thrown = this.thrownForkContext = [];
returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final); returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final);
thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final); thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final);
@ -266,7 +266,7 @@ CodePathState.prototype = {
* @type {ForkContext} * @type {ForkContext}
*/ */
get parentForkContext() { get parentForkContext() {
let current = this.forkContext; const current = this.forkContext;
return current && current.upper; return current && current.upper;
}, },
@ -292,7 +292,7 @@ CodePathState.prototype = {
* @returns {ForkContext} The last context. * @returns {ForkContext} The last context.
*/ */
popForkContext: function() { popForkContext: function() {
let lastContext = this.forkContext; const lastContext = this.forkContext;
this.forkContext = lastContext.upper; this.forkContext = lastContext.upper;
this.forkContext.replaceHead(lastContext.makeNext(0, -1)); this.forkContext.replaceHead(lastContext.makeNext(0, -1));
@ -370,12 +370,12 @@ CodePathState.prototype = {
* @returns {ChoiceContext} The popped context. * @returns {ChoiceContext} The popped context.
*/ */
popChoiceContext: function() { popChoiceContext: function() {
let context = this.choiceContext; const context = this.choiceContext;
this.choiceContext = context.upper; this.choiceContext = context.upper;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let headSegments = forkContext.head; const headSegments = forkContext.head;
switch (context.kind) { switch (context.kind) {
case "&&": case "&&":
@ -396,7 +396,7 @@ CodePathState.prototype = {
* test chunk. * test chunk.
*/ */
if (context.isForkingAsResult) { if (context.isForkingAsResult) {
let parentContext = this.choiceContext; const parentContext = this.choiceContext;
parentContext.trueForkContext.addAll(context.trueForkContext); parentContext.trueForkContext.addAll(context.trueForkContext);
parentContext.falseForkContext.addAll(context.falseForkContext); parentContext.falseForkContext.addAll(context.falseForkContext);
@ -443,7 +443,7 @@ CodePathState.prototype = {
} }
// Merges all paths. // Merges all paths.
let prevForkContext = context.trueForkContext; const prevForkContext = context.trueForkContext;
prevForkContext.addAll(context.falseForkContext); prevForkContext.addAll(context.falseForkContext);
forkContext.replaceHead(prevForkContext.makeNext(0, -1)); forkContext.replaceHead(prevForkContext.makeNext(0, -1));
@ -458,8 +458,8 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeLogicalRight: function() { makeLogicalRight: function() {
let context = this.choiceContext; const context = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (context.processed) { if (context.processed) {
@ -467,7 +467,7 @@ CodePathState.prototype = {
* This got segments already from the child choice context. * This got segments already from the child choice context.
* Creates the next path from own true/false fork context. * Creates the next path from own true/false fork context.
*/ */
let prevForkContext = const prevForkContext =
context.kind === "&&" ? context.trueForkContext : context.kind === "&&" ? context.trueForkContext :
/* kind === "||" */ context.falseForkContext; /* kind === "||" */ context.falseForkContext;
@ -502,8 +502,8 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeIfConsequent: function() { makeIfConsequent: function() {
let context = this.choiceContext; const context = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
/* /*
* If any result were not transferred from child contexts, * If any result were not transferred from child contexts,
@ -529,8 +529,8 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeIfAlternate: function() { makeIfAlternate: function() {
let context = this.choiceContext; const context = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
/* /*
* The head segments are the path of the `if` block. * The head segments are the path of the `if` block.
@ -583,12 +583,12 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
popSwitchContext: function() { popSwitchContext: function() {
let context = this.switchContext; const context = this.switchContext;
this.switchContext = context.upper; this.switchContext = context.upper;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let brokenForkContext = this.popBreakContext().brokenForkContext; const brokenForkContext = this.popBreakContext().brokenForkContext;
if (context.countForks === 0) { if (context.countForks === 0) {
@ -605,10 +605,10 @@ CodePathState.prototype = {
return; return;
} }
let lastSegments = forkContext.head; const lastSegments = forkContext.head;
this.forkBypassPath(); this.forkBypassPath();
let lastCaseSegments = forkContext.head; const lastCaseSegments = forkContext.head;
/* /*
* `brokenForkContext` is used to make the next segment. * `brokenForkContext` is used to make the next segment.
@ -659,7 +659,7 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeSwitchCaseBody: function(isEmpty, isDefault) { makeSwitchCaseBody: function(isEmpty, isDefault) {
let context = this.switchContext; const context = this.switchContext;
if (!context.hasCase) { if (!context.hasCase) {
return; return;
@ -670,8 +670,8 @@ CodePathState.prototype = {
* The parent fork context has two segments. * The parent fork context has two segments.
* Those are from the current case and the body of the previous case. * Those are from the current case and the body of the previous case.
*/ */
let parentForkContext = this.forkContext; const parentForkContext = this.forkContext;
let forkContext = this.pushForkContext(); const forkContext = this.pushForkContext();
forkContext.add(parentForkContext.makeNext(0, -1)); forkContext.add(parentForkContext.makeNext(0, -1));
@ -731,7 +731,7 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
popTryContext: function() { popTryContext: function() {
let context = this.tryContext; const context = this.tryContext;
this.tryContext = context.upper; this.tryContext = context.upper;
@ -747,19 +747,19 @@ CodePathState.prototype = {
* block. * block.
*/ */
let returned = context.returnedForkContext; const returned = context.returnedForkContext;
let thrown = context.thrownForkContext; const thrown = context.thrownForkContext;
if (returned.empty && thrown.empty) { if (returned.empty && thrown.empty) {
return; return;
} }
// Separate head to normal paths and leaving paths. // Separate head to normal paths and leaving paths.
let headSegments = this.forkContext.head; const headSegments = this.forkContext.head;
this.forkContext = this.forkContext.upper; this.forkContext = this.forkContext.upper;
let normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); const normalSegments = headSegments.slice(0, headSegments.length / 2 | 0);
let leavingSegments = headSegments.slice(headSegments.length / 2 | 0); const leavingSegments = headSegments.slice(headSegments.length / 2 | 0);
// Forwards the leaving path to upper contexts. // Forwards the leaving path to upper contexts.
if (!returned.empty) { if (!returned.empty) {
@ -785,9 +785,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeCatchBlock: function() { makeCatchBlock: function() {
let context = this.tryContext; const context = this.tryContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let thrown = context.thrownForkContext; const thrown = context.thrownForkContext;
// Update state. // Update state.
context.position = "catch"; context.position = "catch";
@ -796,7 +796,7 @@ CodePathState.prototype = {
// Merge thrown paths. // Merge thrown paths.
thrown.add(forkContext.head); thrown.add(forkContext.head);
let thrownSegments = thrown.makeNext(0, -1); const thrownSegments = thrown.makeNext(0, -1);
// Fork to a bypass and the merged thrown path. // Fork to a bypass and the merged thrown path.
this.pushForkContext(); this.pushForkContext();
@ -814,11 +814,11 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeFinallyBlock: function() { makeFinallyBlock: function() {
let context = this.tryContext; const context = this.tryContext;
let forkContext = this.forkContext; let forkContext = this.forkContext;
let returned = context.returnedForkContext; const returned = context.returnedForkContext;
let thrown = context.thrownForkContext; const thrown = context.thrownForkContext;
let headOfLeavingSegments = forkContext.head; const headOfLeavingSegments = forkContext.head;
// Update state. // Update state.
if (context.position === "catch") { if (context.position === "catch") {
@ -843,11 +843,11 @@ CodePathState.prototype = {
* Create a parallel segment from merging returned and thrown. * Create a parallel segment from merging returned and thrown.
* This segment will leave at the end of this finally block. * This segment will leave at the end of this finally block.
*/ */
let segments = forkContext.makeNext(-1, -1); const segments = forkContext.makeNext(-1, -1);
let j; let j;
for (let i = 0; i < forkContext.count; ++i) { for (let i = 0; i < forkContext.count; ++i) {
let prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; const prevSegsOfLeavingSegment = [headOfLeavingSegments[i]];
for (j = 0; j < returned.segmentsList.length; ++j) { for (j = 0; j < returned.segmentsList.length; ++j) {
prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]); prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]);
@ -872,13 +872,13 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeFirstThrowablePathInTryBlock: function() { makeFirstThrowablePathInTryBlock: function() {
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (!forkContext.reachable) { if (!forkContext.reachable) {
return; return;
} }
let context = getThrowContext(this); const context = getThrowContext(this);
if (context === this || if (context === this ||
context.position !== "try" || context.position !== "try" ||
@ -905,8 +905,8 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
pushLoopContext: function(type, label) { pushLoopContext: function(type, label) {
let forkContext = this.forkContext; const forkContext = this.forkContext;
let breakContext = this.pushBreakContext(true, label); const breakContext = this.pushBreakContext(true, label);
switch (type) { switch (type) {
case "WhileStatement": case "WhileStatement":
@ -977,12 +977,12 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
popLoopContext: function() { popLoopContext: function() {
let context = this.loopContext; const context = this.loopContext;
this.loopContext = context.upper; this.loopContext = context.upper;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let brokenForkContext = this.popBreakContext().brokenForkContext; const brokenForkContext = this.popBreakContext().brokenForkContext;
let choiceContext; let choiceContext;
// Creates a looped path. // Creates a looped path.
@ -1048,9 +1048,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeWhileTest: function(test) { makeWhileTest: function(test) {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let testSegments = forkContext.makeNext(0, -1); const testSegments = forkContext.makeNext(0, -1);
// Update state. // Update state.
context.test = test; context.test = test;
@ -1064,9 +1064,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeWhileBody: function() { makeWhileBody: function() {
let context = this.loopContext; const context = this.loopContext;
let choiceContext = this.choiceContext; const choiceContext = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (!choiceContext.processed) { if (!choiceContext.processed) {
choiceContext.trueForkContext.add(forkContext.head); choiceContext.trueForkContext.add(forkContext.head);
@ -1086,9 +1086,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeDoWhileBody: function() { makeDoWhileBody: function() {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let bodySegments = forkContext.makeNext(-1, -1); const bodySegments = forkContext.makeNext(-1, -1);
// Update state. // Update state.
context.entrySegments = bodySegments; context.entrySegments = bodySegments;
@ -1102,15 +1102,15 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeDoWhileTest: function(test) { makeDoWhileTest: function(test) {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
context.test = test; context.test = test;
// Creates paths of `continue` statements. // Creates paths of `continue` statements.
if (!context.continueForkContext.empty) { if (!context.continueForkContext.empty) {
context.continueForkContext.add(forkContext.head); context.continueForkContext.add(forkContext.head);
let testSegments = context.continueForkContext.makeNext(0, -1); const testSegments = context.continueForkContext.makeNext(0, -1);
forkContext.replaceHead(testSegments); forkContext.replaceHead(testSegments);
} }
@ -1123,10 +1123,10 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForTest: function(test) { makeForTest: function(test) {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let endOfInitSegments = forkContext.head; const endOfInitSegments = forkContext.head;
let testSegments = forkContext.makeNext(-1, -1); const testSegments = forkContext.makeNext(-1, -1);
// Update state. // Update state.
context.test = test; context.test = test;
@ -1141,9 +1141,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForUpdate: function() { makeForUpdate: function() {
let context = this.loopContext; const context = this.loopContext;
let choiceContext = this.choiceContext; const choiceContext = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
// Make the next paths of the test. // Make the next paths of the test.
if (context.testSegments) { if (context.testSegments) {
@ -1156,7 +1156,7 @@ CodePathState.prototype = {
} }
// Update state. // Update state.
let updateSegments = forkContext.makeDisconnected(-1, -1); const updateSegments = forkContext.makeDisconnected(-1, -1);
context.continueDestSegments = context.updateSegments = updateSegments; context.continueDestSegments = context.updateSegments = updateSegments;
forkContext.replaceHead(updateSegments); forkContext.replaceHead(updateSegments);
@ -1168,9 +1168,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForBody: function() { makeForBody: function() {
let context = this.loopContext; const context = this.loopContext;
let choiceContext = this.choiceContext; const choiceContext = this.choiceContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
// Update state. // Update state.
if (context.updateSegments) { if (context.updateSegments) {
@ -1200,7 +1200,7 @@ CodePathState.prototype = {
* If there is not the `test` part, the `body` path comes from the * If there is not the `test` part, the `body` path comes from the
* `init` part and the `update` part. * `init` part and the `update` part.
*/ */
let prevForkContext = ForkContext.newEmpty(forkContext); const prevForkContext = ForkContext.newEmpty(forkContext);
prevForkContext.add(context.endOfInitSegments); prevForkContext.add(context.endOfInitSegments);
if (context.endOfUpdateSegments) { if (context.endOfUpdateSegments) {
@ -1220,9 +1220,9 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForInOfLeft: function() { makeForInOfLeft: function() {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let leftSegments = forkContext.makeDisconnected(-1, -1); const leftSegments = forkContext.makeDisconnected(-1, -1);
// Update state. // Update state.
context.prevSegments = forkContext.head; context.prevSegments = forkContext.head;
@ -1237,12 +1237,12 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForInOfRight: function() { makeForInOfRight: function() {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let temp = ForkContext.newEmpty(forkContext); const temp = ForkContext.newEmpty(forkContext);
temp.add(context.prevSegments); temp.add(context.prevSegments);
let rightSegments = temp.makeNext(-1, -1); const rightSegments = temp.makeNext(-1, -1);
// Update state. // Update state.
context.endOfLeftSegments = forkContext.head; context.endOfLeftSegments = forkContext.head;
@ -1256,12 +1256,12 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeForInOfBody: function() { makeForInOfBody: function() {
let context = this.loopContext; const context = this.loopContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
let temp = ForkContext.newEmpty(forkContext); const temp = ForkContext.newEmpty(forkContext);
temp.add(context.endOfLeftSegments); temp.add(context.endOfLeftSegments);
let bodySegments = temp.makeNext(-1, -1); const bodySegments = temp.makeNext(-1, -1);
// Make a path: `right` -> `left`. // Make a path: `right` -> `left`.
makeLooped(this, forkContext.head, context.leftSegments); makeLooped(this, forkContext.head, context.leftSegments);
@ -1299,14 +1299,14 @@ CodePathState.prototype = {
* @returns {Object} The removed context. * @returns {Object} The removed context.
*/ */
popBreakContext: function() { popBreakContext: function() {
let context = this.breakContext; const context = this.breakContext;
let forkContext = this.forkContext; const forkContext = this.forkContext;
this.breakContext = context.upper; this.breakContext = context.upper;
// Process this context here for other than switches and loops. // Process this context here for other than switches and loops.
if (!context.breakable) { if (!context.breakable) {
let brokenForkContext = context.brokenForkContext; const brokenForkContext = context.brokenForkContext;
if (!brokenForkContext.empty) { if (!brokenForkContext.empty) {
brokenForkContext.add(forkContext.head); brokenForkContext.add(forkContext.head);
@ -1327,13 +1327,13 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeBreak: function(label) { makeBreak: function(label) {
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (!forkContext.reachable) { if (!forkContext.reachable) {
return; return;
} }
let context = getBreakContext(this, label); const context = getBreakContext(this, label);
/* istanbul ignore else: foolproof (syntax error) */ /* istanbul ignore else: foolproof (syntax error) */
if (context) { if (context) {
@ -1353,13 +1353,13 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeContinue: function(label) { makeContinue: function(label) {
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (!forkContext.reachable) { if (!forkContext.reachable) {
return; return;
} }
let context = getContinueContext(this, label); const context = getContinueContext(this, label);
/* istanbul ignore else: foolproof (syntax error) */ /* istanbul ignore else: foolproof (syntax error) */
if (context) { if (context) {
@ -1388,7 +1388,7 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeReturn: function() { makeReturn: function() {
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (forkContext.reachable) { if (forkContext.reachable) {
getReturnContext(this).returnedForkContext.add(forkContext.head); getReturnContext(this).returnedForkContext.add(forkContext.head);
@ -1405,7 +1405,7 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeThrow: function() { makeThrow: function() {
let forkContext = this.forkContext; const forkContext = this.forkContext;
if (forkContext.reachable) { if (forkContext.reachable) {
getThrowContext(this).thrownForkContext.add(forkContext.head); getThrowContext(this).thrownForkContext.add(forkContext.head);
@ -1418,7 +1418,7 @@ CodePathState.prototype = {
* @returns {void} * @returns {void}
*/ */
makeFinal: function() { makeFinal: function() {
let segments = this.currentSegments; const segments = this.currentSegments;
if (segments.length > 0 && segments[0].reachable) { if (segments.length > 0 && segments[0].reachable) {
this.returnedForkContext.add(segments); this.returnedForkContext.add(segments);

14
tools/eslint/lib/code-path-analysis/code-path.js

@ -9,8 +9,8 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let CodePathState = require("./code-path-state"); const CodePathState = require("./code-path-state");
let IdGenerator = require("./id-generator"); const IdGenerator = require("./id-generator");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Public Interface // Public Interface
@ -130,18 +130,18 @@ CodePath.prototype = {
} }
options = options || {}; options = options || {};
let startSegment = options.first || this.internal.initialSegment; const startSegment = options.first || this.internal.initialSegment;
let lastSegment = options.last; const lastSegment = options.last;
let item = null; let item = null;
let index = 0; let index = 0;
let end = 0; let end = 0;
let segment = null; let segment = null;
let visited = Object.create(null); const visited = Object.create(null);
let stack = [[startSegment, 0]]; const stack = [[startSegment, 0]];
let skippedSegment = null; let skippedSegment = null;
let broken = false; let broken = false;
let controller = { const controller = {
skip: function() { skip: function() {
if (stack.length <= 1) { if (stack.length <= 1) {
broken = true; broken = true;

24
tools/eslint/lib/code-path-analysis/debug-helpers.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let debug = require("debug")("eslint:code-path"); const debug = require("debug")("eslint:code-path");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
@ -55,7 +55,7 @@ module.exports = {
*/ */
dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) { dumpState: !debug.enabled ? debug : /* istanbul ignore next */ function(node, state, leaving) {
for (let i = 0; i < state.currentSegments.length; ++i) { for (let i = 0; i < state.currentSegments.length; ++i) {
let segInternal = state.currentSegments[i].internal; const segInternal = state.currentSegments[i].internal;
if (leaving) { if (leaving) {
segInternal.exitNodes.push(node); segInternal.exitNodes.push(node);
@ -93,11 +93,11 @@ module.exports = {
text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n"; text += "thrown[label=\"✘\",shape=circle,width=0.3,height=0.3,fixedsize];\n";
} }
let traceMap = Object.create(null); const traceMap = Object.create(null);
let arrows = this.makeDotArrows(codePath, traceMap); const arrows = this.makeDotArrows(codePath, traceMap);
for (let id in traceMap) { // eslint-disable-line guard-for-in for (const id in traceMap) { // eslint-disable-line guard-for-in
let segment = traceMap[id]; const segment = traceMap[id];
text += id + "["; text += id + "[";
@ -144,22 +144,22 @@ module.exports = {
* @returns {string} A DOT code of the code path. * @returns {string} A DOT code of the code path.
*/ */
makeDotArrows: function(codePath, traceMap) { makeDotArrows: function(codePath, traceMap) {
let stack = [[codePath.initialSegment, 0]]; const stack = [[codePath.initialSegment, 0]];
let done = traceMap || Object.create(null); const done = traceMap || Object.create(null);
let lastId = codePath.initialSegment.id; let lastId = codePath.initialSegment.id;
let text = "initial->" + codePath.initialSegment.id; let text = "initial->" + codePath.initialSegment.id;
while (stack.length > 0) { while (stack.length > 0) {
let item = stack.pop(); const item = stack.pop();
let segment = item[0]; const segment = item[0];
let index = item[1]; const index = item[1];
if (done[segment.id] && index === 0) { if (done[segment.id] && index === 0) {
continue; continue;
} }
done[segment.id] = segment; done[segment.id] = segment;
let nextSegment = segment.allNextSegments[index]; const nextSegment = segment.allNextSegments[index];
if (!nextSegment) { if (!nextSegment) {
continue; continue;

18
tools/eslint/lib/code-path-analysis/fork-context.js

@ -13,7 +13,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let assert = require("assert"), const assert = require("assert"),
CodePathSegment = require("./code-path-segment"); CodePathSegment = require("./code-path-segment");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -44,7 +44,7 @@ function isReachable(segment) {
* @returns {CodePathSegment[]} New segments. * @returns {CodePathSegment[]} New segments.
*/ */
function makeSegments(context, begin, end, create) { function makeSegments(context, begin, end, create) {
let list = context.segmentsList; const list = context.segmentsList;
if (begin < 0) { if (begin < 0) {
begin = list.length + begin; begin = list.length + begin;
@ -53,10 +53,10 @@ function makeSegments(context, begin, end, create) {
end = list.length + end; end = list.length + end;
} }
let segments = []; const segments = [];
for (let i = 0; i < context.count; ++i) { for (let i = 0; i < context.count; ++i) {
let allPrevSegments = []; const allPrevSegments = [];
for (let j = begin; j <= end; ++j) { for (let j = begin; j <= end; ++j) {
allPrevSegments.push(list[j][i]); allPrevSegments.push(list[j][i]);
@ -80,7 +80,7 @@ function makeSegments(context, begin, end, create) {
*/ */
function mergeExtraSegments(context, segments) { function mergeExtraSegments(context, segments) {
while (segments.length > context.count) { while (segments.length > context.count) {
let merged = []; const merged = [];
for (let i = 0, length = segments.length / 2 | 0; i < length; ++i) { for (let i = 0, length = segments.length / 2 | 0; i < length; ++i) {
merged.push(CodePathSegment.newNext( merged.push(CodePathSegment.newNext(
@ -120,7 +120,7 @@ ForkContext.prototype = {
* @type {CodePathSegment[]} * @type {CodePathSegment[]}
*/ */
get head() { get head() {
let list = this.segmentsList; const list = this.segmentsList;
return list.length === 0 ? [] : list[list.length - 1]; return list.length === 0 ? [] : list[list.length - 1];
}, },
@ -138,7 +138,7 @@ ForkContext.prototype = {
* @type {boolean} * @type {boolean}
*/ */
get reachable() { get reachable() {
let segments = this.head; const segments = this.head;
return segments.length > 0 && segments.some(isReachable); return segments.length > 0 && segments.some(isReachable);
}, },
@ -214,7 +214,7 @@ ForkContext.prototype = {
addAll: function(context) { addAll: function(context) {
assert(context.count === this.count); assert(context.count === this.count);
let source = context.segmentsList; const source = context.segmentsList;
for (let i = 0; i < source.length; ++i) { for (let i = 0; i < source.length; ++i) {
this.segmentsList.push(source[i]); this.segmentsList.push(source[i]);
@ -238,7 +238,7 @@ ForkContext.prototype = {
* @returns {ForkContext} New fork context. * @returns {ForkContext} New fork context.
*/ */
ForkContext.newRoot = function(idGenerator) { ForkContext.newRoot = function(idGenerator) {
let context = new ForkContext(idGenerator, null, 1); const context = new ForkContext(idGenerator, null, 1);
context.add([CodePathSegment.newRoot(idGenerator.next())]); context.add([CodePathSegment.newRoot(idGenerator.next())]);

47
tools/eslint/lib/config.js

@ -9,28 +9,27 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let path = require("path"), const path = require("path"),
ConfigOps = require("./config/config-ops"), ConfigOps = require("./config/config-ops"),
ConfigFile = require("./config/config-file"), ConfigFile = require("./config/config-file"),
Plugins = require("./config/plugins"), Plugins = require("./config/plugins"),
FileFinder = require("./file-finder"), FileFinder = require("./file-finder"),
debug = require("debug"),
userHome = require("user-home"), userHome = require("user-home"),
isResolvable = require("is-resolvable"), isResolvable = require("is-resolvable"),
pathIsInside = require("path-is-inside"); pathIsInside = require("path-is-inside");
const debug = require("debug")("eslint:config");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let PERSONAL_CONFIG_DIR = userHome || null; const PERSONAL_CONFIG_DIR = userHome || null;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:config");
/** /**
* Check if item is an javascript object * Check if item is an javascript object
* @param {*} item object to check for * @param {*} item object to check for
@ -75,11 +74,10 @@ function loadConfig(configToLoad) {
* @private * @private
*/ */
function getPersonalConfig() { function getPersonalConfig() {
let config, let config;
filename;
if (PERSONAL_CONFIG_DIR) { if (PERSONAL_CONFIG_DIR) {
filename = ConfigFile.getFilenameForDirectory(PERSONAL_CONFIG_DIR); const filename = ConfigFile.getFilenameForDirectory(PERSONAL_CONFIG_DIR);
if (filename) { if (filename) {
debug("Using personal config"); debug("Using personal config");
@ -106,20 +104,16 @@ function hasRules(options) {
* @returns {Object} The local config object, or an empty object if there is no local config. * @returns {Object} The local config object, or an empty object if there is no local config.
*/ */
function getLocalConfig(thisConfig, directory) { function getLocalConfig(thisConfig, directory) {
const localConfigFiles = thisConfig.findLocalConfigFiles(directory),
numFiles = localConfigFiles.length,
projectConfigPath = ConfigFile.getFilenameForDirectory(thisConfig.options.cwd);
let found, let found,
i,
localConfig,
localConfigFile,
config = {}, config = {},
localConfigFiles = thisConfig.findLocalConfigFiles(directory), rootPath;
numFiles = localConfigFiles.length,
rootPath,
projectConfigPath = ConfigFile.getFilenameForDirectory(thisConfig.options.cwd),
personalConfig;
for (i = 0; i < numFiles; i++) { for (let i = 0; i < numFiles; i++) {
localConfigFile = localConfigFiles[i]; const localConfigFile = localConfigFiles[i];
// Don't consider the personal config file in the home directory, // Don't consider the personal config file in the home directory,
// except if the home directory is the same as the current working directory // except if the home directory is the same as the current working directory
@ -133,7 +127,7 @@ function getLocalConfig(thisConfig, directory) {
} }
debug("Loading " + localConfigFile); debug("Loading " + localConfigFile);
localConfig = loadConfig(localConfigFile); const localConfig = loadConfig(localConfigFile);
// Don't consider a local config file found if the config is null // Don't consider a local config file found if the config is null
if (!localConfig) { if (!localConfig) {
@ -158,14 +152,14 @@ function getLocalConfig(thisConfig, directory) {
* - Otherwise, if no rules were manually passed in, throw and error. * - Otherwise, if no rules were manually passed in, throw and error.
* - Note: This function is not called if useEslintrc is false. * - Note: This function is not called if useEslintrc is false.
*/ */
personalConfig = getPersonalConfig(); const personalConfig = getPersonalConfig();
if (personalConfig) { if (personalConfig) {
config = ConfigOps.merge(config, personalConfig); config = ConfigOps.merge(config, personalConfig);
} else if (!hasRules(thisConfig.options) && !thisConfig.options.baseConfig) { } else if (!hasRules(thisConfig.options) && !thisConfig.options.baseConfig) {
// No config file, no manual configuration, and no rules, so error. // No config file, no manual configuration, and no rules, so error.
let noConfigError = new Error("No ESLint configuration found."); const noConfigError = new Error("No ESLint configuration found.");
noConfigError.messageTemplate = "no-config-found"; noConfigError.messageTemplate = "no-config-found";
noConfigError.messageData = { noConfigError.messageData = {
@ -191,8 +185,6 @@ function getLocalConfig(thisConfig, directory) {
* @param {Object} options Options to be passed in * @param {Object} options Options to be passed in
*/ */
function Config(options) { function Config(options) {
let useConfig;
options = options || {}; options = options || {};
this.ignore = options.ignore; this.ignore = options.ignore;
@ -217,14 +209,15 @@ function Config(options) {
* If user declares "foo", convert to "foo:false". * If user declares "foo", convert to "foo:false".
*/ */
this.globals = (options.globals || []).reduce(function(globals, def) { this.globals = (options.globals || []).reduce(function(globals, def) {
let parts = def.split(":"); const parts = def.split(":");
globals[parts[0]] = (parts.length > 1 && parts[1] === "true"); globals[parts[0]] = (parts.length > 1 && parts[1] === "true");
return globals; return globals;
}, {}); }, {});
useConfig = options.configFile; const useConfig = options.configFile;
this.options = options; this.options = options;
if (useConfig) { if (useConfig) {
@ -244,9 +237,9 @@ function Config(options) {
* @returns {Object} config object * @returns {Object} config object
*/ */
Config.prototype.getConfig = function(filePath) { Config.prototype.getConfig = function(filePath) {
const directory = filePath ? path.dirname(filePath) : this.options.cwd;
let config, let config,
userConfig, userConfig;
directory = filePath ? path.dirname(filePath) : this.options.cwd;
debug("Constructing config for " + (filePath ? filePath : "text")); debug("Constructing config for " + (filePath ? filePath : "text"));

62
tools/eslint/lib/config/autoconfig.js

@ -9,26 +9,25 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"), const lodash = require("lodash"),
debug = require("debug"),
eslint = require("../eslint"), eslint = require("../eslint"),
configRule = require("./config-rule"), configRule = require("./config-rule"),
ConfigOps = require("./config-ops"), ConfigOps = require("./config-ops"),
recConfig = require("../../conf/eslint.json"); recConfig = require("../../conf/eslint.json");
const debug = require("debug")("eslint:autoconfig");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Data // Data
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only const MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only
RECOMMENDED_CONFIG_NAME = "eslint:recommended"; RECOMMENDED_CONFIG_NAME = "eslint:recommended";
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private // Private
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:autoconfig");
/** /**
* Information about a rule configuration, in the context of a Registry. * Information about a rule configuration, in the context of a Registry.
* *
@ -89,7 +88,7 @@ Registry.prototype = {
* @returns {void} * @returns {void}
*/ */
populateFromCoreRules: function() { populateFromCoreRules: function() {
let rulesConfig = configRule.createCoreRuleConfigs(); const rulesConfig = configRule.createCoreRuleConfigs();
this.rules = makeRegistryItems(rulesConfig); this.rules = makeRegistryItems(rulesConfig);
}, },
@ -109,8 +108,8 @@ Registry.prototype = {
* @returns {Object[]} "rules" configurations to use for linting * @returns {Object[]} "rules" configurations to use for linting
*/ */
buildRuleSets: function() { buildRuleSets: function() {
let idx = 0, let idx = 0;
ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
ruleSets = []; ruleSets = [];
/** /**
@ -122,7 +121,7 @@ Registry.prototype = {
* @param {string} rule The ruleId to add. * @param {string} rule The ruleId to add.
* @returns {void} * @returns {void}
*/ */
let addRuleToRuleSet = function(rule) { const addRuleToRuleSet = function(rule) {
/* /*
* This check ensures that there is a rule configuration and that * This check ensures that there is a rule configuration and that
@ -130,7 +129,7 @@ Registry.prototype = {
* If it has too many configs, we will only use the most basic of * If it has too many configs, we will only use the most basic of
* the possible configurations. * the possible configurations.
*/ */
let hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS); const hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS);
if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) { if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) {
@ -170,12 +169,12 @@ Registry.prototype = {
* @returns {void} * @returns {void}
*/ */
stripFailingConfigs: function() { stripFailingConfigs: function() {
let ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
newRegistry = new Registry(); newRegistry = new Registry();
newRegistry.rules = lodash.assign({}, this.rules); newRegistry.rules = Object.assign({}, this.rules);
ruleIds.forEach(function(ruleId) { ruleIds.forEach(function(ruleId) {
let errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) { const errorFreeItems = newRegistry.rules[ruleId].filter(function(registryItem) {
return (registryItem.errorCount === 0); return (registryItem.errorCount === 0);
}); });
@ -195,10 +194,10 @@ Registry.prototype = {
* @returns {void} * @returns {void}
*/ */
stripExtraConfigs: function() { stripExtraConfigs: function() {
let ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
newRegistry = new Registry(); newRegistry = new Registry();
newRegistry.rules = lodash.assign({}, this.rules); newRegistry.rules = Object.assign({}, this.rules);
ruleIds.forEach(function(ruleId) { ruleIds.forEach(function(ruleId) {
newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(function(registryItem) { newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(function(registryItem) {
return (typeof registryItem.errorCount !== "undefined"); return (typeof registryItem.errorCount !== "undefined");
@ -216,11 +215,11 @@ Registry.prototype = {
* @returns {Registry} A registry of failing rules. * @returns {Registry} A registry of failing rules.
*/ */
getFailingRulesRegistry: function() { getFailingRulesRegistry: function() {
let ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
failingRegistry = new Registry(); failingRegistry = new Registry();
ruleIds.forEach(function(ruleId) { ruleIds.forEach(function(ruleId) {
let failingConfigs = this.rules[ruleId].filter(function(registryItem) { const failingConfigs = this.rules[ruleId].filter(function(registryItem) {
return (registryItem.errorCount > 0); return (registryItem.errorCount > 0);
}); });
@ -239,7 +238,7 @@ Registry.prototype = {
* @returns {Object} An eslint config with rules section populated * @returns {Object} An eslint config with rules section populated
*/ */
createConfig: function() { createConfig: function() {
let ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
config = {rules: {}}; config = {rules: {}};
ruleIds.forEach(function(ruleId) { ruleIds.forEach(function(ruleId) {
@ -258,10 +257,10 @@ Registry.prototype = {
* @returns {Registry} A registry of rules * @returns {Registry} A registry of rules
*/ */
filterBySpecificity: function(specificity) { filterBySpecificity: function(specificity) {
let ruleIds = Object.keys(this.rules), const ruleIds = Object.keys(this.rules),
newRegistry = new Registry(); newRegistry = new Registry();
newRegistry.rules = lodash.assign({}, this.rules); newRegistry.rules = Object.assign({}, this.rules);
ruleIds.forEach(function(ruleId) { ruleIds.forEach(function(ruleId) {
newRegistry.rules[ruleId] = this.rules[ruleId].filter(function(registryItem) { newRegistry.rules[ruleId] = this.rules[ruleId].filter(function(registryItem) {
return (registryItem.specificity === specificity); return (registryItem.specificity === specificity);
@ -280,25 +279,20 @@ Registry.prototype = {
* @returns {Registry} New registry with errorCount populated * @returns {Registry} New registry with errorCount populated
*/ */
lintSourceCode: function(sourceCodes, config, cb) { lintSourceCode: function(sourceCodes, config, cb) {
let totalFilesLinting, let ruleSetIdx,
lintConfig,
ruleSets,
ruleSetIdx,
filenames,
lintedRegistry; lintedRegistry;
lintedRegistry = new Registry(); lintedRegistry = new Registry();
lintedRegistry.rules = lodash.assign({}, this.rules); lintedRegistry.rules = Object.assign({}, this.rules);
ruleSets = lintedRegistry.buildRuleSets(); const ruleSets = lintedRegistry.buildRuleSets();
lintedRegistry = lintedRegistry.stripExtraConfigs(); lintedRegistry = lintedRegistry.stripExtraConfigs();
debug("Linting with all possible rule combinations"); debug("Linting with all possible rule combinations");
filenames = Object.keys(sourceCodes); const filenames = Object.keys(sourceCodes);
const totalFilesLinting = filenames.length * ruleSets.length;
totalFilesLinting = filenames.length * ruleSets.length;
filenames.forEach(function(filename) { filenames.forEach(function(filename) {
debug("Linting file: " + filename); debug("Linting file: " + filename);
@ -306,8 +300,8 @@ Registry.prototype = {
ruleSetIdx = 0; ruleSetIdx = 0;
ruleSets.forEach(function(ruleSet) { ruleSets.forEach(function(ruleSet) {
lintConfig = lodash.assign({}, config, {rules: ruleSet}); const lintConfig = Object.assign({}, config, {rules: ruleSet});
let lintResults = eslint.verify(sourceCodes[filename], lintConfig); const lintResults = eslint.verify(sourceCodes[filename], lintConfig);
lintResults.forEach(function(result) { lintResults.forEach(function(result) {
@ -344,11 +338,11 @@ Registry.prototype = {
* @returns {Object} config object using `"extends": "eslint:recommended"` * @returns {Object} config object using `"extends": "eslint:recommended"`
*/ */
function extendFromRecommended(config) { function extendFromRecommended(config) {
let newConfig = lodash.assign({}, config); const newConfig = Object.assign({}, config);
ConfigOps.normalizeToStrings(newConfig); ConfigOps.normalizeToStrings(newConfig);
let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { const recRules = Object.keys(recConfig.rules).filter(function(ruleId) {
return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]);
}); });

51
tools/eslint/lib/config/config-file.js

@ -11,9 +11,9 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let debug = require("debug"), const fs = require("fs"),
fs = require("fs"),
path = require("path"), path = require("path"),
shell = require("shelljs"),
ConfigOps = require("./config-ops"), ConfigOps = require("./config-ops"),
validator = require("./config-validator"), validator = require("./config-validator"),
Plugins = require("./plugins"), Plugins = require("./plugins"),
@ -26,6 +26,7 @@ let debug = require("debug"),
defaultOptions = require("../../conf/eslint.json"), defaultOptions = require("../../conf/eslint.json"),
requireUncached = require("require-uncached"); requireUncached = require("require-uncached");
const debug = require("debug")("eslint:config-file");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
@ -48,7 +49,7 @@ function sortByKey(a, b) {
// Private // Private
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let CONFIG_FILES = [ const CONFIG_FILES = [
".eslintrc.js", ".eslintrc.js",
".eslintrc.yaml", ".eslintrc.yaml",
".eslintrc.yml", ".eslintrc.yml",
@ -57,9 +58,7 @@ let CONFIG_FILES = [
"package.json" "package.json"
]; ];
let resolver = new ModuleResolver(); const resolver = new ModuleResolver();
debug = debug("eslint:config-file");
/** /**
* Convenience wrapper for synchronously reading file contents. * Convenience wrapper for synchronously reading file contents.
@ -94,7 +93,7 @@ function loadYAMLConfigFile(filePath) {
debug("Loading YAML config file: " + filePath); debug("Loading YAML config file: " + filePath);
// lazy load YAML to improve performance when not used // lazy load YAML to improve performance when not used
let yaml = require("js-yaml"); const yaml = require("js-yaml");
try { try {
@ -137,7 +136,7 @@ function loadLegacyConfigFile(filePath) {
debug("Loading config file: " + filePath); debug("Loading config file: " + filePath);
// lazy load YAML to improve performance when not used // lazy load YAML to improve performance when not used
let yaml = require("js-yaml"); const yaml = require("js-yaml");
try { try {
return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {}; return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
@ -192,8 +191,8 @@ function loadPackageJSONConfigFile(filePath) {
* @private * @private
*/ */
function loadConfigFile(file) { function loadConfigFile(file) {
let config, const filePath = file.filePath;
filePath = file.filePath; let config;
switch (path.extname(filePath)) { switch (path.extname(filePath)) {
case ".js": case ".js":
@ -236,7 +235,7 @@ function loadConfigFile(file) {
function writeJSONConfigFile(config, filePath) { function writeJSONConfigFile(config, filePath) {
debug("Writing JSON config file: " + filePath); debug("Writing JSON config file: " + filePath);
let content = stringify(config, {cmp: sortByKey, space: 4}); const content = stringify(config, {cmp: sortByKey, space: 4});
fs.writeFileSync(filePath, content, "utf8"); fs.writeFileSync(filePath, content, "utf8");
} }
@ -252,9 +251,9 @@ function writeYAMLConfigFile(config, filePath) {
debug("Writing YAML config file: " + filePath); debug("Writing YAML config file: " + filePath);
// lazy load YAML to improve performance when not used // lazy load YAML to improve performance when not used
let yaml = require("js-yaml"); const yaml = require("js-yaml");
let content = yaml.safeDump(config, {sortKeys: true}); const content = yaml.safeDump(config, {sortKeys: true});
fs.writeFileSync(filePath, content, "utf8"); fs.writeFileSync(filePath, content, "utf8");
} }
@ -269,7 +268,7 @@ function writeYAMLConfigFile(config, filePath) {
function writeJSConfigFile(config, filePath) { function writeJSConfigFile(config, filePath) {
debug("Writing JS config file: " + filePath); debug("Writing JS config file: " + filePath);
let content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";"; const content = "module.exports = " + stringify(config, {cmp: sortByKey, space: 4}) + ";";
fs.writeFileSync(filePath, content, "utf8"); fs.writeFileSync(filePath, content, "utf8");
} }
@ -313,7 +312,7 @@ function write(config, filePath) {
function getBaseDir(configFilePath) { function getBaseDir(configFilePath) {
// calculates the path of the project including ESLint as dependency // calculates the path of the project including ESLint as dependency
let projectPath = path.resolve(__dirname, "../../../"); const projectPath = path.resolve(__dirname, "../../../");
if (configFilePath && pathIsInside(configFilePath, projectPath)) { if (configFilePath && pathIsInside(configFilePath, projectPath)) {
@ -336,7 +335,7 @@ function getBaseDir(configFilePath) {
* @private * @private
*/ */
function getLookupPath(configFilePath) { function getLookupPath(configFilePath) {
let basedir = getBaseDir(configFilePath); const basedir = getBaseDir(configFilePath);
return path.join(basedir, "node_modules"); return path.join(basedir, "node_modules");
} }
@ -431,7 +430,7 @@ function normalizePackageName(name, prefix) {
* it's a scoped package * it's a scoped package
* package name is "eslint-config", or just a username * package name is "eslint-config", or just a username
*/ */
let scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"), const scopedPackageShortcutRegex = new RegExp("^(@[^\/]+)(?:\/(?:" + prefix + ")?)?$"),
scopedPackageNameRegex = new RegExp("^" + prefix + "(-|$)"); scopedPackageNameRegex = new RegExp("^" + prefix + "(-|$)");
if (scopedPackageShortcutRegex.test(name)) { if (scopedPackageShortcutRegex.test(name)) {
@ -466,8 +465,8 @@ function resolve(filePath, relativeTo) {
let normalizedPackageName; let normalizedPackageName;
if (filePath.indexOf("plugin:") === 0) { if (filePath.indexOf("plugin:") === 0) {
let packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7); const packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7);
let configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1); const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin"); normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin");
debug("Attempting to resolve " + normalizedPackageName); debug("Attempting to resolve " + normalizedPackageName);
@ -493,10 +492,10 @@ function resolve(filePath, relativeTo) {
* @private * @private
*/ */
function load(filePath, applyEnvironments, relativeTo) { function load(filePath, applyEnvironments, relativeTo) {
let resolvedPath = resolve(filePath, relativeTo), const resolvedPath = resolve(filePath, relativeTo),
dirname = path.dirname(resolvedPath.filePath), dirname = path.dirname(resolvedPath.filePath),
lookupPath = getLookupPath(dirname), lookupPath = getLookupPath(dirname);
config = loadConfigFile(resolvedPath); let config = loadConfigFile(resolvedPath);
if (config) { if (config) {
@ -564,12 +563,10 @@ module.exports = {
* or null if there is no configuration file in the directory. * or null if there is no configuration file in the directory.
*/ */
getFilenameForDirectory: function(directory) { getFilenameForDirectory: function(directory) {
let filename;
for (let i = 0, len = CONFIG_FILES.length; i < len; i++) { for (let i = 0, len = CONFIG_FILES.length; i < len; i++) {
filename = path.join(directory, CONFIG_FILES[i]); const filename = path.join(directory, CONFIG_FILES[i]);
if (fs.existsSync(filename)) {
if (shell.test("-f", filename)) {
return filename; return filename;
} }
} }

78
tools/eslint/lib/config/config-initializer.js

@ -9,9 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let util = require("util"), const util = require("util"),
debug = require("debug"),
lodash = require("lodash"),
inquirer = require("inquirer"), inquirer = require("inquirer"),
ProgressBar = require("progress"), ProgressBar = require("progress"),
autoconfig = require("./autoconfig.js"), autoconfig = require("./autoconfig.js"),
@ -22,7 +20,7 @@ let util = require("util"),
recConfig = require("../../conf/eslint.json"), recConfig = require("../../conf/eslint.json"),
log = require("../logging"); log = require("../logging");
debug = debug("eslint:config-initializer"); const debug = require("debug")("eslint:config-initializer");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private // Private
@ -60,9 +58,7 @@ function writeFile(config, format) {
* @returns {void} * @returns {void}
*/ */
function installModules(config) { function installModules(config) {
let modules = [], let modules = [];
installStatus,
modulesToInstall;
// Create a list of modules which should be installed based on config // Create a list of modules which should be installed based on config
if (config.plugins) { if (config.plugins) {
@ -82,11 +78,11 @@ function installModules(config) {
// Add eslint to list in case user does not have it installed locally // Add eslint to list in case user does not have it installed locally
modules.unshift("eslint"); modules.unshift("eslint");
installStatus = npmUtil.checkDevDeps(modules); const installStatus = npmUtil.checkDevDeps(modules);
// Install packages which aren't already installed // Install packages which aren't already installed
modulesToInstall = Object.keys(installStatus).filter(function(module) { const modulesToInstall = Object.keys(installStatus).filter(function(module) {
let notInstalled = installStatus[module] === false; const notInstalled = installStatus[module] === false;
if (module === "eslint" && notInstalled) { if (module === "eslint" && notInstalled) {
log.info("Local ESLint installation not found."); log.info("Local ESLint installation not found.");
@ -113,31 +109,24 @@ function installModules(config) {
* @returns {Object} config object with configured rules * @returns {Object} config object with configured rules
*/ */
function configureRules(answers, config) { function configureRules(answers, config) {
let BAR_TOTAL = 20, const BAR_TOTAL = 20,
BAR_SOURCE_CODE_TOTAL = 4; BAR_SOURCE_CODE_TOTAL = 4,
newConfig = Object.assign({}, config),
let newConfig = lodash.assign({}, config), disabledConfigs = {};
bar, let sourceCodes,
patterns, registry;
sourceCodes,
fileQty,
registry,
failingRegistry,
disabledConfigs = {},
singleConfigs,
specTwoConfigs,
specThreeConfigs,
defaultConfigs;
// Set up a progress bar, as this process can take a long time // Set up a progress bar, as this process can take a long time
bar = new ProgressBar("Determining Config: :percent [:bar] :elapseds elapsed, eta :etas ", { const bar = new ProgressBar("Determining Config: :percent [:bar] :elapseds elapsed, eta :etas ", {
width: 30, width: 30,
total: BAR_TOTAL total: BAR_TOTAL
}); });
bar.tick(0); // Shows the progress bar bar.tick(0); // Shows the progress bar
// Get the SourceCode of all chosen files // Get the SourceCode of all chosen files
patterns = answers.patterns.split(/[\s]+/); const patterns = answers.patterns.split(/[\s]+/);
try { try {
sourceCodes = getSourceCodeOfFiles(patterns, { baseConfig: newConfig, useEslintrc: false }, function(total) { sourceCodes = getSourceCodeOfFiles(patterns, { baseConfig: newConfig, useEslintrc: false }, function(total) {
bar.tick((BAR_SOURCE_CODE_TOTAL / total)); bar.tick((BAR_SOURCE_CODE_TOTAL / total));
@ -146,7 +135,8 @@ function configureRules(answers, config) {
log.info("\n"); log.info("\n");
throw e; throw e;
} }
fileQty = Object.keys(sourceCodes).length; const fileQty = Object.keys(sourceCodes).length;
if (fileQty === 0) { if (fileQty === 0) {
log.info("\n"); log.info("\n");
throw new Error("Automatic Configuration failed. No files were able to be parsed."); throw new Error("Automatic Configuration failed. No files were able to be parsed.");
@ -163,12 +153,12 @@ function configureRules(answers, config) {
debug("\nRegistry: " + util.inspect(registry.rules, {depth: null})); debug("\nRegistry: " + util.inspect(registry.rules, {depth: null}));
// Create a list of recommended rules, because we don't want to disable them // Create a list of recommended rules, because we don't want to disable them
let recRules = Object.keys(recConfig.rules).filter(function(ruleId) { const recRules = Object.keys(recConfig.rules).filter(function(ruleId) {
return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]); return ConfigOps.isErrorSeverity(recConfig.rules[ruleId]);
}); });
// Find and disable rules which had no error-free configuration // Find and disable rules which had no error-free configuration
failingRegistry = registry.getFailingRulesRegistry(); const failingRegistry = registry.getFailingRulesRegistry();
Object.keys(failingRegistry.rules).forEach(function(ruleId) { Object.keys(failingRegistry.rules).forEach(function(ruleId) {
@ -181,33 +171,33 @@ function configureRules(answers, config) {
// If there is only one config that results in no errors for a rule, we should use it. // If there is only one config that results in no errors for a rule, we should use it.
// createConfig will only add rules that have one configuration in the registry. // createConfig will only add rules that have one configuration in the registry.
singleConfigs = registry.createConfig().rules; const singleConfigs = registry.createConfig().rules;
// The "sweet spot" for number of options in a config seems to be two (severity plus one option). // The "sweet spot" for number of options in a config seems to be two (severity plus one option).
// Very often, a third option (usually an object) is available to address // Very often, a third option (usually an object) is available to address
// edge cases, exceptions, or unique situations. We will prefer to use a config with // edge cases, exceptions, or unique situations. We will prefer to use a config with
// specificity of two. // specificity of two.
specTwoConfigs = registry.filterBySpecificity(2).createConfig().rules; const specTwoConfigs = registry.filterBySpecificity(2).createConfig().rules;
// Maybe a specific combination using all three options works // Maybe a specific combination using all three options works
specThreeConfigs = registry.filterBySpecificity(3).createConfig().rules; const specThreeConfigs = registry.filterBySpecificity(3).createConfig().rules;
// If all else fails, try to use the default (severity only) // If all else fails, try to use the default (severity only)
defaultConfigs = registry.filterBySpecificity(1).createConfig().rules; const defaultConfigs = registry.filterBySpecificity(1).createConfig().rules;
// Combine configs in reverse priority order (later take precedence) // Combine configs in reverse priority order (later take precedence)
newConfig.rules = lodash.assign({}, disabledConfigs, defaultConfigs, specThreeConfigs, specTwoConfigs, singleConfigs); newConfig.rules = Object.assign({}, disabledConfigs, defaultConfigs, specThreeConfigs, specTwoConfigs, singleConfigs);
// Make sure progress bar has finished (floating point rounding) // Make sure progress bar has finished (floating point rounding)
bar.update(BAR_TOTAL); bar.update(BAR_TOTAL);
// Log out some stats to let the user know what happened // Log out some stats to let the user know what happened
let finalRuleIds = Object.keys(newConfig.rules), const finalRuleIds = Object.keys(newConfig.rules);
totalRules = finalRuleIds.length; const totalRules = finalRuleIds.length;
let enabledRules = finalRuleIds.filter(function(ruleId) { const enabledRules = finalRuleIds.filter(function(ruleId) {
return (newConfig.rules[ruleId] !== 0); return (newConfig.rules[ruleId] !== 0);
}).length; }).length;
let resultMessage = [ const resultMessage = [
"\nEnabled " + enabledRules + " out of " + totalRules, "\nEnabled " + enabledRules + " out of " + totalRules,
"rules based on " + fileQty, "rules based on " + fileQty,
"file" + ((fileQty === 1) ? "." : "s.") "file" + ((fileQty === 1) ? "." : "s.")
@ -275,9 +265,9 @@ function processAnswers(answers) {
* @returns {Object} config object * @returns {Object} config object
*/ */
function getConfigForStyleGuide(guide) { function getConfigForStyleGuide(guide) {
let guides = { const guides = {
google: {extends: "google"}, google: {extends: "google"},
airbnb: {extends: "airbnb", plugins: ["react"]}, airbnb: {extends: "airbnb", plugins: ["react", "jsx-a11y", "import"]},
standard: {extends: "standard", plugins: ["standard", "promise"]} standard: {extends: "standard", plugins: ["standard", "promise"]}
}; };
@ -419,7 +409,7 @@ function promptUser(callback) {
// early exit if you are using automatic style generation // early exit if you are using automatic style generation
if (earlyAnswers.source === "auto") { if (earlyAnswers.source === "auto") {
try { try {
let combinedAnswers = lodash.assign({}, earlyAnswers, secondAnswers); const combinedAnswers = Object.assign({}, earlyAnswers, secondAnswers);
config = processAnswers(combinedAnswers); config = processAnswers(combinedAnswers);
installModules(config); installModules(config);
@ -469,7 +459,7 @@ function promptUser(callback) {
} }
], function(answers) { ], function(answers) {
try { try {
let totalAnswers = lodash.assign({}, earlyAnswers, secondAnswers, answers); const totalAnswers = Object.assign({}, earlyAnswers, secondAnswers, answers);
config = processAnswers(totalAnswers); config = processAnswers(totalAnswers);
installModules(config); installModules(config);
@ -488,7 +478,7 @@ function promptUser(callback) {
// Public Interface // Public Interface
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let init = { const init = {
getConfigForStyleGuide: getConfigForStyleGuide, getConfigForStyleGuide: getConfigForStyleGuide,
processAnswers: processAnswers, processAnswers: processAnswers,
initializeConfig: /* istanbul ignore next */ function(callback) { initializeConfig: /* istanbul ignore next */ function(callback) {

24
tools/eslint/lib/config/config-ops.js

@ -9,17 +9,15 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"), const Environments = require("./environments");
debug = require("debug"),
Environments = require("./environments"); const debug = require("debug")("eslint:config-ops");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private // Private
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:config-ops"); const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
let RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce(function(map, value, index) { RULE_SEVERITY = RULE_SEVERITY_STRINGS.reduce(function(map, value, index) {
map[value] = index; map[value] = index;
return map; return map;
@ -53,7 +51,7 @@ module.exports = {
*/ */
createEnvironmentConfig: function(env) { createEnvironmentConfig: function(env) {
let envConfig = this.createEmptyConfig(); const envConfig = this.createEmptyConfig();
if (env) { if (env) {
@ -62,16 +60,16 @@ module.exports = {
Object.keys(env).filter(function(name) { Object.keys(env).filter(function(name) {
return env[name]; return env[name];
}).forEach(function(name) { }).forEach(function(name) {
let environment = Environments.get(name); const environment = Environments.get(name);
if (environment) { if (environment) {
debug("Creating config for environment " + name); debug("Creating config for environment " + name);
if (environment.globals) { if (environment.globals) {
lodash.assign(envConfig.globals, environment.globals); Object.assign(envConfig.globals, environment.globals);
} }
if (environment.parserOptions) { if (environment.parserOptions) {
lodash.assign(envConfig.parserOptions, environment.parserOptions); Object.assign(envConfig.parserOptions, environment.parserOptions);
} }
} }
}); });
@ -134,7 +132,7 @@ module.exports = {
* (https://github.com/KyleAMathews/deepmerge) * (https://github.com/KyleAMathews/deepmerge)
* and modified to meet our needs. * and modified to meet our needs.
*/ */
let array = Array.isArray(src) || Array.isArray(target); const array = Array.isArray(src) || Array.isArray(target);
let dst = array && [] || {}; let dst = array && [] || {};
combine = !!combine; combine = !!combine;
@ -202,7 +200,7 @@ module.exports = {
if (config.rules) { if (config.rules) {
Object.keys(config.rules).forEach(function(ruleId) { Object.keys(config.rules).forEach(function(ruleId) {
let ruleConfig = config.rules[ruleId]; const ruleConfig = config.rules[ruleId];
if (typeof ruleConfig === "string") { if (typeof ruleConfig === "string") {
config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0; config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0;
@ -224,7 +222,7 @@ module.exports = {
if (config.rules) { if (config.rules) {
Object.keys(config.rules).forEach(function(ruleId) { Object.keys(config.rules).forEach(function(ruleId) {
let ruleConfig = config.rules[ruleId]; const ruleConfig = config.rules[ruleId];
if (typeof ruleConfig === "number") { if (typeof ruleConfig === "number") {
config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0]; config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];

31
tools/eslint/lib/config/config-rule.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let rules = require("../rules"), const rules = require("../rules"),
loadRules = require("../load-rules"); loadRules = require("../load-rules");
@ -41,7 +41,7 @@ function explodeArray(xs) {
* @returns {array} A mixture of the elements of the first and second arrays. * @returns {array} A mixture of the elements of the first and second arrays.
*/ */
function combineArrays(arr1, arr2) { function combineArrays(arr1, arr2) {
let res = []; const res = [];
if (arr1.length === 0) { if (arr1.length === 0) {
return explodeArray(arr2); return explodeArray(arr2);
@ -78,8 +78,8 @@ function combineArrays(arr1, arr2) {
* @returns {Array[]} Array of arrays of objects grouped by property * @returns {Array[]} Array of arrays of objects grouped by property
*/ */
function groupByProperty(objects) { function groupByProperty(objects) {
let groupedObj = objects.reduce(function(accumulator, obj) { const groupedObj = objects.reduce(function(accumulator, obj) {
let prop = Object.keys(obj)[0]; const prop = Object.keys(obj)[0];
accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj]; accumulator[prop] = accumulator[prop] ? accumulator[prop].concat(obj) : [obj];
return accumulator; return accumulator;
@ -144,7 +144,7 @@ function groupByProperty(objects) {
* @returns {Object[]} Combined objects for each combination of input properties and values * @returns {Object[]} Combined objects for each combination of input properties and values
*/ */
function combinePropertyObjects(objArr1, objArr2) { function combinePropertyObjects(objArr1, objArr2) {
let res = []; const res = [];
if (objArr1.length === 0) { if (objArr1.length === 0) {
return objArr2; return objArr2;
@ -154,9 +154,9 @@ function combinePropertyObjects(objArr1, objArr2) {
} }
objArr1.forEach(function(obj1) { objArr1.forEach(function(obj1) {
objArr2.forEach(function(obj2) { objArr2.forEach(function(obj2) {
let combinedObj = {}; const combinedObj = {};
let obj1Props = Object.keys(obj1); const obj1Props = Object.keys(obj1);
let obj2Props = Object.keys(obj2); const obj2Props = Object.keys(obj2);
obj1Props.forEach(function(prop1) { obj1Props.forEach(function(prop1) {
combinedObj[prop1] = obj1[prop1]; combinedObj[prop1] = obj1[prop1];
@ -229,13 +229,12 @@ RuleConfigSet.prototype = {
* @returns {void} * @returns {void}
*/ */
addObject: function(obj) { addObject: function(obj) {
let objectConfigSet = { const objectConfigSet = {
objectConfigs: [], objectConfigs: [],
add: function(property, values) { add: function(property, values) {
let optionObj;
for (let idx = 0; idx < values.length; idx++) { for (let idx = 0; idx < values.length; idx++) {
optionObj = {}; const optionObj = {};
optionObj[property] = values[idx]; optionObj[property] = values[idx];
this.objectConfigs.push(optionObj); this.objectConfigs.push(optionObj);
} }
@ -274,7 +273,7 @@ RuleConfigSet.prototype = {
* @returns {array[]} Valid rule configurations * @returns {array[]} Valid rule configurations
*/ */
function generateConfigsFromSchema(schema) { function generateConfigsFromSchema(schema) {
let configSet = new RuleConfigSet(); const configSet = new RuleConfigSet();
if (Array.isArray(schema)) { if (Array.isArray(schema)) {
schema.forEach(function(opt) { schema.forEach(function(opt) {
@ -301,11 +300,11 @@ function generateConfigsFromSchema(schema) {
* @returns {rulesConfig} Hash of rule names and arrays of possible configurations * @returns {rulesConfig} Hash of rule names and arrays of possible configurations
*/ */
function createCoreRuleConfigs() { function createCoreRuleConfigs() {
let ruleList = loadRules(); const ruleList = loadRules();
return Object.keys(ruleList).reduce(function(accumulator, id) { return Object.keys(ruleList).reduce(function(accumulator, id) {
let rule = rules.get(id); const rule = rules.get(id);
let schema = (typeof rule === "function") ? rule.schema : rule.meta.schema; const schema = (typeof rule === "function") ? rule.schema : rule.meta.schema;
accumulator[id] = generateConfigsFromSchema(schema); accumulator[id] = generateConfigsFromSchema(schema);
return accumulator; return accumulator;

13
tools/eslint/lib/config/config-validator.js

@ -9,12 +9,12 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let rules = require("../rules"), const rules = require("../rules"),
Environments = require("./environments"), Environments = require("./environments"),
schemaValidator = require("is-my-json-valid"), schemaValidator = require("is-my-json-valid"),
util = require("util"); util = require("util");
let validators = { const validators = {
rules: Object.create(null) rules: Object.create(null)
}; };
@ -28,7 +28,7 @@ let validators = {
* @returns {Object} JSON Schema for the rule's options. * @returns {Object} JSON Schema for the rule's options.
*/ */
function getRuleOptionsSchema(id) { function getRuleOptionsSchema(id) {
let rule = rules.get(id), const rule = rules.get(id),
schema = rule && rule.schema || rule && rule.meta && rule.meta.schema; schema = rule && rule.schema || rule && rule.meta && rule.meta.schema;
// Given a tuple of schemas, insert warning level at the beginning // Given a tuple of schemas, insert warning level at the beginning
@ -61,11 +61,10 @@ function getRuleOptionsSchema(id) {
* @returns {void} * @returns {void}
*/ */
function validateRuleOptions(id, options, source) { function validateRuleOptions(id, options, source) {
const schema = getRuleOptionsSchema(id);
let validateRule = validators.rules[id], let validateRule = validators.rules[id],
message,
severity, severity,
localOptions, localOptions,
schema = getRuleOptionsSchema(id),
validSeverity = true; validSeverity = true;
if (!validateRule && schema) { if (!validateRule && schema) {
@ -92,7 +91,7 @@ function validateRuleOptions(id, options, source) {
} }
if ((validateRule && validateRule.errors) || !validSeverity) { if ((validateRule && validateRule.errors) || !validSeverity) {
message = [ const message = [
source, ":\n", source, ":\n",
"\tConfiguration for rule \"", id, "\" is invalid:\n" "\tConfiguration for rule \"", id, "\" is invalid:\n"
]; ];
@ -137,7 +136,7 @@ function validateEnvironment(environment, source) {
if (typeof environment === "object") { if (typeof environment === "object") {
Object.keys(environment).forEach(function(env) { Object.keys(environment).forEach(function(env) {
if (!Environments.get(env)) { if (!Environments.get(env)) {
let message = [ const message = [
source, ":\n", source, ":\n",
"\tEnvironment key \"", env, "\" is unknown\n" "\tEnvironment key \"", env, "\" is unknown\n"
]; ];

2
tools/eslint/lib/config/environments.js

@ -8,7 +8,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let envs = require("../../conf/environments"); const envs = require("../../conf/environments");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private // Private

17
tools/eslint/lib/config/plugins.js

@ -8,19 +8,18 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let debug = require("debug"), const Environments = require("./environments"),
Environments = require("./environments"),
rules = require("../rules"); rules = require("../rules");
const debug = require("debug")("eslint:plugins");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private // Private
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
debug = debug("eslint:plugins");
let plugins = Object.create(null); let plugins = Object.create(null);
let PLUGIN_NAME_PREFIX = "eslint-plugin-", const PLUGIN_NAME_PREFIX = "eslint-plugin-",
NAMESPACE_REGEX = /^@.*\//i; NAMESPACE_REGEX = /^@.*\//i;
/** /**
@ -67,7 +66,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
define: function(pluginName, plugin) { define: function(pluginName, plugin) {
let pluginNameWithoutNamespace = removeNamespace(pluginName), const pluginNameWithoutNamespace = removeNamespace(pluginName),
pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace); pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace);
plugins[pluginNameWithoutPrefix] = plugin; plugins[pluginNameWithoutPrefix] = plugin;
@ -104,10 +103,10 @@ module.exports = {
* @throws {Error} If the plugin cannot be loaded. * @throws {Error} If the plugin cannot be loaded.
*/ */
load: function(pluginName) { load: function(pluginName) {
let pluginNamespace = getNamespace(pluginName), const pluginNamespace = getNamespace(pluginName),
pluginNameWithoutNamespace = removeNamespace(pluginName), pluginNameWithoutNamespace = removeNamespace(pluginName),
pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace), pluginNameWithoutPrefix = removePrefix(pluginNameWithoutNamespace);
plugin = null; let plugin = null;
if (!plugins[pluginNameWithoutPrefix]) { if (!plugins[pluginNameWithoutPrefix]) {
try { try {

140
tools/eslint/lib/eslint.js

@ -9,11 +9,10 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let assert = require("assert"), const assert = require("assert"),
EventEmitter = require("events").EventEmitter, EventEmitter = require("events").EventEmitter,
escope = require("escope"), escope = require("escope"),
levn = require("levn"), levn = require("levn"),
lodash = require("lodash"),
blankScriptAST = require("../conf/blank-script.json"), blankScriptAST = require("../conf/blank-script.json"),
DEFAULT_PARSER = require("../conf/eslint.json").parser, DEFAULT_PARSER = require("../conf/eslint.json").parser,
replacements = require("../conf/replacements.json"), replacements = require("../conf/replacements.json"),
@ -41,7 +40,7 @@ let assert = require("assert"),
* @returns {Object} Result map object of names and boolean values * @returns {Object} Result map object of names and boolean values
*/ */
function parseBooleanConfig(string, comment) { function parseBooleanConfig(string, comment) {
let items = {}; const items = {};
// Collapse whitespace around `:` and `,` to make parsing easier // Collapse whitespace around `:` and `,` to make parsing easier
string = string.replace(/\s*([:,])\s*/g, "$1"); string = string.replace(/\s*([:,])\s*/g, "$1");
@ -50,8 +49,8 @@ function parseBooleanConfig(string, comment) {
if (!name) { if (!name) {
return; return;
} }
let pos = name.indexOf(":"), const pos = name.indexOf(":");
value; let value;
if (pos !== -1) { if (pos !== -1) {
value = name.substring(pos + 1, name.length); value = name.substring(pos + 1, name.length);
@ -122,7 +121,7 @@ function parseJsonConfig(string, location, messages) {
* @returns {Object} Result map of values and true values * @returns {Object} Result map of values and true values
*/ */
function parseListConfig(string) { function parseListConfig(string) {
let items = {}; const items = {};
// Collapse whitespace around , // Collapse whitespace around ,
string = string.replace(/\s*,\s*/g, ","); string = string.replace(/\s*,\s*/g, ",");
@ -147,27 +146,27 @@ function parseListConfig(string) {
* @returns {void} * @returns {void}
*/ */
function addDeclaredGlobals(program, globalScope, config) { function addDeclaredGlobals(program, globalScope, config) {
let declaredGlobals = {}, const declaredGlobals = {},
exportedGlobals = {}, exportedGlobals = {},
explicitGlobals = {}, explicitGlobals = {},
builtin = Environments.get("builtin"); builtin = Environments.get("builtin");
lodash.assign(declaredGlobals, builtin); Object.assign(declaredGlobals, builtin);
Object.keys(config.env).forEach(function(name) { Object.keys(config.env).forEach(function(name) {
if (config.env[name]) { if (config.env[name]) {
let env = Environments.get(name), const env = Environments.get(name),
environmentGlobals = env && env.globals; environmentGlobals = env && env.globals;
if (environmentGlobals) { if (environmentGlobals) {
lodash.assign(declaredGlobals, environmentGlobals); Object.assign(declaredGlobals, environmentGlobals);
} }
} }
}); });
lodash.assign(exportedGlobals, config.exported); Object.assign(exportedGlobals, config.exported);
lodash.assign(declaredGlobals, config.globals); Object.assign(declaredGlobals, config.globals);
lodash.assign(explicitGlobals, config.astGlobals); Object.assign(explicitGlobals, config.astGlobals);
Object.keys(declaredGlobals).forEach(function(name) { Object.keys(declaredGlobals).forEach(function(name) {
let variable = globalScope.set.get(name); let variable = globalScope.set.get(name);
@ -196,7 +195,7 @@ function addDeclaredGlobals(program, globalScope, config) {
// mark all exported variables as such // mark all exported variables as such
Object.keys(exportedGlobals).forEach(function(name) { Object.keys(exportedGlobals).forEach(function(name) {
let variable = globalScope.set.get(name); const variable = globalScope.set.get(name);
if (variable) { if (variable) {
variable.eslintUsed = true; variable.eslintUsed = true;
@ -209,8 +208,8 @@ function addDeclaredGlobals(program, globalScope, config) {
* references and remove the ones that were added by configuration. * references and remove the ones that were added by configuration.
*/ */
globalScope.through = globalScope.through.filter(function(reference) { globalScope.through = globalScope.through.filter(function(reference) {
let name = reference.identifier.name; const name = reference.identifier.name;
let variable = globalScope.set.get(name); const variable = globalScope.set.get(name);
if (variable) { if (variable) {
@ -312,12 +311,12 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa
rules: {}, rules: {},
env: {} env: {}
}; };
let commentRules = {}; const commentRules = {};
ast.comments.forEach(function(comment) { ast.comments.forEach(function(comment) {
let value = comment.value.trim(); let value = comment.value.trim();
let match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value); const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value);
if (match) { if (match) {
value = value.substring(match.index + match[1].length); value = value.substring(match.index + match[1].length);
@ -325,16 +324,16 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa
if (comment.type === "Block") { if (comment.type === "Block") {
switch (match[1]) { switch (match[1]) {
case "exported": case "exported":
lodash.assign(commentConfig.exported, parseBooleanConfig(value, comment)); Object.assign(commentConfig.exported, parseBooleanConfig(value, comment));
break; break;
case "globals": case "globals":
case "global": case "global":
lodash.assign(commentConfig.astGlobals, parseBooleanConfig(value, comment)); Object.assign(commentConfig.astGlobals, parseBooleanConfig(value, comment));
break; break;
case "eslint-env": case "eslint-env":
lodash.assign(commentConfig.env, parseListConfig(value)); Object.assign(commentConfig.env, parseListConfig(value));
break; break;
case "eslint-disable": case "eslint-disable":
@ -349,7 +348,7 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa
const items = parseJsonConfig(value, comment.loc, messages); const items = parseJsonConfig(value, comment.loc, messages);
Object.keys(items).forEach(function(name) { Object.keys(items).forEach(function(name) {
let ruleValue = items[name]; const ruleValue = items[name];
validator.validateRuleOptions(name, ruleValue, filename + " line " + comment.loc.start.line); validator.validateRuleOptions(name, ruleValue, filename + " line " + comment.loc.start.line);
commentRules[name] = ruleValue; commentRules[name] = ruleValue;
@ -373,13 +372,13 @@ function modifyConfigsFromComments(filename, ast, config, reportingConfig, messa
// apply environment configs // apply environment configs
Object.keys(commentConfig.env).forEach(function(name) { Object.keys(commentConfig.env).forEach(function(name) {
let env = Environments.get(name); const env = Environments.get(name);
if (env) { if (env) {
commentConfig = ConfigOps.merge(commentConfig, env); commentConfig = ConfigOps.merge(commentConfig, env);
} }
}); });
lodash.assign(commentConfig.rules, commentRules); Object.assign(commentConfig.rules, commentRules);
return ConfigOps.merge(config, commentConfig); return ConfigOps.merge(config, commentConfig);
} }
@ -395,7 +394,7 @@ function isDisabledByReportingConfig(reportingConfig, ruleId, location) {
for (let i = 0, c = reportingConfig.length; i < c; i++) { for (let i = 0, c = reportingConfig.length; i < c; i++) {
let ignore = reportingConfig[i]; const ignore = reportingConfig[i];
if ((!ignore.rule || ignore.rule === ruleId) && if ((!ignore.rule || ignore.rule === ruleId) &&
(location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) && (location.line > ignore.start.line || (location.line === ignore.start.line && location.column >= ignore.start.column)) &&
@ -417,13 +416,12 @@ function prepareConfig(config) {
config.globals = config.globals || config.global || {}; config.globals = config.globals || config.global || {};
delete config.global; delete config.global;
let copiedRules = {}, const copiedRules = {};
parserOptions = {}, let parserOptions = {};
preparedConfig;
if (typeof config.rules === "object") { if (typeof config.rules === "object") {
Object.keys(config.rules).forEach(function(k) { Object.keys(config.rules).forEach(function(k) {
let rule = config.rules[k]; const rule = config.rules[k];
if (rule === null) { if (rule === null) {
throw new Error("Invalid config for rule '" + k + "'\."); throw new Error("Invalid config for rule '" + k + "'\.");
@ -439,7 +437,7 @@ function prepareConfig(config) {
// merge in environment parserOptions // merge in environment parserOptions
if (typeof config.env === "object") { if (typeof config.env === "object") {
Object.keys(config.env).forEach(function(envName) { Object.keys(config.env).forEach(function(envName) {
let env = Environments.get(envName); const env = Environments.get(envName);
if (config.env[envName] && env && env.parserOptions) { if (config.env[envName] && env && env.parserOptions) {
parserOptions = ConfigOps.merge(parserOptions, env.parserOptions); parserOptions = ConfigOps.merge(parserOptions, env.parserOptions);
@ -447,7 +445,7 @@ function prepareConfig(config) {
}); });
} }
preparedConfig = { const preparedConfig = {
rules: copiedRules, rules: copiedRules,
parser: config.parser || DEFAULT_PARSER, parser: config.parser || DEFAULT_PARSER,
globals: ConfigOps.merge({}, config.globals), globals: ConfigOps.merge({}, config.globals),
@ -507,7 +505,7 @@ function createStubRule(message) {
*/ */
function getRuleReplacementMessage(ruleId) { function getRuleReplacementMessage(ruleId) {
if (ruleId in replacements.rules) { if (ruleId in replacements.rules) {
let newRules = replacements.rules[ruleId]; const newRules = replacements.rules[ruleId];
return "Rule \'" + ruleId + "\' was removed and replaced by: " + newRules.join(", "); return "Rule \'" + ruleId + "\' was removed and replaced by: " + newRules.join(", ");
} }
@ -515,7 +513,7 @@ function getRuleReplacementMessage(ruleId) {
return null; return null;
} }
let eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g; const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g;
/** /**
* Checks whether or not there is a comment which has "eslint-env *" in a given text. * Checks whether or not there is a comment which has "eslint-env *" in a given text.
@ -528,7 +526,7 @@ function findEslintEnv(text) {
eslintEnvPattern.lastIndex = 0; eslintEnvPattern.lastIndex = 0;
while ((match = eslintEnvPattern.exec(text))) { while ((match = eslintEnvPattern.exec(text))) {
retv = lodash.assign(retv || {}, parseListConfig(match[1])); retv = Object.assign(retv || {}, parseListConfig(match[1]));
} }
return retv; return retv;
@ -563,8 +561,8 @@ function stripUnicodeBOM(text) {
*/ */
module.exports = (function() { module.exports = (function() {
let api = Object.create(new EventEmitter()), const api = Object.create(new EventEmitter());
messages = [], let messages = [],
currentConfig = null, currentConfig = null,
currentScopes = null, currentScopes = null,
scopeMap = null, scopeMap = null,
@ -613,7 +611,7 @@ module.exports = (function() {
// merge in any additional parser options // merge in any additional parser options
if (config.parserOptions) { if (config.parserOptions) {
parserOptions = lodash.assign({}, config.parserOptions, parserOptions); parserOptions = Object.assign({}, config.parserOptions, parserOptions);
} }
/* /*
@ -627,8 +625,8 @@ module.exports = (function() {
} catch (ex) { } catch (ex) {
// If the message includes a leading line number, strip it: // If the message includes a leading line number, strip it:
let message = ex.message.replace(/^line \d+:/i, "").trim(); const message = ex.message.replace(/^line \d+:/i, "").trim();
let source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null; const source = (ex.lineNumber) ? SourceCode.splitLines(text)[ex.lineNumber - 1] : null;
messages.push({ messages.push({
ruleId: null, ruleId: null,
@ -718,13 +716,10 @@ module.exports = (function() {
* @returns {Object[]} The results as an array of messages or null if no messages. * @returns {Object[]} The results as an array of messages or null if no messages.
*/ */
api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) { api.verify = function(textOrSourceCode, config, filenameOrOptions, saveState) {
const text = (typeof textOrSourceCode === "string") ? textOrSourceCode : null;
let ast, let ast,
shebang, shebang,
ecmaFeatures, allowInlineConfig;
ecmaVersion,
allowInlineConfig,
text = (typeof textOrSourceCode === "string") ? textOrSourceCode : null;
// evaluate arguments // evaluate arguments
if (typeof filenameOrOptions === "object") { if (typeof filenameOrOptions === "object") {
@ -740,14 +735,14 @@ module.exports = (function() {
} }
// search and apply "eslint-env *". // search and apply "eslint-env *".
let envInFile = findEslintEnv(text || textOrSourceCode.text); const envInFile = findEslintEnv(text || textOrSourceCode.text);
if (envInFile) { if (envInFile) {
if (!config || !config.env) { if (!config || !config.env) {
config = lodash.assign({}, config || {}, {env: envInFile}); config = Object.assign({}, config || {}, {env: envInFile});
} else { } else {
config = lodash.assign({}, config); config = Object.assign({}, config);
config.env = lodash.assign({}, config.env, envInFile); config.env = Object.assign({}, config.env, envInFile);
} }
} }
@ -795,15 +790,12 @@ module.exports = (function() {
Object.keys(config.rules).filter(function(key) { Object.keys(config.rules).filter(function(key) {
return getRuleSeverity(config.rules[key]) > 0; return getRuleSeverity(config.rules[key]) > 0;
}).forEach(function(key) { }).forEach(function(key) {
let ruleCreator, let ruleCreator;
severity,
options,
rule;
ruleCreator = rules.get(key); ruleCreator = rules.get(key);
if (!ruleCreator) { if (!ruleCreator) {
let replacementMsg = getRuleReplacementMessage(key); const replacementMsg = getRuleReplacementMessage(key);
if (replacementMsg) { if (replacementMsg) {
ruleCreator = createStubRule(replacementMsg); ruleCreator = createStubRule(replacementMsg);
@ -813,15 +805,15 @@ module.exports = (function() {
rules.define(key, ruleCreator); rules.define(key, ruleCreator);
} }
severity = getRuleSeverity(config.rules[key]); const severity = getRuleSeverity(config.rules[key]);
options = getRuleOptions(config.rules[key]); const options = getRuleOptions(config.rules[key]);
try { try {
let ruleContext = new RuleContext( const ruleContext = new RuleContext(
key, api, severity, options, key, api, severity, options,
config.settings, config.parserOptions, config.parser, ruleCreator.meta); config.settings, config.parserOptions, config.parser, ruleCreator.meta);
rule = ruleCreator.create ? ruleCreator.create(ruleContext) : const rule = ruleCreator.create ? ruleCreator.create(ruleContext) :
ruleCreator(ruleContext); ruleCreator(ruleContext);
// add all the node types as listeners // add all the node types as listeners
@ -841,8 +833,8 @@ module.exports = (function() {
currentConfig = config; currentConfig = config;
traverser = new Traverser(); traverser = new Traverser();
ecmaFeatures = currentConfig.parserOptions.ecmaFeatures || {}; const ecmaFeatures = currentConfig.parserOptions.ecmaFeatures || {};
ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5; const ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5;
// gather scope data that may be needed by the rules // gather scope data that may be needed by the rules
scopeManager = escope.analyze(ast, { scopeManager = escope.analyze(ast, {
@ -863,7 +855,7 @@ module.exports = (function() {
scopeMap = []; scopeMap = [];
currentScopes.forEach(function(scope, index) { currentScopes.forEach(function(scope, index) {
let range = scope.block.range[0]; const range = scope.block.range[0];
/* /*
* Sometimes two scopes are returned for a given node. This is * Sometimes two scopes are returned for a given node. This is
@ -910,7 +902,7 @@ module.exports = (function() {
// sort by line and column // sort by line and column
messages.sort(function(a, b) { messages.sort(function(a, b) {
let lineDiff = a.line - b.line; const lineDiff = a.line - b.line;
if (lineDiff === 0) { if (lineDiff === 0) {
return a.column - b.column; return a.column - b.column;
@ -953,7 +945,7 @@ module.exports = (function() {
} }
// Store end location. // Store end location.
let endLocation = location.end; const endLocation = location.end;
location = location.start || location; location = location.start || location;
@ -972,7 +964,7 @@ module.exports = (function() {
}); });
} }
let problem = { const problem = {
ruleId: ruleId, ruleId: ruleId,
severity: severity, severity: severity,
message: message, message: message,
@ -1011,7 +1003,7 @@ module.exports = (function() {
}; };
// methods that exist on SourceCode object // methods that exist on SourceCode object
let externalMethods = { const externalMethods = {
getSource: "getText", getSource: "getText",
getSourceLines: "getLines", getSourceLines: "getLines",
getAllComments: "getAllComments", getAllComments: "getAllComments",
@ -1033,7 +1025,7 @@ module.exports = (function() {
// copy over methods // copy over methods
Object.keys(externalMethods).forEach(function(methodName) { Object.keys(externalMethods).forEach(function(methodName) {
let exMethodName = externalMethods[methodName]; const exMethodName = externalMethods[methodName];
// All functions expected to have less arguments than 5. // All functions expected to have less arguments than 5.
api[methodName] = function(a, b, c, d, e) { api[methodName] = function(a, b, c, d, e) {
@ -1057,14 +1049,13 @@ module.exports = (function() {
* @returns {Object} An object representing the current node's scope. * @returns {Object} An object representing the current node's scope.
*/ */
api.getScope = function() { api.getScope = function() {
let parents = traverser.parents(), const parents = traverser.parents();
scope = currentScopes[0];
// Don't do this for Program nodes - they have no parents // Don't do this for Program nodes - they have no parents
if (parents.length) { if (parents.length) {
// if current node introduces a scope, add it to the list // if current node introduces a scope, add it to the list
let current = traverser.current(); const current = traverser.current();
if (currentConfig.parserOptions.ecmaVersion >= 6) { if (currentConfig.parserOptions.ecmaVersion >= 6) {
if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) { if (["BlockStatement", "SwitchStatement", "CatchClause", "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(current.type) >= 0) {
@ -1080,7 +1071,8 @@ module.exports = (function() {
for (let i = parents.length - 1; i >= 0; --i) { for (let i = parents.length - 1; i >= 0; --i) {
// Get the innermost scope // Get the innermost scope
scope = scopeManager.acquire(parents[i], true); const scope = scopeManager.acquire(parents[i], true);
if (scope) { if (scope) {
if (scope.type === "function-expression-name") { if (scope.type === "function-expression-name") {
return scope.childScopes[0]; return scope.childScopes[0];
@ -1103,10 +1095,9 @@ module.exports = (function() {
* false if not. * false if not.
*/ */
api.markVariableAsUsed = function(name) { api.markVariableAsUsed = function(name) {
const hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn,
specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module";
let scope = this.getScope(), let scope = this.getScope(),
hasGlobalReturn = currentConfig.parserOptions.ecmaFeatures && currentConfig.parserOptions.ecmaFeatures.globalReturn,
specialScope = hasGlobalReturn || currentConfig.parserOptions.sourceType === "module",
variables,
i, i,
len; len;
@ -1116,7 +1107,8 @@ module.exports = (function() {
} }
do { do {
variables = scope.variables; const variables = scope.variables;
for (i = 0, len = variables.length; i < len; i++) { for (i = 0, len = variables.length; i < len; i++) {
if (variables[i].name === name) { if (variables[i].name === name) {
variables[i].eslintUsed = true; variables[i].eslintUsed = true;
@ -1147,7 +1139,7 @@ module.exports = (function() {
* @param {Function} ruleModule Function from context to object mapping AST node types to event handlers * @param {Function} ruleModule Function from context to object mapping AST node types to event handlers
* @returns {void} * @returns {void}
*/ */
let defineRule = api.defineRule = function(ruleId, ruleModule) { const defineRule = api.defineRule = function(ruleId, ruleModule) {
rules.define(ruleId, ruleModule); rules.define(ruleId, ruleModule);
}; };

31
tools/eslint/lib/file-finder.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let fs = require("fs"), const fs = require("fs"),
path = require("path"); path = require("path");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -55,11 +55,11 @@ function FileFinder(files, cwd) {
* @returns {Object} Hashmap of filenames * @returns {Object} Hashmap of filenames
*/ */
function normalizeDirectoryEntries(entries, directory, supportedConfigs) { function normalizeDirectoryEntries(entries, directory, supportedConfigs) {
let fileHash = {}; const fileHash = {};
entries.forEach(function(entry) { entries.forEach(function(entry) {
if (supportedConfigs.indexOf(entry) >= 0) { if (supportedConfigs.indexOf(entry) >= 0) {
let resolvedEntry = path.resolve(directory, entry); const resolvedEntry = path.resolve(directory, entry);
if (fs.statSync(resolvedEntry).isFile()) { if (fs.statSync(resolvedEntry).isFile()) {
fileHash[entry] = resolvedEntry; fileHash[entry] = resolvedEntry;
@ -79,14 +79,7 @@ function normalizeDirectoryEntries(entries, directory, supportedConfigs) {
* @returns {string[]} The file paths found. * @returns {string[]} The file paths found.
*/ */
FileFinder.prototype.findAllInDirectoryAndParents = function(directory) { FileFinder.prototype.findAllInDirectoryAndParents = function(directory) {
let cache = this.cache, const cache = this.cache;
child,
dirs,
fileNames,
filePath,
i,
j,
searched;
if (directory) { if (directory) {
directory = path.resolve(this.cwd, directory); directory = path.resolve(this.cwd, directory);
@ -98,24 +91,24 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) {
return cache[directory]; return cache[directory];
} }
dirs = []; const dirs = [];
searched = 0; const fileNames = this.fileNames;
fileNames = this.fileNames; let searched = 0;
do { do {
dirs[searched++] = directory; dirs[searched++] = directory;
cache[directory] = []; cache[directory] = [];
let filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames); const filesMap = normalizeDirectoryEntries(getDirectoryEntries(directory), directory, fileNames);
if (Object.keys(filesMap).length) { if (Object.keys(filesMap).length) {
for (let k = 0; k < fileNames.length; k++) { for (let k = 0; k < fileNames.length; k++) {
if (filesMap[fileNames[k]]) { if (filesMap[fileNames[k]]) {
filePath = filesMap[fileNames[k]]; const filePath = filesMap[fileNames[k]];
// Add the file path to the cache of each directory searched. // Add the file path to the cache of each directory searched.
for (j = 0; j < searched; j++) { for (let j = 0; j < searched; j++) {
cache[dirs[j]].push(filePath); cache[dirs[j]].push(filePath);
} }
@ -123,7 +116,7 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) {
} }
} }
} }
child = directory; const child = directory;
// Assign parent directory to directory. // Assign parent directory to directory.
directory = path.dirname(directory); directory = path.dirname(directory);
@ -134,7 +127,7 @@ FileFinder.prototype.findAllInDirectoryAndParents = function(directory) {
} while (!cache.hasOwnProperty(directory)); } while (!cache.hasOwnProperty(directory));
// Add what has been cached previously to the cache of each directory searched. // Add what has been cached previously to the cache of each directory searched.
for (i = 0; i < searched; i++) { for (let i = 0; i < searched; i++) {
dirs.push.apply(cache[dirs[i]], cache[directory]); dirs.push.apply(cache[dirs[i]], cache[directory]);
} }

4
tools/eslint/lib/formatters/checkstyle.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let xmlEscape = require("../util/xml-escape"); const xmlEscape = require("../util/xml-escape");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helper Functions // Helper Functions
@ -36,7 +36,7 @@ module.exports = function(results) {
output += "<checkstyle version=\"4.3\">"; output += "<checkstyle version=\"4.3\">";
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
output += "<file name=\"" + xmlEscape(result.filePath) + "\">"; output += "<file name=\"" + xmlEscape(result.filePath) + "\">";

2
tools/eslint/lib/formatters/compact.js

@ -34,7 +34,7 @@ module.exports = function(results) {
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
total += messages.length; total += messages.length;

21
tools/eslint/lib/formatters/html.js

@ -4,17 +4,17 @@
*/ */
"use strict"; "use strict";
let lodash = require("lodash"); const lodash = require("lodash");
let fs = require("fs"); const fs = require("fs");
let path = require("path"); const path = require("path");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8")); const pageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-page.html"), "utf-8"));
let messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8")); const messageTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-message.html"), "utf-8"));
let resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8")); const resultTemplate = lodash.template(fs.readFileSync(path.join(__dirname, "html-template-result.html"), "utf-8"));
/** /**
* Given a word and a count, append an s if count is not one. * Given a word and a count, append an s if count is not one.
@ -33,7 +33,7 @@ function pluralize(word, count) {
* @returns {string} The formatted string, pluralized where necessary * @returns {string} The formatted string, pluralized where necessary
*/ */
function renderSummary(totalErrors, totalWarnings) { function renderSummary(totalErrors, totalWarnings) {
let totalProblems = totalErrors + totalWarnings; const totalProblems = totalErrors + totalWarnings;
let renderedText = totalProblems + " " + pluralize("problem", totalProblems); let renderedText = totalProblems + " " + pluralize("problem", totalProblems);
if (totalProblems !== 0) { if (totalProblems !== 0) {
@ -71,11 +71,8 @@ function renderMessages(messages, parentIndex) {
* @returns {string} HTML (table row) describing a message. * @returns {string} HTML (table row) describing a message.
*/ */
return lodash.map(messages, function(message) { return lodash.map(messages, function(message) {
let lineNumber, const lineNumber = message.line || 0;
columnNumber; const columnNumber = message.column || 0;
lineNumber = message.line || 0;
columnNumber = message.column || 0;
return messageTemplate({ return messageTemplate({
parentIndex: parentIndex, parentIndex: parentIndex,

4
tools/eslint/lib/formatters/jslint-xml.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let xmlEscape = require("../util/xml-escape"); const xmlEscape = require("../util/xml-escape");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Public Interface // Public Interface
@ -18,7 +18,7 @@ module.exports = function(results) {
output += "<jslint>"; output += "<jslint>";
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
output += "<file name=\"" + result.filePath + "\">"; output += "<file name=\"" + result.filePath + "\">";

6
tools/eslint/lib/formatters/junit.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let xmlEscape = require("../util/xml-escape"); const xmlEscape = require("../util/xml-escape");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helper Functions // Helper Functions
@ -37,14 +37,14 @@ module.exports = function(results) {
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
if (messages.length) { if (messages.length) {
output += "<testsuite package=\"org.eslint\" time=\"0\" tests=\"" + messages.length + "\" errors=\"" + messages.length + "\" name=\"" + result.filePath + "\">\n"; output += "<testsuite package=\"org.eslint\" time=\"0\" tests=\"" + messages.length + "\" errors=\"" + messages.length + "\" name=\"" + result.filePath + "\">\n";
} }
messages.forEach(function(message) { messages.forEach(function(message) {
let type = message.fatal ? "error" : "failure"; const type = message.fatal ? "error" : "failure";
output += "<testcase time=\"0\" name=\"org.eslint." + (message.ruleId || "unknown") + "\">"; output += "<testcase time=\"0\" name=\"org.eslint." + (message.ruleId || "unknown") + "\">";
output += "<" + type + " message=\"" + xmlEscape(message.message || "") + "\">"; output += "<" + type + " message=\"" + xmlEscape(message.message || "") + "\">";

4
tools/eslint/lib/formatters/stylish.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let chalk = require("chalk"), const chalk = require("chalk"),
table = require("text-table"); table = require("text-table");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -34,7 +34,7 @@ module.exports = function(results) {
summaryColor = "yellow"; summaryColor = "yellow";
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
if (messages.length === 0) { if (messages.length === 0) {
return; return;

14
tools/eslint/lib/formatters/table.js

@ -8,13 +8,9 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let chalk, const chalk = require("chalk"),
table, table = require("table").default,
pluralize; pluralize = require("pluralize");
chalk = require("chalk");
table = require("table").default;
pluralize = require("pluralize");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
@ -26,9 +22,7 @@ pluralize = require("pluralize");
* @returns {string} A text table. * @returns {string} A text table.
*/ */
function drawTable(messages) { function drawTable(messages) {
let rows; const rows = [];
rows = [];
if (messages.length === 0) { if (messages.length === 0) {
return ""; return "";

8
tools/eslint/lib/formatters/tap.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let yaml = require("js-yaml"); const yaml = require("js-yaml");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helper Functions // Helper Functions
@ -29,7 +29,7 @@ function getMessageType(message) {
* @returns {string} diagnostics string with YAML embedded - TAP version 13 compliant * @returns {string} diagnostics string with YAML embedded - TAP version 13 compliant
*/ */
function outputDiagnostics(diagnostic) { function outputDiagnostics(diagnostic) {
let prefix = " "; const prefix = " ";
let output = prefix + "---\n"; let output = prefix + "---\n";
output += prefix + yaml.safeDump(diagnostic).split("\n").join("\n" + prefix); output += prefix + yaml.safeDump(diagnostic).split("\n").join("\n" + prefix);
@ -45,7 +45,7 @@ module.exports = function(results) {
let output = "TAP version 13\n1.." + results.length + "\n"; let output = "TAP version 13\n1.." + results.length + "\n";
results.forEach(function(result, id) { results.forEach(function(result, id) {
let messages = result.messages; const messages = result.messages;
let testResult = "ok"; let testResult = "ok";
let diagnostics = {}; let diagnostics = {};
@ -53,7 +53,7 @@ module.exports = function(results) {
testResult = "not ok"; testResult = "not ok";
messages.forEach(function(message) { messages.forEach(function(message) {
let diagnostic = { const diagnostic = {
message: message.message, message: message.message,
severity: getMessageType(message), severity: getMessageType(message),
data: { data: {

2
tools/eslint/lib/formatters/unix.js

@ -33,7 +33,7 @@ module.exports = function(results) {
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
total += messages.length; total += messages.length;

2
tools/eslint/lib/formatters/visualstudio.js

@ -35,7 +35,7 @@ module.exports = function(results) {
results.forEach(function(result) { results.forEach(function(result) {
let messages = result.messages; const messages = result.messages;
total += messages.length; total += messages.length;

25
tools/eslint/lib/ignored-paths.js

@ -9,26 +9,25 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"), const fs = require("fs"),
fs = require("fs"),
path = require("path"), path = require("path"),
debug = require("debug"),
ignore = require("ignore"), ignore = require("ignore"),
shell = require("shelljs"),
pathUtil = require("./util/path-util"); pathUtil = require("./util/path-util");
debug = debug("eslint:ignored-paths"); const debug = require("debug")("eslint:ignored-paths");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let ESLINT_IGNORE_FILENAME = ".eslintignore"; const ESLINT_IGNORE_FILENAME = ".eslintignore";
let DEFAULT_IGNORE_DIRS = [ const DEFAULT_IGNORE_DIRS = [
"node_modules/", "node_modules/",
"bower_components/" "bower_components/"
]; ];
let DEFAULT_OPTIONS = { const DEFAULT_OPTIONS = {
dotfiles: false, dotfiles: false,
cwd: process.cwd() cwd: process.cwd()
}; };
@ -47,9 +46,9 @@ let DEFAULT_OPTIONS = {
function findIgnoreFile(cwd) { function findIgnoreFile(cwd) {
cwd = cwd || DEFAULT_OPTIONS.cwd; cwd = cwd || DEFAULT_OPTIONS.cwd;
let ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME); const ignoreFilePath = path.resolve(cwd, ESLINT_IGNORE_FILENAME);
return fs.existsSync(ignoreFilePath) ? ignoreFilePath : ""; return shell.test("-f", ignoreFilePath) ? ignoreFilePath : "";
} }
/** /**
@ -59,7 +58,7 @@ function findIgnoreFile(cwd) {
*/ */
function mergeDefaultOptions(options) { function mergeDefaultOptions(options) {
options = (options || {}); options = (options || {});
return lodash.assign({}, DEFAULT_OPTIONS, options); return Object.assign({}, DEFAULT_OPTIONS, options);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -175,8 +174,8 @@ function IgnoredPaths(options) {
IgnoredPaths.prototype.contains = function(filepath, category) { IgnoredPaths.prototype.contains = function(filepath, category) {
let result = false; let result = false;
let absolutePath = path.resolve(this.options.cwd, filepath); const absolutePath = path.resolve(this.options.cwd, filepath);
let relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd); const relativePath = pathUtil.getRelativePath(absolutePath, this.options.cwd);
if ((typeof category === "undefined") || (category === "default")) { if ((typeof category === "undefined") || (category === "default")) {
result = result || (this.ig.default.filter([relativePath]).length === 0); result = result || (this.ig.default.filter([relativePath]).length === 0);
@ -201,7 +200,7 @@ IgnoredPaths.prototype.getIgnoredFoldersGlobPatterns = function() {
/* eslint-disable no-underscore-dangle */ /* eslint-disable no-underscore-dangle */
let patterns = this.ig.custom._rules.filter(function(rule) { const patterns = this.ig.custom._rules.filter(function(rule) {
return rule.negative; return rule.negative;
}).map(function(rule) { }).map(function(rule) {
return rule.origin; return rule.origin;

31
tools/eslint/lib/internal-rules/internal-no-invalid-meta.js

@ -17,7 +17,7 @@
* @returns {ASTNode} The Property node or null if not found. * @returns {ASTNode} The Property node or null if not found.
*/ */
function getPropertyFromObject(property, node) { function getPropertyFromObject(property, node) {
let properties = node.properties; const properties = node.properties;
for (let i = 0; i < properties.length; i++) { for (let i = 0; i < properties.length; i++) {
if (properties[i].key.name === property) { if (properties[i].key.name === property) {
@ -55,7 +55,7 @@ function hasMetaDocs(metaPropertyNode) {
* @returns {boolean} `true` if a `docs.description` property exists. * @returns {boolean} `true` if a `docs.description` property exists.
*/ */
function hasMetaDocsDescription(metaPropertyNode) { function hasMetaDocsDescription(metaPropertyNode) {
let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
return metaDocs && getPropertyFromObject("description", metaDocs.value); return metaDocs && getPropertyFromObject("description", metaDocs.value);
} }
@ -67,7 +67,7 @@ function hasMetaDocsDescription(metaPropertyNode) {
* @returns {boolean} `true` if a `docs.category` property exists. * @returns {boolean} `true` if a `docs.category` property exists.
*/ */
function hasMetaDocsCategory(metaPropertyNode) { function hasMetaDocsCategory(metaPropertyNode) {
let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
return metaDocs && getPropertyFromObject("category", metaDocs.value); return metaDocs && getPropertyFromObject("category", metaDocs.value);
} }
@ -79,7 +79,7 @@ function hasMetaDocsCategory(metaPropertyNode) {
* @returns {boolean} `true` if a `docs.recommended` property exists. * @returns {boolean} `true` if a `docs.recommended` property exists.
*/ */
function hasMetaDocsRecommended(metaPropertyNode) { function hasMetaDocsRecommended(metaPropertyNode) {
let metaDocs = getPropertyFromObject("docs", metaPropertyNode.value); const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
return metaDocs && getPropertyFromObject("recommended", metaDocs.value); return metaDocs && getPropertyFromObject("recommended", metaDocs.value);
} }
@ -113,7 +113,7 @@ function hasMetaFixable(metaPropertyNode) {
* @returns {void} * @returns {void}
*/ */
function checkMetaValidity(context, exportsNode, ruleIsFixable) { function checkMetaValidity(context, exportsNode, ruleIsFixable) {
let metaProperty = getMetaPropertyFromExportsNode(exportsNode); const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
if (!metaProperty) { if (!metaProperty) {
context.report(exportsNode, "Rule is missing a meta property."); context.report(exportsNode, "Rule is missing a meta property.");
@ -151,6 +151,16 @@ function checkMetaValidity(context, exportsNode, ruleIsFixable) {
} }
} }
/**
* Whether this node is the correct format for a rule definition or not.
*
* @param {ASTNode} node node that the rule exports.
* @returns {boolean} `true` if the exported node is the correct format for a rule definition
*/
function isCorrectExportsFormat(node) {
return node.type === "ObjectExpression";
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -167,7 +177,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let metaExportsValue; let exportsNode;
let ruleIsFixable = false; let ruleIsFixable = false;
return { return {
@ -178,7 +188,7 @@ module.exports = {
node.left.object.name === "module" && node.left.object.name === "module" &&
node.left.property.name === "exports") { node.left.property.name === "exports") {
metaExportsValue = node.right; exportsNode = node.right;
} }
}, },
@ -205,7 +215,12 @@ module.exports = {
}, },
"Program:exit": function() { "Program:exit": function() {
checkMetaValidity(context, metaExportsValue, ruleIsFixable); if (!isCorrectExportsFormat(exportsNode)) {
context.report(exportsNode, "Rule does not export an Object. Make sure the rule follows the new rule format.");
return;
}
checkMetaValidity(context, exportsNode, ruleIsFixable);
} }
}; };
} }

4
tools/eslint/lib/load-rules.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let fs = require("fs"), const fs = require("fs"),
path = require("path"); path = require("path");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -29,7 +29,7 @@ module.exports = function(rulesDir, cwd) {
rulesDir = path.resolve(cwd, rulesDir); rulesDir = path.resolve(cwd, rulesDir);
} }
let rules = Object.create(null); const rules = Object.create(null);
fs.readdirSync(rulesDir).forEach(function(file) { fs.readdirSync(rulesDir).forEach(function(file) {
if (path.extname(file) !== ".js") { if (path.extname(file) !== ".js") {

2
tools/eslint/lib/options.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let optionator = require("optionator"); const optionator = require("optionator");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Initialization and Public Interface // Initialization and Public Interface

9
tools/eslint/lib/rule-context.js

@ -8,13 +8,13 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let RuleFixer = require("./util/rule-fixer"); const RuleFixer = require("./util/rule-fixer");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let PASSTHROUGHS = [ const PASSTHROUGHS = [
"getAncestors", "getAncestors",
"getDeclaredVariables", "getDeclaredVariables",
"getFilename", "getFilename",
@ -111,12 +111,11 @@ RuleContext.prototype = {
* @returns {void} * @returns {void}
*/ */
report: function(nodeOrDescriptor, location, message, opts) { report: function(nodeOrDescriptor, location, message, opts) {
let descriptor,
fix = null;
// check to see if it's a new style call // check to see if it's a new style call
if (arguments.length === 1) { if (arguments.length === 1) {
descriptor = nodeOrDescriptor; const descriptor = nodeOrDescriptor;
let fix = null;
// if there's a fix specified, get it // if there's a fix specified, get it
if (typeof descriptor.fix === "function") { if (typeof descriptor.fix === "function") {

6
tools/eslint/lib/rules.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let loadRules = require("./load-rules"); const loadRules = require("./load-rules");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Privates // Privates
@ -38,7 +38,7 @@ function define(ruleId, ruleModule) {
* @returns {void} * @returns {void}
*/ */
function load(rulesDir, cwd) { function load(rulesDir, cwd) {
let newRules = loadRules(rulesDir, cwd); const newRules = loadRules(rulesDir, cwd);
Object.keys(newRules).forEach(function(ruleId) { Object.keys(newRules).forEach(function(ruleId) {
define(ruleId, newRules[ruleId]); define(ruleId, newRules[ruleId]);
@ -53,7 +53,7 @@ function load(rulesDir, cwd) {
*/ */
function importPlugin(pluginRules, pluginName) { function importPlugin(pluginRules, pluginName) {
Object.keys(pluginRules).forEach(function(ruleId) { Object.keys(pluginRules).forEach(function(ruleId) {
let qualifiedRuleId = pluginName + "/" + ruleId, const qualifiedRuleId = pluginName + "/" + ruleId,
rule = pluginRules[ruleId]; rule = pluginRules[ruleId];
define(qualifiedRuleId, rule); define(qualifiedRuleId, rule);

12
tools/eslint/lib/rules/accessor-pairs.js

@ -28,7 +28,7 @@ function isIdentifier(node, name) {
* @returns {boolean} `true` if the node is an argument of the specified method call. * @returns {boolean} `true` if the node is an argument of the specified method call.
*/ */
function isArgumentOfMethodCall(node, index, object, property) { function isArgumentOfMethodCall(node, index, object, property) {
let parent = node.parent; const parent = node.parent;
return ( return (
parent.type === "CallExpression" && parent.type === "CallExpression" &&
@ -91,9 +91,9 @@ module.exports = {
}] }]
}, },
create: function(context) { create: function(context) {
let config = context.options[0] || {}; const config = context.options[0] || {};
let checkGetWithoutSet = config.getWithoutSet === true; const checkGetWithoutSet = config.getWithoutSet === true;
let checkSetWithoutGet = config.setWithoutGet !== false; const checkSetWithoutGet = config.setWithoutGet !== false;
/** /**
* Checks a object expression to see if it has setter and getter both present or none. * Checks a object expression to see if it has setter and getter both present or none.
@ -104,10 +104,10 @@ module.exports = {
function checkLonelySetGet(node) { function checkLonelySetGet(node) {
let isSetPresent = false; let isSetPresent = false;
let isGetPresent = false; let isGetPresent = false;
let isDescriptor = isPropertyDescriptor(node); const isDescriptor = isPropertyDescriptor(node);
for (let i = 0, end = node.properties.length; i < end; i++) { for (let i = 0, end = node.properties.length; i < end; i++) {
let property = node.properties[i]; const property = node.properties[i];
let propToCheck = ""; let propToCheck = "";

16
tools/eslint/lib/rules/array-bracket-spacing.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -40,7 +40,7 @@ module.exports = {
] ]
}, },
create: function(context) { create: function(context) {
let spaced = context.options[0] === "always", const spaced = context.options[0] === "always",
sourceCode = context.getSourceCode(); sourceCode = context.getSourceCode();
/** /**
@ -54,7 +54,7 @@ module.exports = {
return context.options[1] ? context.options[1][option] === !spaced : false; return context.options[1] ? context.options[1][option] === !spaced : false;
} }
let options = { const options = {
spaced: spaced, spaced: spaced,
singleElementException: isOptionSet("singleValue"), singleElementException: isOptionSet("singleValue"),
objectsInArraysException: isOptionSet("objectsInArrays"), objectsInArraysException: isOptionSet("objectsInArrays"),
@ -77,7 +77,7 @@ module.exports = {
loc: token.loc.start, loc: token.loc.start,
message: "There should be no space after '" + token.value + "'.", message: "There should be no space after '" + token.value + "'.",
fix: function(fixer) { fix: function(fixer) {
let nextToken = sourceCode.getTokenAfter(token); const nextToken = sourceCode.getTokenAfter(token);
return fixer.removeRange([token.range[1], nextToken.range[0]]); return fixer.removeRange([token.range[1], nextToken.range[0]]);
} }
@ -96,7 +96,7 @@ module.exports = {
loc: token.loc.start, loc: token.loc.start,
message: "There should be no space before '" + token.value + "'.", message: "There should be no space before '" + token.value + "'.",
fix: function(fixer) { fix: function(fixer) {
let previousToken = sourceCode.getTokenBefore(token); const previousToken = sourceCode.getTokenBefore(token);
return fixer.removeRange([previousToken.range[1], token.range[0]]); return fixer.removeRange([previousToken.range[1], token.range[0]]);
} }
@ -165,20 +165,20 @@ module.exports = {
return; return;
} }
let first = sourceCode.getFirstToken(node), const first = sourceCode.getFirstToken(node),
second = sourceCode.getFirstToken(node, 1), second = sourceCode.getFirstToken(node, 1),
penultimate = sourceCode.getLastToken(node, 1), penultimate = sourceCode.getLastToken(node, 1),
last = sourceCode.getLastToken(node), last = sourceCode.getLastToken(node),
firstElement = node.elements[0], firstElement = node.elements[0],
lastElement = node.elements[node.elements.length - 1]; lastElement = node.elements[node.elements.length - 1];
let openingBracketMustBeSpaced = const openingBracketMustBeSpaced =
options.objectsInArraysException && isObjectType(firstElement) || options.objectsInArraysException && isObjectType(firstElement) ||
options.arraysInArraysException && isArrayType(firstElement) || options.arraysInArraysException && isArrayType(firstElement) ||
options.singleElementException && node.elements.length === 1 options.singleElementException && node.elements.length === 1
? !options.spaced : options.spaced; ? !options.spaced : options.spaced;
let closingBracketMustBeSpaced = const closingBracketMustBeSpaced =
options.objectsInArraysException && isObjectType(lastElement) || options.objectsInArraysException && isObjectType(lastElement) ||
options.arraysInArraysException && isArrayType(lastElement) || options.arraysInArraysException && isArrayType(lastElement) ||
options.singleElementException && node.elements.length === 1 options.singleElementException && node.elements.length === 1

44
tools/eslint/lib/rules/array-callback-return.js

@ -9,14 +9,14 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/; const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/;
let TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/; const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|map|reduce(?:Right)?|some|sort)$/;
/** /**
* Checks a given code path segment is reachable. * Checks a given code path segment is reachable.
@ -45,38 +45,6 @@ function getLocation(node, sourceCode) {
return node.id || node; return node.id || node;
} }
/**
* Gets the name of a given node if the node is a Identifier node.
*
* @param {ASTNode} node - A node to get.
* @returns {string} The name of the node, or an empty string.
*/
function getIdentifierName(node) {
return node.type === "Identifier" ? node.name : "";
}
/**
* Gets the value of a given node if the node is a Literal node or a
* TemplateLiteral node.
*
* @param {ASTNode} node - A node to get.
* @returns {string} The value of the node, or an empty string.
*/
function getConstantStringValue(node) {
switch (node.type) {
case "Literal":
return String(node.value);
case "TemplateLiteral":
return node.expressions.length === 0
? node.quasis[0].value.cooked
: "";
default:
return "";
}
}
/** /**
* Checks a given node is a MemberExpression node which has the specified name's * Checks a given node is a MemberExpression node which has the specified name's
* property. * property.
@ -88,9 +56,7 @@ function getConstantStringValue(node) {
function isTargetMethod(node) { function isTargetMethod(node) {
return ( return (
node.type === "MemberExpression" && node.type === "MemberExpression" &&
TARGET_METHODS.test( TARGET_METHODS.test(astUtils.getStaticPropertyName(node) || "")
(node.computed ? getConstantStringValue : getIdentifierName)(node.property)
)
); );
} }
@ -104,7 +70,7 @@ function isTargetMethod(node) {
*/ */
function isCallbackOfArrayMethod(node) { function isCallbackOfArrayMethod(node) {
while (node) { while (node) {
let parent = node.parent; const parent = node.parent;
switch (parent.type) { switch (parent.type) {

14
tools/eslint/lib/rules/arrow-body-style.js

@ -50,11 +50,11 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options; const options = context.options;
let always = options[0] === "always"; const always = options[0] === "always";
let asNeeded = !options[0] || options[0] === "as-needed"; const asNeeded = !options[0] || options[0] === "as-needed";
let never = options[0] === "never"; const never = options[0] === "never";
let requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral; const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
/** /**
* Determines whether a arrow function body needs braces * Determines whether a arrow function body needs braces
@ -62,7 +62,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function validate(node) { function validate(node) {
let arrowBody = node.body; const arrowBody = node.body;
if (arrowBody.type === "BlockStatement") { if (arrowBody.type === "BlockStatement") {
if (never) { if (never) {
@ -72,7 +72,7 @@ module.exports = {
message: "Unexpected block statement surrounding arrow body." message: "Unexpected block statement surrounding arrow body."
}); });
} else { } else {
let blockBody = arrowBody.body; const blockBody = arrowBody.body;
if (blockBody.length !== 1) { if (blockBody.length !== 1) {
return; return;

72
tools/eslint/lib/rules/arrow-parens.js

@ -21,16 +21,29 @@ module.exports = {
schema: [ schema: [
{ {
enum: ["always", "as-needed"] enum: ["always", "as-needed"]
},
{
type: "object",
properties: {
requireForBlockBody: {
type: "boolean"
}
},
additionalProperties: false
} }
] ]
}, },
create: function(context) { create: function(context) {
let message = "Expected parentheses around arrow function argument."; const message = "Expected parentheses around arrow function argument.";
let asNeededMessage = "Unexpected parentheses around single function argument."; const asNeededMessage = "Unexpected parentheses around single function argument.";
let asNeeded = context.options[0] === "as-needed"; const asNeeded = context.options[0] === "as-needed";
const requireForBlockBodyMessage = "Unexpected parentheses around single function argument having a body with no curly braces";
const requireForBlockBodyNoParensMessage = "Expected parentheses around arrow function argument having a body with curly braces.";
const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;
const sourceCode = context.getSourceCode();
let sourceCode = context.getSourceCode();
/** /**
* Determines whether a arrow function argument end with `)` * Determines whether a arrow function argument end with `)`
@ -38,17 +51,58 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function parens(node) { function parens(node) {
let token = sourceCode.getFirstToken(node); const token = sourceCode.getFirstToken(node);
// "as-needed", { "requireForBlockBody": true }: x => x
if (
requireForBlockBody &&
node.params.length === 1 &&
node.params[0].type === "Identifier" &&
node.body.type !== "BlockStatement"
) {
if (token.type === "Punctuator" && token.value === "(") {
context.report({
node: node,
message: requireForBlockBodyMessage,
fix: function(fixer) {
const paramToken = context.getTokenAfter(token);
const closingParenToken = context.getTokenAfter(paramToken);
return fixer.replaceTextRange([
token.range[0],
closingParenToken.range[1]
], paramToken.value);
}
});
}
return;
}
if (
requireForBlockBody &&
node.body.type === "BlockStatement"
) {
if (token.type !== "Punctuator" || token.value !== "(") {
context.report({
node: node,
message: requireForBlockBodyNoParensMessage,
fix: function(fixer) {
return fixer.replaceText(token, "(" + token.value + ")");
}
});
}
return;
}
// as-needed: x => x // "as-needed": x => x
if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") { if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") {
if (token.type === "Punctuator" && token.value === "(") { if (token.type === "Punctuator" && token.value === "(") {
context.report({ context.report({
node: node, node: node,
message: asNeededMessage, message: asNeededMessage,
fix: function(fixer) { fix: function(fixer) {
let paramToken = context.getTokenAfter(token); const paramToken = context.getTokenAfter(token);
let closingParenToken = context.getTokenAfter(paramToken); const closingParenToken = context.getTokenAfter(paramToken);
return fixer.replaceTextRange([ return fixer.replaceTextRange([
token.range[0], token.range[0],
@ -61,7 +115,7 @@ module.exports = {
} }
if (token.type === "Identifier") { if (token.type === "Identifier") {
let after = sourceCode.getTokenAfter(token); const after = sourceCode.getTokenAfter(token);
// (x) => x // (x) => x
if (after.value !== ")") { if (after.value !== ")") {

14
tools/eslint/lib/rules/arrow-spacing.js

@ -37,13 +37,13 @@ module.exports = {
create: function(context) { create: function(context) {
// merge rules with default // merge rules with default
let rule = { before: true, after: true }, const rule = { before: true, after: true },
option = context.options[0] || {}; option = context.options[0] || {};
rule.before = option.before !== false; rule.before = option.before !== false;
rule.after = option.after !== false; rule.after = option.after !== false;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Get tokens of arrow(`=>`) and before/after arrow. * Get tokens of arrow(`=>`) and before/after arrow.
@ -58,7 +58,7 @@ module.exports = {
before = t; before = t;
t = sourceCode.getTokenAfter(t); t = sourceCode.getTokenAfter(t);
} }
let after = sourceCode.getTokenAfter(t); const after = sourceCode.getTokenAfter(t);
return { before: before, arrow: t, after: after }; return { before: before, arrow: t, after: after };
} }
@ -69,8 +69,8 @@ module.exports = {
* @returns {Object} count of space before/after arrow. * @returns {Object} count of space before/after arrow.
*/ */
function countSpaces(tokens) { function countSpaces(tokens) {
let before = tokens.arrow.range[0] - tokens.before.range[1]; const before = tokens.arrow.range[0] - tokens.before.range[1];
let after = tokens.after.range[0] - tokens.arrow.range[1]; const after = tokens.after.range[0] - tokens.arrow.range[1];
return { before: before, after: after }; return { before: before, after: after };
} }
@ -83,8 +83,8 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function spaces(node) { function spaces(node) {
let tokens = getTokens(node); const tokens = getTokens(node);
let countSpace = countSpaces(tokens); const countSpace = countSpaces(tokens);
if (rule.before) { if (rule.before) {

8
tools/eslint/lib/rules/block-scoped-var.js

@ -45,7 +45,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function report(reference) { function report(reference) {
let identifier = reference.identifier; const identifier = reference.identifier;
context.report( context.report(
identifier, identifier,
@ -64,7 +64,7 @@ module.exports = {
} }
// Defines a predicate to check whether or not a given reference is outside of valid scope. // Defines a predicate to check whether or not a given reference is outside of valid scope.
let scopeRange = stack[stack.length - 1]; const scopeRange = stack[stack.length - 1];
/** /**
* Check if a reference is out of scope * Check if a reference is out of scope
@ -73,13 +73,13 @@ module.exports = {
* @private * @private
*/ */
function isOutsideOfScope(reference) { function isOutsideOfScope(reference) {
let idRange = reference.identifier.range; const idRange = reference.identifier.range;
return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1]; return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1];
} }
// Gets declared variables, and checks its references. // Gets declared variables, and checks its references.
let variables = context.getDeclaredVariables(node); const variables = context.getDeclaredVariables(node);
for (let i = 0; i < variables.length; ++i) { for (let i = 0; i < variables.length; ++i) {

12
tools/eslint/lib/rules/block-spacing.js

@ -5,7 +5,7 @@
"use strict"; "use strict";
let util = require("../ast-utils"); const util = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -27,7 +27,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let always = (context.options[0] !== "never"), const always = (context.options[0] !== "never"),
message = always ? "Requires a space" : "Unexpected space(s)", message = always ? "Requires a space" : "Unexpected space(s)",
sourceCode = context.getSourceCode(); sourceCode = context.getSourceCode();
@ -72,10 +72,10 @@ module.exports = {
function checkSpacingInsideBraces(node) { function checkSpacingInsideBraces(node) {
// Gets braces and the first/last token of content. // Gets braces and the first/last token of content.
let openBrace = getOpenBrace(node); const openBrace = getOpenBrace(node);
let closeBrace = sourceCode.getLastToken(node); const closeBrace = sourceCode.getLastToken(node);
let firstToken = sourceCode.getTokenOrCommentAfter(openBrace); const firstToken = sourceCode.getTokenOrCommentAfter(openBrace);
let lastToken = sourceCode.getTokenOrCommentBefore(closeBrace); const lastToken = sourceCode.getTokenOrCommentBefore(closeBrace);
// Skip if the node is invalid or empty. // Skip if the node is invalid or empty.
if (openBrace.type !== "Punctuator" || if (openBrace.type !== "Punctuator" ||

31
tools/eslint/lib/rules/brace-style.js

@ -34,11 +34,11 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let style = context.options[0] || "1tbs", const style = context.options[0] || "1tbs",
params = context.options[1] || {}, params = context.options[1] || {},
sourceCode = context.getSourceCode(); sourceCode = context.getSourceCode();
let OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.", const OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.",
OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.", OPEN_MESSAGE_ALLMAN = "Opening curly brace appears on the same line as controlling statement.",
BODY_MESSAGE = "Statement inside of curly braces should be on next line.", 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.", CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.",
@ -78,24 +78,20 @@ module.exports = {
* @private * @private
*/ */
function checkBlock() { function checkBlock() {
let blockProperties = arguments; const blockProperties = arguments;
return function(node) { return function(node) {
Array.prototype.forEach.call(blockProperties, function(blockProp) { Array.prototype.forEach.call(blockProperties, function(blockProp) {
let block = node[blockProp], const block = node[blockProp];
previousToken,
curlyToken,
curlyTokenEnd,
allOnSameLine;
if (!isBlock(block)) { if (!isBlock(block)) {
return; return;
} }
previousToken = sourceCode.getTokenBefore(block); const previousToken = sourceCode.getTokenBefore(block);
curlyToken = sourceCode.getFirstToken(block); const curlyToken = sourceCode.getFirstToken(block);
curlyTokenEnd = sourceCode.getLastToken(block); const curlyTokenEnd = sourceCode.getLastToken(block);
allOnSameLine = previousToken.loc.start.line === curlyTokenEnd.loc.start.line; const allOnSameLine = previousToken.loc.start.line === curlyTokenEnd.loc.start.line;
if (allOnSameLine && params.allowSingleLine) { if (allOnSameLine && params.allowSingleLine) {
return; return;
@ -129,13 +125,11 @@ module.exports = {
* @private * @private
*/ */
function checkIfStatement(node) { function checkIfStatement(node) {
let tokens;
checkBlock("consequent", "alternate")(node); checkBlock("consequent", "alternate")(node);
if (node.alternate) { if (node.alternate) {
tokens = sourceCode.getTokensBefore(node.alternate, 2); const tokens = sourceCode.getTokensBefore(node.alternate, 2);
if (style === "1tbs") { if (style === "1tbs") {
if (tokens[0].loc.start.line !== tokens[1].loc.start.line && if (tokens[0].loc.start.line !== tokens[1].loc.start.line &&
@ -157,12 +151,11 @@ module.exports = {
* @private * @private
*/ */
function checkTryStatement(node) { function checkTryStatement(node) {
let tokens;
checkBlock("block", "finalizer")(node); checkBlock("block", "finalizer")(node);
if (isBlock(node.finalizer)) { if (isBlock(node.finalizer)) {
tokens = sourceCode.getTokensBefore(node.finalizer, 2); const tokens = sourceCode.getTokensBefore(node.finalizer, 2);
if (style === "1tbs") { if (style === "1tbs") {
if (tokens[0].loc.start.line !== tokens[1].loc.start.line) { if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
context.report(node.finalizer, CLOSE_MESSAGE); context.report(node.finalizer, CLOSE_MESSAGE);
@ -180,7 +173,7 @@ module.exports = {
* @private * @private
*/ */
function checkCatchClause(node) { function checkCatchClause(node) {
let previousToken = sourceCode.getTokenBefore(node), const previousToken = sourceCode.getTokenBefore(node),
firstToken = sourceCode.getFirstToken(node); firstToken = sourceCode.getFirstToken(node);
checkBlock("body")(node); checkBlock("body")(node);

9
tools/eslint/lib/rules/callback-return.js

@ -24,7 +24,7 @@ module.exports = {
create: function(context) { create: function(context) {
let callbacks = context.options[0] || ["callback", "cb", "next"], const callbacks = context.options[0] || ["callback", "cb", "next"],
sourceCode = context.getSourceCode(); sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@ -118,8 +118,7 @@ module.exports = {
} }
// find the closest block, return or loop // find the closest block, return or loop
let closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {}, const closestBlock = findClosestParentOfType(node, ["BlockStatement", "ReturnStatement", "ArrowFunctionExpression"]) || {};
lastItem, parentType;
// if our parent is a return we know we're ok // if our parent is a return we know we're ok
if (closestBlock.type === "ReturnStatement") { if (closestBlock.type === "ReturnStatement") {
@ -135,12 +134,12 @@ module.exports = {
if (closestBlock.type === "BlockStatement") { if (closestBlock.type === "BlockStatement") {
// find the last item in the block // find the last item in the block
lastItem = closestBlock.body[closestBlock.body.length - 1]; const lastItem = closestBlock.body[closestBlock.body.length - 1];
// if the callback is the last thing in a block that might be ok // if the callback is the last thing in a block that might be ok
if (isCallbackExpression(node, lastItem)) { if (isCallbackExpression(node, lastItem)) {
parentType = closestBlock.parent.type; const parentType = closestBlock.parent.type;
// but only if the block is part of a function // but only if the block is part of a function
if (parentType === "FunctionExpression" || if (parentType === "FunctionExpression" ||

16
tools/eslint/lib/rules/camelcase.js

@ -37,7 +37,7 @@ module.exports = {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// contains reported nodes to avoid reporting twice on destructuring with shorthand notation // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
let reported = []; const reported = [];
/** /**
* Checks if a string contains an underscore and isn't all upper-case * Checks if a string contains an underscore and isn't all upper-case
@ -64,8 +64,8 @@ module.exports = {
} }
} }
let options = context.options[0] || {}, const options = context.options[0] || {};
properties = options.properties || ""; let properties = options.properties || "";
if (properties !== "always" && properties !== "never") { if (properties !== "always" && properties !== "never") {
properties = "always"; properties = "always";
@ -79,7 +79,7 @@ module.exports = {
* Leading and trailing underscores are commonly used to flag * Leading and trailing underscores are commonly used to flag
* private/protected identifiers, strip them * private/protected identifiers, strip them
*/ */
let name = node.name.replace(/^_+|_+$/g, ""), const name = node.name.replace(/^_+|_+$/g, ""),
effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
// MemberExpressions get special rules // MemberExpressions get special rules
@ -122,6 +122,14 @@ module.exports = {
report(node); report(node);
} }
// Check if it's an import specifier
} else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
// Report only if the local imported identifier is underscored
if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
report(node);
}
// Report anything that is underscored that isn't a CallExpression // Report anything that is underscored that isn't a CallExpression
} else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {
report(node); report(node);

26
tools/eslint/lib/rules/comma-dangle.js

@ -9,7 +9,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"); const lodash = require("lodash");
/** /**
* Checks whether or not a trailing comma is allowed in a given node. * Checks whether or not a trailing comma is allowed in a given node.
@ -45,9 +45,9 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let mode = context.options[0]; const mode = context.options[0];
let UNEXPECTED_MESSAGE = "Unexpected trailing comma."; const UNEXPECTED_MESSAGE = "Unexpected trailing comma.";
let MISSING_MESSAGE = "Missing trailing comma."; const MISSING_MESSAGE = "Missing trailing comma.";
/** /**
* Checks whether or not a given node is multiline. * Checks whether or not a given node is multiline.
@ -58,14 +58,14 @@ module.exports = {
* @returns {boolean} `true` if the node is multiline. * @returns {boolean} `true` if the node is multiline.
*/ */
function isMultiline(node) { function isMultiline(node) {
let lastItem = lodash.last(node.properties || node.elements || node.specifiers); const lastItem = lodash.last(node.properties || node.elements || node.specifiers);
if (!lastItem) { if (!lastItem) {
return false; return false;
} }
let sourceCode = context.getSourceCode(), const sourceCode = context.getSourceCode();
penultimateToken = sourceCode.getLastToken(lastItem), let penultimateToken = sourceCode.getLastToken(lastItem),
lastToken = sourceCode.getTokenAfter(penultimateToken); lastToken = sourceCode.getTokenAfter(penultimateToken);
// parentheses are a pain // parentheses are a pain
@ -91,14 +91,14 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function forbidTrailingComma(node) { function forbidTrailingComma(node) {
let lastItem = lodash.last(node.properties || node.elements || node.specifiers); const lastItem = lodash.last(node.properties || node.elements || node.specifiers);
if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
return; return;
} }
let sourceCode = context.getSourceCode(), const sourceCode = context.getSourceCode();
trailingToken; let trailingToken;
// last item can be surrounded by parentheses for object and array literals // last item can be surrounded by parentheses for object and array literals
if (node.type === "ObjectExpression" || node.type === "ArrayExpression") { if (node.type === "ObjectExpression" || node.type === "ArrayExpression") {
@ -132,7 +132,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function forceTrailingComma(node) { function forceTrailingComma(node) {
let lastItem = lodash.last(node.properties || node.elements || node.specifiers); const lastItem = lodash.last(node.properties || node.elements || node.specifiers);
if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) { if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
return; return;
@ -142,8 +142,8 @@ module.exports = {
return; return;
} }
let sourceCode = context.getSourceCode(), const sourceCode = context.getSourceCode();
penultimateToken = lastItem, let penultimateToken = lastItem,
trailingToken = sourceCode.getTokenAfter(lastItem); trailingToken = sourceCode.getTokenAfter(lastItem);
// Skip close parentheses. // Skip close parentheses.

20
tools/eslint/lib/rules/comma-spacing.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -38,10 +38,10 @@ module.exports = {
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
let tokensAndComments = sourceCode.tokensAndComments; const tokensAndComments = sourceCode.tokensAndComments;
let options = { const options = {
before: context.options[0] ? !!context.options[0].before : false, before: context.options[0] ? !!context.options[0].before : false,
after: context.options[0] ? !!context.options[0].after : true after: context.options[0] ? !!context.options[0].after : true
}; };
@ -51,7 +51,7 @@ module.exports = {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// list of comma tokens to ignore for the check of leading whitespace // list of comma tokens to ignore for the check of leading whitespace
let commaTokensToIgnore = []; const commaTokensToIgnore = [];
/** /**
* Determines if a given token is a comma operator. * Determines if a given token is a comma operator.
@ -83,7 +83,7 @@ module.exports = {
} }
} else { } else {
let start, end; let start, end;
let newText = ""; const newText = "";
if (dir === "before") { if (dir === "before") {
start = otherNode.range[1]; start = otherNode.range[1];
@ -161,10 +161,6 @@ module.exports = {
return { return {
"Program:exit": function() { "Program:exit": function() {
let previousToken,
nextToken;
tokensAndComments.forEach(function(token, i) { tokensAndComments.forEach(function(token, i) {
if (!isComma(token)) { if (!isComma(token)) {
@ -175,8 +171,8 @@ module.exports = {
return; return;
} }
previousToken = tokensAndComments[i - 1]; const previousToken = tokensAndComments[i - 1];
nextToken = tokensAndComments[i + 1]; const nextToken = tokensAndComments[i + 1];
validateCommaItemSpacing({ validateCommaItemSpacing({
comma: token, comma: token,

19
tools/eslint/lib/rules/comma-style.js

@ -5,7 +5,7 @@
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -39,9 +39,9 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let style = context.options[0] || "last", const style = context.options[0] || "last",
exceptions = {},
sourceCode = context.getSourceCode(); sourceCode = context.getSourceCode();
let exceptions = {};
if (context.options.length === 2 && context.options[1].hasOwnProperty("exceptions")) { if (context.options.length === 2 && context.options[1].hasOwnProperty("exceptions")) {
exceptions = context.options[1].exceptions; exceptions = context.options[1].exceptions;
@ -108,17 +108,16 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function validateComma(node, property) { function validateComma(node, property) {
let items = node[property], const items = node[property],
arrayLiteral = (node.type === "ArrayExpression"), arrayLiteral = (node.type === "ArrayExpression");
previousItemToken;
if (items.length > 1 || arrayLiteral) { if (items.length > 1 || arrayLiteral) {
// seed as opening [ // seed as opening [
previousItemToken = sourceCode.getFirstToken(node); let previousItemToken = sourceCode.getFirstToken(node);
items.forEach(function(item) { items.forEach(function(item) {
let commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken, const commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken,
currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken), currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken),
reportItem = item || currentItemToken, reportItem = item || currentItemToken,
tokenBeforeComma = sourceCode.getTokenBefore(commaToken); tokenBeforeComma = sourceCode.getTokenBefore(commaToken);
@ -158,7 +157,7 @@ module.exports = {
*/ */
if (arrayLiteral) { if (arrayLiteral) {
let lastToken = sourceCode.getLastToken(node), const lastToken = sourceCode.getLastToken(node),
nextToLastToken = sourceCode.getTokenBefore(lastToken); nextToLastToken = sourceCode.getTokenBefore(lastToken);
if (isComma(nextToLastToken)) { if (isComma(nextToLastToken)) {
@ -177,7 +176,7 @@ module.exports = {
// Public // Public
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let nodes = {}; const nodes = {};
if (!exceptions.VariableDeclaration) { if (!exceptions.VariableDeclaration) {
nodes.VariableDeclaration = function(node) { nodes.VariableDeclaration = function(node) {

10
tools/eslint/lib/rules/complexity.js

@ -45,8 +45,8 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let option = context.options[0], const option = context.options[0];
THRESHOLD = 20; let THRESHOLD = 20;
if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
THRESHOLD = option.maximum; THRESHOLD = option.maximum;
@ -63,7 +63,7 @@ module.exports = {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Using a stack to store complexity (handling nested functions) // Using a stack to store complexity (handling nested functions)
let fns = []; const fns = [];
/** /**
* When parsing a new function, store it in our function stack * When parsing a new function, store it in our function stack
@ -81,8 +81,8 @@ module.exports = {
* @private * @private
*/ */
function endFunction(node) { function endFunction(node) {
let complexity = fns.pop(), const complexity = fns.pop();
name = "anonymous"; let name = "anonymous";
if (node.id) { if (node.id) {
name = node.id.name; name = node.id.name;

10
tools/eslint/lib/rules/computed-property-spacing.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -28,8 +28,8 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
let propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never" const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -117,9 +117,9 @@ module.exports = {
return; return;
} }
let property = node[propertyName]; const property = node[propertyName];
let before = sourceCode.getTokenBefore(property), const before = sourceCode.getTokenBefore(property),
first = sourceCode.getFirstToken(property), first = sourceCode.getFirstToken(property),
last = sourceCode.getLastToken(property), last = sourceCode.getLastToken(property),
after = sourceCode.getTokenAfter(property); after = sourceCode.getTokenAfter(property);

8
tools/eslint/lib/rules/consistent-return.js

@ -8,7 +8,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
@ -57,8 +57,8 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options[0] || {}; const options = context.options[0] || {};
let treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true; const treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true;
let funcInfo = null; let funcInfo = null;
/** /**
@ -135,7 +135,7 @@ module.exports = {
// Reports a given return statement if it's inconsistent. // Reports a given return statement if it's inconsistent.
ReturnStatement: function(node) { ReturnStatement: function(node) {
let argument = node.argument; const argument = node.argument;
let hasReturnValue = Boolean(argument); let hasReturnValue = Boolean(argument);
if (treatUndefinedAsUnspecified && hasReturnValue) { if (treatUndefinedAsUnspecified && hasReturnValue) {

12
tools/eslint/lib/rules/consistent-this.js

@ -57,7 +57,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkAssignment(node, name, value) { function checkAssignment(node, name, value) {
let isThis = value.type === "ThisExpression"; const isThis = value.type === "ThisExpression";
if (aliases.indexOf(name) !== -1) { if (aliases.indexOf(name) !== -1) {
if (!isThis || node.operator && node.operator !== "=") { if (!isThis || node.operator && node.operator !== "=") {
@ -78,7 +78,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkWasAssigned(alias, scope) { function checkWasAssigned(alias, scope) {
let variable = scope.set.get(alias); const variable = scope.set.get(alias);
if (!variable) { if (!variable) {
return; return;
@ -94,7 +94,7 @@ module.exports = {
// The alias has been declared and not assigned: check it was // The alias has been declared and not assigned: check it was
// assigned later in the same scope. // assigned later in the same scope.
if (!variable.references.some(function(reference) { if (!variable.references.some(function(reference) {
let write = reference.writeExpr; const write = reference.writeExpr;
return ( return (
reference.from === scope && reference.from === scope &&
@ -115,7 +115,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function ensureWasAssigned() { function ensureWasAssigned() {
let scope = context.getScope(); const scope = context.getScope();
aliases.forEach(function(alias) { aliases.forEach(function(alias) {
checkWasAssigned(alias, scope); checkWasAssigned(alias, scope);
@ -128,8 +128,8 @@ module.exports = {
"FunctionDeclaration:exit": ensureWasAssigned, "FunctionDeclaration:exit": ensureWasAssigned,
VariableDeclarator: function(node) { VariableDeclarator: function(node) {
let id = node.id; const id = node.id;
let isDestructuring = const isDestructuring =
id.type === "ArrayPattern" || id.type === "ObjectPattern"; id.type === "ArrayPattern" || id.type === "ObjectPattern";
if (node.init !== null && !isDestructuring) { if (node.init !== null && !isDestructuring) {

36
tools/eslint/lib/rules/constructor-super.js

@ -164,8 +164,8 @@ module.exports = {
if (isConstructorFunction(node)) { if (isConstructorFunction(node)) {
// Class > ClassBody > MethodDefinition > FunctionExpression // Class > ClassBody > MethodDefinition > FunctionExpression
let classNode = node.parent.parent.parent; const classNode = node.parent.parent.parent;
let superClass = classNode.superClass; const superClass = classNode.superClass;
funcInfo = { funcInfo = {
upper: funcInfo, upper: funcInfo,
@ -193,7 +193,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
onCodePathEnd: function(codePath, node) { onCodePathEnd: function(codePath, node) {
let hasExtends = funcInfo.hasExtends; const hasExtends = funcInfo.hasExtends;
// Pop. // Pop.
funcInfo = funcInfo.upper; funcInfo = funcInfo.upper;
@ -203,9 +203,9 @@ module.exports = {
} }
// Reports if `super()` lacked. // Reports if `super()` lacked.
let segments = codePath.returnedSegments; const segments = codePath.returnedSegments;
let calledInEveryPaths = segments.every(isCalledInEveryPath); const calledInEveryPaths = segments.every(isCalledInEveryPath);
let calledInSomePaths = segments.some(isCalledInSomePath); const calledInSomePaths = segments.some(isCalledInSomePath);
if (!calledInEveryPaths) { if (!calledInEveryPaths) {
context.report({ context.report({
@ -228,14 +228,14 @@ module.exports = {
} }
// Initialize info. // Initialize info.
let info = segInfoMap[segment.id] = { const info = segInfoMap[segment.id] = {
calledInSomePaths: false, calledInSomePaths: false,
calledInEveryPaths: false, calledInEveryPaths: false,
validNodes: [] validNodes: []
}; };
// When there are previous segments, aggregates these. // When there are previous segments, aggregates these.
let prevSegments = segment.prevSegments; const prevSegments = segment.prevSegments;
if (prevSegments.length > 0) { if (prevSegments.length > 0) {
info.calledInSomePaths = prevSegments.some(isCalledInSomePath); info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
@ -258,13 +258,13 @@ module.exports = {
} }
// Update information inside of the loop. // Update information inside of the loop.
let isRealLoop = toSegment.prevSegments.length >= 2; const isRealLoop = toSegment.prevSegments.length >= 2;
funcInfo.codePath.traverseSegments( funcInfo.codePath.traverseSegments(
{first: toSegment, last: fromSegment}, {first: toSegment, last: fromSegment},
function(segment) { function(segment) {
let info = segInfoMap[segment.id]; const info = segInfoMap[segment.id];
let prevSegments = segment.prevSegments; const prevSegments = segment.prevSegments;
// Updates flags. // Updates flags.
info.calledInSomePaths = prevSegments.some(isCalledInSomePath); info.calledInSomePaths = prevSegments.some(isCalledInSomePath);
@ -272,12 +272,12 @@ module.exports = {
// If flags become true anew, reports the valid nodes. // If flags become true anew, reports the valid nodes.
if (info.calledInSomePaths || isRealLoop) { if (info.calledInSomePaths || isRealLoop) {
let nodes = info.validNodes; const nodes = info.validNodes;
info.validNodes = []; info.validNodes = [];
for (let i = 0; i < nodes.length; ++i) { for (let i = 0; i < nodes.length; ++i) {
let node = nodes[i]; const node = nodes[i];
context.report({ context.report({
message: "Unexpected duplicate 'super()'.", message: "Unexpected duplicate 'super()'.",
@ -306,12 +306,12 @@ module.exports = {
// Reports if needed. // Reports if needed.
if (funcInfo.hasExtends) { if (funcInfo.hasExtends) {
let segments = funcInfo.codePath.currentSegments; const segments = funcInfo.codePath.currentSegments;
let duplicate = false; let duplicate = false;
let info = null; let info = null;
for (let i = 0; i < segments.length; ++i) { for (let i = 0; i < segments.length; ++i) {
let segment = segments[i]; const segment = segments[i];
if (segment.reachable) { if (segment.reachable) {
info = segInfoMap[segment.id]; info = segInfoMap[segment.id];
@ -360,13 +360,13 @@ module.exports = {
} }
// Returning argument is a substitute of 'super()'. // Returning argument is a substitute of 'super()'.
let segments = funcInfo.codePath.currentSegments; const segments = funcInfo.codePath.currentSegments;
for (let i = 0; i < segments.length; ++i) { for (let i = 0; i < segments.length; ++i) {
let segment = segments[i]; const segment = segments[i];
if (segment.reachable) { if (segment.reachable) {
let info = segInfoMap[segment.id]; const info = segInfoMap[segment.id];
info.calledInSomePaths = info.calledInEveryPaths = true; info.calledInSomePaths = info.calledInEveryPaths = true;
} }

22
tools/eslint/lib/rules/curly.js

@ -8,7 +8,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -53,12 +53,12 @@ module.exports = {
create: function(context) { create: function(context) {
let multiOnly = (context.options[0] === "multi"); const multiOnly = (context.options[0] === "multi");
let multiLine = (context.options[0] === "multi-line"); const multiLine = (context.options[0] === "multi-line");
let multiOrNest = (context.options[0] === "multi-or-nest"); const multiOrNest = (context.options[0] === "multi-or-nest");
let consistent = (context.options[1] === "consistent"); const consistent = (context.options[1] === "consistent");
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -71,7 +71,7 @@ module.exports = {
* @private * @private
*/ */
function isCollapsedOneLiner(node) { function isCollapsedOneLiner(node) {
let before = sourceCode.getTokenBefore(node), const before = sourceCode.getTokenBefore(node),
last = sourceCode.getLastToken(node); last = sourceCode.getLastToken(node);
return before.loc.start.line === last.loc.end.line; return before.loc.start.line === last.loc.end.line;
@ -84,7 +84,7 @@ module.exports = {
* @private * @private
*/ */
function isOneLiner(node) { function isOneLiner(node) {
let first = sourceCode.getFirstToken(node), const first = sourceCode.getFirstToken(node),
last = sourceCode.getLastToken(node); last = sourceCode.getLastToken(node);
return first.loc.start.line === last.loc.end.line; return first.loc.start.line === last.loc.end.line;
@ -189,7 +189,7 @@ module.exports = {
* properties. * properties.
*/ */
function prepareCheck(node, body, name, suffix) { function prepareCheck(node, body, name, suffix) {
let hasBlock = (body.type === "BlockStatement"); const hasBlock = (body.type === "BlockStatement");
let expected = null; let expected = null;
if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) { if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) {
@ -234,7 +234,7 @@ module.exports = {
* information. * information.
*/ */
function prepareIfChecks(node) { function prepareIfChecks(node) {
let preparedChecks = []; const preparedChecks = [];
do { do {
preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition")); preparedChecks.push(prepareCheck(node, node.consequent, "if", "condition"));
@ -252,7 +252,7 @@ module.exports = {
* all have braces. * all have braces.
* If all nodes shouldn't have braces, make sure they don't. * If all nodes shouldn't have braces, make sure they don't.
*/ */
let expected = preparedChecks.some(function(preparedCheck) { const expected = preparedChecks.some(function(preparedCheck) {
if (preparedCheck.expected !== null) { if (preparedCheck.expected !== null) {
return preparedCheck.expected; return preparedCheck.expected;
} }

16
tools/eslint/lib/rules/default-case.js

@ -4,7 +4,7 @@
*/ */
"use strict"; "use strict";
let DEFAULT_COMMENT_PATTERN = /^no default$/; const DEFAULT_COMMENT_PATTERN = /^no default$/;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -30,12 +30,12 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options[0] || {}; const options = context.options[0] || {};
let commentPattern = options.commentPattern ? const commentPattern = options.commentPattern ?
new RegExp(options.commentPattern) : new RegExp(options.commentPattern) :
DEFAULT_COMMENT_PATTERN; DEFAULT_COMMENT_PATTERN;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -67,18 +67,16 @@ module.exports = {
return; return;
} }
let hasDefault = node.cases.some(function(v) { const hasDefault = node.cases.some(function(v) {
return v.test === null; return v.test === null;
}); });
if (!hasDefault) { if (!hasDefault) {
let comment; let comment;
let comments;
let lastCase = last(node.cases); const lastCase = last(node.cases);
const comments = sourceCode.getComments(lastCase).trailing;
comments = sourceCode.getComments(lastCase).trailing;
if (comments.length) { if (comments.length) {
comment = last(comments); comment = last(comments);

10
tools/eslint/lib/rules/dot-location.js

@ -5,7 +5,7 @@
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -28,12 +28,12 @@ module.exports = {
create: function(context) { create: function(context) {
let config = context.options[0]; const config = context.options[0];
// default to onObject if no preference is passed // default to onObject if no preference is passed
let onObject = config === "object" || !config; const onObject = config === "object" || !config;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Reports if the dot between object and property is on the correct loccation. * Reports if the dot between object and property is on the correct loccation.
@ -43,7 +43,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkDotLocation(obj, prop, node) { function checkDotLocation(obj, prop, node) {
let dot = sourceCode.getTokenBefore(prop); const dot = sourceCode.getTokenBefore(prop);
if (dot.type === "Punctuator" && dot.value === ".") { if (dot.type === "Punctuator" && dot.value === ".") {
if (onObject) { if (onObject) {

8
tools/eslint/lib/rules/dot-notation.js

@ -8,8 +8,8 @@
// Rule Definition // Rule Definition
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
let keywords = require("../util/keywords"); const keywords = require("../util/keywords");
module.exports = { module.exports = {
meta: { meta: {
@ -36,8 +36,8 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options[0] || {}; const options = context.options[0] || {};
let allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; const allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords;
let allowPattern; let allowPattern;

2
tools/eslint/lib/rules/eol-last.js

@ -35,7 +35,7 @@ module.exports = {
Program: function checkBadEOF(node) { Program: function checkBadEOF(node) {
let sourceCode = context.getSourceCode(), const sourceCode = context.getSourceCode(),
src = sourceCode.getText(), src = sourceCode.getText(),
location = {column: 1}, location = {column: 1},
linebreakStyle = context.options[0] || "unix", linebreakStyle = context.options[0] || "unix",

83
tools/eslint/lib/rules/eqeqeq.js

@ -17,15 +17,49 @@ module.exports = {
recommended: false recommended: false
}, },
schema: [ schema: {
{ anyOf: [
enum: ["always", "smart", "allow-null"] {
} type: "array",
] items: [
{
enum: ["always"]
},
{
type: "object",
properties: {
null: {
enum: ["always", "never", "ignore"]
}
},
additionalProperties: false
}
],
additionalItems: false
},
{
type: "array",
items: [
{
enum: ["smart", "allow-null"]
}
],
additionalItems: false
}
]
}
}, },
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const config = context.options[0] || "always";
const options = context.options[1] || {};
const sourceCode = context.getSourceCode();
const nullOption = (config === "always") ?
options.null || "always" :
"ignore";
const enforceRuleForNull = (nullOption === "always");
const enforceInverseRuleForNull = (nullOption === "never");
/** /**
* Checks if an expression is a typeof expression * Checks if an expression is a typeof expression
@ -76,33 +110,48 @@ module.exports = {
* @private * @private
*/ */
function getOperatorLocation(node) { function getOperatorLocation(node) {
let opToken = sourceCode.getTokenAfter(node.left); const opToken = sourceCode.getTokenAfter(node.left);
return {line: opToken.loc.start.line, column: opToken.loc.start.column}; return {line: opToken.loc.start.line, column: opToken.loc.start.column};
} }
/**
* Reports a message for this rule.
* @param {ASTNode} node The binary expression node that was checked
* @param {string} message The message to report
* @returns {void}
* @private
*/
function report(node, message) {
context.report({
node: node,
loc: getOperatorLocation(node),
message: message,
data: { op: node.operator.charAt(0) }
});
}
return { return {
BinaryExpression: function(node) { BinaryExpression: function(node) {
const isNull = isNullCheck(node);
if (node.operator !== "==" && node.operator !== "!=") { if (node.operator !== "==" && node.operator !== "!=") {
if (enforceInverseRuleForNull && isNull) {
report(node, "Expected '{{op}}=' and instead saw '{{op}}=='.");
}
return; return;
} }
if (context.options[0] === "smart" && (isTypeOfBinary(node) || if (config === "smart" && (isTypeOfBinary(node) ||
areLiteralsAndSameType(node) || isNullCheck(node))) { areLiteralsAndSameType(node) || isNull)) {
return; return;
} }
if (context.options[0] === "allow-null" && isNullCheck(node)) { if (!enforceRuleForNull && isNull) {
return; return;
} }
context.report({ report(node, "Expected '{{op}}==' and instead saw '{{op}}='.");
node: node,
loc: getOperatorLocation(node),
message: "Expected '{{op}}=' and instead saw '{{op}}'.",
data: { op: node.operator }
});
} }
}; };

153
tools/eslint/lib/rules/func-call-spacing.js

@ -0,0 +1,153 @@
/**
* @fileoverview Rule to control spacing within function calls
* @author Matt DuVall <http://www.mattduvall.com>
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "require or disallow spacing between `function` identifiers and their invocations",
category: "Stylistic Issues",
recommended: false
},
fixable: "whitespace",
schema: {
anyOf: [
{
type: "array",
items: [
{
enum: ["never"]
}
],
minItems: 0,
maxItems: 1
},
{
type: "array",
items: [
{
enum: ["always"]
},
{
type: "object",
properties: {
allowNewlines: {
type: "boolean"
}
},
additionalProperties: false
}
],
minItems: 0,
maxItems: 2
}
]
}
},
create: function(context) {
const never = context.options[0] !== "always";
const allowNewlines = !never && context.options[1] && context.options[1].allowNewlines;
const sourceCode = context.getSourceCode();
const text = sourceCode.getText();
/**
* Check if open space is present in a function name
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkSpacing(node) {
const lastCalleeToken = sourceCode.getLastToken(node.callee);
let prevToken = lastCalleeToken;
let parenToken = sourceCode.getTokenAfter(lastCalleeToken);
// advances to an open parenthesis.
while (
parenToken &&
parenToken.range[1] < node.range[1] &&
parenToken.value !== "("
) {
prevToken = parenToken;
parenToken = sourceCode.getTokenAfter(parenToken);
}
// Parens in NewExpression are optional
if (!(parenToken && parenToken.range[1] < node.range[1])) {
return;
}
const hasWhitespace = sourceCode.isSpaceBetweenTokens(prevToken, parenToken);
const hasNewline = hasWhitespace &&
/\n/.test(text.slice(prevToken.range[1], parenToken.range[0]).replace(/\/\*.*?\*\//g, ""));
/*
* never allowNewlines hasWhitespace hasNewline message
* F F F F Missing space between function name and paren.
* F F F T (Invalid `!hasWhitespace && hasNewline`)
* F F T T Unexpected newline between function name and paren.
* F F T F (OK)
* F T T F (OK)
* F T T T (OK)
* F T F T (Invalid `!hasWhitespace && hasNewline`)
* F T F F Missing space between function name and paren.
* T T F F (Invalid `never && allowNewlines`)
* T T F T (Invalid `!hasWhitespace && hasNewline`)
* T T T T (Invalid `never && allowNewlines`)
* T T T F (Invalid `never && allowNewlines`)
* T F T F Unexpected space between function name and paren.
* T F T T Unexpected space between function name and paren.
* T F F T (Invalid `!hasWhitespace && hasNewline`)
* T F F F (OK)
*
* T T Unexpected space between function name and paren.
* F F Missing space between function name and paren.
* F F T Unexpected newline between function name and paren.
*/
if (never && hasWhitespace) {
context.report({
node: node,
loc: lastCalleeToken.loc.start,
message: "Unexpected space between function name and paren.",
fix: function(fixer) {
return fixer.removeRange([prevToken.range[1], parenToken.range[0]]);
}
});
} else if (!never && !hasWhitespace) {
context.report({
node: node,
loc: lastCalleeToken.loc.start,
message: "Missing space between function name and paren.",
fix: function(fixer) {
return fixer.insertTextBefore(parenToken, " ");
}
});
} else if (!never && !allowNewlines && hasNewline) {
context.report({
node: node,
loc: lastCalleeToken.loc.start,
message: "Unexpected newline between function name and paren.",
fix: function(fixer) {
return fixer.replaceTextRange([prevToken.range[1], parenToken.range[0]], " ");
}
});
}
}
return {
CallExpression: checkSpacing,
NewExpression: checkSpacing
};
}
};

8
tools/eslint/lib/rules/func-names.js

@ -34,7 +34,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let never = context.options[0] === "never"; const never = context.options[0] === "never";
/** /**
* Determines whether the current FunctionExpression node is a get, set, or * Determines whether the current FunctionExpression node is a get, set, or
@ -42,7 +42,7 @@ module.exports = {
* @returns {boolean} True if the node is a get, set, or shorthand method. * @returns {boolean} True if the node is a get, set, or shorthand method.
*/ */
function isObjectOrClassMethod() { function isObjectOrClassMethod() {
let parent = context.getAncestors().pop(); const parent = context.getAncestors().pop();
return (parent.type === "MethodDefinition" || ( return (parent.type === "MethodDefinition" || (
parent.type === "Property" && ( parent.type === "Property" && (
@ -57,13 +57,13 @@ module.exports = {
"FunctionExpression:exit": function(node) { "FunctionExpression:exit": function(node) {
// Skip recursive functions. // Skip recursive functions.
let nameVar = context.getDeclaredVariables(node)[0]; const nameVar = context.getDeclaredVariables(node)[0];
if (isFunctionName(nameVar) && nameVar.references.length > 0) { if (isFunctionName(nameVar) && nameVar.references.length > 0) {
return; return;
} }
let name = node.id && node.id.name; const name = node.id && node.id.name;
if (never) { if (never) {
if (name) { if (name) {

10
tools/eslint/lib/rules/func-style.js

@ -34,16 +34,12 @@ module.exports = {
create: function(context) { create: function(context) {
let style = context.options[0], const style = context.options[0],
allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true, allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions === true,
enforceDeclarations = (style === "declaration"), enforceDeclarations = (style === "declaration"),
stack = []; stack = [];
let nodesToCheck = { const nodesToCheck = {
Program: function() {
stack = [];
},
FunctionDeclaration: function(node) { FunctionDeclaration: function(node) {
stack.push(false); stack.push(false);
@ -79,7 +75,7 @@ module.exports = {
}; };
nodesToCheck["ArrowFunctionExpression:exit"] = function(node) { nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
let hasThisExpr = stack.pop(); const hasThisExpr = stack.pop();
if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") { if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
context.report(node.parent, "Expected a function declaration."); context.report(node.parent, "Expected a function declaration.");

22
tools/eslint/lib/rules/generator-star-spacing.js

@ -40,7 +40,7 @@ module.exports = {
create: function(context) { create: function(context) {
let mode = (function(option) { const mode = (function(option) {
if (!option || typeof option === "string") { if (!option || typeof option === "string") {
return { return {
before: { before: true, after: false }, before: { before: true, after: false },
@ -52,7 +52,7 @@ module.exports = {
return option; return option;
}(context.options[0])); }(context.options[0]));
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Gets `*` token from a given node. * Gets `*` token from a given node.
@ -83,11 +83,11 @@ module.exports = {
*/ */
function checkSpacing(side, leftToken, rightToken) { function checkSpacing(side, leftToken, rightToken) {
if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) { if (!!(rightToken.range[0] - leftToken.range[1]) !== mode[side]) {
let after = leftToken.value === "*"; const after = leftToken.value === "*";
let spaceRequired = mode[side]; const spaceRequired = mode[side];
let node = after ? leftToken : rightToken; const node = after ? leftToken : rightToken;
let type = spaceRequired ? "Missing" : "Unexpected"; const type = spaceRequired ? "Missing" : "Unexpected";
let message = type + " space " + side + " *."; const message = type + " space " + side + " *.";
context.report({ context.report({
node: node, node: node,
@ -111,7 +111,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkFunction(node) { function checkFunction(node) {
let prevToken, starToken, nextToken; let starToken;
if (!node.generator) { if (!node.generator) {
return; return;
@ -124,12 +124,14 @@ module.exports = {
} }
// Only check before when preceded by `function`|`static` keyword // Only check before when preceded by `function`|`static` keyword
prevToken = sourceCode.getTokenBefore(starToken); const prevToken = sourceCode.getTokenBefore(starToken);
if (prevToken.value === "function" || prevToken.value === "static") { if (prevToken.value === "function" || prevToken.value === "static") {
checkSpacing("before", prevToken, starToken); checkSpacing("before", prevToken, starToken);
} }
nextToken = sourceCode.getTokenAfter(starToken); const nextToken = sourceCode.getTokenAfter(starToken);
checkSpacing("after", starToken, nextToken); checkSpacing("after", starToken, nextToken);
} }

12
tools/eslint/lib/rules/global-require.js

@ -5,7 +5,7 @@
"use strict"; "use strict";
let ACCEPTABLE_PARENTS = [ const ACCEPTABLE_PARENTS = [
"AssignmentExpression", "AssignmentExpression",
"VariableDeclarator", "VariableDeclarator",
"MemberExpression", "MemberExpression",
@ -23,7 +23,7 @@ let ACCEPTABLE_PARENTS = [
* @returns {Reference|null} Returns the found reference or null if none were found. * @returns {Reference|null} Returns the found reference or null if none were found.
*/ */
function findReference(scope, node) { function findReference(scope, node) {
let references = scope.references.filter(function(reference) { const references = scope.references.filter(function(reference) {
return reference.identifier.range[0] === node.range[0] && return reference.identifier.range[0] === node.range[0] &&
reference.identifier.range[1] === node.range[1]; reference.identifier.range[1] === node.range[1];
}); });
@ -43,7 +43,7 @@ function findReference(scope, node) {
* @returns {boolean} Whether or not the name is shadowed. * @returns {boolean} Whether or not the name is shadowed.
*/ */
function isShadowed(scope, node) { function isShadowed(scope, node) {
let reference = findReference(scope, node); const reference = findReference(scope, node);
return reference && reference.resolved && reference.resolved.defs.length > 0; return reference && reference.resolved && reference.resolved.defs.length > 0;
} }
@ -62,13 +62,13 @@ module.exports = {
create: function(context) { create: function(context) {
return { return {
CallExpression: function(node) { CallExpression: function(node) {
let currentScope = context.getScope(), const currentScope = context.getScope();
isGoodRequire;
if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) { if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
isGoodRequire = context.getAncestors().every(function(parent) { const isGoodRequire = context.getAncestors().every(function(parent) {
return ACCEPTABLE_PARENTS.indexOf(parent.type) > -1; return ACCEPTABLE_PARENTS.indexOf(parent.type) > -1;
}); });
if (!isGoodRequire) { if (!isGoodRequire) {
context.report(node, "Unexpected require()."); context.report(node, "Unexpected require().");
} }

2
tools/eslint/lib/rules/guard-for-in.js

@ -30,7 +30,7 @@ module.exports = {
* If the for-in statement has {}, then the real body is the body * If the for-in statement has {}, then the real body is the body
* of the BlockStatement. Otherwise, just use body as provided. * of the BlockStatement. Otherwise, just use body as provided.
*/ */
let body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body; const body = node.body.type === "BlockStatement" ? node.body.body[0] : node.body;
if (body && body.type !== "IfStatement") { if (body && body.type !== "IfStatement") {
context.report(node, "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype."); context.report(node, "The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype.");

8
tools/eslint/lib/rules/handle-callback-err.js

@ -26,7 +26,7 @@ module.exports = {
create: function(context) { create: function(context) {
let errorArgument = context.options[0] || "err"; const errorArgument = context.options[0] || "err";
/** /**
* Checks if the given argument should be interpreted as a regexp pattern. * Checks if the given argument should be interpreted as a regexp pattern.
@ -34,7 +34,7 @@ module.exports = {
* @returns {boolean} Whether or not the string should be interpreted as a pattern. * @returns {boolean} Whether or not the string should be interpreted as a pattern.
*/ */
function isPattern(stringToCheck) { function isPattern(stringToCheck) {
let firstChar = stringToCheck[0]; const firstChar = stringToCheck[0];
return firstChar === "^"; return firstChar === "^";
} }
@ -46,7 +46,7 @@ module.exports = {
*/ */
function matchesConfiguredErrorName(name) { function matchesConfiguredErrorName(name) {
if (isPattern(errorArgument)) { if (isPattern(errorArgument)) {
let regexp = new RegExp(errorArgument); const regexp = new RegExp(errorArgument);
return regexp.test(name); return regexp.test(name);
} }
@ -70,7 +70,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkForError(node) { function checkForError(node) {
let scope = context.getScope(), const scope = context.getScope(),
parameters = getParameters(scope), parameters = getParameters(scope),
firstParameter = parameters[0]; firstParameter = parameters[0];

4
tools/eslint/lib/rules/id-blacklist.js

@ -34,7 +34,7 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let blacklist = context.options; const blacklist = context.options;
/** /**
@ -75,7 +75,7 @@ module.exports = {
return { return {
Identifier: function(node) { Identifier: function(node) {
let name = node.name, const name = node.name,
effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
// MemberExpressions get special rules // MemberExpressions get special rules

22
tools/eslint/lib/rules/id-length.js

@ -45,18 +45,18 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options[0] || {}; const options = context.options[0] || {};
let minLength = typeof options.min !== "undefined" ? options.min : 2; const minLength = typeof options.min !== "undefined" ? options.min : 2;
let maxLength = typeof options.max !== "undefined" ? options.max : Infinity; const maxLength = typeof options.max !== "undefined" ? options.max : Infinity;
let properties = options.properties !== "never"; const properties = options.properties !== "never";
let exceptions = (options.exceptions ? options.exceptions : []) const exceptions = (options.exceptions ? options.exceptions : [])
.reduce(function(obj, item) { .reduce(function(obj, item) {
obj[item] = true; obj[item] = true;
return obj; return obj;
}, {}); }, {});
let SUPPORTED_EXPRESSIONS = { const SUPPORTED_EXPRESSIONS = {
MemberExpression: properties && function(parent) { MemberExpression: properties && function(parent) {
return !parent.computed && ( return !parent.computed && (
@ -87,17 +87,17 @@ module.exports = {
return { return {
Identifier: function(node) { Identifier: function(node) {
let name = node.name; const name = node.name;
let parent = node.parent; const parent = node.parent;
let isShort = name.length < minLength; const isShort = name.length < minLength;
let isLong = name.length > maxLength; const isLong = name.length > maxLength;
if (!(isShort || isLong) || exceptions[name]) { if (!(isShort || isLong) || exceptions[name]) {
return; // Nothing to report return; // Nothing to report
} }
let isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];
if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) { if (isValidExpression && (isValidExpression === true || isValidExpression(parent, node))) {
context.report( context.report(

8
tools/eslint/lib/rules/id-match.js

@ -38,10 +38,10 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let pattern = context.options[0] || "^.+$", const pattern = context.options[0] || "^.+$",
regexp = new RegExp(pattern); regexp = new RegExp(pattern);
let options = context.options[1] || {}, const options = context.options[1] || {},
properties = !!options.properties, properties = !!options.properties,
onlyDeclarations = !!options.onlyDeclarations; onlyDeclarations = !!options.onlyDeclarations;
@ -84,7 +84,7 @@ module.exports = {
return { return {
Identifier: function(node) { Identifier: function(node) {
let name = node.name, const name = node.name,
parent = node.parent, parent = node.parent,
effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent; effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
@ -122,7 +122,7 @@ module.exports = {
} }
} else { } else {
let isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
if (onlyDeclarations && !isDeclaration) { if (onlyDeclarations && !isDeclaration) {
return; return;

92
tools/eslint/lib/rules/indent.js

@ -11,8 +11,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let util = require("util");
let lodash = require("lodash");
module.exports = { module.exports = {
meta: { meta: {
@ -84,12 +82,12 @@ module.exports = {
create: function(context) { create: function(context) {
let MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}."; const MESSAGE = "Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.";
let DEFAULT_VARIABLE_INDENT = 1; const DEFAULT_VARIABLE_INDENT = 1;
let indentType = "space"; let indentType = "space";
let indentSize = 4; let indentSize = 4;
let options = { const options = {
SwitchCase: 0, SwitchCase: 0,
VariableDeclarator: { VariableDeclarator: {
var: DEFAULT_VARIABLE_INDENT, var: DEFAULT_VARIABLE_INDENT,
@ -99,7 +97,7 @@ module.exports = {
outerIIFEBody: null outerIIFEBody: null
}; };
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
if (context.options.length) { if (context.options.length) {
if (context.options[0] === "tab") { if (context.options[0] === "tab") {
@ -111,10 +109,10 @@ module.exports = {
} }
if (context.options[1]) { if (context.options[1]) {
let opts = context.options[1]; const opts = context.options[1];
options.SwitchCase = opts.SwitchCase || 0; options.SwitchCase = opts.SwitchCase || 0;
let variableDeclaratorRules = opts.VariableDeclarator; const variableDeclaratorRules = opts.VariableDeclarator;
if (typeof variableDeclaratorRules === "number") { if (typeof variableDeclaratorRules === "number") {
options.VariableDeclarator = { options.VariableDeclarator = {
@ -123,7 +121,7 @@ module.exports = {
const: variableDeclaratorRules const: variableDeclaratorRules
}; };
} else if (typeof variableDeclaratorRules === "object") { } else if (typeof variableDeclaratorRules === "object") {
lodash.assign(options.VariableDeclarator, variableDeclaratorRules); Object.assign(options.VariableDeclarator, variableDeclaratorRules);
} }
if (typeof opts.outerIIFEBody === "number") { if (typeof opts.outerIIFEBody === "number") {
@ -136,12 +134,12 @@ module.exports = {
} }
} }
let indentPattern = { const indentPattern = {
normal: indentType === "space" ? /^ +/ : /^\t+/, normal: indentType === "space" ? /^ +/ : /^\t+/,
excludeCommas: indentType === "space" ? /^[ ,]+/ : /^[\t,]+/ excludeCommas: indentType === "space" ? /^[ ,]+/ : /^[\t,]+/
}; };
let caseIndentStore = {}; const caseIndentStore = {};
/** /**
* Reports a given indent violation and properly pluralizes the message * Reports a given indent violation and properly pluralizes the message
@ -153,13 +151,13 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function report(node, needed, gotten, loc, isLastNodeCheck) { function report(node, needed, gotten, loc, isLastNodeCheck) {
let msgContext = { const msgContext = {
needed: needed, needed: needed,
type: indentType, type: indentType,
characters: needed === 1 ? "character" : "characters", characters: needed === 1 ? "character" : "characters",
gotten: gotten gotten: gotten
}; };
let indentChar = indentType === "space" ? " " : "\t"; const indentChar = indentType === "space" ? " " : "\t";
/** /**
* Responsible for fixing the indentation issue fix * Responsible for fixing the indentation issue fix
@ -170,7 +168,7 @@ module.exports = {
let rangeToFix = []; let rangeToFix = [];
if (needed > gotten) { if (needed > gotten) {
let spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future const spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future
if (isLastNodeCheck === true) { if (isLastNodeCheck === true) {
rangeToFix = [ rangeToFix = [
@ -232,10 +230,10 @@ module.exports = {
* @returns {int} Indent * @returns {int} Indent
*/ */
function getNodeIndent(node, byLastLine, excludeCommas) { function getNodeIndent(node, byLastLine, excludeCommas) {
let token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node); const token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node);
let src = sourceCode.getText(token, token.loc.start.column); const src = sourceCode.getText(token, token.loc.start.column);
let regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal; const regExp = excludeCommas ? indentPattern.excludeCommas : indentPattern.normal;
let indent = regExp.exec(src); const indent = regExp.exec(src);
return indent ? indent[0].length : 0; return indent ? indent[0].length : 0;
} }
@ -247,7 +245,7 @@ module.exports = {
* @returns {boolean} true if its the first in the its start line * @returns {boolean} true if its the first in the its start line
*/ */
function isNodeFirstInLine(node, byEndLocation) { function isNodeFirstInLine(node, byEndLocation) {
let firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node), const firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node),
startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line, startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line,
endLine = firstToken ? firstToken.loc.end.line : -1; endLine = firstToken ? firstToken.loc.end.line : -1;
@ -262,7 +260,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkNodeIndent(node, indent, excludeCommas) { function checkNodeIndent(node, indent, excludeCommas) {
let nodeIndent = getNodeIndent(node, false, excludeCommas); const nodeIndent = getNodeIndent(node, false, excludeCommas);
if ( if (
node.type !== "ArrayExpression" && node.type !== "ObjectExpression" && node.type !== "ArrayExpression" && node.type !== "ObjectExpression" &&
@ -282,7 +280,7 @@ module.exports = {
function checkNodesIndent(nodes, indent, excludeCommas) { function checkNodesIndent(nodes, indent, excludeCommas) {
nodes.forEach(function(node) { nodes.forEach(function(node) {
if (node.type === "IfStatement" && node.alternate) { if (node.type === "IfStatement" && node.alternate) {
let elseToken = sourceCode.getTokenBefore(node.alternate); const elseToken = sourceCode.getTokenBefore(node.alternate);
checkNodeIndent(elseToken, indent, excludeCommas); checkNodeIndent(elseToken, indent, excludeCommas);
} }
@ -297,8 +295,8 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkLastNodeLineIndent(node, lastLineIndent) { function checkLastNodeLineIndent(node, lastLineIndent) {
let lastToken = sourceCode.getLastToken(node); const lastToken = sourceCode.getLastToken(node);
let endIndent = getNodeIndent(lastToken, true); const endIndent = getNodeIndent(lastToken, true);
if (endIndent !== lastLineIndent && isNodeFirstInLine(node, true)) { if (endIndent !== lastLineIndent && isNodeFirstInLine(node, true)) {
report( report(
@ -318,7 +316,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkFirstNodeLineIndent(node, firstLineIndent) { function checkFirstNodeLineIndent(node, firstLineIndent) {
let startIndent = getNodeIndent(node, false); const startIndent = getNodeIndent(node, false);
if (startIndent !== firstLineIndent && isNodeFirstInLine(node)) { if (startIndent !== firstLineIndent && isNodeFirstInLine(node)) {
report( report(
@ -387,7 +385,7 @@ module.exports = {
* @returns {boolean} True if arguments are multi-line * @returns {boolean} True if arguments are multi-line
*/ */
function isArgBeforeCalleeNodeMultiline(node) { function isArgBeforeCalleeNodeMultiline(node) {
let parent = node.parent; const parent = node.parent;
if (parent.arguments.length >= 2 && parent.arguments[1] === node) { if (parent.arguments.length >= 2 && parent.arguments[1] === node) {
return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line; return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line;
@ -402,7 +400,7 @@ module.exports = {
* @returns {boolean} True if the node is the outer IIFE * @returns {boolean} True if the node is the outer IIFE
*/ */
function isOuterIIFE(node) { function isOuterIIFE(node) {
let parent = node.parent; const parent = node.parent;
let stmt = parent.parent; let stmt = parent.parent;
/* /*
@ -459,7 +457,7 @@ module.exports = {
* *
* Looks for 'Models' * Looks for 'Models'
*/ */
let calleeNode = node.parent; // FunctionExpression const calleeNode = node.parent; // FunctionExpression
let indent; let indent;
if (calleeNode.parent && if (calleeNode.parent &&
@ -475,7 +473,7 @@ module.exports = {
} }
if (calleeNode.parent.type === "CallExpression") { if (calleeNode.parent.type === "CallExpression") {
let calleeParent = calleeNode.parent; const calleeParent = calleeNode.parent;
if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") { if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") {
if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) { if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) {
@ -500,7 +498,7 @@ module.exports = {
indent += functionOffset; indent += functionOffset;
// check if the node is inside a variable // check if the node is inside a variable
let parentVarNode = getVariableDeclaratorNode(node); const parentVarNode = getVariableDeclaratorNode(node);
if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) { if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) {
indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind]; indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
@ -520,7 +518,7 @@ module.exports = {
* @returns {boolean} Whether or not the block starts and ends on the same line. * @returns {boolean} Whether or not the block starts and ends on the same line.
*/ */
function isSingleLineNode(node) { function isSingleLineNode(node) {
let lastToken = sourceCode.getLastToken(node), const lastToken = sourceCode.getLastToken(node),
startLine = node.loc.start.line, startLine = node.loc.start.line,
endLine = lastToken.loc.end.line; endLine = lastToken.loc.end.line;
@ -567,11 +565,11 @@ module.exports = {
let nodeIndent; let nodeIndent;
let elementsIndent; let elementsIndent;
let parentVarNode = getVariableDeclaratorNode(node); const parentVarNode = getVariableDeclaratorNode(node);
// TODO - come up with a better strategy in future // TODO - come up with a better strategy in future
if (isNodeFirstInLine(node)) { if (isNodeFirstInLine(node)) {
let parent = node.parent; const parent = node.parent;
let effectiveParent = parent; let effectiveParent = parent;
if (parent.type === "MemberExpression") { if (parent.type === "MemberExpression") {
@ -668,7 +666,7 @@ module.exports = {
* For this statements we should check indent from statement beginning, * For this statements we should check indent from statement beginning,
* not from the beginning of the block. * not from the beginning of the block.
*/ */
let statementsWithProperties = [ const statementsWithProperties = [
"IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration" "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration"
]; ];
@ -680,7 +678,7 @@ module.exports = {
if (node.type === "IfStatement" && node.consequent.type !== "BlockStatement") { if (node.type === "IfStatement" && node.consequent.type !== "BlockStatement") {
nodesToCheck = [node.consequent]; nodesToCheck = [node.consequent];
} else if (util.isArray(node.body)) { } else if (Array.isArray(node.body)) {
nodesToCheck = node.body; nodesToCheck = node.body;
} else { } else {
nodesToCheck = [node.body]; nodesToCheck = [node.body];
@ -703,7 +701,7 @@ module.exports = {
*/ */
function filterOutSameLineVars(node) { function filterOutSameLineVars(node) {
return node.declarations.reduce(function(finalCollection, elem) { return node.declarations.reduce(function(finalCollection, elem) {
let lastElem = finalCollection[finalCollection.length - 1]; const lastElem = finalCollection[finalCollection.length - 1];
if ((elem.loc.start.line !== node.loc.start.line && !lastElem) || if ((elem.loc.start.line !== node.loc.start.line && !lastElem) ||
(lastElem && lastElem.loc.start.line !== elem.loc.start.line)) { (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) {
@ -720,11 +718,11 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkIndentInVariableDeclarations(node) { function checkIndentInVariableDeclarations(node) {
let elements = filterOutSameLineVars(node); const elements = filterOutSameLineVars(node);
let nodeIndent = getNodeIndent(node); const nodeIndent = getNodeIndent(node);
let lastElement = elements[elements.length - 1]; const lastElement = elements[elements.length - 1];
let elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind]; const elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind];
// Comma can be placed before declaration // Comma can be placed before declaration
checkNodesIndent(elements, elementsIndent, true); checkNodesIndent(elements, elementsIndent, true);
@ -734,7 +732,7 @@ module.exports = {
return; return;
} }
let tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement); const tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement);
if (tokenBeforeLastElement.value === ",") { if (tokenBeforeLastElement.value === ",") {
@ -764,7 +762,7 @@ module.exports = {
* @returns {int} indent size * @returns {int} indent size
*/ */
function expectedCaseIndent(node, switchIndent) { function expectedCaseIndent(node, switchIndent) {
let switchNode = (node.type === "SwitchStatement") ? node : node.parent; const switchNode = (node.type === "SwitchStatement") ? node : node.parent;
let caseIndent; let caseIndent;
if (caseIndentStore[switchNode.loc.start.line]) { if (caseIndentStore[switchNode.loc.start.line]) {
@ -849,11 +847,11 @@ module.exports = {
return; return;
} }
let propertyIndent = getNodeIndent(node) + indentSize * options.MemberExpression; const propertyIndent = getNodeIndent(node) + indentSize * options.MemberExpression;
let checkNodes = [node.property]; const checkNodes = [node.property];
let dot = context.getTokenBefore(node.property); const dot = context.getTokenBefore(node.property);
if (dot.type === "Punctuator" && dot.value === ".") { if (dot.type === "Punctuator" && dot.value === ".") {
checkNodes.push(dot); checkNodes.push(dot);
@ -865,8 +863,8 @@ module.exports = {
SwitchStatement: function(node) { SwitchStatement: function(node) {
// Switch is not a 'BlockStatement' // Switch is not a 'BlockStatement'
let switchIndent = getNodeIndent(node); const switchIndent = getNodeIndent(node);
let caseIndent = expectedCaseIndent(node, switchIndent); const caseIndent = expectedCaseIndent(node, switchIndent);
checkNodesIndent(node.cases, caseIndent); checkNodesIndent(node.cases, caseIndent);
@ -880,7 +878,7 @@ module.exports = {
if (isSingleLineNode(node)) { if (isSingleLineNode(node)) {
return; return;
} }
let caseIndent = expectedCaseIndent(node); const caseIndent = expectedCaseIndent(node);
checkNodesIndent(node.consequent, caseIndent + indentSize); checkNodesIndent(node.consequent, caseIndent + indentSize);
} }

14
tools/eslint/lib/rules/init-declarations.js

@ -26,8 +26,8 @@ function isForLoop(block) {
* @returns {boolean} `true` when the node has its initializer. * @returns {boolean} `true` when the node has its initializer.
*/ */
function isInitialized(node) { function isInitialized(node) {
let declaration = node.parent; const declaration = node.parent;
let block = declaration.parent; const block = declaration.parent;
if (isForLoop(block)) { if (isForLoop(block)) {
if (block.type === "ForStatement") { if (block.type === "ForStatement") {
@ -87,11 +87,11 @@ module.exports = {
create: function(context) { create: function(context) {
let MODE_ALWAYS = "always", const MODE_ALWAYS = "always",
MODE_NEVER = "never"; MODE_NEVER = "never";
let mode = context.options[0] || MODE_ALWAYS; const mode = context.options[0] || MODE_ALWAYS;
let params = context.options[1] || {}; const params = context.options[1] || {};
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Public API // Public API
@ -100,11 +100,11 @@ module.exports = {
return { return {
"VariableDeclaration:exit": function(node) { "VariableDeclaration:exit": function(node) {
let kind = node.kind, const kind = node.kind,
declarations = node.declarations; declarations = node.declarations;
for (let i = 0; i < declarations.length; ++i) { for (let i = 0; i < declarations.length; ++i) {
let declaration = declarations[i], const declaration = declarations[i],
id = declaration.id, id = declaration.id,
initialized = isInitialized(declaration), initialized = isInitialized(declaration),
isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent);

8
tools/eslint/lib/rules/jsx-quotes.js

@ -9,13 +9,13 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let QUOTE_SETTINGS = { const QUOTE_SETTINGS = {
"prefer-double": { "prefer-double": {
quote: "\"", quote: "\"",
description: "singlequote", description: "singlequote",
@ -54,7 +54,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let quoteOption = context.options[0] || "prefer-double", const quoteOption = context.options[0] || "prefer-double",
setting = QUOTE_SETTINGS[quoteOption]; setting = QUOTE_SETTINGS[quoteOption];
/** /**
@ -69,7 +69,7 @@ module.exports = {
return { return {
JSXAttribute: function(node) { JSXAttribute: function(node) {
let attributeValue = node.value; const attributeValue = node.value;
if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) { if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) {
context.report({ context.report({

56
tools/eslint/lib/rules/key-spacing.js

@ -34,9 +34,8 @@ function last(arr) {
* @returns {boolean} True if the candidate property is part of the group. * @returns {boolean} True if the candidate property is part of the group.
*/ */
function continuesPropertyGroup(lastMember, candidate) { function continuesPropertyGroup(lastMember, candidate) {
let groupEndLine = lastMember.loc.start.line, const groupEndLine = lastMember.loc.start.line,
candidateStartLine = candidate.loc.start.line, candidateStartLine = candidate.loc.start.line;
comments, i;
if (candidateStartLine - groupEndLine <= 1) { if (candidateStartLine - groupEndLine <= 1) {
return true; return true;
@ -45,13 +44,14 @@ function continuesPropertyGroup(lastMember, candidate) {
// Check that the first comment is adjacent to the end of the group, the // Check that the first comment is adjacent to the end of the group, the
// last comment is adjacent to the candidate property, and that successive // last comment is adjacent to the candidate property, and that successive
// comments are adjacent to each other. // comments are adjacent to each other.
comments = candidate.leadingComments; const comments = candidate.leadingComments;
if ( if (
comments && comments &&
comments[0].loc.start.line - groupEndLine <= 1 && comments[0].loc.start.line - groupEndLine <= 1 &&
candidateStartLine - last(comments).loc.end.line <= 1 candidateStartLine - last(comments).loc.end.line <= 1
) { ) {
for (i = 1; i < comments.length; i++) { for (let i = 1; i < comments.length; i++) {
if (comments[i].loc.start.line - comments[i - 1].loc.end.line > 1) { if (comments[i].loc.start.line - comments[i - 1].loc.end.line > 1) {
return false; return false;
} }
@ -150,7 +150,7 @@ function initOptions(toOptions, fromOptions) {
// Rule Definition // Rule Definition
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let messages = { const messages = {
key: "{{error}} space after {{computed}}key '{{key}}'.", key: "{{error}} space after {{computed}}key '{{key}}'.",
value: "{{error}} space before value for {{computed}}key '{{key}}'." value: "{{error}} space before value for {{computed}}key '{{key}}'."
}; };
@ -333,13 +333,13 @@ module.exports = {
* align: "colon" // Optional, or "value" * align: "colon" // Optional, or "value"
* } * }
*/ */
let options = context.options[0] || {}, const options = context.options[0] || {},
ruleOptions = initOptions({}, options), ruleOptions = initOptions({}, options),
multiLineOptions = ruleOptions.multiLine, multiLineOptions = ruleOptions.multiLine,
singleLineOptions = ruleOptions.singleLine, singleLineOptions = ruleOptions.singleLine,
alignmentOptions = ruleOptions.align || null; alignmentOptions = ruleOptions.align || null;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Determines if the given property is key-value property. * Determines if the given property is key-value property.
@ -392,7 +392,7 @@ module.exports = {
* @returns {string} The property's key. * @returns {string} The property's key.
*/ */
function getKey(property) { function getKey(property) {
let key = property.key; const key = property.key;
if (property.computed) { if (property.computed) {
return sourceCode.getText().slice(key.range[0], key.range[1]); return sourceCode.getText().slice(key.range[0], key.range[1]);
@ -412,7 +412,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function report(property, side, whitespace, expected, mode) { function report(property, side, whitespace, expected, mode) {
let diff = whitespace.length - expected, const diff = whitespace.length - expected,
nextColon = getNextColon(property.key), nextColon = getNextColon(property.key),
tokenBeforeColon = sourceCode.getTokenBefore(nextColon), tokenBeforeColon = sourceCode.getTokenBefore(nextColon),
tokenAfterColon = sourceCode.getTokenAfter(nextColon), tokenAfterColon = sourceCode.getTokenAfter(nextColon),
@ -420,9 +420,8 @@ module.exports = {
locStart = isKeySide ? tokenBeforeColon.loc.start : tokenAfterColon.loc.start, locStart = isKeySide ? tokenBeforeColon.loc.start : tokenAfterColon.loc.start,
isExtra = diff > 0, isExtra = diff > 0,
diffAbs = Math.abs(diff), diffAbs = Math.abs(diff),
spaces = Array(diffAbs + 1).join(" "), spaces = Array(diffAbs + 1).join(" ");
fix, let fix;
range;
if (( if ((
diff && mode === "strict" || diff && mode === "strict" ||
@ -431,6 +430,7 @@ module.exports = {
!(expected && containsLineTerminator(whitespace)) !(expected && containsLineTerminator(whitespace))
) { ) {
if (isExtra) { if (isExtra) {
let range;
// Remove whitespace // Remove whitespace
if (isKeySide) { if (isKeySide) {
@ -476,10 +476,8 @@ module.exports = {
* @returns {int} Width of the key. * @returns {int} Width of the key.
*/ */
function getKeyWidth(property) { function getKeyWidth(property) {
let startToken, endToken; const startToken = sourceCode.getFirstToken(property);
const endToken = getLastTokenBeforeColon(property.key);
startToken = sourceCode.getFirstToken(property);
endToken = getLastTokenBeforeColon(property.key);
return endToken.range[1] - startToken.range[0]; return endToken.range[1] - startToken.range[0];
} }
@ -490,7 +488,7 @@ module.exports = {
* @returns {Object} Whitespace before and after the property's colon. * @returns {Object} Whitespace before and after the property's colon.
*/ */
function getPropertyWhitespace(property) { function getPropertyWhitespace(property) {
let whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice( const whitespace = /(\s*):(\s*)/.exec(sourceCode.getText().slice(
property.key.range[1], property.value.range[0] property.key.range[1], property.value.range[0]
)); ));
@ -514,7 +512,7 @@ module.exports = {
} }
return node.properties.reduce(function(groups, property) { return node.properties.reduce(function(groups, property) {
let currentGroup = last(groups), const currentGroup = last(groups),
prev = last(currentGroup); prev = last(currentGroup);
if (!prev || continuesPropertyGroup(prev, property)) { if (!prev || continuesPropertyGroup(prev, property)) {
@ -535,11 +533,10 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function verifyGroupAlignment(properties) { function verifyGroupAlignment(properties) {
let length = properties.length, const length = properties.length,
widths = properties.map(getKeyWidth), // Width of keys, including quotes widths = properties.map(getKeyWidth), // Width of keys, including quotes
targetWidth = Math.max.apply(null, widths), align = alignmentOptions.on; // "value" or "colon"
align = alignmentOptions.on, // "value" or "colon" let targetWidth = Math.max.apply(null, widths),
i, property, whitespace, width,
beforeColon, afterColon, mode; beforeColon, afterColon, mode;
if (alignmentOptions && length > 1) { // When aligning values within a group, use the alignment configuration. if (alignmentOptions && length > 1) { // When aligning values within a group, use the alignment configuration.
@ -555,11 +552,12 @@ module.exports = {
// Conditionally include one space before or after colon // Conditionally include one space before or after colon
targetWidth += (align === "colon" ? beforeColon : afterColon); targetWidth += (align === "colon" ? beforeColon : afterColon);
for (i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
property = properties[i]; const property = properties[i];
whitespace = getPropertyWhitespace(property); const whitespace = getPropertyWhitespace(property);
if (whitespace) { // Object literal getters/setters lack a colon if (whitespace) { // Object literal getters/setters lack a colon
width = widths[i]; const width = widths[i];
if (align === "value") { if (align === "value") {
report(property, "key", whitespace.beforeColon, beforeColon, mode); report(property, "key", whitespace.beforeColon, beforeColon, mode);
@ -590,7 +588,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function verifySpacing(node, lineOptions) { function verifySpacing(node, lineOptions) {
let actual = getPropertyWhitespace(node); const actual = getPropertyWhitespace(node);
if (actual) { // Object literal getters/setters lack colons if (actual) { // Object literal getters/setters lack colons
report(node, "key", actual.beforeColon, lineOptions.beforeColon, lineOptions.mode); report(node, "key", actual.beforeColon, lineOptions.beforeColon, lineOptions.mode);
@ -604,7 +602,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function verifyListSpacing(properties) { function verifyListSpacing(properties) {
let length = properties.length; const length = properties.length;
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
verifySpacing(properties[i], singleLineOptions); verifySpacing(properties[i], singleLineOptions);

60
tools/eslint/lib/rules/keyword-spacing.js

@ -9,21 +9,21 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let astUtils = require("../ast-utils"), const astUtils = require("../ast-utils"),
keywords = require("../util/keywords"); keywords = require("../util/keywords");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let PREV_TOKEN = /^[\)\]\}>]$/; const PREV_TOKEN = /^[\)\]\}>]$/;
let NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/; const NEXT_TOKEN = /^(?:[\(\[\{<~!]|\+\+?|--?)$/;
let PREV_TOKEN_M = /^[\)\]\}>*]$/; const PREV_TOKEN_M = /^[\)\]\}>*]$/;
let NEXT_TOKEN_M = /^[\{*]$/; const NEXT_TOKEN_M = /^[\{*]$/;
let TEMPLATE_OPEN_PAREN = /\$\{$/; const TEMPLATE_OPEN_PAREN = /\$\{$/;
let TEMPLATE_CLOSE_PAREN = /^\}/; const TEMPLATE_CLOSE_PAREN = /^\}/;
let CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/; const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template)$/;
let KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]); const KEYS = keywords.concat(["as", "await", "from", "get", "let", "of", "set", "yield"]);
// check duplications. // check duplications.
(function() { (function() {
@ -101,7 +101,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Reports a given token if there are not space(s) before the token. * Reports a given token if there are not space(s) before the token.
@ -114,7 +114,7 @@ module.exports = {
function expectSpaceBefore(token, pattern) { function expectSpaceBefore(token, pattern) {
pattern = pattern || PREV_TOKEN; pattern = pattern || PREV_TOKEN;
let prevToken = sourceCode.getTokenBefore(token); const prevToken = sourceCode.getTokenBefore(token);
if (prevToken && if (prevToken &&
(CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
@ -144,7 +144,7 @@ module.exports = {
function unexpectSpaceBefore(token, pattern) { function unexpectSpaceBefore(token, pattern) {
pattern = pattern || PREV_TOKEN; pattern = pattern || PREV_TOKEN;
let prevToken = sourceCode.getTokenBefore(token); const prevToken = sourceCode.getTokenBefore(token);
if (prevToken && if (prevToken &&
(CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
@ -174,7 +174,7 @@ module.exports = {
function expectSpaceAfter(token, pattern) { function expectSpaceAfter(token, pattern) {
pattern = pattern || NEXT_TOKEN; pattern = pattern || NEXT_TOKEN;
let nextToken = sourceCode.getTokenAfter(token); const nextToken = sourceCode.getTokenAfter(token);
if (nextToken && if (nextToken &&
(CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
@ -204,7 +204,7 @@ module.exports = {
function unexpectSpaceAfter(token, pattern) { function unexpectSpaceAfter(token, pattern) {
pattern = pattern || NEXT_TOKEN; pattern = pattern || NEXT_TOKEN;
let nextToken = sourceCode.getTokenAfter(token); const nextToken = sourceCode.getTokenAfter(token);
if (nextToken && if (nextToken &&
(CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
@ -232,22 +232,22 @@ module.exports = {
* Values are instances of `{"before": function, "after": function}`. * Values are instances of `{"before": function, "after": function}`.
*/ */
function parseOptions(options) { function parseOptions(options) {
let before = !options || options.before !== false; const before = !options || options.before !== false;
let after = !options || options.after !== false; const after = !options || options.after !== false;
let defaultValue = { const defaultValue = {
before: before ? expectSpaceBefore : unexpectSpaceBefore, before: before ? expectSpaceBefore : unexpectSpaceBefore,
after: after ? expectSpaceAfter : unexpectSpaceAfter after: after ? expectSpaceAfter : unexpectSpaceAfter
}; };
let overrides = (options && options.overrides) || {}; const overrides = (options && options.overrides) || {};
let retv = Object.create(null); const retv = Object.create(null);
for (let i = 0; i < KEYS.length; ++i) { for (let i = 0; i < KEYS.length; ++i) {
let key = KEYS[i]; const key = KEYS[i];
let override = overrides[key]; const override = overrides[key];
if (override) { if (override) {
let thisBefore = ("before" in override) ? override.before : before; const thisBefore = ("before" in override) ? override.before : before;
let thisAfter = ("after" in override) ? override.after : after; const thisAfter = ("after" in override) ? override.after : after;
retv[key] = { retv[key] = {
before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore, before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore,
@ -261,7 +261,7 @@ module.exports = {
return retv; return retv;
} }
let checkMethodMap = parseOptions(context.options[0]); const checkMethodMap = parseOptions(context.options[0]);
/** /**
* Reports a given token if usage of spacing followed by the token is * Reports a given token if usage of spacing followed by the token is
@ -308,7 +308,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkSpacingAroundFirstToken(node) { function checkSpacingAroundFirstToken(node) {
let firstToken = node && sourceCode.getFirstToken(node); const firstToken = node && sourceCode.getFirstToken(node);
if (firstToken && firstToken.type === "Keyword") { if (firstToken && firstToken.type === "Keyword") {
checkSpacingAround(firstToken); checkSpacingAround(firstToken);
@ -326,7 +326,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkSpacingBeforeFirstToken(node) { function checkSpacingBeforeFirstToken(node) {
let firstToken = node && sourceCode.getFirstToken(node); const firstToken = node && sourceCode.getFirstToken(node);
if (firstToken && firstToken.type === "Keyword") { if (firstToken && firstToken.type === "Keyword") {
checkSpacingBefore(firstToken); checkSpacingBefore(firstToken);
@ -445,13 +445,13 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkSpacingForModuleDeclaration(node) { function checkSpacingForModuleDeclaration(node) {
let firstToken = sourceCode.getFirstToken(node); const firstToken = sourceCode.getFirstToken(node);
checkSpacingBefore(firstToken, PREV_TOKEN_M); checkSpacingBefore(firstToken, PREV_TOKEN_M);
checkSpacingAfter(firstToken, NEXT_TOKEN_M); checkSpacingAfter(firstToken, NEXT_TOKEN_M);
if (node.source) { if (node.source) {
let fromToken = sourceCode.getTokenBefore(node.source); const fromToken = sourceCode.getTokenBefore(node.source);
checkSpacingBefore(fromToken, PREV_TOKEN_M); checkSpacingBefore(fromToken, PREV_TOKEN_M);
checkSpacingAfter(fromToken, NEXT_TOKEN_M); checkSpacingAfter(fromToken, NEXT_TOKEN_M);
@ -466,7 +466,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkSpacingForImportNamespaceSpecifier(node) { function checkSpacingForImportNamespaceSpecifier(node) {
let asToken = sourceCode.getFirstToken(node, 1); const asToken = sourceCode.getFirstToken(node, 1);
checkSpacingBefore(asToken, PREV_TOKEN_M); checkSpacingBefore(asToken, PREV_TOKEN_M);
} }
@ -483,7 +483,7 @@ module.exports = {
checkSpacingAroundFirstToken(node); checkSpacingAroundFirstToken(node);
} }
if (node.kind === "get" || node.kind === "set") { if (node.kind === "get" || node.kind === "set") {
let token = sourceCode.getFirstToken( const token = sourceCode.getFirstToken(
node, node,
node.static ? 1 : 0 node.static ? 1 : 0
); );

17
tools/eslint/lib/rules/linebreak-style.js

@ -28,10 +28,10 @@ module.exports = {
create: function(context) { create: function(context) {
let EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.", const EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.",
EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'."; EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'.";
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -56,14 +56,12 @@ module.exports = {
return { return {
Program: function checkForlinebreakStyle(node) { Program: function checkForlinebreakStyle(node) {
let linebreakStyle = context.options[0] || "unix", const linebreakStyle = context.options[0] || "unix",
expectedLF = linebreakStyle === "unix", expectedLF = linebreakStyle === "unix",
expectedLFChars = expectedLF ? "\n" : "\r\n", expectedLFChars = expectedLF ? "\n" : "\r\n",
source = sourceCode.getText(), source = sourceCode.getText(),
pattern = /\r\n|\r|\n|\u2028|\u2029/g, pattern = /\r\n|\r|\n|\u2028|\u2029/g;
match, let match;
index,
range;
let i = 0; let i = 0;
@ -73,8 +71,9 @@ module.exports = {
continue; continue;
} }
index = match.index; const index = match.index;
range = [index, index + match[0].length]; const range = [index, index + match[0].length];
context.report({ context.report({
node: node, node: node,
loc: { loc: {

36
tools/eslint/lib/rules/lines-around-comment.js

@ -8,7 +8,7 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"), const lodash = require("lodash"),
astUtils = require("../ast-utils"); astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -21,7 +21,7 @@ let lodash = require("lodash"),
* @returns {Array} An array of line numbers. * @returns {Array} An array of line numbers.
*/ */
function getEmptyLineNums(lines) { function getEmptyLineNums(lines) {
let emptyLines = lines.map(function(line, i) { const emptyLines = lines.map(function(line, i) {
return { return {
code: line.trim(), code: line.trim(),
num: i + 1 num: i + 1
@ -41,11 +41,11 @@ function getEmptyLineNums(lines) {
* @returns {Array} An array of line numbers. * @returns {Array} An array of line numbers.
*/ */
function getCommentLineNums(comments) { function getCommentLineNums(comments) {
let lines = []; const lines = [];
comments.forEach(function(token) { comments.forEach(function(token) {
let start = token.loc.start.line; const start = token.loc.start.line;
let end = token.loc.end.line; const end = token.loc.end.line;
lines.push(start, end); lines.push(start, end);
}); });
@ -108,7 +108,7 @@ module.exports = {
create: function(context) { create: function(context) {
let options = context.options[0] ? lodash.assign({}, context.options[0]) : {}; const options = context.options[0] ? Object.assign({}, context.options[0]) : {};
options.beforeLineComment = options.beforeLineComment || false; options.beforeLineComment = options.beforeLineComment || false;
options.afterLineComment = options.afterLineComment || false; options.afterLineComment = options.afterLineComment || false;
@ -117,9 +117,9 @@ module.exports = {
options.allowBlockStart = options.allowBlockStart || false; options.allowBlockStart = options.allowBlockStart || false;
options.allowBlockEnd = options.allowBlockEnd || false; options.allowBlockEnd = options.allowBlockEnd || false;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
let lines = sourceCode.lines, const lines = sourceCode.lines,
numLines = lines.length + 1, numLines = lines.length + 1,
comments = sourceCode.getAllComments(), comments = sourceCode.getAllComments(),
commentLines = getCommentLineNums(comments), commentLines = getCommentLineNums(comments),
@ -184,7 +184,7 @@ module.exports = {
* @returns {boolean} True if the comment is at parent start. * @returns {boolean} True if the comment is at parent start.
*/ */
function isCommentAtParentStart(node, nodeType) { function isCommentAtParentStart(node, nodeType) {
let ancestors = context.getAncestors(); const ancestors = context.getAncestors();
let parent; let parent;
if (ancestors.length) { if (ancestors.length) {
@ -202,7 +202,7 @@ module.exports = {
* @returns {boolean} True if the comment is at parent end. * @returns {boolean} True if the comment is at parent end.
*/ */
function isCommentAtParentEnd(node, nodeType) { function isCommentAtParentEnd(node, nodeType) {
let ancestors = context.getAncestors(); const ancestors = context.getAncestors();
let parent; let parent;
if (ancestors.length) { if (ancestors.length) {
@ -279,19 +279,19 @@ module.exports = {
let after = opts.after, let after = opts.after,
before = opts.before; before = opts.before;
let prevLineNum = node.loc.start.line - 1, const prevLineNum = node.loc.start.line - 1,
nextLineNum = node.loc.end.line + 1, nextLineNum = node.loc.end.line + 1,
commentIsNotAlone = codeAroundComment(node); commentIsNotAlone = codeAroundComment(node);
let blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node), const blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(node),
blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node), blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(node),
objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node), objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(node),
objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node), objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(node),
arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node), arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(node),
arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node); arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(node);
let exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed; const exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed;
let exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed; const exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed;
// ignore top of the file and bottom of the file // ignore top of the file and bottom of the file
if (prevLineNum < 1) { if (prevLineNum < 1) {
@ -306,14 +306,14 @@ module.exports = {
return; return;
} }
let previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node); const previousTokenOrComment = sourceCode.getTokenOrCommentBefore(node);
let nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node); const nextTokenOrComment = sourceCode.getTokenOrCommentAfter(node);
// check for newline before // check for newline before
if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) && if (!exceptionStartAllowed && before && !lodash.includes(commentAndEmptyLines, prevLineNum) &&
!(isCommentNodeType(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, node))) { !(isCommentNodeType(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, node))) {
let lineStart = node.range[0] - node.loc.start.column; const lineStart = node.range[0] - node.loc.start.column;
let range = [lineStart, lineStart]; const range = [lineStart, lineStart];
context.report({ context.report({
node: node, node: node,

8
tools/eslint/lib/rules/max-depth.js

@ -49,9 +49,9 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let functionStack = [], const functionStack = [],
option = context.options[0], option = context.options[0];
maxDepth = 4; let maxDepth = 4;
if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
maxDepth = option.maximum; maxDepth = option.maximum;
@ -88,7 +88,7 @@ module.exports = {
* @private * @private
*/ */
function pushBlock(node) { function pushBlock(node) {
let len = ++functionStack[functionStack.length - 1]; const len = ++functionStack[functionStack.length - 1];
if (len > maxDepth) { if (len > maxDepth) {
context.report(node, "Blocks are nested too deeply ({{depth}}).", context.report(node, "Blocks are nested too deeply ({{depth}}).",

30
tools/eslint/lib/rules/max-len.js

@ -9,7 +9,7 @@
// Constants // Constants
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let OPTIONS_SCHEMA = { const OPTIONS_SCHEMA = {
type: "object", type: "object",
properties: { properties: {
code: { code: {
@ -40,7 +40,7 @@ let OPTIONS_SCHEMA = {
additionalProperties: false additionalProperties: false
}; };
let OPTIONS_OR_INTEGER_SCHEMA = { const OPTIONS_OR_INTEGER_SCHEMA = {
anyOf: [ anyOf: [
OPTIONS_SCHEMA, OPTIONS_SCHEMA,
{ {
@ -79,9 +79,9 @@ module.exports = {
* too many false positives * too many false positives
* - We don't care about matching the entire URL, any small segment is fine * - We don't care about matching the entire URL, any small segment is fine
*/ */
let URL_REGEXP = /[^:/?#]:\/\/[^?#]/; const URL_REGEXP = /[^:/?#]:\/\/[^?#]/;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Computes the length of a line that may contain tabs. The width of each * Computes the length of a line that may contain tabs. The width of each
@ -95,7 +95,7 @@ module.exports = {
let extraCharacterCount = 0; let extraCharacterCount = 0;
line.replace(/\t/g, function(match, offset) { line.replace(/\t/g, function(match, offset) {
let totalOffset = offset + extraCharacterCount, const totalOffset = offset + extraCharacterCount,
previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0, previousTabStopOffset = tabWidth ? totalOffset % tabWidth : 0,
spaceCount = tabWidth - previousTabStopOffset; spaceCount = tabWidth - previousTabStopOffset;
@ -105,8 +105,8 @@ module.exports = {
} }
// The options object must be the last option specified… // The options object must be the last option specified…
let lastOption = context.options[context.options.length - 1]; const lastOption = context.options[context.options.length - 1];
let options = typeof lastOption === "object" ? Object.create(lastOption) : {}; const options = typeof lastOption === "object" ? Object.create(lastOption) : {};
// …but max code length… // …but max code length…
if (typeof context.options[0] === "number") { if (typeof context.options[0] === "number") {
@ -118,13 +118,13 @@ module.exports = {
options.tabWidth = context.options[1]; options.tabWidth = context.options[1];
} }
let maxLength = options.code || 80, const maxLength = options.code || 80,
tabWidth = options.tabWidth || 4, tabWidth = options.tabWidth || 4,
ignorePattern = options.ignorePattern || null,
ignoreComments = options.ignoreComments || false, ignoreComments = options.ignoreComments || false,
ignoreTrailingComments = options.ignoreTrailingComments || options.ignoreComments || false, ignoreTrailingComments = options.ignoreTrailingComments || options.ignoreComments || false,
ignoreUrls = options.ignoreUrls || false, ignoreUrls = options.ignoreUrls || false,
maxCommentLength = options.comments; maxCommentLength = options.comments;
let ignorePattern = options.ignorePattern || null;
if (ignorePattern) { if (ignorePattern) {
ignorePattern = new RegExp(ignorePattern); ignorePattern = new RegExp(ignorePattern);
@ -156,7 +156,7 @@ module.exports = {
* @returns {boolean} If the comment covers the entire line * @returns {boolean} If the comment covers the entire line
*/ */
function isFullLineComment(line, lineNumber, comment) { function isFullLineComment(line, lineNumber, comment) {
let start = comment.loc.start, const start = comment.loc.start,
end = comment.loc.end, end = comment.loc.end,
isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim(); isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim();
@ -188,18 +188,18 @@ module.exports = {
function checkProgramForMaxLength(node) { function checkProgramForMaxLength(node) {
// split (honors line-ending) // split (honors line-ending)
let lines = sourceCode.lines, const lines = sourceCode.lines,
// list of comments to ignore // list of comments to ignore
comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [], comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [];
// we iterate over comments in parallel with the lines // we iterate over comments in parallel with the lines
commentsIndex = 0; let commentsIndex = 0;
lines.forEach(function(line, i) { lines.forEach(function(line, i) {
// i is zero-indexed, line numbers are one-indexed // i is zero-indexed, line numbers are one-indexed
let lineNumber = i + 1; const lineNumber = i + 1;
/* /*
* if we're checking comment length; we need to know whether this * if we're checking comment length; we need to know whether this
@ -235,7 +235,7 @@ module.exports = {
return; return;
} }
let lineLength = computeLineLength(line, tabWidth); const lineLength = computeLineLength(line, tabWidth);
if (lineIsComment && ignoreComments) { if (lineIsComment && ignoreComments) {
return; return;

24
tools/eslint/lib/rules/max-lines.js

@ -8,8 +8,8 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash"); const lodash = require("lodash");
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -52,8 +52,8 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let option = context.options[0], const option = context.options[0];
max = 300; let max = 300;
if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") { if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
max = option.max; max = option.max;
@ -63,10 +63,10 @@ module.exports = {
max = option; max = option;
} }
let skipComments = option && option.skipComments; const skipComments = option && option.skipComments;
let skipBlankLines = option && option.skipBlankLines; const skipBlankLines = option && option.skipBlankLines;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Returns whether or not a token is a comment node type * Returns whether or not a token is a comment node type
@ -125,9 +125,9 @@ module.exports = {
} }
if (skipComments) { if (skipComments) {
let comments = sourceCode.getAllComments(); const comments = sourceCode.getAllComments();
let commentLines = lodash.flatten(comments.map(function(comment) { const commentLines = lodash.flatten(comments.map(function(comment) {
return getLinesWithoutCode(comment); return getLinesWithoutCode(comment);
})); }));
@ -139,7 +139,11 @@ module.exports = {
if (lines.length > max) { if (lines.length > max) {
context.report({ context.report({
loc: { line: 1, column: 0 }, loc: { line: 1, column: 0 },
message: "File must be at most " + max + " lines long." message: "File must be at most {{max}} lines long. It's {{actual}} lines long.",
data: {
max,
actual: lines.length,
}
}); });
} }
} }

10
tools/eslint/lib/rules/max-nested-callbacks.js

@ -48,8 +48,8 @@ module.exports = {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Constants // Constants
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let option = context.options[0], const option = context.options[0];
THRESHOLD = 10; let THRESHOLD = 10;
if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
THRESHOLD = option.maximum; THRESHOLD = option.maximum;
@ -65,7 +65,7 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let callbackStack = []; const callbackStack = [];
/** /**
* Checks a given function node for too many callbacks. * Checks a given function node for too many callbacks.
@ -74,14 +74,14 @@ module.exports = {
* @private * @private
*/ */
function checkFunction(node) { function checkFunction(node) {
let parent = node.parent; const parent = node.parent;
if (parent.type === "CallExpression") { if (parent.type === "CallExpression") {
callbackStack.push(node); callbackStack.push(node);
} }
if (callbackStack.length > THRESHOLD) { if (callbackStack.length > THRESHOLD) {
let opts = {num: callbackStack.length, max: THRESHOLD}; const opts = {num: callbackStack.length, max: THRESHOLD};
context.report(node, "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", opts); context.report(node, "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.", opts);
} }

4
tools/eslint/lib/rules/max-params.js

@ -45,8 +45,8 @@ module.exports = {
create: function(context) { create: function(context) {
let option = context.options[0], const option = context.options[0];
numParams = 3; let numParams = 3;
if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
numParams = option.maximum; numParams = option.maximum;

12
tools/eslint/lib/rules/max-statements-per-line.js

@ -32,18 +32,18 @@ module.exports = {
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(), const sourceCode = context.getSourceCode(),
options = context.options[0] || {}, options = context.options[0] || {},
lastStatementLine = 0,
numberOfStatementsOnThisLine = 0,
maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1, maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1,
message = "This line has too many statements. Maximum allowed is " + maxStatementsPerLine + "."; message = "This line has too many statements. Maximum allowed is " + maxStatementsPerLine + ".";
let lastStatementLine = 0,
numberOfStatementsOnThisLine = 0;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/; const SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/;
/** /**
* Gets the actual last token of a given node. * Gets the actual last token of a given node.
@ -68,7 +68,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function enterStatement(node) { function enterStatement(node) {
let line = node.loc.start.line; const line = node.loc.start.line;
// Skip to allow non-block statements if this is direct child of control statements. // Skip to allow non-block statements if this is direct child of control statements.
// `if (a) foo();` is counted as 1. // `if (a) foo();` is counted as 1.
@ -100,7 +100,7 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function leaveStatement(node) { function leaveStatement(node) {
let line = getActualLastToken(node).loc.end.line; const line = getActualLastToken(node).loc.end.line;
// Update state. // Update state.
if (line !== lastStatementLine) { if (line !== lastStatementLine) {

10
tools/eslint/lib/rules/max-statements.js

@ -58,11 +58,11 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
let functionStack = [], const functionStack = [],
option = context.options[0], option = context.options[0],
maxStatements = 10,
ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false, ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false,
topLevelFunctions = []; topLevelFunctions = [];
let maxStatements = 10;
if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") { if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
maxStatements = option.maximum; maxStatements = option.maximum;
@ -107,7 +107,7 @@ module.exports = {
* @private * @private
*/ */
function endFunction(node) { function endFunction(node) {
let count = functionStack.pop(); const count = functionStack.pop();
if (ignoreTopLevelFunctions && functionStack.length === 0) { if (ignoreTopLevelFunctions && functionStack.length === 0) {
topLevelFunctions.push({ node: node, count: count}); topLevelFunctions.push({ node: node, count: count});
@ -147,8 +147,8 @@ module.exports = {
} }
topLevelFunctions.forEach(function(element) { topLevelFunctions.forEach(function(element) {
let count = element.count; const count = element.count;
let node = element.node; const node = element.node;
reportIfTooManyStatements(node, count, maxStatements); reportIfTooManyStatements(node, count, maxStatements);
}); });

6
tools/eslint/lib/rules/multiline-ternary.js

@ -5,7 +5,7 @@
"use strict"; "use strict";
let astUtils = require("../ast-utils"); const astUtils = require("../ast-utils");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Rule Definition // Rule Definition
@ -50,8 +50,8 @@ module.exports = {
return { return {
ConditionalExpression: function(node) { ConditionalExpression: function(node) {
let areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent); const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(node.test, node.consequent);
let areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate); const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(node.consequent, node.alternate);
if (areTestAndConsequentOnSameLine) { if (areTestAndConsequentOnSameLine) {
reportError(node.test, node); reportError(node.test, node);

58
tools/eslint/lib/rules/new-cap.js

@ -9,13 +9,11 @@
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let lodash = require("lodash");
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
let CAPS_ALLOWED = [ const CAPS_ALLOWED = [
"Array", "Array",
"Boolean", "Boolean",
"Date", "Date",
@ -98,12 +96,18 @@ module.exports = {
type: "string" type: "string"
} }
}, },
newIsCapExceptionPattern: {
type: "string"
},
capIsNewExceptions: { capIsNewExceptions: {
type: "array", type: "array",
items: { items: {
type: "string" type: "string"
} }
}, },
capIsNewExceptionPattern: {
type: "string"
},
properties: { properties: {
type: "boolean" type: "boolean"
} }
@ -115,19 +119,21 @@ module.exports = {
create: function(context) { create: function(context) {
let config = context.options[0] ? lodash.assign({}, context.options[0]) : {}; const config = context.options[0] ? Object.assign({}, context.options[0]) : {};
config.newIsCap = config.newIsCap !== false; config.newIsCap = config.newIsCap !== false;
config.capIsNew = config.capIsNew !== false; config.capIsNew = config.capIsNew !== false;
let skipProperties = config.properties === false; const skipProperties = config.properties === false;
let newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {}); const newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {});
const newIsCapExceptionPattern = config.newIsCapExceptionPattern ? new RegExp(config.newIsCapExceptionPattern) : null;
let capIsNewExceptions = calculateCapIsNewExceptions(config); const capIsNewExceptions = calculateCapIsNewExceptions(config);
const capIsNewExceptionPattern = config.capIsNewExceptionPattern ? new RegExp(config.capIsNewExceptionPattern) : null;
let listeners = {}; const listeners = {};
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -140,11 +146,10 @@ module.exports = {
*/ */
function extractNameFromExpression(node) { function extractNameFromExpression(node) {
let name = "", let name = "";
property;
if (node.callee.type === "MemberExpression") { if (node.callee.type === "MemberExpression") {
property = node.callee.property; const property = node.callee.property;
if (property.type === "Literal" && (typeof property.value === "string")) { if (property.type === "Literal" && (typeof property.value === "string")) {
name = property.value; name = property.value;
@ -164,10 +169,10 @@ module.exports = {
* @returns {string} capitalization state: "non-alpha", "lower", or "upper" * @returns {string} capitalization state: "non-alpha", "lower", or "upper"
*/ */
function getCap(str) { function getCap(str) {
let firstChar = str.charAt(0); const firstChar = str.charAt(0);
let firstCharLower = firstChar.toLowerCase(); const firstCharLower = firstChar.toLowerCase();
let firstCharUpper = firstChar.toUpperCase(); const firstCharUpper = firstChar.toUpperCase();
if (firstCharLower === firstCharUpper) { if (firstCharLower === firstCharUpper) {
@ -185,10 +190,17 @@ module.exports = {
* @param {Object} allowedMap Object mapping calleeName to a Boolean * @param {Object} allowedMap Object mapping calleeName to a Boolean
* @param {ASTNode} node CallExpression node * @param {ASTNode} node CallExpression node
* @param {string} calleeName Capitalized callee name from a CallExpression * @param {string} calleeName Capitalized callee name from a CallExpression
* @param {Object} pattern RegExp object from options pattern
* @returns {boolean} Returns true if the callee may be capitalized * @returns {boolean} Returns true if the callee may be capitalized
*/ */
function isCapAllowed(allowedMap, node, calleeName) { function isCapAllowed(allowedMap, node, calleeName, pattern) {
if (allowedMap[calleeName] || allowedMap[sourceCode.getText(node.callee)]) { const sourceText = sourceCode.getText(node.callee);
if (allowedMap[calleeName] || allowedMap[sourceText]) {
return true;
}
if (pattern && pattern.test(sourceText)) {
return true; return true;
} }
@ -225,11 +237,11 @@ module.exports = {
if (config.newIsCap) { if (config.newIsCap) {
listeners.NewExpression = function(node) { listeners.NewExpression = function(node) {
let constructorName = extractNameFromExpression(node); const constructorName = extractNameFromExpression(node);
if (constructorName) { if (constructorName) {
let capitalization = getCap(constructorName); const capitalization = getCap(constructorName);
let isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName); const isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName, newIsCapExceptionPattern);
if (!isAllowed) { if (!isAllowed) {
report(node, "A constructor name should not start with a lowercase letter."); report(node, "A constructor name should not start with a lowercase letter.");
@ -241,11 +253,11 @@ module.exports = {
if (config.capIsNew) { if (config.capIsNew) {
listeners.CallExpression = function(node) { listeners.CallExpression = function(node) {
let calleeName = extractNameFromExpression(node); const calleeName = extractNameFromExpression(node);
if (calleeName) { if (calleeName) {
let capitalization = getCap(calleeName); const capitalization = getCap(calleeName);
let isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName); const isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName, capIsNewExceptionPattern);
if (!isAllowed) { if (!isAllowed) {
report(node, "A function with a name starting with an uppercase letter should only be used as a constructor."); report(node, "A function with a name starting with an uppercase letter should only be used as a constructor.");

6
tools/eslint/lib/rules/new-parens.js

@ -21,13 +21,13 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
return { return {
NewExpression: function(node) { NewExpression: function(node) {
let tokens = sourceCode.getTokens(node); const tokens = sourceCode.getTokens(node);
let prenticesTokens = tokens.filter(function(token) { const prenticesTokens = tokens.filter(function(token) {
return token.value === "(" || token.value === ")"; return token.value === "(" || token.value === ")";
}); });

53
tools/eslint/lib/rules/newline-after-var.js

@ -26,16 +26,16 @@ module.exports = {
create: function(context) { create: function(context) {
let ALWAYS_MESSAGE = "Expected blank line after variable declarations.", const ALWAYS_MESSAGE = "Expected blank line after variable declarations.",
NEVER_MESSAGE = "Unexpected blank line after variable declarations."; NEVER_MESSAGE = "Unexpected blank line after variable declarations.";
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
// Default `mode` to "always". // Default `mode` to "always".
let mode = context.options[0] === "never" ? "never" : "always"; const mode = context.options[0] === "never" ? "never" : "always";
// Cache starting and ending line numbers of comments for faster lookup // Cache starting and ending line numbers of comments for faster lookup
let commentEndLine = sourceCode.getAllComments().reduce(function(result, token) { const commentEndLine = sourceCode.getAllComments().reduce(function(result, token) {
result[token.loc.start.line] = token.loc.end.line; result[token.loc.start.line] = token.loc.end.line;
return result; return result;
}, {}); }, {});
@ -45,6 +45,37 @@ module.exports = {
// Helpers // Helpers
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
/**
* Gets a token from the given node to compare line to the next statement.
*
* In general, the token is the last token of the node. However, the token is the second last token if the following conditions satisfy.
*
* - The last token is semicolon.
* - The semicolon is on a different line from the previous token of the semicolon.
*
* This behavior would address semicolon-less style code. e.g.:
*
* var foo = 1
*
* ;(a || b).doSomething()
*
* @param {ASTNode} node - The node to get.
* @returns {Token} The token to compare line to the next statement.
*/
function getLastToken(node) {
const lastToken = sourceCode.getLastToken(node);
if (lastToken.type === "Punctuator" && lastToken.value === ";") {
const prevToken = sourceCode.getTokenBefore(lastToken);
if (prevToken.loc.end.line !== lastToken.loc.start.line) {
return prevToken;
}
}
return lastToken;
}
/** /**
* Determine if provided keyword is a variable declaration * Determine if provided keyword is a variable declaration
* @private * @private
@ -83,7 +114,7 @@ module.exports = {
* @returns {boolean} True if `node` is last of their parent block. * @returns {boolean} True if `node` is last of their parent block.
*/ */
function isLastNode(node) { function isLastNode(node) {
let token = sourceCode.getTokenAfter(node); const token = sourceCode.getTokenAfter(node);
return !token || (token.type === "Punctuator" && token.value === "}"); return !token || (token.type === "Punctuator" && token.value === "}");
} }
@ -95,7 +126,7 @@ module.exports = {
* @returns {boolean} True if `token` does not start immediately after a comment * @returns {boolean} True if `token` does not start immediately after a comment
*/ */
function hasBlankLineAfterComment(token, commentStartLine) { function hasBlankLineAfterComment(token, commentStartLine) {
let commentEnd = commentEndLine[commentStartLine]; const commentEnd = commentEndLine[commentStartLine];
// If there's another comment, repeat check for blank line // If there's another comment, repeat check for blank line
if (commentEndLine[commentEnd + 1]) { if (commentEndLine[commentEnd + 1]) {
@ -114,11 +145,9 @@ module.exports = {
* @returns {void} * @returns {void}
*/ */
function checkForBlankLine(node) { function checkForBlankLine(node) {
let lastToken = sourceCode.getLastToken(node), const lastToken = getLastToken(node),
nextToken = sourceCode.getTokenAfter(node), nextToken = sourceCode.getTokenAfter(node),
nextLineNum = lastToken.loc.end.line + 1, nextLineNum = lastToken.loc.end.line + 1;
noNextLineToken,
hasNextLineComment;
// Ignore if there is no following statement // Ignore if there is no following statement
if (!nextToken) { if (!nextToken) {
@ -147,8 +176,8 @@ module.exports = {
} }
// Next statement is not a `var`... // Next statement is not a `var`...
noNextLineToken = nextToken.loc.start.line > nextLineNum; const noNextLineToken = nextToken.loc.start.line > nextLineNum;
hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined"); const hasNextLineComment = (typeof commentEndLine[nextLineNum] !== "undefined");
if (mode === "never" && noNextLineToken && !hasNextLineComment) { if (mode === "never" && noNextLineToken && !hasNextLineComment) {
context.report(node, NEVER_MESSAGE, { identifier: node.name }); context.report(node, NEVER_MESSAGE, { identifier: node.name });

19
tools/eslint/lib/rules/newline-before-return.js

@ -20,7 +20,7 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Helpers // Helpers
@ -34,7 +34,7 @@ module.exports = {
* @private * @private
*/ */
function isPrecededByTokens(node, testTokens) { function isPrecededByTokens(node, testTokens) {
let tokenBefore = sourceCode.getTokenBefore(node); const tokenBefore = sourceCode.getTokenBefore(node);
return testTokens.some(function(token) { return testTokens.some(function(token) {
return tokenBefore.value === token; return tokenBefore.value === token;
@ -48,7 +48,7 @@ module.exports = {
* @private * @private
*/ */
function isFirstNode(node) { function isFirstNode(node) {
let parentType = node.parent.type; const parentType = node.parent.type;
if (node.parent.body) { if (node.parent.body) {
return Array.isArray(node.parent.body) return Array.isArray(node.parent.body)
@ -75,8 +75,8 @@ module.exports = {
* @private * @private
*/ */
function calcCommentLines(node, lineNumTokenBefore) { function calcCommentLines(node, lineNumTokenBefore) {
let comments = sourceCode.getComments(node).leading, const comments = sourceCode.getComments(node).leading;
numLinesComments = 0; let numLinesComments = 0;
if (!comments.length) { if (!comments.length) {
return numLinesComments; return numLinesComments;
@ -109,10 +109,9 @@ module.exports = {
* @private * @private
*/ */
function hasNewlineBefore(node) { function hasNewlineBefore(node) {
let tokenBefore = sourceCode.getTokenBefore(node), const tokenBefore = sourceCode.getTokenBefore(node),
lineNumNode = node.loc.start.line, lineNumNode = node.loc.start.line;
lineNumTokenBefore, let lineNumTokenBefore;
commentLines;
/** /**
* Global return (at the beginning of a script) is a special case. * Global return (at the beginning of a script) is a special case.
@ -128,7 +127,7 @@ module.exports = {
lineNumTokenBefore = 0; // global return at beginning of script lineNumTokenBefore = 0; // global return at beginning of script
} }
commentLines = calcCommentLines(node, lineNumTokenBefore); const commentLines = calcCommentLines(node, lineNumTokenBefore);
return (lineNumNode - lineNumTokenBefore - commentLines) > 1; return (lineNumNode - lineNumTokenBefore - commentLines) > 1;
} }

12
tools/eslint/lib/rules/newline-per-chained-call.js

@ -33,10 +33,10 @@ module.exports = {
create: function(context) { create: function(context) {
let options = context.options[0] || {}, const options = context.options[0] || {},
ignoreChainWithDepth = options.ignoreChainWithDepth || 2; ignoreChainWithDepth = options.ignoreChainWithDepth || 2;
let sourceCode = context.getSourceCode(); const sourceCode = context.getSourceCode();
/** /**
* Gets the property text of a given MemberExpression node. * Gets the property text of a given MemberExpression node.
@ -46,9 +46,9 @@ module.exports = {
* @returns {string} The property text of the node. * @returns {string} The property text of the node.
*/ */
function getPropertyText(node) { function getPropertyText(node) {
let prefix = node.computed ? "[" : "."; const prefix = node.computed ? "[" : ".";
let lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g); const lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g);
let suffix = node.computed && lines.length === 1 ? "]" : ""; const suffix = node.computed && lines.length === 1 ? "]" : "";
return prefix + lines[0] + suffix; return prefix + lines[0] + suffix;
} }
@ -59,7 +59,7 @@ module.exports = {
return; return;
} }
let callee = node.callee; const callee = node.callee;
let parent = callee.object; let parent = callee.object;
let depth = 1; let depth = 1;

33
tools/eslint/lib/rules/no-alert.js

@ -4,6 +4,12 @@
*/ */
"use strict"; "use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const getPropertyName = require("../ast-utils").getStaticPropertyName;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Helpers // Helpers
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -28,22 +34,6 @@ function report(context, node, identifierName) {
context.report(node, "Unexpected {{name}}.", { name: identifierName }); context.report(node, "Unexpected {{name}}.", { name: identifierName });
} }
/**
* Returns the property name of a MemberExpression.
* @param {ASTNode} memberExpressionNode The MemberExpression node.
* @returns {string|null} Returns the property name if available, null else.
*/
function getPropertyName(memberExpressionNode) {
if (memberExpressionNode.computed) {
if (memberExpressionNode.property.type === "Literal") {
return memberExpressionNode.property.value;
}
} else {
return memberExpressionNode.property.name;
}
return null;
}
/** /**
* Finds the escope reference in the given scope. * Finds the escope reference in the given scope.
* @param {Object} scope The scope to search. * @param {Object} scope The scope to search.
@ -51,7 +41,7 @@ function getPropertyName(memberExpressionNode) {
* @returns {Reference|null} Returns the found reference or null if none were found. * @returns {Reference|null} Returns the found reference or null if none were found.
*/ */
function findReference(scope, node) { function findReference(scope, node) {
let references = scope.references.filter(function(reference) { const references = scope.references.filter(function(reference) {
return reference.identifier.range[0] === node.range[0] && return reference.identifier.range[0] === node.range[0] &&
reference.identifier.range[1] === node.range[1]; reference.identifier.range[1] === node.range[1];
}); });
@ -70,7 +60,7 @@ function findReference(scope, node) {
* @returns {boolean} Whether or not the name is shadowed. * @returns {boolean} Whether or not the name is shadowed.
*/ */
function isShadowed(scope, globalScope, node) { function isShadowed(scope, globalScope, node) {
let reference = findReference(scope, node); const reference = findReference(scope, node);
return reference && reference.resolved && reference.resolved.defs.length > 0; return reference && reference.resolved && reference.resolved.defs.length > 0;
} }
@ -117,20 +107,19 @@ module.exports = {
}, },
CallExpression: function(node) { CallExpression: function(node) {
let callee = node.callee, const callee = node.callee,
identifierName,
currentScope = context.getScope(); currentScope = context.getScope();
// without window. // without window.
if (callee.type === "Identifier") { if (callee.type === "Identifier") {
identifierName = callee.name; const identifierName = callee.name;
if (!isShadowed(currentScope, globalScope, callee) && isProhibitedIdentifier(callee.name)) { if (!isShadowed(currentScope, globalScope, callee) && isProhibitedIdentifier(callee.name)) {
report(context, node, identifierName); report(context, node, identifierName);
} }
} else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, globalScope, callee.object)) { } else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, globalScope, callee.object)) {
identifierName = getPropertyName(callee); const identifierName = getPropertyName(callee);
if (isProhibitedIdentifier(identifierName)) { if (isProhibitedIdentifier(identifierName)) {
report(context, node, identifierName); report(context, node, identifierName);

8
tools/eslint/lib/rules/no-bitwise.js

@ -8,7 +8,7 @@
// //
// Set of bitwise operators. // Set of bitwise operators.
// //
let BITWISE_OPERATORS = [ const BITWISE_OPERATORS = [
"^", "|", "&", "<<", ">>", ">>>", "^", "|", "&", "<<", ">>", ">>>",
"^=", "|=", "&=", "<<=", ">>=", ">>>=", "^=", "|=", "&=", "<<=", ">>=", ">>>=",
"~" "~"
@ -47,9 +47,9 @@ module.exports = {
}, },
create: function(context) { create: function(context) {
let options = context.options[0] || {}; const options = context.options[0] || {};
let allowed = options.allow || []; const allowed = options.allow || [];
let int32Hint = options.int32Hint === true; const int32Hint = options.int32Hint === true;
/** /**
* Reports an unexpected use of a bitwise operator. * Reports an unexpected use of a bitwise operator.

2
tools/eslint/lib/rules/no-caller.js

@ -25,7 +25,7 @@ module.exports = {
return { return {
MemberExpression: function(node) { MemberExpression: function(node) {
let objectName = node.object.name, const objectName = node.object.name,
propertyName = node.property.name; propertyName = node.property.name;
if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) { if (objectName === "arguments" && !node.computed && propertyName && propertyName.match(/^calle[er]$/)) {

2
tools/eslint/lib/rules/no-case-declarations.js

@ -41,7 +41,7 @@ module.exports = {
return { return {
SwitchCase: function(node) { SwitchCase: function(node) {
for (let i = 0; i < node.consequent.length; i++) { for (let i = 0; i < node.consequent.length; i++) {
let statement = node.consequent[i]; const statement = node.consequent[i];
if (isLexicalDeclaration(statement)) { if (isLexicalDeclaration(statement)) {
context.report({ context.report({

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save