eslint 6.6.0 → 6.8.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 (62) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +7 -8
  3. package/conf/config-schema.js +2 -0
  4. package/conf/default-cli-options.js +1 -1
  5. package/conf/eslint-recommended.js +0 -1
  6. package/lib/cli-engine/cascading-config-array-factory.js +38 -13
  7. package/lib/cli-engine/cli-engine.js +41 -14
  8. package/lib/cli-engine/config-array/config-array.js +13 -0
  9. package/lib/cli-engine/config-array/extracted-config.js +27 -0
  10. package/lib/cli-engine/config-array/ignore-pattern.js +231 -0
  11. package/lib/cli-engine/config-array/index.js +2 -0
  12. package/lib/cli-engine/config-array-factory.js +115 -1
  13. package/lib/cli-engine/file-enumerator.js +73 -40
  14. package/lib/cli-engine/lint-result-cache.js +2 -1
  15. package/lib/cli.js +2 -1
  16. package/lib/init/config-initializer.js +4 -3
  17. package/lib/linter/config-comment-parser.js +1 -1
  18. package/lib/linter/report-translator.js +73 -7
  19. package/lib/options.js +6 -0
  20. package/lib/rule-tester/rule-tester.js +42 -6
  21. package/lib/rules/array-bracket-spacing.js +8 -8
  22. package/lib/rules/camelcase.js +19 -6
  23. package/lib/rules/comma-dangle.js +5 -2
  24. package/lib/rules/computed-property-spacing.js +4 -4
  25. package/lib/rules/curly.js +9 -4
  26. package/lib/rules/function-call-argument-newline.js +3 -1
  27. package/lib/rules/grouped-accessor-pairs.js +224 -0
  28. package/lib/rules/indent.js +11 -0
  29. package/lib/rules/index.js +5 -0
  30. package/lib/rules/key-spacing.js +34 -15
  31. package/lib/rules/lines-between-class-members.js +42 -53
  32. package/lib/rules/multiline-comment-style.js +237 -106
  33. package/lib/rules/no-cond-assign.js +14 -4
  34. package/lib/rules/no-constructor-return.js +62 -0
  35. package/lib/rules/no-dupe-else-if.js +122 -0
  36. package/lib/rules/no-implicit-globals.js +90 -8
  37. package/lib/rules/no-inline-comments.js +25 -11
  38. package/lib/rules/no-invalid-this.js +16 -2
  39. package/lib/rules/no-multiple-empty-lines.js +1 -1
  40. package/lib/rules/no-octal-escape.js +1 -1
  41. package/lib/rules/no-restricted-imports.js +2 -2
  42. package/lib/rules/no-setter-return.js +227 -0
  43. package/lib/rules/no-underscore-dangle.js +23 -4
  44. package/lib/rules/no-unexpected-multiline.js +8 -0
  45. package/lib/rules/no-unsafe-negation.js +30 -5
  46. package/lib/rules/no-useless-computed-key.js +60 -33
  47. package/lib/rules/no-useless-escape.js +26 -3
  48. package/lib/rules/object-curly-spacing.js +8 -8
  49. package/lib/rules/operator-assignment.js +11 -2
  50. package/lib/rules/prefer-const.js +14 -7
  51. package/lib/rules/prefer-exponentiation-operator.js +189 -0
  52. package/lib/rules/prefer-numeric-literals.js +29 -28
  53. package/lib/rules/require-atomic-updates.js +1 -1
  54. package/lib/rules/require-await.js +8 -0
  55. package/lib/rules/semi.js +6 -3
  56. package/lib/rules/space-infix-ops.js +1 -1
  57. package/lib/rules/spaced-comment.js +5 -4
  58. package/lib/rules/utils/ast-utils.js +31 -4
  59. package/lib/shared/types.js +9 -0
  60. package/lib/source-code/source-code.js +87 -10
  61. package/package.json +4 -3
  62. package/lib/cli-engine/ignored-paths.js +0 -363
@@ -291,6 +291,7 @@ function processAnswers(answers) {
291
291
  jsx: true
292
292
  };
293
293
  config.plugins = ["react"];
