eslint 9.0.0-alpha.0 → 9.0.0-alpha.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 (85) hide show
  1. package/README.md +5 -0
  2. package/conf/ecma-version.js +16 -0
  3. package/lib/cli-engine/cli-engine.js +1 -1
  4. package/lib/cli-engine/lint-result-cache.js +2 -2
  5. package/lib/cli.js +14 -16
  6. package/lib/linter/apply-disable-directives.js +2 -2
  7. package/lib/linter/code-path-analysis/code-path.js +5 -19
  8. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  9. package/lib/linter/config-comment-parser.js +7 -10
  10. package/lib/linter/linter.js +105 -4
  11. package/lib/linter/report-translator.js +2 -2
  12. package/lib/linter/source-code-fixer.js +1 -1
  13. package/lib/rule-tester/rule-tester.js +1 -26
  14. package/lib/rules/array-bracket-newline.js +1 -1
  15. package/lib/rules/array-bracket-spacing.js +1 -1
  16. package/lib/rules/block-scoped-var.js +1 -1
  17. package/lib/rules/callback-return.js +2 -2
  18. package/lib/rules/comma-dangle.js +1 -1
  19. package/lib/rules/comma-style.js +2 -2
  20. package/lib/rules/complexity.js +1 -1
  21. package/lib/rules/constructor-super.js +1 -1
  22. package/lib/rules/default-case.js +1 -1
  23. package/lib/rules/eol-last.js +2 -2
  24. package/lib/rules/function-paren-newline.js +2 -2
  25. package/lib/rules/indent-legacy.js +5 -5
  26. package/lib/rules/indent.js +5 -5
  27. package/lib/rules/index.js +1 -0
  28. package/lib/rules/key-spacing.js +2 -2
  29. package/lib/rules/line-comment-position.js +1 -1
  30. package/lib/rules/lines-around-directive.js +2 -2
  31. package/lib/rules/max-depth.js +1 -1
  32. package/lib/rules/max-len.js +3 -3
  33. package/lib/rules/max-lines.js +3 -3
  34. package/lib/rules/max-nested-callbacks.js +1 -1
  35. package/lib/rules/max-params.js +1 -1
  36. package/lib/rules/max-statements.js +1 -1
  37. package/lib/rules/multiline-comment-style.js +7 -7
  38. package/lib/rules/new-cap.js +1 -1
  39. package/lib/rules/newline-after-var.js +1 -1
  40. package/lib/rules/newline-before-return.js +1 -1
  41. package/lib/rules/no-constant-binary-expression.js +5 -5
  42. package/lib/rules/no-constructor-return.js +1 -1
  43. package/lib/rules/no-dupe-class-members.js +2 -2
  44. package/lib/rules/no-else-return.js +1 -1
  45. package/lib/rules/no-empty-function.js +2 -2
  46. package/lib/rules/no-fallthrough.js +1 -1
  47. package/lib/rules/no-inner-declarations.js +22 -1
  48. package/lib/rules/no-invalid-this.js +1 -1
  49. package/lib/rules/no-lone-blocks.js +2 -2
  50. package/lib/rules/no-loss-of-precision.js +1 -1
  51. package/lib/rules/no-misleading-character-class.js +174 -65
  52. package/lib/rules/no-multiple-empty-lines.js +1 -1
  53. package/lib/rules/no-restricted-globals.js +1 -1
  54. package/lib/rules/no-restricted-imports.js +2 -2
  55. package/lib/rules/no-restricted-modules.js +2 -2
  56. package/lib/rules/no-return-await.js +1 -1
  57. package/lib/rules/no-trailing-spaces.js +2 -3
  58. package/lib/rules/no-unneeded-ternary.js +1 -1
  59. package/lib/rules/no-unsafe-optional-chaining.js +1 -1
  60. package/lib/rules/no-unused-vars.js +6 -8
  61. package/lib/rules/no-useless-assignment.js +566 -0
  62. package/lib/rules/no-useless-backreference.js +1 -1
  63. package/lib/rules/object-curly-spacing.js +3 -3
  64. package/lib/rules/object-property-newline.js +1 -1
  65. package/lib/rules/one-var.js +5 -5
  66. package/lib/rules/padded-blocks.js +7 -7
  67. package/lib/rules/prefer-arrow-callback.js +3 -3
  68. package/lib/rules/prefer-reflect.js +1 -1
  69. package/lib/rules/prefer-regex-literals.js +1 -1
  70. package/lib/rules/prefer-template.js +1 -1
  71. package/lib/rules/radix.js +2 -2
  72. package/lib/rules/semi-style.js +1 -1
  73. package/lib/rules/sort-imports.js +1 -1
  74. package/lib/rules/sort-keys.js +1 -1
  75. package/lib/rules/sort-vars.js +1 -1
  76. package/lib/rules/space-unary-ops.js +1 -1
  77. package/lib/rules/strict.js +1 -1
  78. package/lib/rules/utils/ast-utils.js +7 -7
  79. package/lib/rules/yield-star-spacing.js +1 -1
  80. package/lib/source-code/source-code.js +4 -4
  81. package/lib/source-code/token-store/index.js +2 -2
  82. package/package.json +4 -4
  83. package/conf/config-schema.js +0 -93
  84. package/lib/shared/config-validator.js +0 -380
  85. package/lib/shared/relative-module-resolver.js +0 -50
