eslint 8.56.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 (121) hide show
  1. package/README.md +7 -2
  2. package/conf/ecma-version.js +16 -0
  3. package/conf/rule-type-list.json +3 -1
  4. package/lib/api.js +1 -1
  5. package/lib/cli-engine/cli-engine.js +14 -3
  6. package/lib/cli-engine/formatters/formatters-meta.json +1 -29
  7. package/lib/cli-engine/lint-result-cache.js +2 -2
  8. package/lib/cli.js +46 -25
  9. package/lib/config/default-config.js +3 -0
  10. package/lib/config/flat-config-array.js +0 -20
  11. package/lib/config/flat-config-helpers.js +41 -20
  12. package/lib/config/flat-config-schema.js +35 -25
  13. package/lib/config/rule-validator.js +27 -4
  14. package/lib/eslint/eslint-helpers.js +32 -12
  15. package/lib/eslint/eslint.js +856 -373
  16. package/lib/eslint/index.js +2 -2
  17. package/lib/eslint/legacy-eslint.js +722 -0
  18. package/lib/linter/apply-disable-directives.js +35 -7
  19. package/lib/linter/code-path-analysis/code-path.js +5 -19
  20. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  21. package/lib/linter/config-comment-parser.js +8 -11
  22. package/lib/linter/linter.js +196 -100
  23. package/lib/linter/report-translator.js +2 -2
  24. package/lib/linter/rules.js +6 -15
  25. package/lib/linter/source-code-fixer.js +1 -1
  26. package/lib/options.js +9 -1
  27. package/lib/rule-tester/rule-tester.js +234 -291
  28. package/lib/rules/array-bracket-newline.js +1 -1
  29. package/lib/rules/array-bracket-spacing.js +1 -1
  30. package/lib/rules/block-scoped-var.js +1 -1
  31. package/lib/rules/callback-return.js +2 -2
  32. package/lib/rules/comma-dangle.js +1 -1
  33. package/lib/rules/comma-style.js +2 -2
  34. package/lib/rules/complexity.js +1 -1
  35. package/lib/rules/constructor-super.js +1 -1
  36. package/lib/rules/default-case.js +1 -1
  37. package/lib/rules/eol-last.js +2 -2
  38. package/lib/rules/function-paren-newline.js +2 -2
  39. package/lib/rules/indent-legacy.js +5 -5
  40. package/lib/rules/indent.js +5 -5
  41. package/lib/rules/index.js +1 -2
  42. package/lib/rules/key-spacing.js +2 -2
  43. package/lib/rules/line-comment-position.js +1 -1
  44. package/lib/rules/lines-around-directive.js +2 -2
  45. package/lib/rules/max-depth.js +1 -1
  46. package/lib/rules/max-len.js +3 -3
  47. package/lib/rules/max-lines.js +3 -3
  48. package/lib/rules/max-nested-callbacks.js +1 -1
  49. package/lib/rules/max-params.js +1 -1
  50. package/lib/rules/max-statements.js +1 -1
  51. package/lib/rules/multiline-comment-style.js +7 -7
  52. package/lib/rules/new-cap.js +1 -1
  53. package/lib/rules/newline-after-var.js +1 -1
  54. package/lib/rules/newline-before-return.js +1 -1
  55. package/lib/rules/no-constant-binary-expression.js +6 -6
  56. package/lib/rules/no-constructor-return.js +2 -2
  57. package/lib/rules/no-dupe-class-members.js +2 -2
  58. package/lib/rules/no-else-return.js +1 -1
  59. package/lib/rules/no-empty-function.js +2 -2
  60. package/lib/rules/no-empty-static-block.js +1 -1
  61. package/lib/rules/no-extra-semi.js +1 -1
  62. package/lib/rules/no-fallthrough.js +1 -1
  63. package/lib/rules/no-implicit-coercion.js +17 -1
  64. package/lib/rules/no-inner-declarations.js +23 -2
  65. package/lib/rules/no-invalid-regexp.js +1 -1
  66. package/lib/rules/no-invalid-this.js +1 -1
  67. package/lib/rules/no-lone-blocks.js +2 -2
  68. package/lib/rules/no-loss-of-precision.js +1 -1
  69. package/lib/rules/no-misleading-character-class.js +174 -65
  70. package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
  71. package/lib/rules/no-multiple-empty-lines.js +1 -1
  72. package/lib/rules/no-new-native-nonconstructor.js +1 -1
  73. package/lib/rules/no-new-symbol.js +8 -1
  74. package/lib/rules/no-restricted-globals.js +1 -1
  75. package/lib/rules/no-restricted-imports.js +2 -2
  76. package/lib/rules/no-restricted-modules.js +2 -2
  77. package/lib/rules/no-return-await.js +1 -1
  78. package/lib/rules/no-sequences.js +1 -0
  79. package/lib/rules/no-trailing-spaces.js +2 -3
  80. package/lib/rules/no-unneeded-ternary.js +1 -1
  81. package/lib/rules/no-unsafe-optional-chaining.js +1 -1
  82. package/lib/rules/no-unused-private-class-members.js +1 -1
  83. package/lib/rules/no-unused-vars.js +6 -8
  84. package/lib/rules/no-useless-assignment.js +566 -0
  85. package/lib/rules/no-useless-backreference.js +1 -1
  86. package/lib/rules/object-curly-spacing.js +3 -3
  87. package/lib/rules/object-property-newline.js +1 -1
  88. package/lib/rules/one-var.js +5 -5
  89. package/lib/rules/padded-blocks.js +7 -7
  90. package/lib/rules/prefer-arrow-callback.js +3 -3
  91. package/lib/rules/prefer-reflect.js +1 -1
  92. package/lib/rules/prefer-regex-literals.js +1 -1
  93. package/lib/rules/prefer-template.js +1 -1
  94. package/lib/rules/radix.js +2 -2
  95. package/lib/rules/semi-style.js +1 -1
  96. package/lib/rules/sort-imports.js +1 -1
  97. package/lib/rules/sort-keys.js +1 -1
  98. package/lib/rules/sort-vars.js +1 -1
  99. package/lib/rules/space-unary-ops.js +1 -1
  100. package/lib/rules/strict.js +1 -1
  101. package/lib/rules/utils/ast-utils.js +7 -7
  102. package/lib/rules/yield-star-spacing.js +1 -1
  103. package/lib/shared/types.js +1 -1
  104. package/lib/source-code/source-code.js +5 -83
  105. package/lib/source-code/token-store/index.js +2 -2
  106. package/lib/unsupported-api.js +3 -5
  107. package/package.json +12 -14
  108. package/conf/config-schema.js +0 -93
  109. package/lib/cli-engine/formatters/checkstyle.js +0 -60
  110. package/lib/cli-engine/formatters/compact.js +0 -60
  111. package/lib/cli-engine/formatters/jslint-xml.js +0 -41
  112. package/lib/cli-engine/formatters/junit.js +0 -82
  113. package/lib/cli-engine/formatters/tap.js +0 -95
  114. package/lib/cli-engine/formatters/unix.js +0 -58
  115. package/lib/cli-engine/formatters/visualstudio.js +0 -63
  116. package/lib/eslint/flat-eslint.js +0 -1142
  117. package/lib/rule-tester/flat-rule-tester.js +0 -1122
  118. package/lib/rules/require-jsdoc.js +0 -122
  119. package/lib/rules/valid-jsdoc.js +0 -516
  120. package/lib/shared/config-validator.js +0 -347
  121. package/lib/shared/relative-module-resolver.js +0 -50
