eslint 9.0.0-alpha.0 → 9.0.0-alpha.2

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 (89) hide show
  1. package/README.md +6 -1
  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/eslint/eslint.js +7 -0
  7. package/lib/linter/apply-disable-directives.js +2 -2
  8. package/lib/linter/code-path-analysis/code-path.js +32 -30
  9. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  10. package/lib/linter/config-comment-parser.js +7 -10
  11. package/lib/linter/linter.js +105 -4
  12. package/lib/linter/report-translator.js +2 -2
  13. package/lib/linter/source-code-fixer.js +1 -1
  14. package/lib/rule-tester/rule-tester.js +45 -26
  15. package/lib/rules/array-bracket-newline.js +1 -1
  16. package/lib/rules/array-bracket-spacing.js +1 -1
  17. package/lib/rules/block-scoped-var.js +1 -1
  18. package/lib/rules/callback-return.js +2 -2
  19. package/lib/rules/comma-dangle.js +1 -1
  20. package/lib/rules/comma-style.js +2 -2
  21. package/lib/rules/complexity.js +1 -1
  22. package/lib/rules/constructor-super.js +1 -1
  23. package/lib/rules/default-case.js +1 -1
  24. package/lib/rules/eol-last.js +2 -2
  25. package/lib/rules/function-paren-newline.js +2 -2
  26. package/lib/rules/indent-legacy.js +5 -5
  27. package/lib/rules/indent.js +5 -5
  28. package/lib/rules/index.js +1 -0
  29. package/lib/rules/key-spacing.js +2 -2
  30. package/lib/rules/line-comment-position.js +1 -1
  31. package/lib/rules/lines-around-directive.js +2 -2
  32. package/lib/rules/max-depth.js +1 -1
  33. package/lib/rules/max-len.js +3 -3
  34. package/lib/rules/max-lines.js +3 -3
  35. package/lib/rules/max-nested-callbacks.js +1 -1
  36. package/lib/rules/max-params.js +1 -1
  37. package/lib/rules/max-statements.js +1 -1
  38. package/lib/rules/multiline-comment-style.js +7 -7
  39. package/lib/rules/new-cap.js +1 -1
  40. package/lib/rules/newline-after-var.js +1 -1
  41. package/lib/rules/newline-before-return.js +1 -1
  42. package/lib/rules/no-constant-binary-expression.js +5 -5
  43. package/lib/rules/no-constructor-return.js +1 -1
  44. package/lib/rules/no-dupe-class-members.js +2 -2
  45. package/lib/rules/no-else-return.js +1 -1
  46. package/lib/rules/no-empty-function.js +2 -2
  47. package/lib/rules/no-fallthrough.js +1 -1
  48. package/lib/rules/no-implicit-coercion.js +51 -25
  49. package/lib/rules/no-inner-declarations.js +22 -1
  50. package/lib/rules/no-invalid-this.js +1 -1
  51. package/lib/rules/no-lone-blocks.js +2 -2
  52. package/lib/rules/no-loss-of-precision.js +1 -1
  53. package/lib/rules/no-misleading-character-class.js +174 -65
  54. package/lib/rules/no-multiple-empty-lines.js +1 -1
  55. package/lib/rules/no-restricted-globals.js +1 -1
  56. package/lib/rules/no-restricted-imports.js +54 -44
  57. package/lib/rules/no-restricted-modules.js +2 -2
  58. package/lib/rules/no-return-await.js +1 -1
  59. package/lib/rules/no-this-before-super.js +17 -4
  60. package/lib/rules/no-trailing-spaces.js +2 -3
  61. package/lib/rules/no-unneeded-ternary.js +1 -1
  62. package/lib/rules/no-unsafe-optional-chaining.js +1 -1
  63. package/lib/rules/no-unused-vars.js +6 -8
  64. package/lib/rules/no-useless-assignment.js +566 -0
  65. package/lib/rules/no-useless-backreference.js +1 -1
  66. package/lib/rules/object-curly-spacing.js +3 -3
  67. package/lib/rules/object-property-newline.js +1 -1
  68. package/lib/rules/one-var.js +5 -5
  69. package/lib/rules/padded-blocks.js +7 -7
  70. package/lib/rules/prefer-arrow-callback.js +3 -3
  71. package/lib/rules/prefer-reflect.js +1 -1
  72. package/lib/rules/prefer-regex-literals.js +1 -1
  73. package/lib/rules/prefer-template.js +1 -1
  74. package/lib/rules/radix.js +2 -2
  75. package/lib/rules/semi-style.js +1 -1
  76. package/lib/rules/sort-imports.js +1 -1
  77. package/lib/rules/sort-keys.js +1 -1
  78. package/lib/rules/sort-vars.js +1 -1
  79. package/lib/rules/space-unary-ops.js +1 -1
  80. package/lib/rules/strict.js +1 -1
  81. package/lib/rules/utils/ast-utils.js +7 -7
  82. package/lib/rules/yield-star-spacing.js +1 -1
  83. package/lib/shared/serialization.js +55 -0
  84. package/lib/source-code/source-code.js +4 -4
  85. package/lib/source-code/token-store/index.js +2 -2
  86. package/package.json +7 -7
  87. package/conf/config-schema.js +0 -93
  88. package/lib/shared/config-validator.js +0 -380
  89. package/lib/shared/relative-module-resolver.js +0 -50
