eslint 6.2.0 → 6.4.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 (40) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +8 -2
  3. package/conf/config-schema.js +1 -0
  4. package/conf/default-cli-options.js +1 -1
  5. package/lib/cli-engine/config-array/config-array.js +6 -0
  6. package/lib/cli-engine/config-array/extracted-config.js +6 -0
  7. package/lib/cli-engine/config-array/override-tester.js +2 -2
  8. package/lib/cli-engine/config-array-factory.js +2 -0
  9. package/lib/cli-engine/formatters/stylish.js +2 -1
  10. package/lib/init/config-initializer.js +29 -0
  11. package/lib/init/npm-utils.js +8 -8
  12. package/lib/linter/apply-disable-directives.js +17 -9
  13. package/lib/linter/linter.js +23 -3
  14. package/lib/options.js +1 -1
  15. package/lib/rules/accessor-pairs.js +51 -11
  16. package/lib/rules/computed-property-spacing.js +18 -1
  17. package/lib/rules/default-param-last.js +61 -0
  18. package/lib/rules/eqeqeq.js +7 -19
  19. package/lib/rules/func-name-matching.js +1 -0
  20. package/lib/rules/function-paren-newline.js +2 -2
  21. package/lib/rules/indent.js +16 -6
  22. package/lib/rules/index.js +3 -0
  23. package/lib/rules/no-extra-boolean-cast.js +12 -2
  24. package/lib/rules/no-extra-parens.js +8 -1
  25. package/lib/rules/no-import-assign.js +238 -0
  26. package/lib/rules/no-lone-blocks.js +6 -1
  27. package/lib/rules/no-obj-calls.js +29 -9
  28. package/lib/rules/no-octal-escape.js +14 -8
  29. package/lib/rules/no-self-assign.js +17 -6
  30. package/lib/rules/no-sequences.js +2 -2
  31. package/lib/rules/no-unsafe-negation.js +2 -10
  32. package/lib/rules/object-curly-spacing.js +1 -1
  33. package/lib/rules/object-shorthand.js +35 -9
  34. package/lib/rules/prefer-regex-literals.js +125 -0
  35. package/lib/rules/quotes.js +6 -0
  36. package/lib/rules/space-before-function-paren.js +12 -1
  37. package/lib/rules/space-in-parens.js +77 -71
  38. package/lib/rules/yoda.js +11 -2
  39. package/lib/shared/types.js +2 -0
  40. package/package.json +3 -3
@@ -116,18 +116,6 @@ module.exports = {
116
116
  return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
117
117
  }
118
118
 
119
- /**
120
- * Gets the location (line and column) of the binary expression's operator
121
- * @param {ASTNode} node The binary expression node to check
122
- * @returns {Object} { line, column } location of operator
123
- * @private
124
- */
125
- function getOperatorLocation(node) {
126
- const opToken = sourceCode.getTokenAfter(node.left);
127
-
128
- return { line: opToken.loc.start.line, column: opToken.loc.start.column };
129
- }
130
-
131
119
  /**
132
120
  * Reports a message for this rule.
133
121
  * @param {ASTNode} node The binary expression node that was checked
@@ -136,21 +124,21 @@ module.exports = {
136
124
  * @private
137
125
  */