@@ -52,6 +52,7 @@ const DEFAULT_ECMA_VERSION = 5;
52
52
  const commentParser = new ConfigCommentParser();
53
53
  const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
54
54
  const parserSymbol = Symbol.for("eslint.RuleTester.parser");
55
+ const { LATEST_ECMA_VERSION } = require("../../conf/ecma-version");
55
56
 
56
57
  //------------------------------------------------------------------------------
57
58
  // Typedefs
@@ -105,6 +106,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
105
106
  * @property {string} [filename] the filename of the source code.
106
107
  * @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
107
108
  * unused `eslint-disable` directives.
109
+ * @property {Function} [ruleFilter] A predicate function that determines whether a given rule should run.
108
110
  */
109
111
 
110
112
  /**
@@ -230,7 +232,7 @@ function addDeclaredGlobals(globalScope, configGlobals, { exportedVariables, ena
230
232
  * @private
231
233
  */
232
234
  function createMissingRuleMessage(ruleId) {
233
- return Object.prototype.hasOwnProperty.call(ruleReplacements.rules, ruleId)
235
+ return Object.hasOwn(ruleReplacements.rules, ruleId)
234
236
  ? `Rule '${ruleId}' was removed and replaced by: ${ruleReplacements.rules[ruleId].join(", ")}`
235
237
  : `Definition for rule '${ruleId}' was not found.`;
236
238
  }
