eslint 4.7.1 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +34 -19
  3. package/conf/default-cli-options.js +2 -1
  4. package/conf/eslint-recommended.js +2 -0
  5. package/lib/ast-utils.js +2 -1
  6. package/lib/cli-engine.js +26 -5
  7. package/lib/cli.js +17 -9
  8. package/lib/code-path-analysis/code-path-segment.js +39 -39
  9. package/lib/code-path-analysis/code-path-state.js +3 -0
  10. package/lib/formatters/html-template-message.html +1 -1
  11. package/lib/formatters/html-template-page.html +3 -1
  12. package/lib/formatters/html.js +2 -1
  13. package/lib/ignored-paths.js +1 -1
  14. package/lib/linter.js +43 -71
  15. package/lib/logging.js +2 -2
  16. package/lib/options.js +12 -0
  17. package/lib/rules/array-bracket-newline.js +19 -5
  18. package/lib/rules/block-spacing.js +1 -1
  19. package/lib/rules/callback-return.js +2 -1
  20. package/lib/rules/capitalized-comments.js +2 -1
  21. package/lib/rules/comma-style.js +3 -1
  22. package/lib/rules/dot-notation.js +56 -35
  23. package/lib/rules/generator-star-spacing.js +3 -3
  24. package/lib/rules/indent-legacy.js +5 -2
  25. package/lib/rules/indent.js +25 -19
  26. package/lib/rules/lines-around-comment.js +33 -4
  27. package/lib/rules/lines-between-class-members.js +91 -0
  28. package/lib/rules/max-len.js +2 -3
  29. package/lib/rules/multiline-comment-style.js +294 -0
  30. package/lib/rules/new-cap.js +2 -1
  31. package/lib/rules/newline-before-return.js +4 -2
  32. package/lib/rules/no-alert.js +7 -15
  33. package/lib/rules/no-catch-shadow.js +1 -1
  34. package/lib/rules/no-constant-condition.js +2 -2
  35. package/lib/rules/no-control-regex.js +2 -1
  36. package/lib/rules/no-else-return.js +43 -8
  37. package/lib/rules/no-extra-parens.js +6 -3
  38. package/lib/rules/no-lonely-if.js +2 -1
  39. package/lib/rules/no-loop-func.js +2 -3
  40. package/lib/rules/no-mixed-requires.js +8 -4
  41. package/lib/rules/no-restricted-imports.js +86 -17
  42. package/lib/rules/no-restricted-modules.js +84 -15
  43. package/lib/rules/no-trailing-spaces.js +1 -1
  44. package/lib/rules/no-unneeded-ternary.js +3 -1
  45. package/lib/rules/no-unused-labels.js +2 -1
  46. package/lib/rules/no-useless-computed-key.js +2 -1
  47. package/lib/rules/no-useless-escape.js +8 -1
  48. package/lib/rules/no-var.js +11 -0
  49. package/lib/rules/object-shorthand.js +6 -2
  50. package/lib/rules/operator-linebreak.js +3 -1
  51. package/lib/rules/padding-line-between-statements.js +2 -2
  52. package/lib/rules/require-jsdoc.js +11 -18
  53. package/lib/rules/sort-imports.js +6 -3
  54. package/lib/rules/space-unary-ops.js +6 -8
  55. package/lib/rules/valid-jsdoc.js +39 -33
  56. package/lib/testers/rule-tester.js +20 -6
  57. package/lib/util/apply-disable-directives.js +56 -27
  58. package/lib/util/node-event-generator.js +6 -20
  59. package/lib/util/safe-emitter.js +54 -0
  60. package/lib/util/source-code.js +73 -67
  61. package/messages/no-config-found.txt +1 -1
  62. package/package.json +3 -4
  63. package/lib/internal-rules/.eslintrc.yml +0 -3
  64. package/lib/internal-rules/internal-consistent-docs-description.js +0 -130
  65. package/lib/internal-rules/internal-no-invalid-meta.js +0 -188