138
126
  function report(node, expectedOperator) {
127
+ const operatorToken = sourceCode.getFirstTokenBetween(
128
+ node.left,
129
+ node.right,
130
+ token => token.value === node.operator
131
+ );
132
+
139
133
  context.report({
140
134
  node,
141
- loc: getOperatorLocation(node),
135
+ loc: operatorToken.loc,
142
136
  messageId: "unexpected",
143
137
  data: { expectedOperator, actualOperator: node.operator },
144
138
  fix(fixer) {
145
139
 
146
140
  // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
147
141
  if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
148
- const operatorToken = sourceCode.getFirstTokenBetween(
149
- node.left,
150
- node.right,
151
- token => token.value === node.operator
152
- );
153
-
154
142
  return fixer.replaceText(operatorToken, expectedOperator);
155
143
  }
156
144
  return null;
@@ -118,6 +118,7 @@ module.exports = {
118
118
  return false;
119
119
  }
120
120
  return node.type === "CallExpression" &&
121
+ node.callee.type === "MemberExpression" &&
121
122
  node.callee.object.name === objName &&
122
123
  node.callee.property.name === funcName;
123
124
  }
@@ -51,8 +51,8 @@ module.exports = {
51
51
  expectedBefore: "Expected newline before ')'.",
52
52
  expectedAfter: "Expected newline after '('.",
53
53
  expectedBetween: "Expected newline between arguments/params.",
54
- unexpectedBefore: "Unexpected newline before '('.",
55
- unexpectedAfter: "Unexpected newline after ')'."
54
+ unexpectedBefore: "Unexpected newline before ')'.",
55
+ unexpectedAfter: "Unexpected newline after '('."
56
56
  }
57
57
  },
58
58
 
@@ -1588,18 +1588,23 @@ module.exports = {
1588
1588
  return;
1589
1589
  }
1590
1590
 
1591
- // If the token matches the expected expected indentation, don't report it.
1592
- if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
1593
- return;
1594
- }
1595
-
1596
1591
  if (astUtils.isCommentToken(firstTokenOfLine)) {
1597
1592
  const tokenBefore = precedingTokens.get(firstTokenOfLine);
1598
1593
  const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0];
1599
-
1600
1594
  const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine);
1601
1595
  const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter);
1602
1596
 
1597
+ /*
1598
+ * If a comment precedes a line that begins with a semicolon token, align to that token, i.e.
1599
+ *
1600
+ * let foo
1601
+ * // comment
1602
+ * ;(async () => {})()
1603
+ */
1604
+ if (tokenAfter && astUtils.isSemicolonToken(tokenAfter) && !astUtils.isTokenOnSameLine(firstTokenOfLine, tokenAfter)) {
1605
+ offsets.setDesiredOffset(firstTokenOfLine, tokenAfter, 0);
1606
+ }
1607
+
1603
1608
  // If a comment matches the expected indentation of the token immediately before or after, don't report it.
1604
1609
  if (
1605
1610
  mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
@@ -1609,6 +1614,11 @@ module.exports = {
1609
1614
  }
1610
1615
  }
1611
1616
 
1617
+ // If the token matches the expected indentation, don't report it.
1618
+ if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
1619
+ return;
1620
+ }
1621
+
1612
1622
  // Otherwise, report the token/comment.
1613
1623
  report(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine));
1614
1624
  });
@@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
37
37
  "constructor-super": () => require("./constructor-super"),
38
38
  curly: () => require("./curly"),
39
39
  "default-case": () => require("./default-case"),
40
+ "default-param-last": () => require("./default-param-last"),
40
41
  "dot-location": () => require("./dot-location"),
41
42
  "dot-notation": () => require("./dot-notation"),
42
43
  "eol-last": () => require("./eol-last"),
@@ -131,6 +132,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
131
132
  "no-implicit-coercion": () => require("./no-implicit-coercion"),
132
133
  "no-implicit-globals": () => require("./no-implicit-globals"),
133
134
  "no-implied-eval": () => require("./no-implied-eval"),
135
+ "no-import-assign": () => require("./no-import-assign"),
134
136
  "no-inline-comments": () => require("./no-inline-comments"),
135
137
  "no-inner-declarations": () => require("./no-inner-declarations"),
136
138
  "no-invalid-regexp": () => require("./no-invalid-regexp"),
@@ -241,6 +243,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
241
243
  "prefer-object-spread": () => require("./prefer-object-spread"),
242
244
  "prefer-promise-reject-errors": () => require("./prefer-promise-reject-errors"),
243
245
  "prefer-reflect": () => require("./prefer-reflect"),
246
+ "prefer-regex-literals": () => require("./prefer-regex-literals"),
244
247
  "prefer-rest-params": () => require("./prefer-rest-params"),
245
248
  "prefer-spread": () => require("./prefer-spread"),
246
249
  "prefer-template": () => require("./prefer-template"),
@@ -96,13 +96,23 @@ module.exports = {
96
96
  grandparent.callee.name === "Boolean")