@@ -392,7 +394,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
392
394
  }
393
395
 
394
396
  case "exported":
395
- Object.assign(exportedVariables, commentParser.parseStringConfig(directiveValue, comment));
397
+ Object.assign(exportedVariables, commentParser.parseListConfig(directiveValue, comment));
396
398
  break;
397
399
 
398
400
  case "globals":
@@ -439,6 +441,15 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
439
441
  try {
440
442
  validator.validateRuleOptions(rule, name, ruleValue);
441
443
  } catch (err) {
444
+
445
+ /*
446
+ * If the rule has invalid `meta.schema`, throw the error because
447
+ * this is not an invalid inline configuration but an invalid rule.
448
+ */
449
+ if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
450
+ throw err;
451
+ }
452
+
442
453
  problems.push(createLintingProblem({
443
454
  ruleId: name,
444
455
  message: err.message,
@@ -584,7 +595,7 @@ function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
584
595
  * that is used for a number of processes inside of ESLint. It's normally
585
596
  * safe to assume people want the latest unless otherwise specified.
586
597
  */
587
- return espree.latestEcmaVersion + 2009;
598
+ return LATEST_ECMA_VERSION;
588
599
  }
589
600
 
590
601
  const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)(?:\*\/|$)/gsu;
@@ -661,6 +672,12 @@ function normalizeVerifyOptions(providedOptions, config) {
661
672
  }
662
673
  }
663
674
 
675
+ let ruleFilter = providedOptions.ruleFilter;
676
+
677
+ if (typeof ruleFilter !== "function") {
678
+ ruleFilter = () => true;
679
+ }
680
+
664
681
  return {
665
682
  filename: normalizeFilename(providedOptions.filename || "<input>"),
666
683
  allowInlineConfig: !ignoreInlineConfig,
@@ -668,7 +685,8 @@ function normalizeVerifyOptions(providedOptions, config) {
668
685
  ? `your config${configNameOfNoInlineConfig}`
669
686
  : null,
670
687
  reportUnusedDisableDirectives,
671
- disableFixes: Boolean(providedOptions.disableFixes)
688
+ disableFixes: Boolean(providedOptions.disableFixes),
689
+ ruleFilter
672
690
  };
673
691
  }
674
692
 