@@ -1077,7 +1077,7 @@ module.exports = {
1077
1077
  "ObjectExpression, ObjectPattern"(node) {
1078
1078
  const openingCurly = sourceCode.getFirstToken(node);
1079
1079
  const closingCurly = sourceCode.getTokenAfter(
1080
- node.properties.length ? node.properties[node.properties.length - 1] : openingCurly,
1080
+ node.properties.length ? node.properties.at(-1) : openingCurly,
1081
1081
  astUtils.isClosingBraceToken
1082
1082
  );
1083
1083
 
@@ -1407,7 +1407,7 @@ module.exports = {
1407
1407
  PropertyDefinition(node) {
1408
1408
  const firstToken = sourceCode.getFirstToken(node);
1409
1409
  const maybeSemicolonToken = sourceCode.getLastToken(node);
1410
- let keyLastToken = null;
1410
+ let keyLastToken;
1411
1411
 
1412
1412
  // Indent key.
1413
1413
  if (node.computed) {
@@ -1458,7 +1458,7 @@ module.exports = {
1458
1458
 
1459
1459
  if (node.cases.length) {
1460
1460
  sourceCode.getTokensBetween(
1461
- node.cases[node.cases.length - 1],
1461
+ node.cases.at(-1),
1462
1462
  closingCurly,
1463
1463
  { includeComments: true, filter: astUtils.isCommentToken }
1464
1464
  ).forEach(token => offsets.ignoreToken(token));
@@ -1488,7 +1488,7 @@ module.exports = {
1488
1488
  },
1489
1489
 
1490
1490
  VariableDeclaration(node) {
1491
- let variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
1491
+ let variableIndent = Object.hasOwn(options.VariableDeclarator, node.kind)
1492
1492
  ? options.VariableDeclarator[node.kind]
1493
1493
  : DEFAULT_VARIABLE_INDENT;
1494
1494
 
@@ -1509,7 +1509,7 @@ module.exports = {
1509
1509
  variableIndent = DEFAULT_VARIABLE_INDENT;
1510
1510
  }
1511
1511
 
1512
- if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
1512
+ if (node.declarations.at(-1).loc.start.line > node.loc.start.line) {
1513
1513
 
1514
1514
  /*
1515
1515
  * VariableDeclarator indentation is a bit different from other forms of indentation, in that the
@@ -229,6 +229,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
229
229
  "no-unused-private-class-members": () => require("./no-unused-private-class-members"),
230
230
  "no-unused-vars": () => require("./no-unused-vars"),
231
231
  "no-use-before-define": () => require("./no-use-before-define"),
232
+ "no-useless-assignment": () => require("./no-useless-assignment"),
232
233
  "no-useless-backreference": () => require("./no-useless-backreference"),
233
234
  "no-useless-call": () => require("./no-useless-call"),
234
235
  "no-useless-catch": () => require("./no-useless-catch"),
@@ -28,7 +28,7 @@ function containsLineTerminator(str) {
28
28
  * @returns {any} Last element of arr.
29
29
  */
30
30
  function last(arr) {
31
- return arr[arr.length - 1];
31
+ return arr.at(-1);
32
32
  }
33
33
 
34
34
  /**
@@ -489,7 +489,7 @@ module.exports = {
489
489
  }
490
490
  }
491
491
 
492
- let messageId = "";
492
+ let messageId;
493
493
 
494
494
  if (isExtra) {
495
495
  messageId = side === "key" ? "extraKey" : "extraValue";
@@ -68,7 +68,7 @@ module.exports = {
68
68
  above = !options.position || options.position === "above";
69
69
  ignorePattern = options.ignorePattern;
70
70
 
71
- if (Object.prototype.hasOwnProperty.call(options, "applyDefaultIgnorePatterns")) {
71
+ if (Object.hasOwn(options, "applyDefaultIgnorePatterns")) {
72
72
  applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns;
73
73
  } else {
74
74
  applyDefaultIgnorePatterns = options.applyDefaultPatterns !== false;
@@ -166,7 +166,7 @@ module.exports = {
166
166
  reportError(firstDirective, "before", false);
167
167
  }
168
168
 
169
- const lastDirective = directives[directives.length - 1];
169
+ const lastDirective = directives.at(-1);
170
170
  const statements = node.type === "Program" ? node.body : node.body.body;
171
171
 
172
172
  /*
@@ -174,7 +174,7 @@ module.exports = {
174
174
  * contains a directive prologue and isn't followed by a comment to ensure
175
175
  * this rule behaves well with padded-blocks.
176
176
  */
177
- if (lastDirective === statements[statements.length - 1] && !lastDirective.trailingComments) {
177
+ if (lastDirective === statements.at(-1) && !lastDirective.trailingComments) {
178
178
  return;
179
179
  }
180
180
 
@@ -61,7 +61,7 @@ module.exports = {
61
61
 
62
62
  if (
63
63
  typeof option === "object" &&
64
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
64
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
65
65
  ) {
66
66
  maxDepth = option.maximum || option.max;
67
67
  }
@@ -124,7 +124,7 @@ module.exports = {
124
124
  }
125
125
 
126
126
  // The options object must be the last option specified…
127
- const options = Object.assign({}, context.options[context.options.length - 1]);
127
+ const options = Object.assign({}, context.options.at(-1));
128
128
 
129
129
  // …but max code length…
130
130
  if (typeof context.options[0] === "number") {
@@ -290,7 +290,7 @@ module.exports = {
290
290
  if (isJSXEmptyExpressionInSingleLineContainer(containingNode)) {
291
291
 
292
292
  // push a unique node only
293
- if (comments[comments.length - 1] !== containingNode.parent) {
293
+ if (comments.at(-1) !== containingNode.parent) {
294
294
  comments.push(containingNode.parent);
295
295
  }
296
296
  } else {
@@ -344,7 +344,7 @@ module.exports = {
344
344
  * comments to check.
345
345
  */
346
346
  if (commentsIndex < comments.length) {
347
- let comment = null;
347
+ let comment;
348
348
 
349
349
  // iterate over comments until we find one past the current line
350
350
  do {
@@ -77,7 +77,7 @@ module.exports = {
77
77
 
78
78
  if (
79
79
  typeof option === "object" &&
80
- Object.prototype.hasOwnProperty.call(option, "max")
80
+ Object.hasOwn(option, "max")
81
81
  ) {
82
82
  max = option.max;
83
83
  } else if (typeof option === "number") {
@@ -148,7 +148,7 @@ module.exports = {
148
148
  * If file ends with a linebreak, `sourceCode.lines` will have one extra empty line at the end.
149
149
  * That isn't a real line, so we shouldn't count it.
150
150
  */
151
- if (lines.length > 1 && lines[lines.length - 1].text === "") {
151
+ if (lines.length > 1 && lines.at(-1).text === "") {
152
152
  lines.pop();
153
153
  }
154
154
 
@@ -174,7 +174,7 @@ module.exports = {
174
174
  },
175
175
  end: {
176
176
  line: sourceCode.lines.length,
177
- column: sourceCode.lines[sourceCode.lines.length - 1].length
177
+ column: sourceCode.lines.at(-1).length
178
178
  }
179
179
  };
180
180
 
@@ -59,7 +59,7 @@ module.exports = {
59
59
 
60
60
  if (
61
61
  typeof option === "object" &&
62
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
62
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
63
63
  ) {
64
64
  THRESHOLD = option.maximum || option.max;
65
65
  } else if (typeof option === "number") {
@@ -63,7 +63,7 @@ module.exports = {
63
63
 
64
64
  if (
65
65
  typeof option === "object" &&
66
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
66
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
67
67
  ) {
68
68
  numParams = option.maximum || option.max;
69
69
  }
@@ -79,7 +79,7 @@ module.exports = {
79
79
 
80
80
  if (
81
81
  typeof option === "object" &&
82
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
82
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
83
83
  ) {
84
84
  maxStatements = option.maximum || option.max;
85
85
  } else if (typeof option === "number") {
@@ -113,7 +113,7 @@ module.exports = {
113
113
 
114
114
  return /^\*\s*$/u.test(lines[0]) &&
115
115
  lines.slice(1, -1).every(line => /^\s* /u.test(line)) &&
116
- /^\s*$/u.test(lines[lines.length - 1]);
116
+ /^\s*$/u.test(lines.at(-1));
117
117
  }
118
118
 
119
119
  /**
@@ -272,11 +272,11 @@ module.exports = {
272
272
  context.report({
273
273
  loc: {
274
274
  start: firstComment.loc.start,
275
- end: commentGroup[commentGroup.length - 1].loc.end
275
+ end: commentGroup.at(-1).loc.end
276
276
  },
277
277
  messageId: "expectedBlock",
278
278
  fix(fixer) {
279
- const range = [firstComment.range[0], commentGroup[commentGroup.length - 1].range[1]];
279
+ const range = [firstComment.range[0], commentGroup.at(-1).range[1]];
280
280
 
281
281
  return commentLines.some(value => value.startsWith("/"))
282
282
  ? null
@@ -301,7 +301,7 @@ module.exports = {
301
301
  });
302
302
  }
303
303
 
304
- if (!/^\s*$/u.test(lines[lines.length - 1])) {
304
+ if (!/^\s*$/u.test(lines.at(-1))) {
305
305
  context.report({
306
306
  loc: {
307
307
  start: { line: firstComment.loc.end.line, column: firstComment.loc.end.column - 2 },
@@ -408,12 +408,12 @@ module.exports = {
408
408
  context.report({
409
409
  loc: {
410
410
  start: firstComment.loc.start,
411
- end: commentGroup[commentGroup.length - 1].loc.end
411
+ end: commentGroup.at(-1).loc.end
412
412
  },
413
413
  messageId: "expectedBlock",
414
414
  fix(fixer) {
415
415
  return fixer.replaceTextRange(
416
- [firstComment.range[0], commentGroup[commentGroup.length - 1].range[1]],
416
+ [firstComment.range[0], commentGroup.at(-1).range[1]],
417
417
  convertToBlock(firstComment, commentLines)
418
418
  );
419
419
  }
@@ -459,7 +459,7 @@ module.exports = {
459
459
  tokenBefore && tokenBefore.loc.end.line === comment.loc.start.line - 1 &&
460
460
  tokenBefore === commentList[index - 1]
461
461
  ) {
462
- commentGroups[commentGroups.length - 1].push(comment);
462
+ commentGroups.at(-1).push(comment);
463
463
  } else {
464
464
  commentGroups.push([comment]);
465
465
  }
@@ -40,7 +40,7 @@ const CAPS_ALLOWED = [
40
40
  function checkArray(obj, key, fallback) {
41
41
 
42
42
  /* c8 ignore start */
43
- if (Object.prototype.hasOwnProperty.call(obj, key) && !Array.isArray(obj[key])) {
43
+ if (Object.hasOwn(obj, key) && !Array.isArray(obj[key])) {
44
44
  throw new TypeError(`${key}, if provided, must be an Array`);
45
45
  }/* c8 ignore stop */
46
46
  return obj[key] || fallback;
@@ -215,7 +215,7 @@ module.exports = {
215
215
  fix(fixer) {
216
216
  const linesBetween = sourceCode.getText().slice(lastToken.range[1], nextToken.range[0]).split(astUtils.LINEBREAK_MATCHER);
217
217
 
218
- return fixer.replaceTextRange([lastToken.range[1], nextToken.range[0]], `${linesBetween.slice(0, -1).join("")}\n${linesBetween[linesBetween.length - 1]}`);
218
+ return fixer.replaceTextRange([lastToken.range[1], nextToken.range[0]], `${linesBetween.slice(0, -1).join("")}\n${linesBetween.at(-1)}`);
219
219
  }
220
220
  });
221
221
  }
@@ -166,7 +166,7 @@ module.exports = {
166
166
  */
167
167
  function canFix(node) {
168
168
  const leadingComments = sourceCode.getCommentsBefore(node);
169
- const lastLeadingComment = leadingComments[leadingComments.length - 1];
169
+ const lastLeadingComment = leadingComments.at(-1);
170
170
  const tokenBefore = sourceCode.getTokenBefore(node);
171
171
 
172
172
  if (leadingComments.length === 0) {
@@ -103,7 +103,7 @@ function hasConstantNullishness(scope, node, nonNullish) {
103
103
 
104
104
  return true;
105
105
  case "SequenceExpression": {
106
- const last = node.expressions[node.expressions.length - 1];
106
+ const last = node.expressions.at(-1);
107
107
 
108
108
  return hasConstantNullishness(scope, last, nonNullish);
109
109
  }
@@ -248,7 +248,7 @@ function hasConstantLooseBooleanComparison(scope, node) {
248
248
  */
249
249
  return false;
250
250
  case "SequenceExpression": {
251
- const last = node.expressions[node.expressions.length - 1];
251
+ const last = node.expressions.at(-1);
252
252
 
253
253
  return hasConstantLooseBooleanComparison(scope, last);
254
254
  }
@@ -299,7 +299,7 @@ function hasConstantStrictBooleanComparison(scope, node) {
299
299
  return true;
300
300
  }
301
301
  case "SequenceExpression": {
302
- const last = node.expressions[node.expressions.length - 1];
302
+ const last = node.expressions.at(-1);
303
303
 
304
304
  return hasConstantStrictBooleanComparison(scope, last);
305
305
  }
@@ -376,7 +376,7 @@ function isAlwaysNew(scope, node) {
376
376
  * Catching these is especially useful for primitive constructors
377
377
  * which return boxed values, a surprising gotcha' in JavaScript.
378
378
  */
379
- return Object.hasOwnProperty.call(globals.builtin, node.callee.name) &&
379
+ return Object.hasOwn(globals.builtin, node.callee.name) &&
380
380
  isReferenceToGlobalVariable(scope, node.callee);
381
381
  }
382
382
  case "Literal":
@@ -384,7 +384,7 @@ function isAlwaysNew(scope, node) {
384
384
  // Regular expressions are objects, and thus always new
385
385
  return typeof node.regex === "object";
386
386
  case "SequenceExpression": {
387
- const last = node.expressions[node.expressions.length - 1];
387
+ const last = node.expressions.at(-1);
388
388
 
389
389
  return isAlwaysNew(scope, last);
390
390
  }
@@ -40,7 +40,7 @@ module.exports = {
40
40
  stack.pop();
41
41
  },
42
42
  ReturnStatement(node) {
43
- const last = stack[stack.length - 1];
43
+ const last = stack.at(-1);
44
44
 
45
45
  if (!last.parent) {
46
46
  return;
@@ -42,7 +42,7 @@ module.exports = {
42
42
  * - retv.set {boolean} A flag which shows the name is declared as setter.
43
43
  */
44
44
  function getState(name, isStatic) {
45
- const stateMap = stack[stack.length - 1];
45
+ const stateMap = stack.at(-1);
46
46
  const key = `$${name}`; // to avoid "__proto__".
47
47
 
48
48
  if (!stateMap[key]) {
@@ -82,7 +82,7 @@ module.exports = {
82
82
  }
83
83
 
84
84
  const state = getState(name, node.static);
85
- let isDuplicate = false;
85
+ let isDuplicate;
86
86
 
87
87
  if (kind === "get") {
88
88
  isDuplicate = (state.init || state.get);
@@ -270,7 +270,7 @@ module.exports = {
270
270
  function naiveHasReturn(node) {
271
271
  if (node.type === "BlockStatement") {
272
272
  const body = node.body,
273
- lastChildNode = body[body.length - 1];
273
+ lastChildNode = body.at(-1);
274
274
 
275
275
  return lastChildNode && checkForReturn(lastChildNode);
276
276
  }
@@ -40,7 +40,7 @@ const ALLOW_OPTIONS = Object.freeze([
40
40
  */
41
41
  function getKind(node) {
42
42
  const parent = node.parent;
43
- let kind = "";
43
+ let kind;
44
44
 
45
45
  if (node.type === "ArrowFunctionExpression") {
46
46
  return "arrowFunctions";
@@ -73,7 +73,7 @@ function getKind(node) {
73
73
  }
74
74
 
75
75
  // Detects prefix.
76
- let prefix = "";
76
+ let prefix;
77
77
 
78
78
  if (node.generator) {
79
79
  prefix = "generator";
@@ -187,7 +187,7 @@ module.exports = {
187
187
  */
188
188
  if (isAnySegmentReachable(currentCodePathSegments) &&
189
189
  (node.consequent.length > 0 || (!allowEmptyCase && hasBlankLinesBetween(node, nextToken))) &&
190
- node.parent.cases[node.parent.cases.length - 1] !== node) {
190
+ node.parent.cases.at(-1) !== node) {
191
191
  fallthroughCase = node;
192
192
  }
193
193
  }
@@ -56,6 +56,15 @@ module.exports = {
56
56
  schema: [
57
57
  {
58
58
  enum: ["functions", "both"]
59
+ },
60
+ {
61
+ type: "object",
62
+ properties: {
63
+ blockScopedFunctions: {
64
+ enum: ["allow", "disallow"]
65
+ }
66
+ },
67
+ additionalProperties: false
59
68
  }
60
69
  ],
61
70
 
@@ -66,6 +75,10 @@ module.exports = {
66
75
 
67
76
  create(context) {
68
77
 
78
+ const sourceCode = context.sourceCode;
79
+ const ecmaVersion = context.languageOptions.ecmaVersion;
80
+ const blockScopedFunctions = context.options[1]?.blockScopedFunctions ?? "allow";
81
+
69
82
  /**
70
83
  * Ensure that a given node is at a program or function body's root.
71
84
  * @param {ASTNode} node Declaration node to check.
@@ -97,7 +110,15 @@ module.exports = {
97
110
 
98
111
  return {
99
112
 
100
- FunctionDeclaration: check,
113
+ FunctionDeclaration(node) {
114
+ const isInStrictCode = sourceCode.getScope(node).upper.isStrict;
115
+
116
+ if (blockScopedFunctions === "allow" && ecmaVersion >= 2015 && isInStrictCode) {
117
+ return;
118
+ }
119
+
120
+ check(node);
121
+ },
101
122
  VariableDeclaration(node) {
102
123
  if (context.options[0] === "both" && node.kind === "var") {
103
124
  check(node);
@@ -74,7 +74,7 @@ module.exports = {
74
74
  * an object which has a flag that whether or not `this` keyword is valid.
75
75
  */
76
76
  stack.getCurrent = function() {
77
- const current = this[this.length - 1];
77
+ const current = this.at(-1);
78
78
 
79
79
  if (!current.init) {
80
80
  current.init = true;
@@ -78,7 +78,7 @@ module.exports = {
78
78
 
79
79
  const block = node.parent;
80
80
 
81
- if (loneBlocks[loneBlocks.length - 1] === block) {
81
+ if (loneBlocks.at(-1) === block) {
82
82
  loneBlocks.pop();
83
83
  }
84
84
  }
@@ -101,7 +101,7 @@ module.exports = {
101
101
  }
102
102
  },
103
103
  "BlockStatement:exit"(node) {
104
- if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
104
+ if (loneBlocks.length > 0 && loneBlocks.at(-1) === node) {
105
105
  loneBlocks.pop();
106
106
  report(node);
107
107
  } else if (
@@ -64,7 +64,7 @@ module.exports = {
64
64
  */
65
65
  function notBaseTenLosesPrecision(node) {
66
66
  const rawString = getRaw(node).toUpperCase();
67
- let base = 0;
67
+ let base;
68
68
 
69
69
  if (rawString.startsWith("0B")) {
70
70
  base = 2;