eslint 8.0.0 → 8.3.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 (41) hide show
  1. package/README.md +8 -2
  2. package/lib/cli-engine/cli-engine.js +10 -21
  3. package/lib/eslint/eslint.js +2 -15
  4. package/lib/linter/code-path-analysis/code-path-analyzer.js +6 -1
  5. package/lib/linter/code-path-analysis/code-path.js +1 -1
  6. package/lib/linter/config-comment-parser.js +1 -1
  7. package/lib/linter/linter.js +2 -2
  8. package/lib/linter/node-event-generator.js +7 -0
  9. package/lib/rule-tester/rule-tester.js +5 -2
  10. package/lib/rules/block-scoped-var.js +2 -0
  11. package/lib/rules/block-spacing.js +10 -3
  12. package/lib/rules/brace-style.js +6 -0
  13. package/lib/rules/class-methods-use-this.js +10 -1
  14. package/lib/rules/complexity.js +14 -6
  15. package/lib/rules/indent.js +21 -0
  16. package/lib/rules/index.js +1 -0
  17. package/lib/rules/key-spacing.js +14 -13
  18. package/lib/rules/keyword-spacing.js +15 -1
  19. package/lib/rules/lines-around-comment.js +54 -7
  20. package/lib/rules/max-depth.js +2 -0
  21. package/lib/rules/max-statements.js +10 -0
  22. package/lib/rules/no-eval.js +2 -0
  23. package/lib/rules/no-extra-semi.js +1 -1
  24. package/lib/rules/no-inner-declarations.js +26 -4
  25. package/lib/rules/no-invalid-this.js +4 -0
  26. package/lib/rules/no-lone-blocks.js +8 -2
  27. package/lib/rules/no-redeclare.js +2 -0
  28. package/lib/rules/no-unused-expressions.js +6 -0
  29. package/lib/rules/no-unused-private-class-members.js +194 -0
  30. package/lib/rules/no-use-before-define.js +175 -74
  31. package/lib/rules/one-var.js +5 -1
  32. package/lib/rules/padded-blocks.js +8 -0
  33. package/lib/rules/padding-line-between-statements.js +2 -0
  34. package/lib/rules/prefer-const.js +1 -1
  35. package/lib/rules/require-atomic-updates.js +14 -2
  36. package/lib/rules/semi-style.js +8 -2
  37. package/lib/rules/semi.js +18 -9
  38. package/lib/rules/utils/ast-utils.js +15 -3
  39. package/lib/rules/vars-on-top.js +25 -12
  40. package/lib/shared/types.js +1 -1
  41. package/package.json +9 -9
package/README.md CHANGED
@@ -206,6 +206,9 @@ This means:
206
206
  These folks keep the project moving and are resources for help.
207
207
 
208
208
  <!-- NOTE: This section is autogenerated. Do not manually edit.-->
209
+
210
+
211
+
209
212
  <!--teamstart-->
210
213
 
211
214
  ### Technical Steering Committee (TSC)
@@ -242,7 +245,7 @@ Toru Nagashima
242
245
  </td><td align="center" valign="top" width="11%">
243
246
  <a href="https://github.com/aladdin-add">
244
247
  <img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
245
- 薛定谔的猫
248
+ 唯然
246
249
  </a>
247
250
  </td></tr></tbody></table>
248
251
 
@@ -288,6 +291,9 @@ Nitin Kumar
288
291
 
289
292
  <!--teamend-->
290
293
 
294
+
295
+
296
+
291
297
  ## <a name="sponsors"></a>Sponsors
292
298
 
293
299
  The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://opencollective.com/eslint) to get your logo on our README and website.
@@ -298,7 +304,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
298
304
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
299
305
  <p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
300
306
  <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
301
- <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://troypoint.com"><img src="https://images.opencollective.com/troypoint/080f96f/avatar.png" alt="TROYPOINT" height="32"></a> <a href="https://mobilen.nu"><img src="https://images.opencollective.com/mobilen/e19860d/logo.png" alt="Mobilen" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
307
+ <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://troypoint.com"><img src="https://images.opencollective.com/troypoint/080f96f/avatar.png" alt="TROYPOINT" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
302
308
  <!--sponsorsend-->
303
309
 