@@ -885,12 +903,18 @@ function parse(text, languageOptions, filePath) {
885
903
 
886
904
  /**
887
905
  * Runs a rule, and gets its listeners
888
- * @param {Rule} rule A normalized rule with a `create` method
906
+ * @param {Rule} rule A rule object
889
907
  * @param {Context} ruleContext The context that should be passed to the rule
908
+ * @throws {TypeError} If `rule` is not an object with a `create` method
890
909
  * @throws {any} Any error during the rule's `create`
891
910
  * @returns {Object} A map of selector listeners provided by the rule
892
911
  */
893
912
  function createRuleListeners(rule, ruleContext) {
913
+
914
+ if (!rule || typeof rule !== "object" || typeof rule.create !== "function") {
915
+ throw new TypeError(`Error while loading rule '${ruleContext.id}': Rule must be an object with a \`create\` method`);
916
+ }
917
+
894
918
  try {
895
919
  return rule.create(ruleContext);
896
920
  } catch (ex) {
@@ -899,43 +923,6 @@ function createRuleListeners(rule, ruleContext) {
899
923
  }
900
924
  }
901
925
 
902
- // methods that exist on SourceCode object
903
- const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
904
- getSource: "getText",
905
- getSourceLines: "getLines",
906
- getAllComments: "getAllComments",
907
- getNodeByRangeIndex: "getNodeByRangeIndex",
908
- getComments: "getComments",
909
- getCommentsBefore: "getCommentsBefore",
910
- getCommentsAfter: "getCommentsAfter",
911
- getCommentsInside: "getCommentsInside",
912
- getJSDocComment: "getJSDocComment",
913
- getFirstToken: "getFirstToken",
914
- getFirstTokens: "getFirstTokens",
915
- getLastToken: "getLastToken",
916
- getLastTokens: "getLastTokens",
917
- getTokenAfter: "getTokenAfter",
918
- getTokenBefore: "getTokenBefore",
919
- getTokenByRangeStart: "getTokenByRangeStart",
920
- getTokens: "getTokens",
921
- getTokensAfter: "getTokensAfter",
922
- getTokensBefore: "getTokensBefore",
923
- getTokensBetween: "getTokensBetween"
924
- };
925
-
926
-
927
- const BASE_TRAVERSAL_CONTEXT = Object.freeze(
928
- Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).reduce(
929
- (contextInfo, methodName) =>
930
- Object.assign(contextInfo, {
931
- [methodName](...args) {
932
- return this.sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
933
- }
934
- }),
935
- {}
936
- )
937
- );
938
-
939
926
  /**
940
927
  * Runs the given rules on the given SourceCode object
941
928
  * @param {SourceCode} sourceCode A SourceCode object for the given text
@@ -948,9 +935,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
948
935
  * @param {boolean} disableFixes If true, it doesn't make `fix` properties.
949
936
  * @param {string | undefined} cwd cwd of the cli
950
937
  * @param {string} physicalFilename The full path of the file on disk without any code block information
938
+ * @param {Function} ruleFilter A predicate function to filter which rules should be executed.
951
939
  * @returns {LintMessage[]} An array of reported problems
952
940
  */
953
- function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename) {
941
+ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename, ruleFilter) {
954
942
  const emitter = createEmitter();
955
943
  const nodeQueue = [];
956
944
  let currentNode = sourceCode.ast;
@@ -972,30 +960,22 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
972
960
  * properties once for each rule.
973
961
  */
974
962
  const sharedTraversalContext = Object.freeze(
975
- Object.assign(
976
- Object.create(BASE_TRAVERSAL_CONTEXT),
977
- {
978
- getAncestors: () => sourceCode.getAncestors(currentNode),
979
- getDeclaredVariables: node => sourceCode.getDeclaredVariables(node),
980
- getCwd: () => cwd,
981
- cwd,
982
- getFilename: () => filename,
983
- filename,
984
- getPhysicalFilename: () => physicalFilename || filename,
985
- physicalFilename: physicalFilename || filename,
986
- getScope: () => sourceCode.getScope(currentNode),
987
- getSourceCode: () => sourceCode,
988
- sourceCode,
989
- markVariableAsUsed: name => sourceCode.markVariableAsUsed(name, currentNode),
990
- parserOptions: {
991
- ...languageOptions.parserOptions
992
- },
993
- parserPath: parserName,
994
- languageOptions,
995
- parserServices: sourceCode.parserServices,
996
- settings
997
- }
998
- )
963
+ {
964
+ getCwd: () => cwd,
965
+ cwd,
966
+ getFilename: () => filename,
967
+ filename,
968
+ getPhysicalFilename: () => physicalFilename || filename,
969
+ physicalFilename: physicalFilename || filename,
970
+ getSourceCode: () => sourceCode,
971
+ sourceCode,
972
+ parserOptions: {
973
+ ...languageOptions.parserOptions
974
+ },
975
+ parserPath: parserName,
976
+ languageOptions,
977
+ settings
978
+ }
999
979
  );
1000
980
 
1001
981
  const lintingProblems = [];
@@ -1008,6 +988,10 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
1008
988
  return;
1009
989
  }