@@ -53,11 +53,10 @@ function findReference(scope, node) {
53
53
  /**
54
54
  * Checks if the given identifier node is shadowed in the given scope.
55
55
  * @param {Object} scope The current scope.
56
- * @param {Object} globalScope The global scope.
57
56
  * @param {string} node The identifier node to check
58
57
  * @returns {boolean} Whether or not the name is shadowed.
59
58
  */
60
- function isShadowed(scope, globalScope, node) {
59
+ function isShadowed(scope, node) {
61
60
  const reference = findReference(scope, node);
62
61
 
63
62
  return reference && reference.resolved && reference.resolved.defs.length > 0;
@@ -66,15 +65,15 @@ function isShadowed(scope, globalScope, node) {
66
65
  /**
67
66
  * Checks if the given identifier node is a ThisExpression in the global scope or the global window property.
68
67
  * @param {Object} scope The current scope.
69
- * @param {Object} globalScope The global scope.
70
68
  * @param {string} node The identifier node to check
71
69
  * @returns {boolean} Whether or not the node is a reference to the global object.
72
70
  */
73
- function isGlobalThisReferenceOrGlobalWindow(scope, globalScope, node) {
71
+ function isGlobalThisReferenceOrGlobalWindow(scope, node) {
74
72
  if (scope.type === "global" && node.type === "ThisExpression") {
75
73
  return true;
76
- } else if (node.name === "window") {
77
- return !isShadowed(scope, globalScope, node);
74
+ }
75
+ if (node.name === "window") {
76
+ return !isShadowed(scope, node);
78
77
  }
79
78
 
80
79
  return false;
@@ -96,14 +95,7 @@ module.exports = {
96
95
  },
97
96
 
98
97
  create(context) {
99
- let globalScope;
100
-
101
98
  return {
102
-
103
- Program() {
104
- globalScope = context.getScope();
105
- },
106
-
107
99
  CallExpression(node) {
108
100
  const callee = node.callee,
109
101
  currentScope = context.getScope();
@@ -112,11 +104,11 @@ module.exports = {
112
104
  if (callee.type === "Identifier") {
113
105
  const identifierName = callee.name;
114
106
 
115
- if (!isShadowed(currentScope, globalScope, callee) && isProhibitedIdentifier(callee.name)) {
107
+ if (!isShadowed(currentScope, callee) && isProhibitedIdentifier(callee.name)) {
116
108
  report(context, node, identifierName);
117
109
  }
118
110
 
119
- } else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, globalScope, callee.object)) {
111
+ } else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, callee.object)) {
120
112
  const identifierName = getPropertyName(callee);
121
113
 
122
114
  if (isProhibitedIdentifier(identifierName)) {
@@ -51,7 +51,7 @@ module.exports = {
51
51
  CatchClause(node) {
52
52
  let scope = context.getScope();
53
53
 
54
- // When blockBindings is enabled, CatchClause creates its own scope
54
+ // When ecmaVersion >= 6, CatchClause creates its own scope
55
55
  // so start from one upper scope to exclude the current node
56
56
  if (scope.block === node) {
57
57
  scope = scope.upper;
@@ -138,7 +138,7 @@ module.exports = {
138
138
  function checkConstantConditionLoopInSet(node) {
139
139
  if (loopsInCurrentScope.has(node)) {
140
140
  loopsInCurrentScope.delete(node);
141
- context.report({ node, message: "Unexpected constant condition." });
141
+ context.report({ node: node.test, message: "Unexpected constant condition." });
142
142
  }
143
143
  }
144
144
 
@@ -150,7 +150,7 @@ module.exports = {
150
150
  */
151
151
  function reportIfConstant(node) {
152
152
  if (node.test && isConstant(node.test, true)) {
153
- context.report({ node, message: "Unexpected constant condition." });
153
+ context.report({ node: node.test, message: "Unexpected constant condition." });
154
154
  }
155
155
  }
156
156
 
@@ -31,7 +31,8 @@ module.exports = {
31
31
  function getRegExp(node) {
32
32
  if (node.value instanceof RegExp) {
33
33
  return node.value;
34
- } else if (typeof node.value === "string") {
34
+ }
35
+ if (typeof node.value === "string") {
35
36
 
36
37
  const parent = context.getAncestors().pop();
37
38
 
@@ -24,8 +24,15 @@ module.exports = {
24
24
  recommended: false
25
25
  },
26
26
 
27
- schema: [],
28
-
27
+ schema: [{
28
+ type: "object",
29
+ properties: {
30
+ allowElseIf: {
31
+ type: "boolean"
32
+ }
33
+ },
34
+ additionalProperties: false
35
+ }],
29
36
  fixable: "code"
30
37
  },
31
38
 
@@ -134,13 +141,13 @@ module.exports = {
134
141
 
135
142
  /**
136
143
  * Check to see if the node is valid for evaluation,
137
- * meaning it has an else and not an else-if
144
+ * meaning it has an else.
138
145
  *
139
146
  * @param {Node} node The node being evaluated
140
147
  * @returns {boolean} True if the node is valid
141
148
  */
142
149
  function hasElse(node) {
143
- return node.alternate && node.consequent && node.alternate.type !== "IfStatement";
150
+ return node.alternate && node.consequent;
144
151
  }
145
152
 
146
153
  /**
@@ -189,14 +196,15 @@ module.exports = {
189
196
  return checkForReturnOrIf(node);
190
197
  }
191
198
 
199
+
192
200
  /**
193
- * Check the if statement
201
+ * Check the if statement, but don't catch else-if blocks.
194
202
  * @returns {void}
195
203
  * @param {Node} node The node for the if statement to check
196
204
  * @private
197
205
  */
198
- function IfStatement(node) {
199
- const parent = context.getAncestors().pop();
206
+ function checkIfWithoutElse(node) {
207
+ const parent = node.parent;
200
208
  let consequents,
201
209
  alternate;
202
210
 
@@ -221,13 +229,40 @@ module.exports = {
221
229
  }
222
230
  }
223
231
 
232
+ /**
233
+ * Check the if statement
234
+ * @returns {void}
235
+ * @param {Node} node The node for the if statement to check
236
+ * @private
237
+ */
238
+ function checkIfWithElse(node) {
239
+ const parent = node.parent;
240
+
241
+
242
+ /*
243
+ * Fixing this would require splitting one statement into two, so no error should
244
+ * be reported if this node is in a position where only one statement is allowed.
245
+ */
246
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
247
+ return;
248
+ }
249
+
250
+ const alternate = node.alternate;
251
+
252
+ if (alternate && alwaysReturns(node.consequent)) {
253
+ displayReport(alternate);
254
+ }
255
+ }
256
+
257
+ const allowElseIf = !(context.options[0] && context.options[0].allowElseIf === false);
258
+
224
259
  //--------------------------------------------------------------------------
225
260
  // Public API
226
261
  //--------------------------------------------------------------------------
227
262
 
228
263
  return {
229
264
 
230
- "IfStatement:exit": IfStatement
265
+ "IfStatement:exit": allowElseIf ? checkIfWithoutElse : checkIfWithElse
231
266
 
232
267
  };
233
268
 
@@ -195,10 +195,12 @@ module.exports = {
195
195
  function containsAssignment(node) {
196
196
  if (node.type === "AssignmentExpression") {
197
197
  return true;
198
- } else if (node.type === "ConditionalExpression" &&
198
+ }
199
+ if (node.type === "ConditionalExpression" &&
199
200
  (node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression")) {
200
201
  return true;
201
- } else if ((node.left && node.left.type === "AssignmentExpression") ||
202
+ }
203
+ if ((node.left && node.left.type === "AssignmentExpression") ||
202
204
  (node.right && node.right.type === "AssignmentExpression")) {
203
205
  return true;
204
206
  }
@@ -219,7 +221,8 @@ module.exports = {
219
221
 
220
222
  if (node.type === "ReturnStatement") {
221
223
  return node.argument && containsAssignment(node.argument);
222
- } else if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
224
+ }
225
+ if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
223
226
  return containsAssignment(node.body);
224
227
  }
225
228
  return containsAssignment(node);
@@ -45,7 +45,8 @@ module.exports = {
45
45
  const lastIfToken = sourceCode.getLastToken(node.consequent);
46
46
  const sourceText = sourceCode.getText();
47
47
 
48
- if (sourceText.slice(openingElseCurly.range[1], node.range[0]).trim() || sourceText.slice(node.range[1], closingElseCurly.range[0]).trim()) {
48
+ if (sourceText.slice(openingElseCurly.range[1],
49
+ node.range[0]).trim() || sourceText.slice(node.range[1], closingElseCurly.range[0]).trim()) {
49
50
 
50
51
  // Don't fix if there are any non-whitespace characters interfering (e.g. comments)
51
52
  return null;
@@ -88,12 +88,11 @@ function getTopLoopNode(node, excludedNode) {
88
88
  * Checks whether a given reference which refers to an upper scope's variable is
89
89
  * safe or not.
90
90
  *
91
- * @param {ASTNode} funcNode - A target function node.
92
91
  * @param {ASTNode} loopNode - A containing loop node.
93
92
  * @param {eslint-scope.Reference} reference - A reference to check.
94
93
  * @returns {boolean} `true` if the reference is safe or not.
95
94
  */
96
- function isSafe(funcNode, loopNode, reference) {
95
+ function isSafe(loopNode, reference) {
97
96
  const variable = reference.resolved;
98
97
  const definition = variable && variable.defs[0];
99
98
  const declaration = definition && definition.parent;
@@ -183,7 +182,7 @@ module.exports = {
183
182
  const references = context.getScope().through;
184
183
 
185
184
  if (references.length > 0 &&
186
- !references.every(isSafe.bind(null, node, loopNode))
185
+ !references.every(isSafe.bind(null, loopNode))
187
186
  ) {
188
187
  context.report({ node, message: "Don't make functions within a loop." });
189
188
  }
@@ -104,14 +104,16 @@ module.exports = {
104
104
 
105
105
  // "var x = require('util');"
106
106
  return DECL_REQUIRE;
107
- } else if (allowCall &&
107
+ }
108
+ if (allowCall &&
108
109
  initExpression.type === "CallExpression" &&
109
110
  initExpression.callee.type === "CallExpression"
110
111
  ) {
111
112
 
112
113
  // "var x = require('diagnose')('sub-module');"
113
114
  return getDeclarationType(initExpression.callee);
114
- } else if (initExpression.type === "MemberExpression") {
115
+ }
116
+ if (initExpression.type === "MemberExpression") {
115
117
 
116
118
  // "var x = require('glob').Glob;"
117
119
  return getDeclarationType(initExpression.object);
@@ -131,7 +133,8 @@ module.exports = {
131
133
 
132
134
  // "var x = require('glob').Glob;"
133
135
  return inferModuleType(initExpression.object);
134
- } else if (initExpression.arguments.length === 0) {
136
+ }
137
+ if (initExpression.arguments.length === 0) {
135
138
 
136
139
  // "var x = require();"
137
140
  return REQ_COMPUTED;
@@ -149,7 +152,8 @@ module.exports = {
149
152
 
150
153
  // "var fs = require('fs');"
151
154
  return REQ_CORE;
152
- } else if (/^\.{0,2}\//.test(arg.value)) {
155
+ }
156
+ if (/^\.{0,2}\//.test(arg.value)) {
153
157
 
154
158
  // "var utils = require('./utils');"
155
159
  return REQ_FILE;
@@ -4,6 +4,13 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Helpers
9
+ //------------------------------------------------------------------------------
10
+
11
+ const DEFAULT_MESSAGE_TEMPLATE = "'{{importName}}' import is restricted from being used.";
12
+ const CUSTOM_MESSAGE_TEMPLATE = "'{{importName}}' import is restricted from being used. {{customMessage}}";
13
+
7
14
  //------------------------------------------------------------------------------
8
15
  // Rule Definition
9
16
  //------------------------------------------------------------------------------
@@ -11,9 +18,29 @@
11
18
  const ignore = require("ignore");
12
19
 
13
20
  const arrayOfStrings = {
21
+ type: "array",
22
+ items: { type: "string" },
23
+ uniqueItems: true
24
+ };
25
+
26
+ const arrayOfStringsOrObjects = {
14
27
  type: "array",
15
28
  items: {
16
- type: "string"
29
+ anyOf: [
30
+ { type: "string" },
31
+ {
32
+ type: "object",
33
+ properties: {
34
+ name: { type: "string" },
35
+ message: {
36
+ type: "string",
37
+ minLength: 1
38
+ }
39
+ },
40
+ additionalProperties: false,
41
+ required: ["name"]
42
+ }
43
+ ]
17
44
  },
18
45
  uniqueItems: true
19
46
  };
@@ -28,17 +55,17 @@ module.exports = {
28
55
 
29
56
  schema: {
30
57
  anyOf: [
31
- arrayOfStrings,
58
+ arrayOfStringsOrObjects,
32
59
  {
33
60
  type: "array",
34
- items: [{
61
+ items: {
35
62
  type: "object",
36
63
  properties: {
37
- paths: arrayOfStrings,
64
+ paths: arrayOfStringsOrObjects,
38
65
  patterns: arrayOfStrings
39
66
  },
40
67
  additionalProperties: false
41
- }],
68
+ },
42
69
  additionalItems: false
43
70
  }
44
71
  ]
@@ -47,35 +74,77 @@ module.exports = {
47
74
 
48
75
  create(context) {
49
76
  const options = Array.isArray(context.options) ? context.options : [];
50
- const isStringArray = typeof options[0] !== "object";
51
- const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
52
- const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
77
+ const isPathAndPatternsObject =
78
+ typeof options[0] === "object" &&
79
+ (options[0].hasOwnProperty("paths") || options[0].hasOwnProperty("patterns"));
80
+
81
+ const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
82
+ const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
83
+
84
+ const restrictedPathMessages = restrictedPaths.reduce((memo, importName) => {
85
+ if (typeof importName === "string") {
86
+ memo[importName] = null;
87
+ } else {
88
+ memo[importName.name] = importName.message;
89
+ }
90
+ return memo;
91
+ }, {});
53
92
 
54
93
  // if no imports are restricted we don"t need to check
55
- if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
94
+ if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) {
56
95
  return {};
57
96
  }
58
97
 
59
98
  const ig = ignore().add(restrictedPatterns);
60
99
 
100
+ /**
101
+ * Report a restricted path.
102
+ * @param {node} node representing the restricted path reference
103
+ * @returns {void}
104
+ * @private
105
+ */
106
+ function reportPath(node) {
107
+ const importName = node.source.value.trim();
108
+ const customMessage = restrictedPathMessages[importName];
109
+ const message = customMessage
110
+ ? CUSTOM_MESSAGE_TEMPLATE
111
+ : DEFAULT_MESSAGE_TEMPLATE;
112
+
113
+ context.report({
114
+ node,
115
+ message,
116
+ data: {
117
+ importName,
118
+ customMessage
119
+ }
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Check if the given name is a restricted path name.
125
+ * @param {string} name name of a variable
126
+ * @returns {boolean} whether the variable is a restricted path or not
127
+ * @private
128
+ */
129
+ function isRestrictedPath(name) {
130
+ return Object.prototype.hasOwnProperty.call(restrictedPathMessages, name);
131
+ }
132
+
61
133
  return {
62
134
  ImportDeclaration(node) {
63
135
  if (node && node.source && node.source.value) {
64
-
65
136
  const importName = node.source.value.trim();
66
137
 
67
- if (restrictedPaths.has(importName)) {
68
- context.report({
69
- node,
70
- message: "'{{importName}}' import is restricted from being used.",
71
- data: { importName }
72
- });
138
+ if (isRestrictedPath(importName)) {
139
+ reportPath(node);
73
140
  }
74
141
  if (restrictedPatterns.length > 0 && ig.ignores(importName)) {
75
142
  context.report({
76
143
  node,
77
144
  message: "'{{importName}}' import is restricted from being used by a pattern.",
78
- data: { importName }
145
+ data: {
146
+ importName
147
+ }
79
148
  });
80
149
  }
81
150
  }
@@ -4,6 +4,13 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Helpers
9
+ //------------------------------------------------------------------------------
10
+
11
+ const DEFAULT_MESSAGE_TEMPLATE = "'{{moduleName}}' module is restricted from being used.";
12
+ const CUSTOM_MESSAGE_TEMPLATE = "'{{moduleName}}' module is restricted from being used. {{customMessage}}";
13
+
7
14
  //------------------------------------------------------------------------------
8
15
  // Rule Definition
9
16
  //------------------------------------------------------------------------------
@@ -11,9 +18,29 @@
11
18
  const ignore = require("ignore");
12
19
 
13
20
  const arrayOfStrings = {
21
+ type: "array",
22
+ items: { type: "string" },
23
+ uniqueItems: true
24
+ };
25
+
26
+ const arrayOfStringsOrObjects = {
14
27
  type: "array",
15
28
  items: {
16
- type: "string"
29
+ anyOf: [
30
+ { type: "string" },
31
+ {
32
+ type: "object",
33
+ properties: {
34
+ name: { type: "string" },
35
+ message: {
36
+ type: "string",
37
+ minLength: 1
38
+ }
39
+ },
40
+ additionalProperties: false,
41
+ required: ["name"]
42
+ }
43
+ ]
17
44
  },
18
45
  uniqueItems: true
19
46
  };
@@ -28,17 +55,17 @@ module.exports = {
28
55
 
29
56
  schema: {
30
57
  anyOf: [
31
- arrayOfStrings,
58
+ arrayOfStringsOrObjects,
32
59
  {
33
60
  type: "array",
34
- items: [{
61
+ items: {
35
62
  type: "object",
36
63
  properties: {
37
- paths: arrayOfStrings,
64
+ paths: arrayOfStringsOrObjects,
38
65
  patterns: arrayOfStrings
39
66
  },
40
67
  additionalProperties: false
41
- }],
68
+ },
42
69
  additionalItems: false
43
70
  }
44
71
  ]
@@ -47,17 +74,30 @@ module.exports = {
47
74
 
48
75
  create(context) {
49
76
  const options = Array.isArray(context.options) ? context.options : [];
50
- const isStringArray = typeof options[0] !== "object";
51
- const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
52
- const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
77
+ const isPathAndPatternsObject =
78
+ typeof options[0] === "object" &&
79
+ (options[0].hasOwnProperty("paths") || options[0].hasOwnProperty("patterns"));
80
+
81
+ const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
82
+ const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
83
+
84
+ const restrictedPathMessages = restrictedPaths.reduce((memo, importName) => {
85
+ if (typeof importName === "string") {
86
+ memo[importName] = null;
87
+ } else {
88
+ memo[importName.name] = importName.message;
89
+ }
90
+ return memo;
91
+ }, {});
53
92
 
54
93
  // if no imports are restricted we don"t need to check
55
- if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
94
+ if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) {
56
95
  return {};
57
96
  }
58
97
 
59
98
  const ig = ignore().add(restrictedPatterns);
60
99
 
100
+
61
101
  /**
62
102
  * Function to check if a node is a string literal.
63
103
  * @param {ASTNode} node The node to check.
@@ -76,6 +116,39 @@ module.exports = {
76
116
  return node.callee.type === "Identifier" && node.callee.name === "require";
77
117
  }
78
118
 
119
+ /**
120
+ * Report a restricted path.
121
+ * @param {node} node representing the restricted path reference
122
+ * @returns {void}
123
+ * @private
124
+ */
125
+ function reportPath(node) {
126
+ const moduleName = node.arguments[0].value.trim();
127
+ const customMessage = restrictedPathMessages[moduleName];
128
+ const message = customMessage
129
+ ? CUSTOM_MESSAGE_TEMPLATE
130
+ : DEFAULT_MESSAGE_TEMPLATE;
131
+
132
+ context.report({
133
+ node,
134
+ message,
135
+ data: {
136
+ moduleName,
137
+ customMessage
138
+ }
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Check if the given name is a restricted path name
144
+ * @param {string} name name of a variable
145
+ * @returns {boolean} whether the variable is a restricted path or not
146
+ * @private
147
+ */
148
+ function isRestrictedPath(name) {
149
+ return Object.prototype.hasOwnProperty.call(restrictedPathMessages, name);
150
+ }
151
+
79
152
  return {
80
153
  CallExpression(node) {
81
154
  if (isRequireCall(node)) {
@@ -85,12 +158,8 @@ module.exports = {
85
158
  const moduleName = node.arguments[0].value.trim();
86
159
 
87
160
  // check if argument value is in restricted modules array
88
- if (restrictedPaths.has(moduleName)) {
89
- context.report({
90
- node,
91
- message: "'{{moduleName}}' module is restricted from being used.",
92
- data: { moduleName }
93
- });
161
+ if (isRestrictedPath(moduleName)) {
162
+ reportPath(node);
94
163
  }
95
164
 
96
165
  if (restrictedPatterns.length > 0 && ig.ignores(moduleName)) {
@@ -49,7 +49,7 @@ module.exports = {
49
49
 
50
50
  const options = context.options[0] || {},
51
51
  skipBlankLines = options.skipBlankLines || false,
52
- ignoreComments = typeof options.ignoreComments === "undefined" || options.ignoreComments;
52
+ ignoreComments = typeof options.ignoreComments === "boolean" && options.ignoreComments;
53
53
 
54
54
  /**
55
55
  * Report the error message
@@ -72,8 +72,10 @@ module.exports = {
72
72
  node.right,
73
73
  token => token.value === node.operator
74
74
  );
75
+ const text = sourceCode.getText();
75
76
 
76
- return sourceCode.getText().slice(node.range[0], operatorToken.range[0]) + OPERATOR_INVERSES[node.operator] + sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
77
+ return text.slice(node.range[0],
78
+ operatorToken.range[0]) + OPERATOR_INVERSES[node.operator] + text.slice(operatorToken.range[1], node.range[1]);
77
79
  }
78
80
 
79
81
  if (astUtils.getPrecedence(node) < astUtils.getPrecedence({ type: "UnaryExpression" })) {
@@ -59,7 +59,8 @@ module.exports = {
59
59
  * Only perform a fix if there are no comments between the label and the body. This will be the case
60
60
  * when there is exactly one token/comment (the ":") between the label and the body.
61
61
  */
62
- if (sourceCode.getTokenAfter(node.label, { includeComments: true }) === sourceCode.getTokenBefore(node.body, { includeComments: true })) {
62
+ if (sourceCode.getTokenAfter(node.label, { includeComments: true }) ===
63
+ sourceCode.getTokenBefore(node.body, { includeComments: true })) {
63
64
  return fixer.removeRange([node.range[0], node.body.range[0]]);
64
65
  }
65
66
 
@@ -50,7 +50,8 @@ module.exports = {
50
50
  const rightSquareBracket = sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken);
51
51
  const tokensBetween = sourceCode.getTokensBetween(leftSquareBracket, rightSquareBracket, 1);
52
52
 
53
- if (tokensBetween.slice(0, -1).some((token, index) => sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) {
53
+ if (tokensBetween.slice(0, -1).some((token, index) =>
54
+ sourceCode.getText().slice(token.range[1], tokensBetween[index + 1].range[0]).trim())) {
54
55
 
55
56
  // If there are comments between the brackets and the property name, don't do a fix.
56
57
  return null;
@@ -63,7 +63,14 @@ function parseRegExp(regExpText) {
63
63
  return Object.assign(state, { inCharClass: false, startingCharClass: false });
64
64
  }
65
65
  }
66
- charList.push({ text: char, index, escaped: state.escapeNextChar, inCharClass: state.inCharClass, startsCharClass: state.startingCharClass, endsCharClass: false });
66
+ charList.push({
67
+ text: char,
68
+ index,
69
+ escaped: state.escapeNextChar,
70
+ inCharClass: state.inCharClass,
71
+ startsCharClass: state.startingCharClass,
72
+ endsCharClass: false
73
+ });
67
74
  return Object.assign(state, { escapeNextChar: false, startingCharClass: false });
68
75
  }, { escapeNextChar: false, inCharClass: false, startingCharClass: false });
69
76