@@ -79,7 +79,7 @@ module.exports = {
79
79
  }
80
80
 
81
81
  // Defines a predicate to check whether or not a given reference is outside of valid scope.
82
- const scopeRange = stack[stack.length - 1];
82
+ const scopeRange = stack.at(-1);
83
83
 
84
84
  /**
85
85
  * Check if a reference is out of scope
@@ -147,7 +147,7 @@ module.exports = {
147
147
  if (closestBlock.type === "BlockStatement") {
148
148
 
149
149
  // find the last item in the block
150
- const lastItem = closestBlock.body[closestBlock.body.length - 1];
150
+ const lastItem = closestBlock.body.at(-1);
151
151
 
152
152
  // if the callback is the last thing in a block that might be ok
153
153
  if (isCallbackExpression(node, lastItem)) {
@@ -168,7 +168,7 @@ module.exports = {
168
168
  if (lastItem.type === "ReturnStatement") {
169
169
 
170
170
  // but only if the callback is immediately before
171
- if (isCallbackExpression(node, closestBlock.body[closestBlock.body.length - 2])) {
171
+ if (isCallbackExpression(node, closestBlock.body.at(-2))) {
172
172
  return;
173
173
  }
174
174
  }
@@ -154,7 +154,7 @@ module.exports = {
154
154
  * @returns {any} The last element
155
155
  */
156
156
  function last(array) {
157
- return array[array.length - 1];
157
+ return array.at(-1);
158
158
  }
159
159
 