1010
990
 
991
+ if (ruleFilter && !ruleFilter({ ruleId, severity })) {
992
+ return;
993
+ }
994
+
1011
995
  const rule = ruleMapper(ruleId);
1012
996
 
1013
997
  if (!rule) {
@@ -1217,9 +1201,9 @@ class Linter {
1217
1201
  * Initialize the Linter.
1218
1202
  * @param {Object} [config] the config object
1219
1203
  * @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
1220
- * @param {"flat"|"eslintrc"} [config.configType="eslintrc"] the type of config used.
1204
+ * @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
1221
1205
  */
1222
- constructor({ cwd, configType } = {}) {
1206
+ constructor({ cwd, configType = "flat" } = {}) {
1223
1207
  internalSlotsMap.set(this, {
1224
1208
  cwd: normalizeCwd(cwd),
1225
1209
  lastConfigArray: null,
@@ -1348,7 +1332,56 @@ class Linter {
1348
1332
  { exportedVariables: commentDirectives.exportedVariables, enabledGlobals: commentDirectives.enabledGlobals }
1349
1333
  );
1350
1334
 
1335
+ /*
1336
+ * Now we determine the final configurations for rules.
1337
+ * First, let all inline rule configurations override those from the config.
1338
+ * Then, check for a special case: if a rule is configured in both places,
1339
+ * inline rule configuration that only has severity should retain options from
1340
+ * the config and just override the severity.
1341
+ *
1342
+ * Example:
1343
+ *
1344
+ * {
1345
+ * rules: {
1346
+ * curly: ["error", "multi"]
1347
+ * }
1348
+ * }
1349
+ *
1350
+ * /* eslint curly: ["warn"] * /
1351
+ *
1352
+ * Results in:
1353
+ *
1354
+ * curly: ["warn", "multi"]
1355
+ */
1351
1356
  const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
1357
+
1358
+ if (config.rules) {
1359
+ for (const [ruleId, ruleInlineConfig] of Object.entries(commentDirectives.configuredRules)) {
1360
+ if (
1361
+
1362
+ /*
1363
+ * If inline config for the rule has only severity
1364
+ */
1365
+ (!Array.isArray(ruleInlineConfig) || ruleInlineConfig.length === 1) &&
1366
+
1367
+ /*
1368
+ * And provided config for the rule has options
1369
+ */
1370
+ Object.hasOwn(config.rules, ruleId) &&
1371
+ (Array.isArray(config.rules[ruleId]) && config.rules[ruleId].length > 1)
1372
+ ) {
1373
+
1374
+ /*
1375
+ * Then use severity from the inline config and options from the provided config
1376
+ */
1377
+ configuredRules[ruleId] = [
1378
+ Array.isArray(ruleInlineConfig) ? ruleInlineConfig[0] : ruleInlineConfig, // severity from the inline config
1379
+ ...config.rules[ruleId].slice(1) // options from the provided config
1380
+ ];
1381
+ }
1382
+ }
1383
+ }
1384
+
1352
1385
  let lintingProblems;
1353
1386
 
1354
1387
  try {
@@ -1362,7 +1395,8 @@ class Linter {
1362
1395
  options.filename,
1363
1396
  options.disableFixes,
1364
1397
  slots.cwd,
1365
- providedOptions.physicalFilename
1398
+ providedOptions.physicalFilename,
1399
+ null
1366
1400
  );
1367
1401
  } catch (err) {
1368
1402
  err.message += `\nOccurred while linting ${options.filename}`;
@@ -1413,29 +1447,29 @@ class Linter {
1413
1447
  ? { filename: filenameOrOptions }
1414
1448
  : filenameOrOptions || {};
1415
1449
 
1416
- if (config) {
1417
- if (configType === "flat") {
1418
-
1419
- /*
1420
- * Because of how Webpack packages up the files, we can't
1421
- * compare directly to `FlatConfigArray` using `instanceof`
1422
- * because it's not the same `FlatConfigArray` as in the tests.
1423
- * So, we work around it by assuming an array is, in fact, a
1424
- * `FlatConfigArray` if it has a `getConfig()` method.
1425
- */
1426
- let configArray = config;
1427
-
1428
- if (!Array.isArray(config) || typeof config.getConfig !== "function") {
1429
- configArray = new FlatConfigArray(config, { basePath: cwd });
1430
- configArray.normalizeSync();
1431
- }
1450
+ const configToUse = config ?? {};
1432
1451
 
1433
- return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
1434
- }
1452
+ if (configType !== "eslintrc") {
1435
1453
 
1436
- if (typeof config.extractConfig === "function") {
1437
- return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, config, options));
1454
+ /*
1455
+ * Because of how Webpack packages up the files, we can't
1456
+ * compare directly to `FlatConfigArray` using `instanceof`
1457
+ * because it's not the same `FlatConfigArray` as in the tests.
1458
+ * So, we work around it by assuming an array is, in fact, a
1459
+ * `FlatConfigArray` if it has a `getConfig()` method.
1460
+ */
1461
+ let configArray = configToUse;
1462
+
1463
+ if (!Array.isArray(configToUse) || typeof configToUse.getConfig !== "function") {
1464
+ configArray = new FlatConfigArray(configToUse, { basePath: cwd });
1465
+ configArray.normalizeSync();
1438
1466
  }
1467
+
1468
+ return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
1469
+ }
1470
+
1471
+ if (typeof configToUse.extractConfig === "function") {
1472
+ return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, configToUse, options));
1439
1473
  }
1440
1474
 
1441
1475
  /*
@@ -1448,9 +1482,9 @@ class Linter {
1448
1482
  * So we cannot apply multiple processors.
1449
1483
  */
1450
1484
  if (options.preprocess || options.postprocess) {
1451
- return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, config, options));
1485
+ return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, configToUse, options));
1452
1486
  }
1453
- return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, config, options));
1487
+ return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, configToUse, options));
1454
1488
  }