304
310
  ## <a name="technology-sponsors"></a>Technology Sponsors
@@ -570,8 +570,10 @@ class CLIEngine {
570
570
  /**
571
571
  * Creates a new instance of the core CLI engine.
572
572
  * @param {CLIEngineOptions} providedOptions The options for this instance.
573
+ * @param {Object} [additionalData] Additional settings that are not CLIEngineOptions.
574
+ * @param {Record<string,Plugin>|null} [additionalData.preloadedPlugins] Preloaded plugins.
573
575
  */
574
- constructor(providedOptions) {
576
+ constructor(providedOptions, { preloadedPlugins } = {}) {
575
577
  const options = Object.assign(
576
578
  Object.create(null),
577
579
  defaultOptions,
@@ -584,6 +586,13 @@ class CLIEngine {
584
586
  }
585
587
 
586
588
  const additionalPluginPool = new Map();
589
+
590
+ if (preloadedPlugins) {
591
+ for (const [id, plugin] of Object.entries(preloadedPlugins)) {
592
+ additionalPluginPool.set(id, plugin);
593
+ }
594
+ }
595
+
587
596
  const cacheFilePath = getCacheFile(
588
597
  options.cacheLocation || options.cacheFile,
589
598
  options.cwd
@@ -698,26 +707,6 @@ class CLIEngine {
698
707
  });
699
708
  }
700
709
 
701
-
702
- /**
703
- * Add a plugin by passing its configuration
704
- * @param {string} name Name of the plugin.
705
- * @param {Plugin} pluginObject Plugin configuration object.
706
- * @returns {void}
707
- */
708
- addPlugin(name, pluginObject) {
709
- const {
710
- additionalPluginPool,
711
- configArrayFactory,
712
- lastConfigArrays
713
- } = internalSlotsMap.get(this);
714
-
715
- additionalPluginPool.set(name, pluginObject);
716
- configArrayFactory.clearCache();
717
- lastConfigArrays.length = 1;
718
- lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
719
- }
720
-
721
710
  /**
722
711
  * Resolves the patterns passed into executeOnFiles() into glob-based patterns
723
712
  * for easier handling.
@@ -54,7 +54,7 @@ const { version } = require("../../package.json");
54
54
  * @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
55
55
  * @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
56
56
  * @property {string} [overrideConfigFile] The configuration file to use.
57
- * @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
57
+ * @property {Record<string,Plugin>|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation.
58
58
  * @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives.
59
59
  * @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD.
60
60
  * @property {string[]} [rulePaths] An array of directories to load custom rules from.
@@ -433,26 +433,13 @@ class ESLint {
433
433
  */
434
434
  constructor(options = {}) {
435
435
  const processedOptions = processOptions(options);
436
- const cliEngine = new CLIEngine(processedOptions);
436
+ const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins });
437
437
  const {
438
- additionalPluginPool,
439
438
  configArrayFactory,
440
439
  lastConfigArrays
441
440
  } = getCLIEngineInternalSlots(cliEngine);
442
441
  let updated = false;
443
442
 
444
- /*
445
- * Address `plugins` to add plugin implementations.
446
- * Operate the `additionalPluginPool` internal slot directly to avoid
447
- * using `addPlugin(id, plugin)` method that resets cache everytime.
448
- */
449
- if (options.plugins) {
450
- for (const [id, plugin] of Object.entries(options.plugins)) {
451
- additionalPluginPool.set(id, plugin);
452
- updated = true;
453
- }
454
- }
455
-
456
443
  /*
457
444
  * Address `overrideConfig` to set override config.
458
445
  * Operate the `configArrayFactory` internal slot directly because this
@@ -461,6 +461,10 @@ function processCodePathToEnter(analyzer, node) {
461
461
  startCodePath("function");
462
462
  break;
463
463
 
464
+ case "StaticBlock":
465
+ startCodePath("class-static-block");
466
+ break;
467
+
464
468
  case "ChainExpression":
465
469
  state.pushChainContext();
466
470
  break;
@@ -706,7 +710,8 @@ function postprocess(analyzer, node) {
706
710
  case "Program":
707
711
  case "FunctionDeclaration":
708
712
  case "FunctionExpression":
709
- case "ArrowFunctionExpression": {
713
+ case "ArrowFunctionExpression":
714
+ case "StaticBlock": {
710
715
  endCodePath();
711
716
  break;
712
717
  }
@@ -40,7 +40,7 @@ class CodePath {
40
40
 
41
41
  /**
42
42
  * The reason that this code path was started. May be "program",
43
- * "function", or "class-field-initializer".
43
+ * "function", "class-field-initializer", or "class-static-block".
44
44
  * @type {string}
45
45
  */
46
46
  this.origin = origin;
@@ -15,7 +15,7 @@ const levn = require("levn"),
15
15
  Legacy: {
16
16
  ConfigOps
17
17
  }
18
- } = require("@eslint/eslintrc/universal"); // eslint-disable-line node/no-missing-require -- false positive
18
+ } = require("@eslint/eslintrc/universal");
19
19
 
