eslint 6.2.2 → 6.5.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 (63) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +9 -8
  3. package/bin/eslint.js +38 -12
  4. package/conf/config-schema.js +1 -0
  5. package/conf/default-cli-options.js +1 -1
  6. package/lib/cli-engine/cli-engine.js +2 -4
  7. package/lib/cli-engine/config-array/config-array.js +6 -0
  8. package/lib/cli-engine/config-array/extracted-config.js +6 -0
  9. package/lib/cli-engine/config-array/override-tester.js +2 -2
  10. package/lib/cli-engine/config-array-factory.js +2 -0
  11. package/lib/cli-engine/formatters/stylish.js +2 -1
  12. package/lib/cli-engine/ignored-paths.js +3 -3
  13. package/lib/cli-engine/lint-result-cache.js +0 -1
  14. package/lib/cli.js +13 -12
  15. package/lib/init/config-initializer.js +29 -0
  16. package/lib/init/config-rule.js +2 -2
  17. package/lib/init/npm-utils.js +9 -9
  18. package/lib/linter/apply-disable-directives.js +17 -9
  19. package/lib/linter/code-path-analysis/debug-helpers.js +1 -1
  20. package/lib/linter/linter.js +23 -4
  21. package/lib/options.js +7 -1
  22. package/lib/rule-tester/rule-tester.js +1 -2
  23. package/lib/rules/accessor-pairs.js +51 -11
  24. package/lib/rules/capitalized-comments.js +2 -2
  25. package/lib/rules/computed-property-spacing.js +18 -1
  26. package/lib/rules/default-param-last.js +61 -0
  27. package/lib/rules/eqeqeq.js +7 -19
  28. package/lib/rules/func-name-matching.js +1 -0
  29. package/lib/rules/function-paren-newline.js +2 -2
  30. package/lib/rules/indent-legacy.js +1 -1
  31. package/lib/rules/indent.js +44 -6
  32. package/lib/rules/index.js +3 -0
  33. package/lib/rules/new-parens.js +5 -1
  34. package/lib/rules/no-extra-bind.js +7 -1
  35. package/lib/rules/no-extra-boolean-cast.js +12 -2
  36. package/lib/rules/no-extra-label.js +9 -1
  37. package/lib/rules/no-extra-parens.js +23 -3
  38. package/lib/rules/no-import-assign.js +238 -0
  39. package/lib/rules/no-lone-blocks.js +6 -1
  40. package/lib/rules/no-obj-calls.js +29 -9
  41. package/lib/rules/no-octal-escape.js +14 -8
  42. package/lib/rules/no-regex-spaces.js +106 -45
  43. package/lib/rules/no-self-assign.js +17 -6
  44. package/lib/rules/no-sequences.js +2 -2
  45. package/lib/rules/no-undef-init.js +7 -1
  46. package/lib/rules/no-unsafe-negation.js +2 -10
  47. package/lib/rules/no-useless-rename.js +25 -13
  48. package/lib/rules/no-useless-return.js +3 -2
  49. package/lib/rules/object-curly-spacing.js +1 -1
  50. package/lib/rules/object-shorthand.js +35 -9
  51. package/lib/rules/prefer-named-capture-group.js +3 -15
  52. package/lib/rules/prefer-numeric-literals.js +4 -0
  53. package/lib/rules/prefer-regex-literals.js +125 -0
  54. package/lib/rules/quotes.js +6 -0
  55. package/lib/rules/space-before-function-paren.js +12 -1
  56. package/lib/rules/space-in-parens.js +77 -71
  57. package/lib/rules/use-isnan.js +67 -6
  58. package/lib/rules/yoda.js +11 -2
  59. package/lib/shared/logging.js +2 -0
  60. package/lib/shared/runtime-info.js +163 -0
  61. package/lib/shared/types.js +2 -0
  62. package/lib/source-code/source-code.js +3 -4
  63. package/package.json +3 -1
@@ -93,7 +93,7 @@ function applyDirectives(options) {
93
93
  : "Unused eslint-disable directive (no problems were reported).",
94
94
  line: directive.unprocessedDirective.line,
95
95
  column: directive.unprocessedDirective.column,
96
- severity: 2,
96
+ severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
97
97
  nodeType: null
98
98
  }));