1455
1489
 
1456
1490
  /**
@@ -1690,9 +1724,17 @@ class Linter {
1690
1724
  [ruleId]: ruleOptions
1691
1725
  }
1692
1726
  });
1693
- mergedInlineConfig.rules[ruleId] = ruleValue;
1727
+ mergedInlineConfig.rules[ruleId] = ruleOptions;
1694
1728
  } catch (err) {
1695
1729
 
1730
+ /*
1731
+ * If the rule has invalid `meta.schema`, throw the error because
1732
+ * this is not an invalid inline configuration but an invalid rule.
1733
+ */
1734
+ if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
1735
+ throw err;
1736
+ }
1737
+
1696
1738
  let baseMessage = err.message.slice(
1697
1739
  err.message.startsWith("Key \"rules\":")
1698
1740
  ? err.message.indexOf(":", 12) + 1
@@ -1721,7 +1763,58 @@ class Linter {
1721
1763
  )
1722
1764
  : { problems: [], disableDirectives: [] };
1723
1765
 
1766
+ /*
1767
+ * Now we determine the final configurations for rules.
1768
+ * First, let all inline rule configurations override those from the config.
1769
+ * Then, check for a special case: if a rule is configured in both places,
1770
+ * inline rule configuration that only has severity should retain options from
1771
+ * the config and just override the severity.
1772
+ *
1773
+ * Example:
1774
+ *
1775
+ * {
1776
+ * rules: {
1777
+ * curly: ["error", "multi"]
1778
+ * }
1779
+ * }
1780
+ *
1781
+ * /* eslint curly: ["warn"] * /
1782
+ *
1783
+ * Results in:
1784
+ *
1785
+ * curly: ["warn", "multi"]
1786
+ *
1787
+ * At this point, all rule configurations are normalized to arrays.
1788
+ */
1724
1789
  const configuredRules = Object.assign({}, config.rules, mergedInlineConfig.rules);
1790
+
1791
+ if (config.rules) {
1792
+ for (const [ruleId, ruleInlineConfig] of Object.entries(mergedInlineConfig.rules)) {
1793
+ if (
1794
+
1795
+ /*
1796
+ * If inline config for the rule has only severity
1797
+ */
1798
+ ruleInlineConfig.length === 1 &&
1799
+
1800
+ /*
1801
+ * And provided config for the rule has options
1802
+ */
1803
+ Object.hasOwn(config.rules, ruleId) &&
1804
+ config.rules[ruleId].length > 1
1805
+ ) {
1806
+
1807
+ /*
1808
+ * Then use severity from the inline config and options from the provided config
1809
+ */
1810
+ configuredRules[ruleId] = [
1811
+ ruleInlineConfig[0], // severity from the inline config
1812
+ ...config.rules[ruleId].slice(1) // options from the provided config
1813
+ ];
1814
+ }
1815
+ }
1816
+ }
1817
+
1725
1818
  let lintingProblems;
1726
1819
 
1727
1820
  sourceCode.finalize();
@@ -1737,7 +1830,8 @@ class Linter {
1737
1830
  options.filename,
1738
1831
  options.disableFixes,
1739
1832
  slots.cwd,
1740
- providedOptions.physicalFilename
1833
+ providedOptions.physicalFilename,
1834
+ options.ruleFilter
1741
1835
  );
1742
1836
  } catch (err) {
1743
1837
  err.message += `\nOccurred while linting ${options.filename}`;
@@ -1768,7 +1862,9 @@ class Linter {
1768
1862
  .concat(commentDirectives.problems)
1769
1863
  .concat(inlineConfigProblems)
1770
1864
  .sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
1771
- reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
1865
+ reportUnusedDisableDirectives: options.reportUnusedDisableDirectives,
1866
+ ruleFilter: options.ruleFilter,
1867
+ configuredRules
1772
1868
  });