160
160
  switch (node.type) {
@@ -66,7 +66,7 @@ module.exports = {
66
66
  NewExpression: true
67
67
  };
68
68
 
69
- if (context.options.length === 2 && Object.prototype.hasOwnProperty.call(context.options[1], "exceptions")) {
69
+ if (context.options.length === 2 && Object.hasOwn(context.options[1], "exceptions")) {
70
70
  const keys = Object.keys(context.options[1].exceptions);
71
71
 
72
72
  for (let i = 0; i < keys.length; i++) {
@@ -218,7 +218,7 @@ module.exports = {
218
218
 
219
219
  previousItemToken = tokenAfterItem
220
220
  ? sourceCode.getTokenBefore(tokenAfterItem)
221
- : sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
221
+ : sourceCode.ast.tokens.at(-1);
222
222
  } else {
223
223
  previousItemToken = currentItemToken;
224
224
  }
@@ -64,7 +64,7 @@ module.exports = {
64
64
 
65
65
  if (
66
66
  typeof option === "object" &&
67
- (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
67
+ (Object.hasOwn(option, "maximum") || Object.hasOwn(option, "max"))
68
68
  ) {
69
69
  THRESHOLD = option.maximum || option.max;
70
70
  } else if (typeof option === "number") {
@@ -109,7 +109,7 @@ function isPossibleConstructor(node) {
109
109
  );
110
110
 
111
111
  case "SequenceExpression": {
112
- const lastExpression = node.expressions[node.expressions.length - 1];
112
+ const lastExpression = node.expressions.at(-1);
113
113
 
114
114
  return isPossibleConstructor(lastExpression);
115
115
  }
@@ -54,7 +54,7 @@ module.exports = {
54
54
  * @returns {any} Last element
55
55
  */
56
56
  function last(collection) {
57
- return collection[collection.length - 1];
57
+ return collection.at(-1);
58
58
  }
59
59
 
60
60
  //--------------------------------------------------------------------------
@@ -45,7 +45,7 @@ module.exports = {
45
45
  Program: function checkBadEOF(node) {
46
46
  const sourceCode = context.sourceCode,
47
47
  src = sourceCode.getText(),
48
- lastLine = sourceCode.lines[sourceCode.lines.length - 1],
48
+ lastLine = sourceCode.lines.at(-1),
49
49
  location = {
50
50
  column: lastLine.length,
51
51
  line: sourceCode.lines.length
@@ -89,7 +89,7 @@ module.exports = {
89
89
  });
90
90
  } else if (mode === "never" && endsWithNewline) {
91
91
 
92
- const secondLastLine = sourceCode.lines[sourceCode.lines.length - 2];
92
+ const secondLastLine = sourceCode.lines.at(-2);
93
93
 
94
94
  // File is newline-terminated, but shouldn't be
95
95
  context.report({
@@ -218,7 +218,7 @@ module.exports = {
218
218
  case "FunctionExpression": {
219
219
  const leftParen = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
220
220
  const rightParen = node.params.length
221
- ? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken)
221
+ ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
222
222
  : sourceCode.getTokenAfter(leftParen);
223
223
 
224
224
  return { leftParen, rightParen };
@@ -234,7 +234,7 @@ module.exports = {
234
234
  }
235
235
 
236
236
  const rightParen = node.params.length
237
- ? sourceCode.getTokenAfter(node.params[node.params.length - 1], astUtils.isClosingParenToken)
237
+ ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
238
238
  : sourceCode.getTokenAfter(firstToken);
239
239
 
240
240
  return {
@@ -789,7 +789,7 @@ module.exports = {
789
789
  if (elements.length > 0) {
790
790
 
791
791
  // Skip last block line check if last item in same line
792
- if (elements[elements.length - 1].loc.end.line === node.loc.end.line) {
792
+ if (elements.at(-1).loc.end.line === node.loc.end.line) {
793
793
  return;
794
794
  }
795
795
  }
@@ -830,7 +830,7 @@ module.exports = {
830
830
  }
831
831
 
832
832
  let indent;
833
- let nodesToCheck = [];
833
+ let nodesToCheck;
834
834
 
835
835
  /*
836
836
  * For this statements we should check indent from statement beginning,
@@ -873,7 +873,7 @@ module.exports = {
873
873
  */
874
874
  function filterOutSameLineVars(node) {
875
875
  return node.declarations.reduce((finalCollection, elem) => {
876
- const lastElem = finalCollection[finalCollection.length - 1];
876
+ const lastElem = finalCollection.at(-1);
877
877
 
878
878
  if ((elem.loc.start.line !== node.loc.start.line && !lastElem) ||
879
879
  (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) {
@@ -892,7 +892,7 @@ module.exports = {
892
892
  function checkIndentInVariableDeclarations(node) {
893
893
  const elements = filterOutSameLineVars(node);
894
894
  const nodeIndent = getNodeIndent(node).goodChar;
895
- const lastElement = elements[elements.length - 1];
895
+ const lastElement = elements.at(-1);
896
896
 
897
897
  const elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind];
898
898
 
@@ -999,7 +999,7 @@ module.exports = {
999
999
  },
1000
1000
 
1001
1001
  VariableDeclaration(node) {
1002
- if (node.declarations[node.declarations.length - 1].loc.start.line > node.declarations[0].loc.start.line) {
1002
+ if (node.declarations.at(-1).loc.start.line > node.declarations[0].loc.start.line) {
1003
1003
  checkIndentInVariableDeclarations(node);
1004
1004
  }
1005
1005
  },
@@ -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
  }