99
99
 
@@ -114,17 +114,17 @@ function applyDirectives(options) {
114
114
  * comment for two different rules is represented as two directives).
115
115
  * @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
116
116
  * A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
117
- * @param {boolean} options.reportUnusedDisableDirectives If `true`, adds additional problems for unused directives
117
+ * @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
118
118
  * @returns {{ruleId: (string|null), line: number, column: number}[]}
119
119
  * A list of reported problems that were not disabled by the directive comments.
120
120
  */
121
- module.exports = options => {
122
- const blockDirectives = options.directives
121
+ module.exports = ({ directives, problems, reportUnusedDisableDirectives = "off" }) => {
122
+ const blockDirectives = directives
123
123
  .filter(directive => directive.type === "disable" || directive.type === "enable")
124
124
  .map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
125
125
  .sort(compareLocations);
126
126
 
127
- const lineDirectives = lodash.flatMap(options.directives, directive => {
127
+ const lineDirectives = lodash.flatMap(directives, directive => {
128
128
  switch (directive.type) {
129
129
  case "disable":
130
130
  case "enable":
@@ -147,10 +147,18 @@ module.exports = options => {
147
147
  }
148
148
  }).sort(compareLocations);
149
149
 
150
- const blockDirectivesResult = applyDirectives({ problems: options.problems, directives: blockDirectives });
151
- const lineDirectivesResult = applyDirectives({ problems: blockDirectivesResult.problems, directives: lineDirectives });
152
-
153
- return options.reportUnusedDisableDirectives
150
+ const blockDirectivesResult = applyDirectives({
151
+ problems,
152
+ directives: blockDirectives,
153
+ reportUnusedDisableDirectives
154
+ });
155
+ const lineDirectivesResult = applyDirectives({
156
+ problems: blockDirectivesResult.problems,
157
+ directives: lineDirectives,
158
+ reportUnusedDisableDirectives
159
+ });
160
+
161
+ return reportUnusedDisableDirectives !== "off"
154
162
  ? lineDirectivesResult.problems
155
163
  .concat(blockDirectivesResult.unusedDisableDirectives)
156
164
  .concat(lineDirectivesResult.unusedDisableDirectives)
@@ -21,7 +21,7 @@ const debug = require("debug")("eslint:code-path");
21
21
  * @returns {string} Id of the segment.
22
22
  */
23
23
  /* istanbul ignore next */
24
- function getId(segment) { // eslint-disable-line require-jsdoc
24
+ function getId(segment) { // eslint-disable-line jsdoc/require-jsdoc
25
25
  return segment.id + (segment.reachable ? "" : "!");
26
26
  }
27
27
 
@@ -54,6 +54,11 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
54
54
  /** @typedef {import("../shared/types").Processor} Processor */
55
55
  /** @typedef {import("../shared/types").Rule} Rule */
56
56
 
57
+ /**
58
+ * @template T
59
+ * @typedef {{ [P in keyof T]-?: T[P] }} Required
60
+ */
61
+
57
62
  /**
58
63
  * @typedef {Object} DisableDirective
59
64
  * @property {("disable"|"enable"|"disable-line"|"disable-next-line")} type
@@ -79,7 +84,7 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
79
84
  * @property {boolean} [disableFixes] if `true` then the linter doesn't make `fix`
80
85
  * properties into the lint result.
81
86
  * @property {string} [filename] the filename of the source code.
82
- * @property {boolean} [reportUnusedDisableDirectives] Adds reported errors for
87
+ * @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
83
88
  * unused `eslint-disable` directives.
84
89
  */
85
90
 
@@ -103,6 +108,12 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
103
108
  * whether fixes should be applied.
104
109
  */
105
110
 
111
+ /**
112
+ * @typedef {Object} InternalOptions
113
+ * @property {string | null} warnInlineConfig The config name what `noInlineConfig` setting came from. If `noInlineConfig` setting didn't exist, this is null. If this is a config name, then the linter warns directive comments.
114
+ * @property {"off" | "warn" | "error"} reportUnusedDisableDirectives (boolean values were normalized)
115
+ */
116
+
106
117
  //------------------------------------------------------------------------------
107
118
  // Helpers
108
119
  //------------------------------------------------------------------------------
@@ -461,13 +472,12 @@ function normalizeFilename(filename) {
461
472
  return index === -1 ? filename : parts.slice(index).join(path.sep);
462
473
  }
463
474
 
464
- // eslint-disable-next-line valid-jsdoc
465
475
  /**
466
476
  * Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
467
477
  * consistent shape.
468
478
  * @param {VerifyOptions} providedOptions Options
469
479
  * @param {ConfigData} config Config.
470
- * @returns {Required<VerifyOptions> & { warnInlineConfig: string|null }} Normalized options
480
+ * @returns {Required<VerifyOptions> & InternalOptions} Normalized options
471
481
  */
472
482
  function normalizeVerifyOptions(providedOptions, config) {
473
483
  const disableInlineConfig = config.noInlineConfig === true;
@@ -476,13 +486,22 @@ function normalizeVerifyOptions(providedOptions, config) {
476
486
  ? ` (${config.configNameOfNoInlineConfig})`
477
487
  : "";
478
488
 
489
+ let reportUnusedDisableDirectives = providedOptions.reportUnusedDisableDirectives;
490
+
491
+ if (typeof reportUnusedDisableDirectives === "boolean") {
492
+ reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
493
+ }
494
+ if (typeof reportUnusedDisableDirectives !== "string") {
495
+ reportUnusedDisableDirectives = config.reportUnusedDisableDirectives ? "warn" : "off";
496
+ }
497
+
479
498
  return {
480
499
  filename: normalizeFilename(providedOptions.filename || "<input>"),
481
500
  allowInlineConfig: !ignoreInlineConfig,
482
501
  warnInlineConfig: disableInlineConfig && !ignoreInlineConfig
483
502
  ? `your config${configNameOfNoInlineConfig}`
484
503
  : null,
485
- reportUnusedDisableDirectives: Boolean(providedOptions.reportUnusedDisableDirectives),
504
+ reportUnusedDisableDirectives,
486
505
  disableFixes: Boolean(providedOptions.disableFixes)
487
506
  };
488
507
  }
package/lib/options.js CHANGED
@@ -192,7 +192,7 @@ module.exports = optionator({
192
192
  {
193
193
  option: "report-unused-disable-directives",
194
194
  type: "Boolean",
195
- default: false,
195
+ default: void 0,
196
196
  description: "Adds reported errors for unused eslint-disable directives"
197
197
  },
198
198
  {
@@ -224,6 +224,12 @@ module.exports = optionator({
224
224
  default: "false",
225
225
  description: "Run config initialization wizard"
226
226
  },
227
+ {
228
+ option: "env-info",
229
+ type: "Boolean",
230
+ default: "false",
231
+ description: "Output execution environment information"
232
+ },
227
233
  {
228
234
  option: "debug",
229
235
  type: "Boolean",
@@ -130,7 +130,7 @@ function freezeDeeply(x) {
130
130
  */
131
131
  function sanitize(text) {
132
132
  return text.replace(
133
- /[\u0000-\u001f]/gu, // eslint-disable-line no-control-regex
133
+ /[\u0000-\u0009|\u000b-\u001a]/gu, // eslint-disable-line no-control-regex
134
134
  c => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}`
135
135
  );
136
136
  }
@@ -177,7 +177,6 @@ class RuleTester {
177
177
  /**
178
178
  * Creates a new instance of RuleTester.
179
179
  * @param {Object} [testerConfig] Optional, extra configuration for the tester
180
- * @constructor
181
180
  */
182
181
  constructor(testerConfig) {
183
182
 
@@ -152,7 +152,7 @@ module.exports = {
152
152
  type: "suggestion",
153
153
 
154
154
  docs: {
155
- description: "enforce getter and setter pairs in objects",
155
+ description: "enforce getter and setter pairs in objects and classes",
156
156
  category: "Best Practices",
157
157
  recommended: false,
158
158
  url: "https://eslint.org/docs/rules/accessor-pairs"
@@ -168,6 +168,10 @@ module.exports = {
168
168
  setWithoutGet: {
169
169
  type: "boolean",
170
170
  default: true
171
+ },
172
+ enforceForClassMembers: {
173
+ type: "boolean",
174
+ default: false
171
175
  }
172
176
  },
173
177
  additionalProperties: false
@@ -177,13 +181,16 @@ module.exports = {
177
181
  missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.",
178
182
  missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.",
179
183
  missingGetterInObjectLiteral: "Getter is not present for {{ name }}.",
180
- missingSetterInObjectLiteral: "Setter is not present for {{ name }}."
184
+ missingSetterInObjectLiteral: "Setter is not present for {{ name }}.",
185
+ missingGetterInClass: "Getter is not present for class {{ name }}.",
186
+ missingSetterInClass: "Setter is not present for class {{ name }}."
181
187
  }
182
188
  },
183
189
  create(context) {
184
190
  const config = context.options[0] || {};
185
191
  const checkGetWithoutSet = config.getWithoutSet === true;
186
192
  const checkSetWithoutGet = config.setWithoutGet !== false;
193
+ const enforceForClassMembers = config.enforceForClassMembers === true;
187
194
  const sourceCode = context.getSourceCode();
188
195
 
189
196
  /**
@@ -201,6 +208,13 @@ module.exports = {
201
208
  loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
202
209
  data: { name: astUtils.getFunctionNameWithKind(node.value) }
203
210
  });
211
+ } else if (node.type === "MethodDefinition") {
212
+ context.report({
213
+ node,
214
+ messageId: `${messageKind}InClass`,
215
+ loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
216
+ data: { name: astUtils.getFunctionNameWithKind(node.value) }
217
+ });
204
218
  } else {
205
219
  context.report({
206
220
  node,
@@ -313,15 +327,41 @@ module.exports = {
313
327
  }
314
328
  }
315
329
 
316
- return {
317
- ObjectExpression(node) {
318
- if (checkSetWithoutGet || checkGetWithoutSet) {
319
- checkObjectLiteral(node);
320
- if (isPropertyDescriptor(node)) {
321
- checkPropertyDescriptor(node);
322
- }
323
- }
330
+ /**
331
+ * Checks the given object expression as an object literal and as a possible property descriptor.
332
+ * @param {ASTNode} node `ObjectExpression` node to check.
333
+ * @returns {void}
334
+ * @private
335
+ */
336
+ function checkObjectExpression(node) {
337
+ checkObjectLiteral(node);
338
+ if (isPropertyDescriptor(node)) {
339
+ checkPropertyDescriptor(node);
324
340
  }
325
- };
341
+ }
342
+
343
+ /**
344
+ * Checks the given class body.
345
+ * @param {ASTNode} node `ClassBody` node to check.
346
+ * @returns {void}
347
+ * @private
348
+ */
349
+ function checkClassBody(node) {
350
+ const methodDefinitions = node.body.filter(m => m.type === "MethodDefinition");
351
+
352
+ checkList(methodDefinitions.filter(m => m.static));
353
+ checkList(methodDefinitions.filter(m => !m.static));
354
+ }
355
+
356
+ const listeners = {};
357
+
358
+ if (checkSetWithoutGet || checkGetWithoutSet) {
359
+ listeners.ObjectExpression = checkObjectExpression;
360
+ if (enforceForClassMembers) {
361
+ listeners.ClassBody = checkClassBody;
362
+ }
363
+ }
364
+
365
+ return listeners;
326
366
  }
327
367
  };
@@ -59,7 +59,7 @@ const DEFAULTS = {
59
59
  * @param {string} which Either "line" or "block".
60
60
  * @returns {Object} The normalized options.
61
61
  */
62
- function getNormalizedOptions(rawOptions = {}, which) {
62
+ function getNormalizedOptions(rawOptions, which) {
63
63
  return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions);
64
64
  }
65
65
 
@@ -70,7 +70,7 @@ function getNormalizedOptions(rawOptions = {}, which) {
70
70
  * @returns {Object} An object with "Line" and "Block" keys and corresponding
71
71
  * normalized options objects.
72
72
  */
73
- function getAllNormalizedOptions(rawOptions) {
73
+ function getAllNormalizedOptions(rawOptions = {}) {
74
74
  return {
75
75
  Line: getNormalizedOptions(rawOptions, "line"),
76
76
  Block: getNormalizedOptions(rawOptions, "block")
@@ -26,6 +26,16 @@ module.exports = {
26
26
  schema: [
27
27
  {
28
28
  enum: ["always", "never"]
29
+ },
30
+ {
31
+ type: "object",
32
+ properties: {
33
+ enforceForClassMembers: {
34
+ type: "boolean",
35
+ default: false
36
+ }
37
+ },
38
+ additionalProperties: false
29
39
  }
30
40
  ],
31
41
 
@@ -41,6 +51,7 @@ module.exports = {
41
51
  create(context) {
42
52
  const sourceCode = context.getSourceCode();
43
53
  const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
54
+ const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers;
44
55
 
45
56
  //--------------------------------------------------------------------------
46
57
  // Helpers
@@ -178,10 +189,16 @@ module.exports = {
178
189
  // Public
179
190
  //--------------------------------------------------------------------------
180
191
 
181
- return {
192
+ const listeners = {
182
193
  Property: checkSpacing("key"),
183
194
  MemberExpression: checkSpacing("property")
184
195
  };
185
196
 
197
+ if (enforceForClassMembers) {
198
+ listeners.MethodDefinition = checkSpacing("key");
199
+ }
200
+
201
+ return listeners;
202
+
186
203
  }
187
204
  };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview enforce default parameters to be last
3
+ * @author Chiawen Chen
4
+ */
5
+
6
+ "use strict";
7
+
8
+ module.exports = {
9
+ meta: {
10
+ type: "suggestion",
11
+
12
+ docs: {
13
+ description: "enforce default parameters to be last",
14
+ category: "Best Practices",
15
+ recommended: false,
16
+ url: "https://eslint.org/docs/rules/default-param-last"
17
+ },
18
+
19
+ schema: [],
20
+
21
+ messages: {
22
+ shouldBeLast: "Default parameters should be last."
23
+ }
24
+ },
25
+
26
+ create(context) {
27
+
28
+ /**
29
+ * @param {ASTNode} node function node
30
+ * @returns {void}
31
+ */
32
+ function handleFunction(node) {
33
+ let hasSeenPlainParam = false;
34
+
35
+ for (let i = node.params.length - 1; i >= 0; i -= 1) {
36
+ const param = node.params[i];
37
+
38
+ if (
39
+ param.type !== "AssignmentPattern" &&
40
+ param.type !== "RestElement"
41
+ ) {
42
+ hasSeenPlainParam = true;
43
+ continue;
44
+ }
45
+
46
+ if (hasSeenPlainParam && param.type === "AssignmentPattern") {
47
+ context.report({
48
+ node: param,
49
+ messageId: "shouldBeLast"
50
+ });
51
+ }
52
+ }
53
+ }
54
+
55
+ return {
56
+ FunctionDeclaration: handleFunction,
57
+ FunctionExpression: handleFunction,
58
+ ArrowFunctionExpression: handleFunction
59
+ };
60
+ }
61
+ };
@@ -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
 
@@ -303,7 +303,7 @@ module.exports = {
303
303
  * @param {int} needed Expected indentation character count
304
304
  * @param {int} gottenSpaces Indentation space count in the actual node/code
305
305
  * @param {int} gottenTabs Indentation tab count in the actual node/code
306
- * @param {Object=} loc Error line and column location
306
+ * @param {Object} [loc] Error line and column location
307
307
  * @param {boolean} isLastNodeCheck Is the error for last node check
308
308
  * @returns {void}
309
309
  */
@@ -81,6 +81,9 @@ const KNOWN_NODES = new Set([
81
81
  "WhileStatement",
82
82
  "WithStatement",
83
83
  "YieldExpression",
84
+ "JSXFragment",
85
+ "JSXOpeningFragment",
86
+ "JSXClosingFragment",
84
87
  "JSXIdentifier",
85
88
  "JSXNamespacedName",
86
89
  "JSXMemberExpression",
@@ -1453,6 +1456,31 @@ module.exports = {
1453
1456
  offsets.setDesiredOffsets(node.name.range, firstToken, 1);
1454
1457
  },
1455
1458
 
1459
+ JSXFragment(node) {
1460
+ const firstOpeningToken = sourceCode.getFirstToken(node.openingFragment);
1461
+ const firstClosingToken = sourceCode.getFirstToken(node.closingFragment);
1462
+
1463
+ addElementListIndent(node.children, firstOpeningToken, firstClosingToken, 1);
1464
+ },
1465
+
1466
+ JSXOpeningFragment(node) {
1467
+ const firstToken = sourceCode.getFirstToken(node);
1468
+ const closingToken = sourceCode.getLastToken(node);
1469
+
1470
+ offsets.setDesiredOffsets(node.range, firstToken, 1);
1471
+ offsets.matchOffsetOf(firstToken, closingToken);
1472
+ },
1473
+
1474
+ JSXClosingFragment(node) {
1475
+ const firstToken = sourceCode.getFirstToken(node);
1476
+ const slashToken = sourceCode.getLastToken(node, { skip: 1 });
1477
+ const closingToken = sourceCode.getLastToken(node);
1478
+ const tokenToMatch = astUtils.isTokenOnSameLine(slashToken, closingToken) ? slashToken : closingToken;
1479
+
1480
+ offsets.setDesiredOffsets(node.range, firstToken, 1);
1481
+ offsets.matchOffsetOf(firstToken, tokenToMatch);
1482
+ },
1483
+
1456
1484
  JSXExpressionContainer(node) {
1457
1485
  const openingCurly = sourceCode.getFirstToken(node);
1458
1486
  const closingCurly = sourceCode.getLastToken(node);
@@ -1588,18 +1616,23 @@ module.exports = {
1588
1616
  return;
1589
1617
  }
1590
1618
 
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
1619
  if (astUtils.isCommentToken(firstTokenOfLine)) {
1597
1620
  const tokenBefore = precedingTokens.get(firstTokenOfLine);
1598
1621
  const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0];
1599
-
1600
1622
  const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine);
1601
1623
  const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter);
1602
1624
 
1625
+ /*
1626
+ * If a comment precedes a line that begins with a semicolon token, align to that token, i.e.
1627
+ *
1628
+ * let foo
1629
+ * // comment
1630
+ * ;(async () => {})()
1631
+ */
1632
+ if (tokenAfter && astUtils.isSemicolonToken(tokenAfter) && !astUtils.isTokenOnSameLine(firstTokenOfLine, tokenAfter)) {
1633
+ offsets.setDesiredOffset(firstTokenOfLine, tokenAfter, 0);
1634
+ }
1635
+
1603
1636
  // If a comment matches the expected indentation of the token immediately before or after, don't report it.
1604
1637
  if (
1605
1638
  mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
@@ -1609,6 +1642,11 @@ module.exports = {
1609
1642
  }
1610
1643
  }
1611
1644
 
1645
+ // If the token matches the expected indentation, don't report it.
1646
+ if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
1647
+ return;
1648
+ }
1649
+
1612
1650
  // Otherwise, report the token/comment.
1613
1651
  report(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine));
1614
1652
  });
@@ -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"),
@@ -65,7 +65,11 @@ module.exports = {
65
65
 
66
66
  const lastToken = sourceCode.getLastToken(node);
67
67
  const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
68
- const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));
68
+
69
+ // `hasParens` is true only if the new expression ends with its own parens, e.g., new new foo() does not end with its own parens
70
+ const hasParens = hasLastParen &&
71
+ astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken)) &&
72
+ node.callee.range[1] < node.range[1];
69
73
 
70
74
  if (always) {
71
75
  if (!hasParens) {
@@ -40,6 +40,7 @@ module.exports = {
40
40
  },
41
41
 
42
42
  create(context) {
43
+ const sourceCode = context.getSourceCode();
43
44
  let scopeInfo = null;
44
45
 
45
46
  /**
@@ -71,8 +72,13 @@ module.exports = {
71
72
  return null;
72
73
  }
73
74
 
74
- const firstTokenToRemove = context.getSourceCode()
75
+ const firstTokenToRemove = sourceCode
75
76
  .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
77
+ const lastTokenToRemove = sourceCode.getLastToken(node.parent.parent);
78
+
79
+ if (sourceCode.commentsExistBetween(firstTokenToRemove, lastTokenToRemove)) {
80
+ return null;
81
+ }
76
82
 
77
83
  return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]);
78
84
  }
@@ -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
  }