1773
1869
  }
1774
1870
 
@@ -1986,17 +2082,17 @@ class Linter {
1986
2082
  /**
1987
2083
  * Defines a new linting rule.
1988
2084
  * @param {string} ruleId A unique rule identifier
1989
- * @param {Function | Rule} ruleModule Function from context to object mapping AST node types to event handlers
2085
+ * @param {Rule} rule A rule object
1990
2086
  * @returns {void}
1991
2087
  */
1992
- defineRule(ruleId, ruleModule) {
2088
+ defineRule(ruleId, rule) {
1993
2089
  assertEslintrcConfig(this);
1994
- internalSlotsMap.get(this).ruleMap.define(ruleId, ruleModule);
2090
+ internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
1995
2091
  }
1996
2092
 
1997
2093
  /**
1998
2094
  * Defines many new linting rules.
1999
- * @param {Record<string, Function | Rule>} rulesToDefine map from unique rule identifier to rule
2095
+ * @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
2000
2096
  * @returns {void}
2001
2097
  */
2002
2098
  defineRules(rulesToDefine) {
@@ -2044,7 +2140,7 @@ class Linter {
2044
2140
  * SourceCodeFixer.
2045
2141
  */
2046
2142
  verifyAndFix(text, config, options) {
2047
- let messages = [],
2143
+ let messages,
2048
2144
  fixedResult,
2049
2145
  fixed = false,
2050
2146
  passNumber = 0,
@@ -160,7 +160,7 @@ function mergeFixes(fixes, sourceCode) {
160
160
 
161
161
  const originalText = sourceCode.text;
162
162
  const start = fixes[0].range[0];
163
- const end = fixes[fixes.length - 1].range[1];
163
+ const end = fixes.at(-1).range[1];
164
164
  let text = "";
165
165
  let lastPos = Number.MIN_SAFE_INTEGER;
166
166
 
@@ -343,7 +343,7 @@ module.exports = function createReportTranslator(metadata) {
343
343
  if (descriptor.message) {
344
344
  throw new TypeError("context.report() called with a message and a messageId. Please only pass one.");
345
345
  }
346
- if (!messages || !Object.prototype.hasOwnProperty.call(messages, id)) {
346
+ if (!messages || !Object.hasOwn(messages, id)) {
347
347
  throw new TypeError(`context.report() called with a messageId of '${id}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`);
348
348
  }
349
349
  computedMessage = messages[id];
@@ -13,18 +13,10 @@
13
13
  const builtInRules = require("../rules");
14
14
 
15
15
  //------------------------------------------------------------------------------
16
- // Helpers
16
+ // Typedefs
17
17
  //------------------------------------------------------------------------------
18
18
 
19
- /**
20
- * Normalizes a rule module to the new-style API
21
- * @param {(Function|{create: Function})} rule A rule object, which can either be a function
22
- * ("old-style") or an object with a `create` method ("new-style")
23
- * @returns {{create: Function}} A new-style rule.
24
- */
25
- function normalizeRule(rule) {
26
- return typeof rule === "function" ? Object.assign({ create: rule }, rule) : rule;
27
- }
19
+ /** @typedef {import("../shared/types").Rule} Rule */
28
20
 
29
21
  //------------------------------------------------------------------------------
30
22
  // Public Interface
@@ -41,18 +33,17 @@ class Rules {
41
33
  /**
42
34
  * Registers a rule module for rule id in storage.
43
35
  * @param {string} ruleId Rule id (file name).
44
- * @param {Function} ruleModule Rule handler.
36
+ * @param {Rule} rule Rule object.
45
37
  * @returns {void}
46
38
  */
47
- define(ruleId, ruleModule) {
48
- this._rules[ruleId] = normalizeRule(ruleModule);
39
+ define(ruleId, rule) {
40
+ this._rules[ruleId] = rule;
49
41
  }
50
42
 
51
43
  /**
52
44
  * Access rule handler by id (file name).
53
45
  * @param {string} ruleId Rule id (file name).
54
- * @returns {{create: Function, schema: JsonSchema[]}}
55
- * A rule. This is normalized to always have the new-style shape with a `create` method.
46
+ * @returns {Rule} Rule object.
56
47
  */
57
48
  get(ruleId) {
58
49
  if (typeof this._rules[ruleId] === "string") {
@@ -107,7 +107,7 @@ SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {
107
107
  }
108
108
 
109
109
  messages.forEach(problem => {
110
- if (Object.prototype.hasOwnProperty.call(problem, "fix")) {
110
+ if (Object.hasOwn(problem, "fix")) {
111
111
  fixes.push(problem);
112
112
  } else {
113
113
  remainingMessages.push(problem);
package/lib/options.js CHANGED
@@ -57,6 +57,8 @@ const optionator = require("optionator");
57
57
  * @property {boolean} quiet Report errors only
58
58
  * @property {boolean} [version] Output the version number
59
59
  * @property {boolean} warnIgnored Show warnings when the file list includes ignored files
60
+ * @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
61
+ * the linting operation to short circuit and not report any failures.
60
62
  * @property {string[]} _ Positional filenames or patterns
61
63
  */
62
64
 
@@ -168,7 +170,7 @@ module.exports = function(usingFlatConfig) {
168
170
  alias: "c",
169
171
  type: "path::String",
170
172
  description: usingFlatConfig
171
- ? "Use this configuration instead of eslint.config.js"
173
+ ? "Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs"
172
174
  : "Use this configuration, overriding .eslintrc.* config options if present"
173
175
  },
174
176
  envFlag,
@@ -370,6 +372,12 @@ module.exports = function(usingFlatConfig) {
370
372
  description: "Exit with exit code 2 in case of fatal error"
371
373
  },
372
374
  warnIgnoredFlag,
375
+ {
376
+ option: "pass-on-no-patterns",
377
+ type: "Boolean",
378
+ default: false,
379
+ description: "Exit with exit code 0 in case no file patterns are passed"
380
+ },
373
381
  {
374
382
  option: "debug",
375
383
  type: "Boolean",