20
20
  const debug = require("debug")("eslint:config-comment-parser");
21
21
 
@@ -24,7 +24,7 @@ const
24
24
  ConfigValidator,
25
25
  environments: BuiltInEnvironments
26
26
  }
27
- } = require("@eslint/eslintrc/universal"), // eslint-disable-line node/no-missing-require -- false positive
27
+ } = require("@eslint/eslintrc/universal"),
28
28
  Traverser = require("../shared/traverser"),
29
29
  { SourceCode } = require("../source-code"),
30
30
  CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
@@ -626,7 +626,7 @@ function analyzeScope(ast, parserOptions, visitorKeys) {
626
626
  ignoreEval: true,
627
627
  nodejsScope: ecmaFeatures.globalReturn,
628
628
  impliedStrict: ecmaFeatures.impliedStrict,
629
- ecmaVersion,
629
+ ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
630
630
  sourceType: parserOptions.sourceType || "script",
631
631
  childVisitorKeys: visitorKeys || evk.KEYS,
632
632
  fallback: Traverser.getKeys
@@ -98,6 +98,13 @@ function getPossibleTypes(parsedSelector) {
98
98
  case "adjacent":
99
99
  return getPossibleTypes(parsedSelector.right);
100
100
 
101
+ case "class":
102
+ if (parsedSelector.name === "function") {
103
+ return ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"];
104
+ }
105
+
106
+ return null;
107
+
101
108
  default:
102
109
  return null;
103
110
 
@@ -67,6 +67,7 @@ const { SourceCode } = require("../source-code");
67
67
  /**
68
68
  * A test case that is expected to pass lint.
69
69
  * @typedef {Object} ValidTestCase
70
+ * @property {string} [name] Name for the test case.
70
71
  * @property {string} code Code for the test case.
71
72
  * @property {any[]} [options] Options for the test case.
72
73
  * @property {{ [name: string]: any }} [settings] Settings for the test case.
@@ -81,6 +82,7 @@ const { SourceCode } = require("../source-code");
81
82
  /**
82
83
  * A test case that is expected to fail lint.
83
84
  * @typedef {Object} InvalidTestCase
85
+ * @property {string} [name] Name for the test case.
84
86
  * @property {string} code Code for the test case.
85
87
  * @property {number | Array<TestCaseError | string | RegExp>} errors Expected errors.
86
88
  * @property {string | null} [output] The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested.
@@ -124,6 +126,7 @@ let defaultConfig = { rules: {} };
124
126
  * configuration
125
127
  */
126
128
  const RuleTesterParameters = [
129
+ "name",
127
130
  "code",
128
131
  "filename",
129
132
  "options",
@@ -964,7 +967,7 @@ class RuleTester {
964
967
  RuleTester.describe("valid", () => {
965
968
  test.valid.forEach(valid => {
966
969
  RuleTester[valid.only ? "itOnly" : "it"](
967
- sanitize(typeof valid === "object" ? valid.code : valid),
970
+ sanitize(typeof valid === "object" ? valid.name || valid.code : valid),
968
971
  () => {
969
972
  testValidTemplate(valid);
970
973
  }
@@ -975,7 +978,7 @@ class RuleTester {
975
978
  RuleTester.describe("invalid", () => {
976
979
  test.invalid.forEach(invalid => {
977
980
  RuleTester[invalid.only ? "itOnly" : "it"](
978
- sanitize(invalid.code),
981
+ sanitize(invalid.name || invalid.code),
979
982
  () => {
980
983
  testInvalidTemplate(invalid);
981
984
  }
@@ -112,6 +112,8 @@ module.exports = {
112
112
  "SwitchStatement:exit": exitScope,
113
113
  CatchClause: enterScope,
114
114
  "CatchClause:exit": exitScope,
115
+ StaticBlock: enterScope,
116
+ "StaticBlock:exit": exitScope,
115
117
 
116
118
  // Finds and reports references which are outside of valid scope.
117
119
  VariableDeclaration: checkForVariables
@@ -40,7 +40,7 @@ module.exports = {
40
40
 
41
41
  /**
42
42
  * Gets the open brace token from a given node.
43
- * @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
43
+ * @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
44
44
  * @returns {Token} The token of the open brace.
45
45
  */
46
46
  function getOpenBrace(node) {
@@ -50,6 +50,12 @@ module.exports = {
50
50
  }
51
51
  return sourceCode.getLastToken(node, 1);
52
52
  }
53
+
54
+ if (node.type === "StaticBlock") {
55
+ return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
56
+ }
57
+
58
+ // "BlockStatement"
53
59
  return sourceCode.getFirstToken(node);
54
60
  }
55
61
 
@@ -72,8 +78,8 @@ module.exports = {
72
78
  }
73
79
 
74
80
  /**
75
- * Reports invalid spacing style inside braces.
76
- * @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
81
+ * Checks and reports invalid spacing style inside braces.
82
+ * @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
77
83
  * @returns {void}
78
84
  */
79
85
  function checkSpacingInsideBraces(node) {
@@ -157,6 +163,7 @@ module.exports = {
157
163
 
158
164
  return {
159
165
  BlockStatement: checkSpacingInsideBraces,
166
+ StaticBlock: checkSpacingInsideBraces,
160
167
  SwitchStatement: checkSpacingInsideBraces
161
168
  };
162
169
  }
@@ -155,6 +155,12 @@ module.exports = {
155
155
  validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
156
156
  }
157
157
  },
158
+ StaticBlock(node) {
159
+ validateCurlyPair(
160
+ sourceCode.getFirstToken(node, { skip: 1 }), // skip the `static` token
161
+ sourceCode.getLastToken(node)
162
+ );
163
+ },
158
164
  ClassBody(node) {
159
165
  validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
160
166
  },
@@ -161,8 +161,17 @@ module.exports = {
161
161
  /*
162
162
  * Class field value are implicit functions.
163
163
  */
164
- "PropertyDefinition:exit": popContext,
165
164
  "PropertyDefinition > *.key:exit": pushContext,
165
+ "PropertyDefinition:exit": popContext,
166
+
167
+ /*
168
+ * Class static blocks are implicit functions. They aren't required to use `this`,
169
+ * but we have to push context so that it captures any use of `this` in the static block
170
+ * separately from enclosing contexts, because static blocks have their own `this` and it
171
+ * shouldn't count as used `this` in enclosing contexts.
172
+ */
173
+ StaticBlock: pushContext,
174
+ "StaticBlock:exit": popContext,
166
175
 
167
176
  ThisExpression: markThisUsed,
168
177
  Super: markThisUsed,
@@ -124,20 +124,28 @@ module.exports = {
124
124
 
125
125
  /*
126
126
  * This rule only evaluates complexity of functions, so "program" is excluded.
127
- * Class field initializers are implicit functions. Therefore, they shouldn't contribute
128
- * to the enclosing function's complexity, but their own complexity should be evaluated.
127
+ * Class field initializers and class static blocks are implicit functions. Therefore,
128
+ * they shouldn't contribute to the enclosing function's complexity, but their
129
+ * own complexity should be evaluated.
129
130
  */
130
131
  if (
131
132
  codePath.origin !== "function" &&
132
- codePath.origin !== "class-field-initializer"
133
+ codePath.origin !== "class-field-initializer" &&
134
+ codePath.origin !== "class-static-block"
133
135
  ) {
134
136
  return;
135
137
  }
136
138
 
137
139
  if (complexity > THRESHOLD) {
138
- const name = codePath.origin === "class-field-initializer"
139
- ? "class field initializer"
140
- : astUtils.getFunctionNameWithKind(node);
140
+ let name;
141
+
142
+ if (codePath.origin === "class-field-initializer") {
143
+ name = "class field initializer";
144
+ } else if (codePath.origin === "class-static-block") {
145
+ name = "class static block";
146
+ } else {
147
+ name = astUtils.getFunctionNameWithKind(node);
148
+ }
141
149
 
142
150
  context.report({
143
151
  node,
@@ -68,6 +68,7 @@ const KNOWN_NODES = new Set([
68
68
  "ReturnStatement",
69
69
  "SequenceExpression",
70
70
  "SpreadElement",
71
+ "StaticBlock",
71
72
  "Super",
72
73
  "SwitchCase",
73
74
  "SwitchStatement",
@@ -583,6 +584,16 @@ module.exports = {
583
584
  },
584
585
  additionalProperties: false
585
586
  },
587
+ StaticBlock: {
588
+ type: "object",
589
+ properties: {
590
+ body: {
591
+ type: "integer",
592
+ minimum: 0
593
+ }
594
+ },
595
+ additionalProperties: false
596
+ },
586
597
  CallExpression: {
587
598
  type: "object",
588
599
  properties: {
@@ -646,6 +657,9 @@ module.exports = {
646
657
  parameters: DEFAULT_PARAMETER_INDENT,
647
658
  body: DEFAULT_FUNCTION_BODY_INDENT
648
659
  },
660
+ StaticBlock: {
661
+ body: DEFAULT_FUNCTION_BODY_INDENT
662
+ },
649
663
  CallExpression: {
650
664
  arguments: DEFAULT_PARAMETER_INDENT
651
665
  },
@@ -1397,6 +1411,13 @@ module.exports = {
1397
1411
  }
1398
1412
  },
1399
1413
 
1414
+ StaticBlock(node) {
1415
+ const openingCurly = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
1416
+ const closingCurly = sourceCode.getLastToken(node);
1417
+
1418
+ addElementListIndent(node.body, openingCurly, closingCurly, options.StaticBlock.body);
1419
+ },
1420
+
1400
1421
  SwitchStatement(node) {
1401
1422
  const openingCurly = sourceCode.getTokenAfter(node.discriminant, astUtils.isOpeningBraceToken);
1402
1423
  const closingCurly = sourceCode.getLastToken(node);
@@ -221,6 +221,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
221
221
  "no-unsafe-optional-chaining": () => require("./no-unsafe-optional-chaining"),
222
222
  "no-unused-expressions": () => require("./no-unused-expressions"),
223
223
  "no-unused-labels": () => require("./no-unused-labels"),
224
+ "no-unused-private-class-members": () => require("./no-unused-private-class-members"),
224
225
  "no-unused-vars": () => require("./no-unused-vars"),
225
226
  "no-use-before-define": () => require("./no-use-before-define"),
226
227
  "no-useless-backreference": () => require("./no-useless-backreference"),
@@ -427,19 +427,7 @@ module.exports = {
427
427
  * @returns {void}
428
428
  */
429
429
  function report(property, side, whitespace, expected, mode) {
430
- const diff = whitespace.length - expected,
431
- nextColon = getNextColon(property.key),
432
- tokenBeforeColon = sourceCode.getTokenBefore(nextColon, { includeComments: true }),
433
- tokenAfterColon = sourceCode.getTokenAfter(nextColon, { includeComments: true }),
434
- isKeySide = side === "key",
435
- isExtra = diff > 0,
436
- diffAbs = Math.abs(diff),
437
- spaces = Array(diffAbs + 1).join(" ");
438
-
439
- const locStart = isKeySide ? tokenBeforeColon.loc.end : nextColon.loc.start;
440
- const locEnd = isKeySide ? nextColon.loc.start : tokenAfterColon.loc.start;
441
- const missingLoc = isKeySide ? tokenBeforeColon.loc : tokenAfterColon.loc;
442
- const loc = isExtra ? { start: locStart, end: locEnd } : missingLoc;
430
+ const diff = whitespace.length - expected;
443
431
 
444
432
  if ((
445
433
  diff && mode === "strict" ||
@@ -447,6 +435,19 @@ module.exports = {
447
435
  diff > 0 && !expected && mode === "minimum") &&
448
436
  !(expected && containsLineTerminator(whitespace))
449
437
  ) {
438
+ const nextColon = getNextColon(property.key),
439
+ tokenBeforeColon = sourceCode.getTokenBefore(nextColon, { includeComments: true }),
440
+ tokenAfterColon = sourceCode.getTokenAfter(nextColon, { includeComments: true }),
441
+ isKeySide = side === "key",
442
+ isExtra = diff > 0,
443
+ diffAbs = Math.abs(diff),
444
+ spaces = Array(diffAbs + 1).join(" ");
445
+
446
+ const locStart = isKeySide ? tokenBeforeColon.loc.end : nextColon.loc.start;
447
+ const locEnd = isKeySide ? nextColon.loc.start : tokenAfterColon.loc.start;
448
+ const missingLoc = isKeySide ? tokenBeforeColon.loc : tokenAfterColon.loc;
449
+ const loc = isExtra ? { start: locStart, end: locEnd } : missingLoc;
450
+
450
451
  let fix;
451
452
 
452
453
  if (isExtra) {
@@ -109,6 +109,8 @@ module.exports = {
109
109
  create(context) {
110
110
  const sourceCode = context.getSourceCode();
111
111
 
112
+ const tokensToIgnore = new WeakSet();
113
+
112
114
  /**
113
115
  * Reports a given token if there are not space(s) before the token.
114
116
  * @param {Token} token A token to report.
@@ -121,6 +123,7 @@ module.exports = {
121
123
  if (prevToken &&
122
124
  (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
123
125
  !isOpenParenOfTemplate(prevToken) &&
126
+ !tokensToIgnore.has(prevToken) &&
124
127
  astUtils.isTokenOnSameLine(prevToken, token) &&
125
128
  !sourceCode.isSpaceBetweenTokens(prevToken, token)
126
129
  ) {
@@ -147,6 +150,7 @@ module.exports = {
147
150
  if (prevToken &&
148
151
  (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
149
152
  !isOpenParenOfTemplate(prevToken) &&
153
+ !tokensToIgnore.has(prevToken) &&
150
154
  astUtils.isTokenOnSameLine(prevToken, token) &&
151
155
  sourceCode.isSpaceBetweenTokens(prevToken, token)
152
156
  ) {
@@ -173,6 +177,7 @@ module.exports = {
173
177
  if (nextToken &&
174
178
  (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
175
179
  !isCloseParenOfTemplate(nextToken) &&
180
+ !tokensToIgnore.has(nextToken) &&
176
181
  astUtils.isTokenOnSameLine(token, nextToken) &&
177
182
  !sourceCode.isSpaceBetweenTokens(token, nextToken)
178
183
  ) {
@@ -199,6 +204,7 @@ module.exports = {
199
204
  if (nextToken &&
200
205
  (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
201
206
  !isCloseParenOfTemplate(nextToken) &&
207
+ !tokensToIgnore.has(nextToken) &&
202
208
  astUtils.isTokenOnSameLine(token, nextToken) &&
203
209
  sourceCode.isSpaceBetweenTokens(token, nextToken)
204
210
  ) {
@@ -584,7 +590,15 @@ module.exports = {
584
590
  ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
585
591
  MethodDefinition: checkSpacingForProperty,
586
592
  PropertyDefinition: checkSpacingForProperty,
587
- Property: checkSpacingForProperty
593
+ StaticBlock: checkSpacingAroundFirstToken,
594
+ Property: checkSpacingForProperty,
595
+
596
+ // To avoid conflicts with `space-infix-ops`, e.g. `a > this.b`
597
+ "BinaryExpression[operator='>']"(node) {
598
+ const operatorToken = sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken);
599
+
600
+ tokensToIgnore.add(operatorToken);
601
+ }
588
602
  };
589
603
  }
590
604
  };
@@ -185,10 +185,39 @@ module.exports = {
185
185
  /**
186
186
  * Returns the parent node that contains the given token.
187
187
  * @param {token} token The token to check.
188
- * @returns {ASTNode} The parent node that contains the given token.
188
+ * @returns {ASTNode|null} The parent node that contains the given token.
189
189
  */
190
190
  function getParentNodeOfToken(token) {
191
- return sourceCode.getNodeByRangeIndex(token.range[0]);
191
+ const node = sourceCode.getNodeByRangeIndex(token.range[0]);
192
+
193
+ /*
194
+ * For the purpose of this rule, the comment token is in a `StaticBlock` node only
195
+ * if it's inside the braces of that `StaticBlock` node.
196
+ *
197
+ * Example where this function returns `null`:
198
+ *
199
+ * static
200
+ * // comment
201
+ * {
202
+ * }
203
+ *
204
+ * Example where this function returns `StaticBlock` node:
205
+ *
206
+ * static
207
+ * {
208
+ * // comment
209
+ * }
210
+ *
211
+ */
212
+ if (node && node.type === "StaticBlock") {
213
+ const openingBrace = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
214
+
215
+ return token.range[0] >= openingBrace.range[0]
216
+ ? node
217
+ : null;
218
+ }
219
+
220
+ return node;
192
221
  }
193
222
 
194
223
  /**
@@ -200,8 +229,15 @@ module.exports = {
200
229
  function isCommentAtParentStart(token, nodeType) {
201
230
  const parent = getParentNodeOfToken(token);
202
231
 
203
- return parent && isParentNodeType(parent, nodeType) &&
204
- token.loc.start.line - parent.loc.start.line === 1;
232
+ if (parent && isParentNodeType(parent, nodeType)) {
233
+ const parentStartNodeOrToken = parent.type === "StaticBlock"
234
+ ? sourceCode.getFirstToken(parent, { skip: 1 }) // opening brace of the static block
235
+ : parent;
236
+
237
+ return token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1;
238
+ }
239
+
240
+ return false;
205
241
  }
206
242
 
207
243
  /**
@@ -213,7 +249,7 @@ module.exports = {
213
249
  function isCommentAtParentEnd(token, nodeType) {
214
250
  const parent = getParentNodeOfToken(token);
215
251
 
216
- return parent && isParentNodeType(parent, nodeType) &&
252
+ return !!parent && isParentNodeType(parent, nodeType) &&
217
253
  parent.loc.end.line - token.loc.end.line === 1;
218
254
  }
219
255
 
@@ -223,7 +259,12 @@ module.exports = {
223
259
  * @returns {boolean} True if the comment is at block start.
224
260
  */
225
261
  function isCommentAtBlockStart(token) {
226
- return isCommentAtParentStart(token, "ClassBody") || isCommentAtParentStart(token, "BlockStatement") || isCommentAtParentStart(token, "SwitchCase");
262
+ return (
263
+ isCommentAtParentStart(token, "ClassBody") ||
264
+ isCommentAtParentStart(token, "BlockStatement") ||
265
+ isCommentAtParentStart(token, "StaticBlock") ||
266
+ isCommentAtParentStart(token, "SwitchCase")
267
+ );
227
268
  }
228
269
 
229
270
  /**
@@ -232,7 +273,13 @@ module.exports = {
232
273
  * @returns {boolean} True if the comment is at block end.
233
274
  */
234
275
  function isCommentAtBlockEnd(token) {
235
- return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement");
276
+ return (
277
+ isCommentAtParentEnd(token, "ClassBody") ||
278
+ isCommentAtParentEnd(token, "BlockStatement") ||
279
+ isCommentAtParentEnd(token, "StaticBlock") ||
280
+ isCommentAtParentEnd(token, "SwitchCase") ||
281
+ isCommentAtParentEnd(token, "SwitchStatement")
282
+ );
236
283
  }
237
284
 
238
285
  /**
@@ -118,6 +118,7 @@ module.exports = {
118
118
  FunctionDeclaration: startFunction,
119
119
  FunctionExpression: startFunction,
120
120
  ArrowFunctionExpression: startFunction,
121
+ StaticBlock: startFunction,
121
122
 
122
123
  IfStatement(node) {
123
124
  if (node.parent.type !== "IfStatement") {
@@ -146,6 +147,7 @@ module.exports = {
146
147
  "FunctionDeclaration:exit": endFunction,
147
148
  "FunctionExpression:exit": endFunction,
148
149
  "ArrowFunctionExpression:exit": endFunction,
150
+ "StaticBlock:exit": endFunction,
149
151
  "Program:exit": endFunction
150
152
  };
151
153