97
97
  ) {
98
98
  context.report({
99
- node,
99
+ node: parent,
100
100
  messageId: "unexpectedNegation",
101
101
  fix: fixer => {
102
102
  if (hasCommentsInside(parent)) {
103
103
  return null;
104
104
  }
105
- return fixer.replaceText(parent, sourceCode.getText(node.argument));
105
+
106
+ let prefix = "";
107
+ const tokenBefore = sourceCode.getTokenBefore(parent);
108
+ const firstReplacementToken = sourceCode.getFirstToken(node.argument);
109
+
110
+ if (tokenBefore && tokenBefore.range[1] === parent.range[0] &&
111
+ !astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)) {
112
+ prefix = " ";
113
+ }
114
+
115
+ return fixer.replaceText(parent, prefix + sourceCode.getText(node.argument));
106
116
  }
107
117
  });
108
118
  }
@@ -49,7 +49,8 @@ module.exports = {
49
49
  nestedBinaryExpressions: { type: "boolean" },
50
50
  returnAssign: { type: "boolean" },
51
51
  ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] },
52
- enforceForArrowConditionals: { type: "boolean" }
52
+ enforceForArrowConditionals: { type: "boolean" },
53
+ enforceForSequenceExpressions: { type: "boolean" }
53
54
  },
54
55
  additionalProperties: false
55
56
  }
@@ -77,6 +78,8 @@ module.exports = {
77
78
  const IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX;
78
79
  const IGNORE_ARROW_CONDITIONALS = ALL_NODES && context.options[1] &&
79
80
  context.options[1].enforceForArrowConditionals === false;
81
+ const IGNORE_SEQUENCE_EXPRESSIONS = ALL_NODES && context.options[1] &&
82
+ context.options[1].enforceForSequenceExpressions === false;
80
83
 
81
84
  const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
82
85
  const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
@@ -115,6 +118,10 @@ module.exports = {
115
118
  }
116
119
  }
117
120
 
121
+ if (node.type === "SequenceExpression" && IGNORE_SEQUENCE_EXPRESSIONS) {
122
+ return false;
123
+ }
124
+
118
125
  return ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
119
126
  }
120
127
 
