eslint 3.15.0 → 3.17.1

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 (118) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/conf/{eslint.json → eslint-recommended.js} +87 -71
  3. package/lib/ast-utils.js +182 -80
  4. package/lib/code-path-analysis/code-path-state.js +2 -2
  5. package/lib/config/autoconfig.js +3 -3
  6. package/lib/config/config-file.js +14 -7
  7. package/lib/config/config-initializer.js +1 -1
  8. package/lib/config.js +3 -2
  9. package/lib/eslint.js +4 -4
  10. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/arrow-body-style.js +7 -4
  13. package/lib/rules/arrow-spacing.js +7 -6
  14. package/lib/rules/block-spacing.js +2 -2
  15. package/lib/rules/brace-style.js +2 -6
  16. package/lib/rules/capitalized-comments.js +8 -7
  17. package/lib/rules/comma-spacing.js +3 -3
  18. package/lib/rules/complexity.js +14 -8
  19. package/lib/rules/consistent-return.js +18 -11
  20. package/lib/rules/constructor-super.js +3 -3
  21. package/lib/rules/curly.js +11 -7
  22. package/lib/rules/default-case.js +3 -3
  23. package/lib/rules/eqeqeq.js +15 -6
  24. package/lib/rules/func-call-spacing.js +10 -13
  25. package/lib/rules/func-names.js +20 -5
  26. package/lib/rules/generator-star-spacing.js +18 -19
  27. package/lib/rules/id-blacklist.js +2 -2
  28. package/lib/rules/id-length.js +3 -3
  29. package/lib/rules/id-match.js +2 -2
  30. package/lib/rules/indent.js +7 -6
  31. package/lib/rules/key-spacing.js +12 -16
  32. package/lib/rules/keyword-spacing.js +21 -17
  33. package/lib/rules/line-comment-position.js +16 -6
  34. package/lib/rules/linebreak-style.js +7 -1
  35. package/lib/rules/lines-around-comment.js +23 -4
  36. package/lib/rules/lines-around-directive.js +3 -3
  37. package/lib/rules/max-lines.js +2 -2
  38. package/lib/rules/max-params.js +17 -4
  39. package/lib/rules/max-statements-per-line.js +7 -6
  40. package/lib/rules/max-statements.js +11 -10
  41. package/lib/rules/newline-after-var.js +7 -2
  42. package/lib/rules/newline-per-chained-call.js +3 -1
  43. package/lib/rules/no-compare-neg-zero.js +53 -0
  44. package/lib/rules/no-cond-assign.js +3 -3
  45. package/lib/rules/no-else-return.js +13 -1
  46. package/lib/rules/no-empty-function.js +9 -16
  47. package/lib/rules/no-extend-native.js +3 -3
  48. package/lib/rules/no-extra-bind.js +3 -4
  49. package/lib/rules/no-extra-boolean-cast.js +8 -0
  50. package/lib/rules/no-extra-parens.js +1 -2
  51. package/lib/rules/no-extra-semi.js +13 -1
  52. package/lib/rules/no-inner-declarations.js +4 -4
  53. package/lib/rules/no-invalid-regexp.js +2 -1
  54. package/lib/rules/no-irregular-whitespace.js +7 -1
  55. package/lib/rules/no-lone-blocks.js +10 -10
  56. package/lib/rules/no-mixed-operators.js +1 -7
  57. package/lib/rules/no-multi-spaces.js +4 -1
  58. package/lib/rules/no-multi-str.js +7 -3
  59. package/lib/rules/no-multiple-empty-lines.js +2 -4
  60. package/lib/rules/no-param-reassign.js +29 -6
  61. package/lib/rules/no-restricted-properties.js +2 -0
  62. package/lib/rules/no-return-assign.js +7 -14
  63. package/lib/rules/no-return-await.js +1 -1
  64. package/lib/rules/no-sequences.js +7 -6
  65. package/lib/rules/no-trailing-spaces.js +8 -2
  66. package/lib/rules/no-undefined.js +45 -6
  67. package/lib/rules/no-unexpected-multiline.js +9 -8
  68. package/lib/rules/no-unneeded-ternary.js +5 -1
  69. package/lib/rules/no-unused-labels.js +17 -2
  70. package/lib/rules/no-unused-vars.js +13 -27
  71. package/lib/rules/no-use-before-define.js +1 -1
  72. package/lib/rules/no-useless-computed-key.js +8 -3
  73. package/lib/rules/no-useless-concat.js +10 -7
  74. package/lib/rules/no-useless-escape.js +2 -2
  75. package/lib/rules/no-useless-return.js +14 -9
  76. package/lib/rules/no-var.js +1 -3
  77. package/lib/rules/no-whitespace-before-property.js +5 -16
  78. package/lib/rules/nonblock-statement-body-position.js +114 -0
  79. package/lib/rules/object-curly-newline.js +2 -2
  80. package/lib/rules/object-curly-spacing.js +7 -25
  81. package/lib/rules/object-property-newline.js +3 -3
  82. package/lib/rules/object-shorthand.js +4 -3
  83. package/lib/rules/operator-assignment.js +2 -2
  84. package/lib/rules/operator-linebreak.js +8 -10
  85. package/lib/rules/padded-blocks.js +39 -30
  86. package/lib/rules/prefer-destructuring.js +1 -1
  87. package/lib/rules/prefer-spread.js +1 -1
  88. package/lib/rules/prefer-template.js +1 -1
  89. package/lib/rules/quotes.js +10 -6
  90. package/lib/rules/semi-spacing.js +4 -0
  91. package/lib/rules/semi.js +13 -1
  92. package/lib/rules/space-before-function-paren.js +8 -5
  93. package/lib/rules/space-unary-ops.js +19 -1
  94. package/lib/rules/spaced-comment.js +2 -2
  95. package/lib/rules/strict.js +10 -4
  96. package/lib/rules/unicode-bom.js +1 -1
  97. package/lib/rules/wrap-iife.js +5 -5
  98. package/lib/rules/yoda.js +4 -9
  99. package/lib/testers/rule-tester.js +46 -9
  100. package/lib/token-store/backward-token-comment-cursor.js +57 -0
  101. package/lib/token-store/backward-token-cursor.js +56 -0
  102. package/lib/token-store/cursor.js +76 -0
  103. package/lib/token-store/cursors.js +92 -0
  104. package/lib/token-store/decorative-cursor.js +39 -0
  105. package/lib/token-store/filter-cursor.js +43 -0
  106. package/lib/token-store/forward-token-comment-cursor.js +57 -0
  107. package/lib/token-store/forward-token-cursor.js +61 -0
  108. package/lib/token-store/index.js +604 -0
  109. package/lib/token-store/limit-cursor.js +40 -0
  110. package/lib/token-store/padded-token-cursor.js +38 -0
  111. package/lib/token-store/skip-cursor.js +42 -0
  112. package/lib/token-store/utils.js +100 -0
  113. package/lib/util/fix-tracker.js +121 -0
  114. package/lib/util/source-code-fixer.js +35 -39
  115. package/lib/util/source-code.js +129 -16
  116. package/messages/extend-config-missing.txt +3 -0
  117. package/package.json +5 -6
  118. package/lib/token-store.js +0 -203
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -201,8 +207,7 @@ module.exports = {
201
207
  message: NEVER_MESSAGE,
202
208
  data: { identifier: node.name },
203
209
  fix(fixer) {
204
- const NEWLINE_REGEX = /\r\n|\r|\n|\u2028|\u2029/;
205
- const linesBetween = sourceCode.getText().slice(lastToken.range[1], nextToken.range[0]).split(NEWLINE_REGEX);
210
+ const linesBetween = sourceCode.getText().slice(lastToken.range[1], nextToken.range[0]).split(astUtils.LINEBREAK_MATCHER);
206
211
 
207
212
  return fixer.replaceTextRange([lastToken.range[1], nextToken.range[0]], `${linesBetween.slice(0, -1).join("")}\n${linesBetween[linesBetween.length - 1]}`);
208
213
  }
@@ -6,6 +6,8 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ const astUtils = require("../ast-utils");
10
+
9
11
  //------------------------------------------------------------------------------
10
12
  // Rule Definition
11
13
  //------------------------------------------------------------------------------
@@ -47,7 +49,7 @@ module.exports = {
47
49
  */
48
50
  function getPropertyText(node) {
49
51
  const prefix = node.computed ? "[" : ".";
50
- const lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g);
52
+ const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
51
53
  const suffix = node.computed && lines.length === 1 ? "]" : "";
52
54
 
53
55
  return prefix + lines[0] + suffix;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @fileoverview The rule should warn against code that tries to compare against -0.
3
+ * @author Aladdin-ADD <hh_2013@foxmail.com>
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ //------------------------------------------------------------------------------
10
+
11
+ module.exports = {
12
+ meta: {
13
+ docs: {
14
+ description: "disallow comparing against -0",
15
+ category: "Possible Errors",
16
+ recommended: false
17
+ },
18
+ fixable: null,
19
+ schema: []
20
+ },
21
+
22
+ create(context) {
23
+
24
+ //--------------------------------------------------------------------------
25
+ // Helpers
26
+ //--------------------------------------------------------------------------
27
+
28
+ /**
29
+ * Checks a given node is -0
30
+ *
31
+ * @param {ASTNode} node - A node to check.
32
+ * @returns {boolean} `true` if the node is -0.
33
+ */
34
+ function isNegZero(node) {
35
+ return node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "Literal" && node.argument.value === 0;
36
+ }
37
+ const OPERATORS_TO_CHECK = new Set([">", ">=", "<", "<=", "==", "===", "!=", "!=="]);
38
+
39
+ return {
40
+ BinaryExpression(node) {
41
+ if (OPERATORS_TO_CHECK.has(node.operator)) {
42
+ if (isNegZero(node.left) || isNegZero(node.right)) {
43
+ context.report({
44
+ node,
45
+ message: "Do not use the '{{operator}}' operator to compare against -0.",
46
+ data: { operator: node.operator }
47
+ });
48
+ }
49
+ }
50
+ }
51
+ };
52
+ }
53
+ };
@@ -101,9 +101,9 @@ module.exports = {
101
101
  function testForAssign(node) {
102
102
  if (node.test &&
103
103
  (node.test.type === "AssignmentExpression") &&
104
- (node.type === "ForStatement" ?
105
- !isParenthesised(node.test) :
106
- !isParenthesisedTwice(node.test)
104
+ (node.type === "ForStatement"
105
+ ? !isParenthesised(node.test)
106
+ : !isParenthesisedTwice(node.test)
107
107
  )
108
108
  ) {
109
109
 
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const FixTracker = require("../util/fix-tracker");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -86,7 +92,13 @@ module.exports = {
86
92
  } else {
87
93
  fixedSource = source;
88
94
  }
89
- return fixer.replaceTextRange([elseToken.start, node.end], fixedSource);
95
+
96
+ // Extend the replacement range to include the entire
97
+ // function to avoid conflicting with no-useless-return.
98
+ // https://github.com/eslint/eslint/issues/8026
99
+ return new FixTracker(fixer, sourceCode)
100
+ .retainEnclosingFunction(node)
101
+ .replaceTextRange([elseToken.start, node.end], fixedSource);
90
102
  }
91
103
  });
92
104
  }
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Helpers
10
16
  //------------------------------------------------------------------------------
@@ -19,18 +25,6 @@ const ALLOW_OPTIONS = Object.freeze([
19
25
  "setters",
20
26
  "constructors"
21
27
  ]);
22
- const SHOW_KIND = Object.freeze({
23
- functions: "function",
24
- arrowFunctions: "arrow function",
25
- generatorFunctions: "generator function",
26
- asyncFunctions: "async function",
27
- methods: "method",
28
- generatorMethods: "generator method",
29
- asyncMethods: "async method",
30
- getters: "getter",
31
- setters: "setter",
32
- constructors: "constructor"
33
- });
34
28
 
35
29
  /**
36
30
  * Gets the kind of a given function node.
@@ -137,6 +131,7 @@ module.exports = {
137
131
  */
138
132
  function reportIfEmpty(node) {
139
133
  const kind = getKind(node);
134
+ const name = astUtils.getFunctionNameWithKind(node);
140
135
 
141
136
  if (allowed.indexOf(kind) === -1 &&
142
137
  node.body.type === "BlockStatement" &&
@@ -146,10 +141,8 @@ module.exports = {
146
141
  context.report({
147
142
  node,
148
143
  loc: node.body.loc.start,
149
- message: "Unexpected empty {{kind}}.",
150
- data: {
151
- kind: SHOW_KIND[kind]
152
- }
144
+ message: "Unexpected empty {{name}}.",
145
+ data: { name }
153
146
  });
154
147
  }
155
148
  }
@@ -60,9 +60,9 @@ module.exports = {
60
60
  return;
61
61
  }
62
62
 
63
- const affectsProto = lhs.object.computed ?
64
- lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype" :
65
- lhs.object.property.name === "prototype";
63
+ const affectsProto = lhs.object.computed
64
+ ? lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype"
65
+ : lhs.object.property.name === "prototype";
66
66
 
67
67
  if (!affectsProto) {
68
68
  return;
@@ -8,7 +8,7 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const getPropertyName = require("../ast-utils").getStaticPropertyName;
11
+ const astUtils = require("../ast-utils");
12
12
 
13
13
  //------------------------------------------------------------------------------
14
14
  // Rule Definition
@@ -44,8 +44,7 @@ module.exports = {
44
44
  loc: node.parent.property.loc.start,
45
45
  fix(fixer) {
46
46
  const firstTokenToRemove = context.getSourceCode()
47
- .getTokensBetween(node.parent.object, node.parent.property)
48
- .find(token => token.value !== ")");
47
+ .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
49
48
 
50
49
  return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]);
51
50
  }
@@ -73,7 +72,7 @@ module.exports = {
73
72
  grandparent.arguments.length === 1 &&
74
73
  parent.type === "MemberExpression" &&
75
74
  parent.object === node &&
76
- getPropertyName(parent) === "bind"
75
+ astUtils.getStaticPropertyName(parent) === "bind"
77
76
  );
78
77
  }
79
78
 
@@ -98,6 +98,14 @@ module.exports = {
98
98
  node,
99
99
  message: "Redundant Boolean call.",
100
100
  fix: fixer => {
101
+ if (!node.arguments.length) {
102
+ return fixer.replaceText(parent, "true");
103
+ }
104
+
105
+ if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") {
106
+ return null;
107
+ }
108
+
101
109
  const argument = node.arguments[0];
102
110
 
103
111
  if (astUtils.getPrecedence(argument) < astUtils.getPrecedence(node.parent)) {
@@ -557,8 +557,7 @@ module.exports = {
557
557
  !(
558
558
  (node.object.type === "Literal" &&
559
559
  typeof node.object.value === "number" &&
560
- astUtils.isDecimalInteger(node.object))
561
- ||
560
+ astUtils.isDecimalInteger(node.object)) ||
562
561
 
563
562
  // RegExp literal is allowed to have parens (#1589)
564
563
  (node.object.type === "Literal" && node.object.regex)
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const FixTracker = require("../util/fix-tracker");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -34,7 +40,13 @@ module.exports = {
34
40
  node: nodeOrToken,
35
41
  message: "Unnecessary semicolon.",
36
42
  fix(fixer) {
37
- return fixer.remove(nodeOrToken);
43
+
44
+ // Expand the replacement range to include the surrounding
45
+ // tokens to avoid conflicting with semi.
46
+ // https://github.com/eslint/eslint/issues/7928
47
+ return new FixTracker(fixer, context.getSourceCode())
48
+ .retainSurroundingTokens(nodeOrToken)
49
+ .remove(nodeOrToken);
38
50
  }
39
51
  });
40
52
  }
@@ -64,10 +64,10 @@ module.exports = {
64
64
 
65
65
  if (!valid) {
66
66
  context.report({ node, message: "Move {{type}} declaration to {{body}} root.", data: {
67
- type: (node.type === "FunctionDeclaration" ?
68
- "function" : "variable"),
69
- body: (body.type === "Program" ?
70
- "program" : "function body")
67
+ type: (node.type === "FunctionDeclaration"
68
+ ? "function" : "variable"),
69
+ body: (body.type === "Program"
70
+ ? "program" : "function body")
71
71
  } });
72
72
  }
73
73
  }
@@ -74,7 +74,8 @@ module.exports = {
74
74
  } catch (e) {
75
75
  context.report({
76
76
  node,
77
- message: `${e.message}.`
77
+ message: "{{message}}.",
78
+ data: e
78
79
  });
79
80
  }
80
81
 
@@ -6,6 +6,12 @@
6
6
 
7
7
  "use strict";
8
8
 
9
+ //------------------------------------------------------------------------------
10
+ // Requirements
11
+ //------------------------------------------------------------------------------
12
+
13
+ const astUtils = require("../ast-utils");
14
+
9
15
  //------------------------------------------------------------------------------
10
16
  // Constants
11
17
  //------------------------------------------------------------------------------
@@ -13,7 +19,7 @@
13
19
  const ALL_IRREGULARS = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000\u2028\u2029]/;
14
20
  const IRREGULAR_WHITESPACE = /[\f\v\u0085\u00A0\ufeff\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u202f\u205f\u3000]+/mg;
15
21
  const IRREGULAR_LINE_TERMINATORS = /[\u2028\u2029]/mg;
16
- const LINE_BREAK = /\r\n|\r|\n|\u2028|\u2029/g;
22
+ const LINE_BREAK = astUtils.createGlobalLinebreakMatcher();
17
23
 
18
24
  //------------------------------------------------------------------------------
19
25
  // Rule Definition
@@ -32,22 +32,22 @@ module.exports = {
32
32
  * @returns {void}
33
33
  */
34
34
  function report(node) {
35
- const parent = context.getAncestors().pop();
35
+ const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant.";
36
36
 
37
- context.report({ node, message: parent.type === "Program" ?
38
- "Block is redundant." :
39
- "Nested block is redundant."
40
- });
37
+ context.report({ node, message });
41
38
  }
42
39
 
43
40
  /**
44
- * Checks for any ocurrence of BlockStatement > BlockStatement or Program > BlockStatement
45
- * @returns {boolean} True if the current node is a lone block.
41
+ * Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
42
+ * @param {ASTNode} node The node to check
43
+ * @returns {boolean} True if the node is a lone block.
46
44
  */
47
- function isLoneBlock() {
48
- const parent = context.getAncestors().pop();
45
+ function isLoneBlock(node) {
46
+ return node.parent.type === "BlockStatement" ||
47
+ node.parent.type === "Program" ||
49
48
 
50
- return parent.type === "BlockStatement" || parent.type === "Program";
49
+ // Don't report blocks in switch cases if the block is the only statement of the case.
50
+ node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
51
51
  }
52
52
 
53
53
  /**
@@ -148,13 +148,7 @@ module.exports = {
148
148
  * @returns {Token} The operator token of the node.
149
149
  */
150
150
  function getOperatorToken(node) {
151
- let token = sourceCode.getTokenAfter(node.left);
152
-
153
- while (token.value === ")") {
154
- token = sourceCode.getTokenAfter(token);
155
- }
156
-
157
- return token;
151
+ return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
158
152
  }
159
153
 
160
154
  /**
@@ -5,6 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const astUtils = require("../ast-utils");
9
+
8
10
  //------------------------------------------------------------------------------
9
11
  // Rule Definition
10
12
  //------------------------------------------------------------------------------
@@ -93,7 +95,8 @@ module.exports = {
93
95
  const sourceCode = context.getSourceCode(),
94
96
  source = sourceCode.getText(),
95
97
  allComments = sourceCode.getAllComments(),
96
- pattern = /[^\n\r\u2028\u2029\t ].? {2,}/g; // note: repeating space
98
+ JOINED_LINEBEAKS = Array.from(astUtils.LINEBREAKS).join(""),
99
+ pattern = new RegExp(String.raw`[^ \t${JOINED_LINEBEAKS}].? {2,}`, "g"); // note: repeating space
97
100
  let parent;
98
101
 
99
102
 
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -39,9 +45,7 @@ module.exports = {
39
45
  return {
40
46
 
41
47
  Literal(node) {
42
- const lineBreak = /\n/;
43
-
44
- if (lineBreak.test(node.raw) && !isJSXElement(node.parent)) {
48
+ if (astUtils.LINEBREAK_MATCHER.test(node.raw) && !isJSXElement(node.parent)) {
45
49
  context.report({ node, message: "Multiline support is limited to browsers supporting ES5 only." });
46
50
  }
47
51
  }
@@ -5,8 +5,6 @@
5
5
  */
6
6
  "use strict";
7
7
 
8
- const astUtils = require("../ast-utils");
9
-
10
8
  //------------------------------------------------------------------------------
11
9
  // Rule Definition
12
10
  //------------------------------------------------------------------------------
@@ -114,8 +112,8 @@ module.exports = {
114
112
  data: { max: maxAllowed, pluralizedLines: maxAllowed === 1 ? "line" : "lines" },
115
113
  fix(fixer) {
116
114
  return fixer.removeRange([
117
- astUtils.getRangeIndexFromLocation(sourceCode, { line: lastLineNumber + 1, column: 0 }),
118
- astUtils.getRangeIndexFromLocation(sourceCode, { line: lineNumber - maxAllowed, column: 0 })
115
+ sourceCode.getIndexFromLoc({ line: lastLineNumber + 1, column: 0 }),
116
+ sourceCode.getIndexFromLoc({ line: lineNumber - maxAllowed, column: 0 })
119
117
  ]);
120
118
  }
121
119
  });
@@ -20,17 +20,40 @@ module.exports = {
20
20
 
21
21
  schema: [
22
22
  {
23
- type: "object",
24
- properties: {
25
- props: { type: "boolean" }
26
- },
27
- additionalProperties: false
23
+ oneOf: [
24
+ {
25
+ type: "object",
26
+ properties: {
27
+ props: {
28
+ enum: [false]
29
+ }
30
+ },
31
+ additionalProperties: false
32
+ },
33
+ {
34
+ type: "object",
35
+ properties: {
36
+ props: {
37
+ enum: [true]
38
+ },
39
+ ignorePropertyModificationsFor: {
40
+ type: "array",
41
+ items: {
42
+ type: "string"
43
+ },
44
+ uniqueItems: true
45
+ }
46
+ },
47
+ additionalProperties: false
48
+ }
49
+ ]
28
50
  }
29
51
  ]
30
52
  },
31
53
 
32
54
  create(context) {
33
55
  const props = context.options[0] && Boolean(context.options[0].props);
56
+ const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
34
57
 
35
58
  /**
36
59
  * Checks whether or not the reference modifies properties of its variable.
@@ -103,7 +126,7 @@ module.exports = {
103
126
  ) {
104
127
  if (reference.isWrite()) {
105
128
  context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
106
- } else if (props && isModifyingProp(reference)) {
129
+ } else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
107
130
  context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
108
131
  }
109
132
  }
@@ -109,6 +109,7 @@ module.exports = {
109
109
  if (matchedObjectProperty) {
110
110
  const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : "";
111
111
 
112
+ // eslint-disable-next-line eslint-plugin/report-message-format
112
113
  context.report({ node, message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", data: {
113
114
  objectName,
114
115
  propertyName,
@@ -117,6 +118,7 @@ module.exports = {
117
118
  } else if (globalMatchedProperty) {
118
119
  const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : "";
119
120
 
121
+ // eslint-disable-next-line eslint-plugin/report-message-format
120
122
  context.report({ node, message: "'{{propertyName}}' is restricted from being used.{{message}}", data: {
121
123
  propertyName,
122
124
  message
@@ -5,23 +5,16 @@
5
5
  "use strict";
6
6
 
7
7
  //------------------------------------------------------------------------------
8
- // Helpers
8
+ // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/;
11
+ const astUtils = require("../ast-utils");
12
12
 
13
- /**
14
- * Checks whether or not a node is enclosed in parentheses.
15
- * @param {Node|null} node - A node to check.
16
- * @param {sourceCode} sourceCode - The ESLint SourceCode object.
17
- * @returns {boolean} Whether or not the node is enclosed in parentheses.
18
- */
19
- function isEnclosedInParens(node, sourceCode) {
20
- const prevToken = sourceCode.getTokenBefore(node);
21
- const nextToken = sourceCode.getTokenAfter(node);
13
+ //------------------------------------------------------------------------------
14
+ // Helpers
15
+ //------------------------------------------------------------------------------
22
16
 
23
- return prevToken && prevToken.value === "(" && nextToken && nextToken.value === ")";
24
- }
17
+ const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionExpression|ClassExpression)$/;
25
18
 
26
19
  //------------------------------------------------------------------------------
27
20
  // Rule Definition
@@ -48,7 +41,7 @@ module.exports = {
48
41
 
49
42
  return {
50
43
  AssignmentExpression(node) {
51
- if (!always && isEnclosedInParens(node, sourceCode)) {
44
+ if (!always && astUtils.isParenthesised(sourceCode, node)) {
52
45
  return;
53
46
  }
54
47
 
@@ -19,7 +19,7 @@ module.exports = {
19
19
  category: "Best Practices",
20
20
  recommended: false // TODO: set to true
21
21
  },
22
- fixable: false,
22
+ fixable: null,
23
23
  schema: [
24
24
  ]
25
25
  },
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("../ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -57,12 +63,7 @@ module.exports = {
57
63
  * @returns {boolean} True if the node has a paren on each side.
58
64
  */
59
65
  function isParenthesised(node) {
60
- const previousToken = sourceCode.getTokenBefore(node),
61
- nextToken = sourceCode.getTokenAfter(node);
62
-
63
- return previousToken && nextToken &&
64
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
65
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
66
+ return astUtils.isParenthesised(sourceCode, node);
66
67
  }
67
68
 
68
69
  /**
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const astUtils = require("../ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
@@ -34,7 +40,7 @@ module.exports = {
34
40
  create(context) {
35
41
  const sourceCode = context.getSourceCode();
36
42
 
37
- const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u2028\u2029\u3000]",
43
+ const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u3000]",
38
44
  SKIP_BLANK = `^${BLANK_CLASS}*$`,
39
45
  NONBLANK = `${BLANK_CLASS}+$`;
40
46
 
@@ -81,7 +87,7 @@ module.exports = {
81
87
  const re = new RegExp(NONBLANK),
82
88
  skipMatch = new RegExp(SKIP_BLANK),
83
89
  lines = sourceCode.lines,
84
- linebreaks = sourceCode.getText().match(/\r\n|\r|\n|\u2028|\u2029/g);
90
+ linebreaks = sourceCode.getText().match(astUtils.createGlobalLinebreakMatcher());
85
91
  let totalLength = 0,
86
92
  fixRange = [];
87
93