294
+ config.extends.push("plugin:react/recommended");
294
295
  } else if (answers.framework === "vue") {
295
296
  config.plugins = ["vue"];
296
297
  config.extends.push("plugin:vue/essential");
@@ -522,9 +523,9 @@ function promptUser() {
522
523
  name: "styleguide",
523
524
  message: "Which style guide do you want to follow?",
524
525
  choices: [
525
- { name: "Airbnb (https://github.com/airbnb/javascript)", value: "airbnb" },
526
- { name: "Standard (https://github.com/standard/standard)", value: "standard" },
527
- { name: "Google (https://github.com/google/eslint-config-google)", value: "google" }
526
+ { name: "Airbnb: https://github.com/airbnb/javascript", value: "airbnb" },
527
+ { name: "Standard: https://github.com/standard/standard", value: "standard" },
528
+ { name: "Google: https://github.com/google/eslint-config-google", value: "google" }
528
529
  ],
529
530
  when(answers) {
530
531
  answers.packageJsonExists = npmUtils.checkPackageJson();
@@ -90,7 +90,7 @@ module.exports = class ConfigCommentParser {
90
90
  * But we are supporting that. So this is a fallback for that.
91
91
  */
92
92
  items = {};
93
- const normalizedString = string.replace(/([a-zA-Z0-9\-/]+):/gu, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/u, "$1,");
93
+ const normalizedString = string.replace(/([-a-zA-Z0-9/]+):/gu, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/u, "$1,");
94
94
 
95
95
  try {
96
96
  items = JSON.parse(`{${normalizedString}}`);
@@ -26,6 +26,7 @@ const interpolate = require("./interpolate");
26
26
  * @property {Object} [data] Optional data to use to fill in placeholders in the
27
27
  * message.
28
28
  * @property {Function} [fix] The function to call that creates a fix command.
29
+ * @property {Array<{desc?: string, messageId?: string, fix: Function}>} suggest Suggestion descriptions and functions to create a the associated fixes.
29
30
  */
30
31
 
31
32
  /**
@@ -34,14 +35,15 @@ const interpolate = require("./interpolate");
34
35
  * @property {string} ruleId
35
36
  * @property {(0|1|2)} severity
36
37
  * @property {(string|undefined)} message
37
- * @property {(string|undefined)} messageId
38
+ * @property {(string|undefined)} [messageId]
38
39
  * @property {number} line
39
40
  * @property {number} column
40
- * @property {(number|undefined)} endLine
41
- * @property {(number|undefined)} endColumn
41
+ * @property {(number|undefined)} [endLine]
42
+ * @property {(number|undefined)} [endColumn]
42
43
  * @property {(string|null)} nodeType
43
44
  * @property {string} source
44
- * @property {({text: string, range: (number[]|null)}|null)} fix
45
+ * @property {({text: string, range: (number[]|null)}|null)} [fix]
46
+ * @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions]
45
47
  */
46
48
 
47
49
  //------------------------------------------------------------------------------
@@ -182,6 +184,29 @@ function normalizeFixes(descriptor, sourceCode) {
182
184
  return fix;
183
185
  }
184
186
 
187
+ /**
188
+ * Gets an array of suggestion objects from the given descriptor.
189
+ * @param {MessageDescriptor} descriptor The report descriptor.
190
+ * @param {SourceCode} sourceCode The source code object to get text between fixes.
191
+ * @param {Object} messages Object of meta messages for the rule.
192
+ * @returns {Array<SuggestionResult>} The suggestions for the descriptor
193
+ */
194
+ function mapSuggestions(descriptor, sourceCode, messages) {
195
+ if (!descriptor.suggest || !Array.isArray(descriptor.suggest)) {
196
+ return [];
197
+ }
198
+
199
+ return descriptor.suggest.map(suggestInfo => {
200
+ const computedDesc = suggestInfo.desc || messages[suggestInfo.messageId];
201
+
202
+ return {
203
+ ...suggestInfo,
204
+ desc: interpolate(computedDesc, suggestInfo.data),
205
+ fix: normalizeFixes(suggestInfo, sourceCode)
206
+ };
207
+ });
208
+ }
209
+
185
210
  /**
186
211
  * Creates information about the report from a descriptor
187
212
  * @param {Object} options Information about the problem
@@ -192,6 +217,7 @@ function normalizeFixes(descriptor, sourceCode) {
192
217
  * @param {string} [options.messageId] The error message ID.
193
218
  * @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
194
219
  * @param {{text: string, range: (number[]|null)}} options.fix The fix object
220
+ * @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
195
221
  * @returns {function(...args): ReportInfo} Function that returns information about the report
196
222
  */
197
223
  function createProblem(options) {
@@ -221,9 +247,47 @@ function createProblem(options) {
221
247
  problem.fix = options.fix;
222
248
  }
223
249
 
250
+ if (options.suggestions && options.suggestions.length > 0) {
251
+ problem.suggestions = options.suggestions;
252
+ }
253
+
224
254
  return problem;
225
255
  }
226
256
 
257
+ /**
258
+ * Validates that suggestions are properly defined. Throws if an error is detected.
259
+ * @param {Array<{ desc?: string, messageId?: string }>} suggest The incoming suggest data.
260
+ * @param {Object} messages Object of meta messages for the rule.
261
+ * @returns {void}
262
+ */
263
+ function validateSuggestions(suggest, messages) {
264
+ if (suggest && Array.isArray(suggest)) {
265
+ suggest.forEach(suggestion => {
266
+ if (suggestion.messageId) {
267
+ const { messageId } = suggestion;
268
+
269
+ if (!messages) {
270
+ throw new TypeError(`context.report() called with a suggest option with a messageId '${messageId}', but no messages were present in the rule metadata.`);
271
+ }
272
+
273
+ if (!messages[messageId]) {
274
+ throw new TypeError(`context.report() called with a suggest option with a messageId '${messageId}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`);
275
+ }
276
+
277
+ if (suggestion.desc) {
278
+ throw new TypeError("context.report() called with a suggest option that defines both a 'messageId' and an 'desc'. Please only pass one.");
279
+ }
280
+ } else if (!suggestion.desc) {
281
+ throw new TypeError("context.report() called with a suggest option that doesn't have either a `desc` or `messageId`");
282
+ }
283
+
284
+ if (typeof suggestion.fix !== "function") {
285
+ throw new TypeError(`context.report() called with a suggest option without a fix function. See: ${suggestion}`);
286
+ }
287
+ });
288
+ }
289
+ }
290
+
227
291
  /**
228
292
  * Returns a function that converts the arguments of a `context.report` call from a rule into a reported
229
293
  * problem for the Node.js API.
@@ -242,17 +306,17 @@ module.exports = function createReportTranslator(metadata) {
242
306
  */
243
307
  return (...args) => {
244
308
  const descriptor = normalizeMultiArgReportCall(...args);
309
+ const messages = metadata.messageIds;
245
310
 
246
311
  assertValidNodeInfo(descriptor);
247
312
 
248
313
  let computedMessage;
249
314
 
250
315
  if (descriptor.messageId) {
251
- if (!metadata.messageIds) {
316
+ if (!messages) {
252
317
  throw new TypeError("context.report() called with a messageId, but no messages were present in the rule metadata.");
253
318
  }
254
319
  const id = descriptor.messageId;
255
- const messages = metadata.messageIds;
256
320
 
257
321
  if (descriptor.message) {
258
322
  throw new TypeError("context.report() called with a message and a messageId. Please only pass one.");
@@ -267,6 +331,7 @@ module.exports = function createReportTranslator(metadata) {
267
331
  throw new TypeError("Missing `message` property in report() call; add a message that describes the linting problem.");
268
332
  }
269
333
 
334
+ validateSuggestions(descriptor.suggest, messages);
270
335
 
271
336
  return createProblem({
272
337
  ruleId: metadata.ruleId,
@@ -275,7 +340,8 @@ module.exports = function createReportTranslator(metadata) {
275
340
  message: interpolate(computedMessage, descriptor.data),
276
341
  messageId: descriptor.messageId,
277
342
  loc: normalizeReportLoc(descriptor),
278
- fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode)
343
+ fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode),
344
+ suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, metadata.sourceCode, messages)
279
345
  });
280
346
  };
281
347
  };
package/lib/options.js CHANGED
@@ -230,6 +230,12 @@ module.exports = optionator({
230
230
  default: "false",
231
231
  description: "Output execution environment information"
232
232
  },
233
+ {
234
+ option: "error-on-unmatched-pattern",
235
+ type: "Boolean",
236
+ default: "true",
237
+ description: "Prevent errors when pattern is unmatched"
238
+ },
233
239
  {
234
240
  option: "debug",
235
241
  type: "Boolean",
@@ -349,7 +349,7 @@ class RuleTester {
349
349
  filename = item.filename;
350
350
  }
351
351
 
352
- if (Object.prototype.hasOwnProperty.call(item, "options")) {
352
+ if (hasOwnProperty(item, "options")) {
353
353
  assert(Array.isArray(item.options), "options must be an array");
354
354
  config.rules[ruleName] = [1].concat(item.options);
355
355
  } else {
@@ -577,21 +577,57 @@ class RuleTester {
577
577
  assert.strictEqual(message.nodeType, error.type, `Error type should be ${error.type}, found ${message.nodeType}`);
578
578
  }
579
579
 
580
- if (Object.prototype.hasOwnProperty.call(error, "line")) {
580
+ if (hasOwnProperty(error, "line")) {
581
581
  assert.strictEqual(message.line, error.line, `Error line should be ${error.line}`);
582
582
  }
583
583
 
584
- if (Object.prototype.hasOwnProperty.call(error, "column")) {
584
+ if (hasOwnProperty(error, "column")) {
585
585
  assert.strictEqual(message.column, error.column, `Error column should be ${error.column}`);
586
586
  }
587
587
 
588
- if (Object.prototype.hasOwnProperty.call(error, "endLine")) {
588
+ if (hasOwnProperty(error, "endLine")) {
589
589
  assert.strictEqual(message.endLine, error.endLine, `Error endLine should be ${error.endLine}`);
590
590
  }
591
591
 
592
- if (Object.prototype.hasOwnProperty.call(error, "endColumn")) {
592
+ if (hasOwnProperty(error, "endColumn")) {
593
593
  assert.strictEqual(message.endColumn, error.endColumn, `Error endColumn should be ${error.endColumn}`);
594
594
  }
595
+
596
+ if (hasOwnProperty(error, "suggestions")) {
597
+
598
+ // Support asserting there are no suggestions
599
+ if (!error.suggestions || (Array.isArray(error.suggestions) && error.suggestions.length === 0)) {
600
+ if (Array.isArray(message.suggestions) && message.suggestions.length > 0) {
601
+ assert.fail(`Error should have no suggestions on error with message: "${message.message}"`);
602
+ }
603
+ } else {
604
+ assert.strictEqual(Array.isArray(message.suggestions), true, `Error should have an array of suggestions. Instead received "${message.suggestions}" on error with message: "${message.message}"`);
605
+ assert.strictEqual(message.suggestions.length, error.suggestions.length, `Error should have ${error.suggestions.length} suggestions. Instead found ${message.suggestions.length} suggestions`);
606
+
607
+ error.suggestions.forEach((expectedSuggestion, index) => {
608
+ const actualSuggestion = message.suggestions[index];
609
+
610
+ /**
611
+ * Tests equality of a suggestion key if that key is defined in the expected output.
612
+ * @param {string} key Key to validate from the suggestion object
613
+ * @returns {void}
614
+ */
615
+ function assertSuggestionKeyEquals(key) {
616
+ if (hasOwnProperty(expectedSuggestion, key)) {
617
+ assert.deepStrictEqual(actualSuggestion[key], expectedSuggestion[key], `Error suggestion at index: ${index} should have desc of: "${actualSuggestion[key]}"`);
618
+ }
619
+ }
620
+ assertSuggestionKeyEquals("desc");
621
+ assertSuggestionKeyEquals("messageId");
622
+
623
+ if (hasOwnProperty(expectedSuggestion, "output")) {
624
+ const codeWithAppliedSuggestion = SourceCodeFixer.applyFixes(item.code, [actualSuggestion]).output;
625
+
626
+ assert.strictEqual(codeWithAppliedSuggestion, expectedSuggestion.output, `Expected the applied suggestion fix to match the test suggestion output for suggestion at index: ${index} on error with message: "${message.message}"`);
627
+ }
628
+ });
629
+ }
630
+ }
595
631
  } else {
596
632
 
597
633
  // Message was an unexpected type
@@ -600,7 +636,7 @@ class RuleTester {
600
636
  }
601
637
  }
602
638
 
603
- if (Object.prototype.hasOwnProperty.call(item, "output")) {
639
+ if (hasOwnProperty(item, "output")) {
604
640
  if (item.output === null) {
605
641
  assert.strictEqual(
606
642
  result.output,
@@ -84,16 +84,16 @@ module.exports = {
84
84
  * @returns {void}
85
85
  */
86
86
  function reportNoBeginningSpace(node, token) {
87
+ const nextToken = sourceCode.getTokenAfter(token);
88
+
87
89
  context.report({
88
90
  node,
89
- loc: token.loc.start,
91
+ loc: { start: token.loc.end, end: nextToken.loc.start },
90
92
  messageId: "unexpectedSpaceAfter",
91
93
  data: {
92
94
  tokenValue: token.value
93
95
  },
94
96
  fix(fixer) {
95
- const nextToken = sourceCode.getTokenAfter(token);
96
-
97
97
  return fixer.removeRange([token.range[1], nextToken.range[0]]);
98
98
  }
99
99
  });
@@ -106,16 +106,16 @@ module.exports = {
106
106
  * @returns {void}
107
107
  */
108
108
  function reportNoEndingSpace(node, token) {
109
+ const previousToken = sourceCode.getTokenBefore(token);
110
+
109
111
  context.report({
110
112
  node,
111
- loc: token.loc.start,
113
+ loc: { start: previousToken.loc.end, end: token.loc.start },
112
114
  messageId: "unexpectedSpaceBefore",
113
115
  data: {
114
116
  tokenValue: token.value
115
117
  },
116
118
  fix(fixer) {
117
- const previousToken = sourceCode.getTokenBefore(token);
118
-
119
119
  return fixer.removeRange([previousToken.range[1], token.range[0]]);
120
120
  }
121
121
  });
@@ -130,7 +130,7 @@ module.exports = {
130
130
  function reportRequiredBeginningSpace(node, token) {
131
131
  context.report({
132
132
  node,
133
- loc: token.loc.start,
133
+ loc: token.loc,
134
134
  messageId: "missingSpaceAfter",
135
135
  data: {
136
136
  tokenValue: token.value
@@ -150,7 +150,7 @@ module.exports = {
150
150
  function reportRequiredEndingSpace(node, token) {
151
151
  context.report({
152
152
  node,
153
- loc: token.loc.start,
153
+ loc: token.loc,
154
154
  messageId: "missingSpaceBefore",
155
155
  data: {
156
156
  tokenValue: token.value
@@ -28,6 +28,10 @@ module.exports = {
28
28
  type: "boolean",
29
29
  default: false
30
30
  },
31
+ ignoreImports: {
32
+ type: "boolean",
33
+ default: false
34
+ },
31
35
  properties: {
32
36
  enum: ["always", "never"]
33
37
  },
@@ -56,6 +60,7 @@ module.exports = {
56
60
  const options = context.options[0] || {};
57
61
  let properties = options.properties || "";
58
62
  const ignoreDestructuring = options.ignoreDestructuring;
63
+ const ignoreImports = options.ignoreImports;
59
64
  const allow = options.allow || [];
60
65
 
61
66
  if (properties !== "always" && properties !== "never") {
@@ -79,7 +84,7 @@ module.exports = {
79
84
  function isUnderscored(name) {
80
85
 
81
86
  // if there's an underscore, it might be A_CONSTANT, which is okay
82
- return name.indexOf("_") > -1 && name !== name.toUpperCase();
87
+ return name.includes("_") && name !== name.toUpperCase();
83
88
  }
84
89
 
85
90
  /**
@@ -89,9 +94,9 @@ module.exports = {
89
94
  * @private
90
95
  */
91
96
  function isAllowed(name) {
92
- return allow.findIndex(
97
+ return allow.some(
93
98
  entry => name === entry || name.match(new RegExp(entry, "u"))
94
- ) !== -1;
99
+ );
95
100
  }
96
101
 
97
102
  /**
@@ -127,7 +132,7 @@ module.exports = {
127
132
  * @private
128
133
  */
129
134
  function report(node) {
130
- if (reported.indexOf(node) < 0) {
135
+ if (!reported.includes(node)) {
131
136
  reported.push(node);
132
137
  context.report({ node, messageId: "notCamelCase", data: { name: node.name } });
133
138
  }
@@ -209,10 +214,18 @@ module.exports = {
209
214
  }
210
215
 
211
216
  // Check if it's an import specifier
212
- } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
217
+ } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].includes(node.parent.type)) {
218
+
219
+ if (node.parent.type === "ImportSpecifier" && ignoreImports) {
220
+ return;
221
+ }
213
222
 
214
223
  // Report only if the local imported identifier is underscored
215
- if (node.parent.local && node.parent.local.name === node.name && nameIsUnderscored) {
224
+ if (
225
+ node.parent.local &&
226
+ node.parent.local.name === node.name &&
227
+ nameIsUnderscored
228
+ ) {
216
229
  report(node);
217
230
  }
218
231
 
@@ -231,7 +231,7 @@ module.exports = {
231
231
  if (astUtils.isCommaToken(trailingToken)) {
232
232
  context.report({
233
233
  node: lastItem,
234
- loc: trailingToken.loc.start,
234
+ loc: trailingToken.loc,
235
235
  messageId: "unexpected",
236
236
  fix(fixer) {
237
237
  return fixer.remove(trailingToken);
@@ -267,7 +267,10 @@ module.exports = {
267
267
  if (trailingToken.value !== ",") {
268
268
  context.report({
269
269
  node: lastItem,
270
- loc: trailingToken.loc.end,
270
+ loc: {
271
+ start: trailingToken.loc.end,
272
+ end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)
273
+ },
271
274
  messageId: "missing",
272
275
  fix(fixer) {
273
276
  return fixer.insertTextAfter(trailingToken, ",");
@@ -153,10 +153,10 @@ module.exports = {
153
153
 
154
154
  const property = node[propertyName];
155
155
 
156
- const before = sourceCode.getTokenBefore(property),
157
- first = sourceCode.getFirstToken(property),
158
- last = sourceCode.getLastToken(property),
159
- after = sourceCode.getTokenAfter(property);
156
+ const before = sourceCode.getTokenBefore(property, astUtils.isOpeningBracketToken),
157
+ first = sourceCode.getTokenAfter(before, { includeComments: true }),
158
+ after = sourceCode.getTokenAfter(property, astUtils.isClosingBracketToken),
159
+ last = sourceCode.getTokenBefore(after, { includeComments: true });
160
160
 
161
161
  if (astUtils.isTokenOnSameLine(before, first)) {
162
162
  if (propertyNameMustBeSpaced) {
@@ -97,10 +97,15 @@ module.exports = {
97
97
  * @private
98
98
  */
99
99
  function isOneLiner(node) {
100
- const first = sourceCode.getFirstToken(node),
101
- last = sourceCode.getLastToken(node);
100
+ if (node.type === "EmptyStatement") {
101
+ return true;
102
+ }
103
+
104
+ const first = sourceCode.getFirstToken(node);
105
+ const last = sourceCode.getLastToken(node);
106
+ const lastExcludingSemicolon = astUtils.isSemicolonToken(last) ? sourceCode.getTokenBefore(last) : last;
102
107
 
103
- return first.loc.start.line === last.loc.end.line;
108
+ return first.loc.start.line === lastExcludingSemicolon.loc.end.line;
104
109
  }
105
110
 
106
111
  /**
@@ -240,7 +245,7 @@ module.exports = {
240
245
  if (node.type === "IfStatement" && node.consequent === body && requiresBraceOfConsequent(node)) {
241
246
  expected = true;
242
247
  } else if (multiOnly) {
243
- if (hasBlock && body.body.length === 1) {
248
+ if (hasBlock && body.body.length === 1 && !isLexicalDeclaration(body.body[0])) {
244
249
  expected = false;
245
250
  }
246
251
  } else if (multiLine) {
@@ -70,6 +70,8 @@ module.exports = {
70
70
  { includeComments: true }
71
71
  );
72
72
 
73
+ const hasLineCommentBefore = tokenBefore.type === "Line";
74
+
73
75
  context.report({
74
76
  node,
75
77
  loc: {
@@ -77,7 +79,7 @@ module.exports = {
77
79
  end: currentArgToken.loc.start
78
80
  },
79
81
  messageId: checker.messageId,
80
- fix: checker.createFix(currentArgToken, tokenBefore)
82
+ fix: hasLineCommentBefore ? null : checker.createFix(currentArgToken, tokenBefore)
81
83
  });
82
84
  }
83
85
  }