@@ -0,0 +1,238 @@
1
+ /**
2
+ * @fileoverview Rule to flag updates of imported bindings.
3
+ * @author Toru Nagashima <https://github.com/mysticatea>
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Helpers
10
+ //------------------------------------------------------------------------------
11
+
12
+ const { findVariable, getPropertyName } = require("eslint-utils");
13
+
14
+ const MutationMethods = {
15
+ Object: new Set([
16
+ "assign", "defineProperties", "defineProperty", "freeze",
17
+ "setPrototypeOf"
18
+ ]),
19
+ Reflect: new Set([
20
+ "defineProperty", "deleteProperty", "set", "setPrototypeOf"
21
+ ])
22
+ };
23
+
24
+ /**
25
+ * Check if a given node is LHS of an assignment node.
26
+ * @param {ASTNode} node The node to check.
27
+ * @returns {boolean} `true` if the node is LHS.
28
+ */
29
+ function isAssignmentLeft(node) {
30
+ const { parent } = node;
31
+
32
+ return (
33
+ (
34
+ parent.type === "AssignmentExpression" &&
35
+ parent.left === node
36
+ ) ||
37
+
38
+ // Destructuring assignments
39
+ parent.type === "ArrayPattern" ||
40
+ (
41
+ parent.type === "Property" &&
42
+ parent.value === node &&
43
+ parent.parent.type === "ObjectPattern"
44
+ ) ||
45
+ parent.type === "RestElement" ||
46
+ (
47
+ parent.type === "AssignmentPattern" &&
48
+ parent.left === node
49
+ )
50
+ );
51
+ }
52
+
53
+ /**
54
+ * Check if a given node is the operand of mutation unary operator.
55
+ * @param {ASTNode} node The node to check.
56
+ * @returns {boolean} `true` if the node is the operand of mutation unary operator.
57
+ */
58
+ function isOperandOfMutationUnaryOperator(node) {
59
+ const { parent } = node;
60
+
61
+ return (
62
+ (
63
+ parent.type === "UpdateExpression" &&
64
+ parent.argument === node
65
+ ) ||
66
+ (
67
+ parent.type === "UnaryExpression" &&
68
+ parent.operator === "delete" &&
69
+ parent.argument === node
70
+ )
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Check if a given node is the iteration variable of `for-in`/`for-of` syntax.
76
+ * @param {ASTNode} node The node to check.
77
+ * @returns {boolean} `true` if the node is the iteration variable.
78
+ */
79
+ function isIterationVariable(node) {
80
+ const { parent } = node;
81
+
82
+ return (
83
+ (
84
+ parent.type === "ForInStatement" &&
85
+ parent.left === node
86
+ ) ||
87
+ (
88
+ parent.type === "ForOfStatement" &&
89
+ parent.left === node
90
+ )
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Check if a given node is the iteration variable of `for-in`/`for-of` syntax.
96
+ * @param {ASTNode} node The node to check.
97
+ * @param {Scope} scope A `escope.Scope` object to find variable (whichever).
98
+ * @returns {boolean} `true` if the node is the iteration variable.
99
+ */
100
+ function isArgumentOfWellKnownMutationFunction(node, scope) {
101
+ const { parent } = node;
102
+
103
+ if (
104
+ parent.type === "CallExpression" &&
105
+ parent.arguments[0] === node &&
106
+ parent.callee.type === "MemberExpression" &&
107
+ parent.callee.object.type === "Identifier"
108
+ ) {
109
+ const { callee } = parent;
110
+ const { object } = callee;
111
+
112
+ if (Object.keys(MutationMethods).includes(object.name)) {
113
+ const variable = findVariable(scope, object);
114
+
115
+ return (
116
+ variable !== null &&
117
+ variable.scope.type === "global" &&
118
+ MutationMethods[object.name].has(getPropertyName(callee, scope))
119
+ );
120
+ }
121
+ }
122
+
123
+ return false;
124
+ }
125
+
126
+ /**
127
+ * Check if the identifier node is placed at to update members.
128
+ * @param {ASTNode} id The Identifier node to check.
129
+ * @param {Scope} scope A `escope.Scope` object to find variable (whichever).
130
+ * @returns {boolean} `true` if the member of `id` was updated.
131
+ */
132
+ function isMemberWrite(id, scope) {
133
+ const { parent } = id;
134
+
135
+ return (
136
+ (
137
+ parent.type === "MemberExpression" &&
138
+ parent.object === id &&
139
+ (
140
+ isAssignmentLeft(parent) ||
141
+ isOperandOfMutationUnaryOperator(parent) ||
142
+ isIterationVariable(parent)
143
+ )
144
+ ) ||
145
+ isArgumentOfWellKnownMutationFunction(id, scope)
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Get the mutation node.
151
+ * @param {ASTNode} id The Identifier node to get.
152
+ * @returns {ASTNode} The mutation node.
153
+ */
154
+ function getWriteNode(id) {
155
+ let node = id.parent;
156
+
157
+ while (
158
+ node &&
159
+ node.type !== "AssignmentExpression" &&
160
+ node.type !== "UpdateExpression" &&
161
+ node.type !== "UnaryExpression" &&
162
+ node.type !== "CallExpression" &&
163
+ node.type !== "ForInStatement" &&
164
+ node.type !== "ForOfStatement"
165
+ ) {
166
+ node = node.parent;
167
+ }
168
+
169
+ return node || id;
170
+ }
171
+
172
+ //------------------------------------------------------------------------------
173
+ // Rule Definition
174
+ //------------------------------------------------------------------------------
175
+
176
+ module.exports = {
177
+ meta: {
178
+ type: "problem",
179
+
180
+ docs: {
181
+ description: "disallow assigning to imported bindings",
182
+ category: "Possible Errors",
183
+ recommended: false,
184
+ url: "https://eslint.org/docs/rules/no-import-assign"
185
+ },
186
+
187
+ schema: [],
188
+
189
+ messages: {
190
+ readonly: "'{{name}}' is read-only.",
191
+ readonlyMember: "The members of '{{name}}' are read-only."
192
+ }
193
+ },
194
+
195
+ create(context) {
196
+ return {
197
+ ImportDeclaration(node) {
198
+ const scope = context.getScope();
199
+
200
+ for (const variable of context.getDeclaredVariables(node)) {
201
+ const shouldCheckMembers = variable.defs.some(
202
+ d => d.node.type === "ImportNamespaceSpecifier"
203
+ );
204
+ let prevIdNode = null;
205
+
206
+ for (const reference of variable.references) {
207
+ const idNode = reference.identifier;
208
+
209
+ /*
210
+ * AssignmentPattern (e.g. `[a = 0] = b`) makes two write
211
+ * references for the same identifier. This should skip
212
+ * the one of the two in order to prevent redundant reports.
213
+ */
214
+ if (idNode === prevIdNode) {
215
+ continue;
216
+ }
217
+ prevIdNode = idNode;
218
+
219
+ if (reference.isWrite()) {
220
+ context.report({
221
+ node: getWriteNode(idNode),
222
+ messageId: "readonly",
223
+ data: { name: idNode.name }
224
+ });
225
+ } else if (shouldCheckMembers && isMemberWrite(idNode, scope)) {
226
+ context.report({
227
+ node: getWriteNode(idNode),
228
+ messageId: "readonlyMember",
229
+ data: { name: idNode.name }
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+ };
236
+
237
+ }
238
+ };
@@ -79,7 +79,7 @@ module.exports = {
79
79
  }
80
80
  };
81
81
 
82
- // ES6: report blocks without block-level bindings
82
+ // ES6: report blocks without block-level bindings, or that's only child of another block
83
83
  if (context.parserOptions.ecmaVersion >= 6) {
84
84
  ruleDef = {
85
85
  BlockStatement(node) {
@@ -91,6 +91,11 @@ module.exports = {
91
91
  if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
92
92
  loneBlocks.pop();
93
93
  report(node);
94
+ } else if (
95
+ node.parent.type === "BlockStatement" &&
96
+ node.parent.body.length === 1
97
+ ) {
98
+ report(node);
94
99
  }
95
100
  }
96
101
  };
@@ -5,6 +5,18 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const { CALL, ReferenceTracker } = require("eslint-utils");
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Helpers
16
+ //------------------------------------------------------------------------------
17
+
18
+ const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
19
+
8
20
  //------------------------------------------------------------------------------
9
21
  // Rule Definition
10
22
  //------------------------------------------------------------------------------
@@ -20,23 +32,31 @@ module.exports = {
20
32
  url: "https://eslint.org/docs/rules/no-obj-calls"
21
33
  },
22
34
 
23
- schema: []
35
+ schema: [],
36
+
37
+ messages: {
38
+ unexpectedCall: "'{{name}}' is not a function."
39
+ }
24
40
  },
25
41
 
26
42
  create(context) {
27
43
 
28
44
  return {
29
- CallExpression(node) {
30
-
31
- if (node.callee.type === "Identifier") {
32
- const name = node.callee.name;
45
+ Program() {
46
+ const scope = context.getScope();
47
+ const tracker = new ReferenceTracker(scope);
48
+ const traceMap = {};
49
+
50
+ for (const global of nonCallableGlobals) {
51
+ traceMap[global] = {
52
+ [CALL]: true
53
+ };
54
+ }
33
55
 
34
- if (name === "Math" || name === "JSON" || name === "Reflect") {
35
- context.report({ node, message: "'{{name}}' is not a function.", data: { name } });
36
- }
56
+ for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
57
+ context.report({ node, messageId: "unexpectedCall", data: { name: node.callee.name } });
37
58
  }
38
59
  }
39
60
  };
40
-
41
61
  }
42
62
  };
@@ -20,7 +20,11 @@ module.exports = {
20
20
  url: "https://eslint.org/docs/rules/no-octal-escape"
21
21
  },
22
22
 
23
- schema: []
23
+ schema: [],
24
+
25
+ messages: {
26
+ octalEscapeSequence: "Don't use octal: '\\{{sequence}}'. Use '\\u....' instead."
27
+ }
24
28
  },
25
29
 
26
30
  create(context) {
@@ -32,15 +36,17 @@ module.exports = {
32
36
  return;
33
37
  }
34
38
 
35
- const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/u);
39
+ // \0 represents a valid NULL character if it isn't followed by a digit.
40
+ const match = node.raw.match(
41
+ /^(?:[^\\]|\\.)*?\\([0-3][0-7]{1,2}|[4-7][0-7]|[1-7])/u
42
+ );
36
43
 
37
44
  if (match) {
38
- const octalDigit = match[2];
39
-
40
- // \0 is actually not considered an octal
41
- if (match[2] !== "0" || typeof match[3] !== "undefined") {
42
- context.report({ node, message: "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", data: { octalDigit } });
43
- }
45
+ context.report({
46
+ node,
47
+ messageId: "octalEscapeSequence",
48
+ data: { sequence: match[1] }
49
+ });
44
50
  }
45
51
  }
46
52
 
@@ -94,9 +94,19 @@ function eachSelfAssignment(left, right, props, report) {
94
94
  const end = Math.min(left.elements.length, right.elements.length);
95
95
 
96
96
  for (let i = 0; i < end; ++i) {
97
+ const leftElement = left.elements[i];
97
98
  const rightElement = right.elements[i];
98
99
 
99
- eachSelfAssignment(left.elements[i], rightElement, props, report);
100
+ // Avoid cases such as [...a] = [...a, 1]
101
+ if (
102
+ leftElement &&
103
+ leftElement.type === "RestElement" &&
104
+ i < right.elements.length - 1
105
+ ) {
106
+ break;
107
+ }
108
+
109
+ eachSelfAssignment(leftElement, rightElement, props, report);
100
110
 
101
111
  // After a spread element, those indices are unknown.
102
112
  if (rightElement && rightElement.type === "SpreadElement") {
@@ -142,13 +152,14 @@ function eachSelfAssignment(left, right, props, report) {
142
152
  } else if (
143
153
  left.type === "Property" &&
144
154
  right.type === "Property" &&
145
- !left.computed &&
146
- !right.computed &&
147
155
  right.kind === "init" &&
148
- !right.method &&
149
- left.key.name === right.key.name
156
+ !right.method
150
157
  ) {
151
- eachSelfAssignment(left.value, right.value, props, report);
158
+ const leftName = astUtils.getStaticPropertyName(left);
159
+
160
+ if (leftName !== null && leftName === astUtils.getStaticPropertyName(right)) {
161
+ eachSelfAssignment(left.value, right.value, props, report);
162
+ }
152
163
  } else if (
153
164
  props &&
154
165
  left.type === "MemberExpression" &&
@@ -105,9 +105,9 @@ module.exports = {
105
105
  }
106
106
  }
107
107
 
108
- const child = sourceCode.getTokenAfter(node.expressions[0]);
108
+ const firstCommaToken = sourceCode.getTokenAfter(node.expressions[0], astUtils.isCommaToken);
109
109
 
110
- context.report({ node, loc: child.loc.start, message: "Unexpected use of comma operator." });
110
+ context.report({ node, loc: firstCommaToken.loc, message: "Unexpected use of comma operator." });
111
111
  }
112
112
  };
113
113
 
@@ -51,7 +51,7 @@ module.exports = {
51
51
  },
52
52
 
53
53
  schema: [],
54
- fixable: "code",
54
+ fixable: null,
55
55
  messages: {
56
56
  unexpected: "Unexpected negating the left operand of '{{operator}}' operator."
57
57
  }
@@ -70,15 +70,7 @@ module.exports = {
70
70
  node,
71
71
  loc: node.left.loc,
72
72
  messageId: "unexpected",
73
- data: { operator: node.operator },
74
-
75
- fix(fixer) {
76
- const negationToken = sourceCode.getFirstToken(node.left);
77
- const fixRange = [negationToken.range[1], node.range[1]];
78
- const text = sourceCode.text.slice(fixRange[0], fixRange[1]);
79
-
80
- return fixer.replaceTextRange(fixRange, `(${text})`);
81
- }
73
+ data: { operator: node.operator }
82
74
  });
83
75
  }
84
76
  }
@@ -167,7 +167,7 @@ module.exports = {
167
167
  if (options.spaced && !firstSpaced) {
168
168
  reportRequiredBeginningSpace(node, first);
169
169
  }
170
- if (!options.spaced && firstSpaced) {
170
+ if (!options.spaced && firstSpaced && second.type !== "Line") {
171
171
  reportNoBeginningSpace(node, first);
172
172
  }
173
173
  }