eslint-plugin-react-hooks 6.1.0 → 6.1.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.
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # `eslint-plugin-react-hooks`
2
2
 
3
- This ESLint plugin enforces the [Rules of Hooks](https://react.dev/reference/rules/rules-of-hooks).
4
-
5
- It is a part of the [Hooks API](https://react.dev/reference/react/hooks) for React.
3
+ The official ESLint plugin for [React](https://react.dev) which enforces the [Rules of React](https://react.dev/reference/eslint-plugin-react-hooks) and other best practices.
6
4
 
7
5
  ## Installation
8
6
 
@@ -89,7 +87,7 @@ If you're using a version earlier than 5.2.0, the legacy config was simply `reco
89
87
 
90
88
  ### Custom Configuration
91
89
 
92
- If you want more fine-grained configuration, you can instead add a snippet like this to your ESLint configuration file:
90
+ If you want more fine-grained configuration, you can instead choose to enable specific rules. However, we strongly encourage using the recommended presets — see above — so that you will automatically receive new recommended rules as we add them in future versions of the plugin.
93
91
 
94
92
  #### Flat Config (eslint.config.js|ts)
95
93
 
@@ -1,11 +1,10 @@
1
1
  import * as estree from 'estree';
2
- import { Rule } from 'eslint';
2
+ import { Rule, Linter } from 'eslint';
3
3
 
4
4
  declare const plugin: {
5
5
  meta: {
6
6
  name: string;
7
7
  };
8
- configs: {};
9
8
  rules: {
10
9
  'exhaustive-deps': {
11
10
  meta: {
@@ -73,6 +72,19 @@ declare const plugin: {
73
72
  };
74
73
  };
75
74
  };
75
+ configs: {
76
+ "recommended-legacy": {
77
+ plugins: Array<string>;
78
+ rules: Linter.RulesRecord;
79
+ };
80
+ "recommended-latest-legacy": {
81
+ plugins: Array<string>;
82
+ rules: Linter.RulesRecord;
83
+ };
84
+ "flat/recommended": Array<Linter.Config>;
85
+ "recommended-latest": Array<Linter.Config>;
86
+ recommended: Array<Linter.Config>;
87
+ };
76
88
  };
77
89
 
78
90
  export { plugin as default };
@@ -19,8 +19,6 @@ var BabelParser = require('@babel/parser');
19
19
  var zod = require('zod');
20
20
  var zodValidationError = require('zod-validation-error');
21
21
  var crypto = require('crypto');
22
- var PluginProposalPrivateMethods = require('@babel/plugin-proposal-private-methods');
23
- var HermesParser = require('hermes-parser');
24
22
  var util = require('util');
25
23
 
26
24
  const SETTINGS_KEY = 'react-hooks';
@@ -32072,15 +32070,15 @@ const HookSchema = zod.z.object({
32072
32070
  });
32073
32071
  const EnvironmentConfigSchema = zod.z.object({
32074
32072
  customHooks: zod.z.map(zod.z.string(), HookSchema).default(new Map()),
32075
- moduleTypeProvider: zod.z.nullable(zod.z.function().args(zod.z.string())).default(null),
32073
+ moduleTypeProvider: zod.z.nullable(zod.z.any()).default(null),
32076
32074
  customMacros: zod.z.nullable(zod.z.array(MacroSchema)).default(null),
32077
32075
  enableResetCacheOnSourceFileChanges: zod.z.nullable(zod.z.boolean()).default(null),
32078
- enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(false),
32076
+ enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
32079
32077
  validatePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
32080
32078
  enablePreserveExistingManualUseMemo: zod.z.boolean().default(false),
32081
32079
  enableForest: zod.z.boolean().default(false),
32082
32080
  enableUseTypeAnnotations: zod.z.boolean().default(false),
32083
- flowTypeProvider: zod.z.nullable(zod.z.function().args(zod.z.string())).default(null),
32081
+ flowTypeProvider: zod.z.nullable(zod.z.any()).default(null),
32084
32082
  enableOptionalDependencies: zod.z.boolean().default(true),
32085
32083
  enableFire: zod.z.boolean().default(false),
32086
32084
  enableNameAnonymousFunctions: zod.z.boolean().default(false),
@@ -32445,6 +32443,12 @@ _Environment_globals = new WeakMap(), _Environment_shapes = new WeakMap(), _Envi
32445
32443
  if (moduleTypeProvider == null) {
32446
32444
  return null;
32447
32445
  }
32446
+ if (typeof moduleTypeProvider !== 'function') {
32447
+ CompilerError.throwInvalidConfig({
32448
+ reason: `Expected a function for \`moduleTypeProvider\``,
32449
+ loc,
32450
+ });
32451
+ }
32448
32452
  const unparsedModuleConfig = moduleTypeProvider(moduleName);
32449
32453
  if (unparsedModuleConfig != null) {
32450
32454
  const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig);
@@ -45315,6 +45319,29 @@ function collectNonNullsInBlocks(fn, context) {
45315
45319
  }
45316
45320
  }
45317
45321
  }
45322
+ else if (fn.env.config.enablePreserveExistingMemoizationGuarantees &&
45323
+ instr.value.kind === 'StartMemoize' &&
45324
+ instr.value.deps != null) {
45325
+ for (const dep of instr.value.deps) {
45326
+ if (dep.root.kind === 'NamedLocal') {
45327
+ if (!isImmutableAtInstr(dep.root.value.identifier, instr.id, context)) {
45328
+ continue;
45329
+ }
45330
+ for (let i = 0; i < dep.path.length; i++) {
45331
+ const pathEntry = dep.path[i];
45332
+ if (pathEntry.optional) {
45333
+ break;
45334
+ }
45335
+ const depNode = context.registry.getOrCreateProperty({
45336
+ identifier: dep.root.value.identifier,
45337
+ path: dep.path.slice(0, i),
45338
+ reactive: dep.root.value.reactive,
45339
+ });
45340
+ assumedNonNullObjects.add(depNode);
45341
+ }
45342
+ }
45343
+ }
45344
+ }
45318
45345
  }
45319
45346
  nodes.set(block.id, {
45320
45347
  block,
@@ -54127,20 +54154,6 @@ function getFlowSuppressions(sourceCode) {
54127
54154
  }
54128
54155
  return results;
54129
54156
  }
54130
- function filterUnusedOptOutDirectives(directives) {
54131
- const results = [];
54132
- for (const directive of directives) {
54133
- if (OPT_OUT_DIRECTIVES.has(directive.value.value) &&
54134
- directive.loc != null) {
54135
- results.push({
54136
- loc: directive.loc,
54137
- directive: directive.value.value,
54138
- range: [directive.start, directive.end],
54139
- });
54140
- }
54141
- }
54142
- return results;
54143
- }
54144
54157
  function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
54145
54158
  var _a, _b;
54146
54159
  const options = parsePluginOptions(Object.assign(Object.assign(Object.assign({}, COMPILER_OPTIONS), userOpts), { environment: Object.assign(Object.assign({}, COMPILER_OPTIONS.environment), userOpts.environment) }));
@@ -54149,7 +54162,6 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
54149
54162
  filename,
54150
54163
  userOpts,
54151
54164
  flowSuppressions: [],
54152
- unusedOptOutDirectives: [],
54153
54165
  events: [],
54154
54166
  };
54155
54167
  const userLogger = options.logger;
@@ -54166,28 +54178,14 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
54166
54178
  (_b = options.logger) === null || _b === void 0 ? void 0 : _b.logEvent(filename, err);
54167
54179
  }
54168
54180
  let babelAST = null;
54169
- if (filename.endsWith('.tsx') || filename.endsWith('.ts')) {
54170
- try {
54171
- babelAST = BabelParser.parse(sourceCode.text, {
54172
- sourceFilename: filename,
54173
- sourceType: 'unambiguous',
54174
- plugins: ['typescript', 'jsx'],
54175
- });
54176
- }
54177
- catch (_c) {
54178
- }
54181
+ try {
54182
+ babelAST = BabelParser.parse(sourceCode.text, {
54183
+ sourceFilename: filename,
54184
+ sourceType: 'unambiguous',
54185
+ plugins: ['typescript', 'jsx'],
54186
+ });
54179
54187
  }
54180
- else {
54181
- try {
54182
- babelAST = HermesParser.parse(sourceCode.text, {
54183
- babel: true,
54184
- enableExperimentalComponentSyntax: true,
54185
- sourceFilename: filename,
54186
- sourceType: 'module',
54187
- });
54188
- }
54189
- catch (_d) {
54190
- }
54188
+ catch (err) {
54191
54189
  }
54192
54190
  if (babelAST != null) {
54193
54191
  results.flowSuppressions = getFlowSuppressions(sourceCode);
@@ -54196,29 +54194,11 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
54196
54194
  filename,
54197
54195
  highlightCode: false,
54198
54196
  retainLines: true,
54199
- plugins: [
54200
- [PluginProposalPrivateMethods.default, { loose: true }],
54201
- [BabelPluginReactCompiler, options],
54202
- ],
54197
+ plugins: [[BabelPluginReactCompiler, options]],
54203
54198
  sourceType: 'module',
54204
54199
  configFile: false,
54205
54200
  babelrc: false,
54206
54201
  });
54207
- if (results.events.filter(e => e.kind === 'CompileError').length === 0) {
54208
- core$1.traverse(babelAST, {
54209
- FunctionDeclaration(path) {
54210
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54211
- },
54212
- ArrowFunctionExpression(path) {
54213
- if (path.node.body.type === 'BlockStatement') {
54214
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54215
- }
54216
- },
54217
- FunctionExpression(path) {
54218
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54219
- },
54220
- });
54221
- }
54222
54202
  }
54223
54203
  catch (err) {
54224
54204
  }
@@ -54388,53 +54368,31 @@ function makeRule(rule) {
54388
54368
  create,
54389
54369
  };
54390
54370
  }
54391
- const NoUnusedDirectivesRule = {
54392
- meta: {
54393
- type: 'suggestion',
54394
- docs: {
54395
- recommended: true,
54396
- },
54397
- fixable: 'code',
54398
- hasSuggestions: true,
54399
- schema: [{ type: 'object', additionalProperties: true }],
54400
- },
54401
- create(context) {
54402
- const results = getReactCompilerResult(context);
54403
- for (const directive of results.unusedOptOutDirectives) {
54404
- context.report({
54405
- message: `Unused '${directive.directive}' directive`,
54406
- loc: directive.loc,
54407
- suggest: [
54408
- {
54409
- desc: 'Remove the directive',
54410
- fix(fixer) {
54411
- return fixer.removeRange(directive.range);
54412
- },
54413
- },
54414
- ],
54415
- });
54416
- }
54417
- return {};
54418
- },
54419
- };
54420
54371
  const allRules = LintRules.reduce((acc, rule) => {
54421
54372
  acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
54422
54373
  return acc;
54423
- }, {
54424
- 'no-unused-directives': {
54425
- rule: NoUnusedDirectivesRule,
54426
- severity: ErrorSeverity.Error,
54427
- },
54428
- });
54429
- LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
54374
+ }, {});
54375
+ const recommendedRules = LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
54430
54376
  acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
54431
54377
  return acc;
54432
- }, {
54433
- 'no-unused-directives': {
54434
- rule: NoUnusedDirectivesRule,
54435
- severity: ErrorSeverity.Error,
54436
- },
54437
- });
54378
+ }, {});
54379
+ function mapErrorSeverityToESlint(severity) {
54380
+ switch (severity) {
54381
+ case ErrorSeverity.Error: {
54382
+ return 'error';
54383
+ }
54384
+ case ErrorSeverity.Warning: {
54385
+ return 'warn';
54386
+ }
54387
+ case ErrorSeverity.Hint:
54388
+ case ErrorSeverity.Off: {
54389
+ return 'off';
54390
+ }
54391
+ default: {
54392
+ assertExhaustive(severity, `Unhandled severity: ${severity}`);
54393
+ }
54394
+ }
54395
+ }
54438
54396
 
54439
54397
  var assert_1;
54440
54398
  var hasRequiredAssert;
@@ -57722,28 +57680,39 @@ function last(array) {
57722
57680
  }
57723
57681
 
57724
57682
  const rules = Object.assign({ 'exhaustive-deps': rule$1, 'rules-of-hooks': rule }, Object.fromEntries(Object.entries(allRules).map(([name, config]) => [name, config.rule])));
57725
- const ruleConfigs = {
57683
+ const basicRuleConfigs = {
57726
57684
  'react-hooks/rules-of-hooks': 'error',
57727
57685
  'react-hooks/exhaustive-deps': 'warn',
57728
57686
  };
57687
+ const compilerRuleConfigs = Object.fromEntries(Object.entries(recommendedRules).map(([name, ruleConfig]) => {
57688
+ return [
57689
+ `react-hooks/${name}`,
57690
+ mapErrorSeverityToESlint(ruleConfig.severity),
57691
+ ];
57692
+ }));
57693
+ const allRuleConfigs = Object.assign(Object.assign({}, basicRuleConfigs), compilerRuleConfigs);
57729
57694
  const plugin = {
57730
57695
  meta: {
57731
57696
  name: 'eslint-plugin-react-hooks',
57732
57697
  },
57733
- configs: {},
57734
57698
  rules,
57699
+ configs: {},
57735
57700
  };
57736
57701
  Object.assign(plugin.configs, {
57737
57702
  'recommended-legacy': {
57738
57703
  plugins: ['react-hooks'],
57739
- rules: ruleConfigs,
57704
+ rules: basicRuleConfigs,
57705
+ },
57706
+ 'recommended-latest-legacy': {
57707
+ plugins: ['react-hooks'],
57708
+ rules: allRuleConfigs,
57740
57709
  },
57741
57710
  'flat/recommended': [
57742
57711
  {
57743
57712
  plugins: {
57744
57713
  'react-hooks': plugin,
57745
57714
  },
57746
- rules: ruleConfigs,
57715
+ rules: basicRuleConfigs,
57747
57716
  },
57748
57717
  ],
57749
57718
  'recommended-latest': [
@@ -57751,13 +57720,17 @@ Object.assign(plugin.configs, {
57751
57720
  plugins: {
57752
57721
  'react-hooks': plugin,
57753
57722
  },
57754
- rules: ruleConfigs,
57723
+ rules: allRuleConfigs,
57724
+ },
57725
+ ],
57726
+ recommended: [
57727
+ {
57728
+ plugins: {
57729
+ 'react-hooks': plugin,
57730
+ },
57731
+ rules: basicRuleConfigs,
57755
57732
  },
57756
57733
  ],
57757
- recommended: {
57758
- plugins: ['react-hooks'],
57759
- rules: ruleConfigs,
57760
- },
57761
57734
  });
57762
57735
 
57763
57736
  module.exports = plugin;
@@ -15,8 +15,6 @@ var BabelParser = require('@babel/parser');
15
15
  var zod = require('zod');
16
16
  var zodValidationError = require('zod-validation-error');
17
17
  var crypto = require('crypto');
18
- var PluginProposalPrivateMethods = require('@babel/plugin-proposal-private-methods');
19
- var HermesParser = require('hermes-parser');
20
18
  var util = require('util');
21
19
 
22
20
  const SETTINGS_KEY = 'react-hooks';
@@ -31899,15 +31897,15 @@ const HookSchema = zod.z.object({
31899
31897
  });
31900
31898
  const EnvironmentConfigSchema = zod.z.object({
31901
31899
  customHooks: zod.z.map(zod.z.string(), HookSchema).default(new Map()),
31902
- moduleTypeProvider: zod.z.nullable(zod.z.function().args(zod.z.string())).default(null),
31900
+ moduleTypeProvider: zod.z.nullable(zod.z.any()).default(null),
31903
31901
  customMacros: zod.z.nullable(zod.z.array(MacroSchema)).default(null),
31904
31902
  enableResetCacheOnSourceFileChanges: zod.z.nullable(zod.z.boolean()).default(null),
31905
- enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(false),
31903
+ enablePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
31906
31904
  validatePreserveExistingMemoizationGuarantees: zod.z.boolean().default(true),
31907
31905
  enablePreserveExistingManualUseMemo: zod.z.boolean().default(false),
31908
31906
  enableForest: zod.z.boolean().default(false),
31909
31907
  enableUseTypeAnnotations: zod.z.boolean().default(false),
31910
- flowTypeProvider: zod.z.nullable(zod.z.function().args(zod.z.string())).default(null),
31908
+ flowTypeProvider: zod.z.nullable(zod.z.any()).default(null),
31911
31909
  enableOptionalDependencies: zod.z.boolean().default(true),
31912
31910
  enableFire: zod.z.boolean().default(false),
31913
31911
  enableNameAnonymousFunctions: zod.z.boolean().default(false),
@@ -32272,6 +32270,12 @@ _Environment_globals = new WeakMap(), _Environment_shapes = new WeakMap(), _Envi
32272
32270
  if (moduleTypeProvider == null) {
32273
32271
  return null;
32274
32272
  }
32273
+ if (typeof moduleTypeProvider !== 'function') {
32274
+ CompilerError.throwInvalidConfig({
32275
+ reason: `Expected a function for \`moduleTypeProvider\``,
32276
+ loc,
32277
+ });
32278
+ }
32275
32279
  const unparsedModuleConfig = moduleTypeProvider(moduleName);
32276
32280
  if (unparsedModuleConfig != null) {
32277
32281
  const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig);
@@ -45142,6 +45146,29 @@ function collectNonNullsInBlocks(fn, context) {
45142
45146
  }
45143
45147
  }
45144
45148
  }
45149
+ else if (fn.env.config.enablePreserveExistingMemoizationGuarantees &&
45150
+ instr.value.kind === 'StartMemoize' &&
45151
+ instr.value.deps != null) {
45152
+ for (const dep of instr.value.deps) {
45153
+ if (dep.root.kind === 'NamedLocal') {
45154
+ if (!isImmutableAtInstr(dep.root.value.identifier, instr.id, context)) {
45155
+ continue;
45156
+ }
45157
+ for (let i = 0; i < dep.path.length; i++) {
45158
+ const pathEntry = dep.path[i];
45159
+ if (pathEntry.optional) {
45160
+ break;
45161
+ }
45162
+ const depNode = context.registry.getOrCreateProperty({
45163
+ identifier: dep.root.value.identifier,
45164
+ path: dep.path.slice(0, i),
45165
+ reactive: dep.root.value.reactive,
45166
+ });
45167
+ assumedNonNullObjects.add(depNode);
45168
+ }
45169
+ }
45170
+ }
45171
+ }
45145
45172
  }
45146
45173
  nodes.set(block.id, {
45147
45174
  block,
@@ -53954,20 +53981,6 @@ function getFlowSuppressions(sourceCode) {
53954
53981
  }
53955
53982
  return results;
53956
53983
  }
53957
- function filterUnusedOptOutDirectives(directives) {
53958
- const results = [];
53959
- for (const directive of directives) {
53960
- if (OPT_OUT_DIRECTIVES.has(directive.value.value) &&
53961
- directive.loc != null) {
53962
- results.push({
53963
- loc: directive.loc,
53964
- directive: directive.value.value,
53965
- range: [directive.start, directive.end],
53966
- });
53967
- }
53968
- }
53969
- return results;
53970
- }
53971
53984
  function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
53972
53985
  var _a, _b;
53973
53986
  const options = parsePluginOptions(Object.assign(Object.assign(Object.assign({}, COMPILER_OPTIONS), userOpts), { environment: Object.assign(Object.assign({}, COMPILER_OPTIONS.environment), userOpts.environment) }));
@@ -53976,7 +53989,6 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
53976
53989
  filename,
53977
53990
  userOpts,
53978
53991
  flowSuppressions: [],
53979
- unusedOptOutDirectives: [],
53980
53992
  events: [],
53981
53993
  };
53982
53994
  const userLogger = options.logger;
@@ -53993,28 +54005,14 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
53993
54005
  (_b = options.logger) === null || _b === void 0 ? void 0 : _b.logEvent(filename, err);
53994
54006
  }
53995
54007
  let babelAST = null;
53996
- if (filename.endsWith('.tsx') || filename.endsWith('.ts')) {
53997
- try {
53998
- babelAST = BabelParser.parse(sourceCode.text, {
53999
- sourceFilename: filename,
54000
- sourceType: 'unambiguous',
54001
- plugins: ['typescript', 'jsx'],
54002
- });
54003
- }
54004
- catch (_c) {
54005
- }
54008
+ try {
54009
+ babelAST = BabelParser.parse(sourceCode.text, {
54010
+ sourceFilename: filename,
54011
+ sourceType: 'unambiguous',
54012
+ plugins: ['typescript', 'jsx'],
54013
+ });
54006
54014
  }
54007
- else {
54008
- try {
54009
- babelAST = HermesParser.parse(sourceCode.text, {
54010
- babel: true,
54011
- enableExperimentalComponentSyntax: true,
54012
- sourceFilename: filename,
54013
- sourceType: 'module',
54014
- });
54015
- }
54016
- catch (_d) {
54017
- }
54015
+ catch (err) {
54018
54016
  }
54019
54017
  if (babelAST != null) {
54020
54018
  results.flowSuppressions = getFlowSuppressions(sourceCode);
@@ -54023,29 +54021,11 @@ function runReactCompilerImpl({ sourceCode, filename, userOpts, }) {
54023
54021
  filename,
54024
54022
  highlightCode: false,
54025
54023
  retainLines: true,
54026
- plugins: [
54027
- [PluginProposalPrivateMethods.default, { loose: true }],
54028
- [BabelPluginReactCompiler, options],
54029
- ],
54024
+ plugins: [[BabelPluginReactCompiler, options]],
54030
54025
  sourceType: 'module',
54031
54026
  configFile: false,
54032
54027
  babelrc: false,
54033
54028
  });
54034
- if (results.events.filter(e => e.kind === 'CompileError').length === 0) {
54035
- core$1.traverse(babelAST, {
54036
- FunctionDeclaration(path) {
54037
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54038
- },
54039
- ArrowFunctionExpression(path) {
54040
- if (path.node.body.type === 'BlockStatement') {
54041
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54042
- }
54043
- },
54044
- FunctionExpression(path) {
54045
- results.unusedOptOutDirectives.push(...filterUnusedOptOutDirectives(path.node.body.directives));
54046
- },
54047
- });
54048
- }
54049
54029
  }
54050
54030
  catch (err) {
54051
54031
  }
@@ -54215,53 +54195,31 @@ function makeRule(rule) {
54215
54195
  create,
54216
54196
  };
54217
54197
  }
54218
- const NoUnusedDirectivesRule = {
54219
- meta: {
54220
- type: 'suggestion',
54221
- docs: {
54222
- recommended: true,
54223
- },
54224
- fixable: 'code',
54225
- hasSuggestions: true,
54226
- schema: [{ type: 'object', additionalProperties: true }],
54227
- },
54228
- create(context) {
54229
- const results = getReactCompilerResult(context);
54230
- for (const directive of results.unusedOptOutDirectives) {
54231
- context.report({
54232
- message: `Unused '${directive.directive}' directive`,
54233
- loc: directive.loc,
54234
- suggest: [
54235
- {
54236
- desc: 'Remove the directive',
54237
- fix(fixer) {
54238
- return fixer.removeRange(directive.range);
54239
- },
54240
- },
54241
- ],
54242
- });
54243
- }
54244
- return {};
54245
- },
54246
- };
54247
54198
  const allRules = LintRules.reduce((acc, rule) => {
54248
54199
  acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
54249
54200
  return acc;
54250
- }, {
54251
- 'no-unused-directives': {
54252
- rule: NoUnusedDirectivesRule,
54253
- severity: ErrorSeverity.Error,
54254
- },
54255
- });
54256
- LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
54201
+ }, {});
54202
+ const recommendedRules = LintRules.filter(rule => rule.recommended).reduce((acc, rule) => {
54257
54203
  acc[rule.name] = { rule: makeRule(rule), severity: rule.severity };
54258
54204
  return acc;
54259
- }, {
54260
- 'no-unused-directives': {
54261
- rule: NoUnusedDirectivesRule,
54262
- severity: ErrorSeverity.Error,
54263
- },
54264
- });
54205
+ }, {});
54206
+ function mapErrorSeverityToESlint(severity) {
54207
+ switch (severity) {
54208
+ case ErrorSeverity.Error: {
54209
+ return 'error';
54210
+ }
54211
+ case ErrorSeverity.Warning: {
54212
+ return 'warn';
54213
+ }
54214
+ case ErrorSeverity.Hint:
54215
+ case ErrorSeverity.Off: {
54216
+ return 'off';
54217
+ }
54218
+ default: {
54219
+ assertExhaustive(severity, `Unhandled severity: ${severity}`);
54220
+ }
54221
+ }
54222
+ }
54265
54223
 
54266
54224
  var assert_1;
54267
54225
  var hasRequiredAssert;
@@ -57549,28 +57507,39 @@ function last(array) {
57549
57507
  }
57550
57508
 
57551
57509
  const rules = Object.assign({ 'exhaustive-deps': rule$1, 'rules-of-hooks': rule }, Object.fromEntries(Object.entries(allRules).map(([name, config]) => [name, config.rule])));
57552
- const ruleConfigs = {
57510
+ const basicRuleConfigs = {
57553
57511
  'react-hooks/rules-of-hooks': 'error',
57554
57512
  'react-hooks/exhaustive-deps': 'warn',
57555
57513
  };
57514
+ const compilerRuleConfigs = Object.fromEntries(Object.entries(recommendedRules).map(([name, ruleConfig]) => {
57515
+ return [
57516
+ `react-hooks/${name}`,
57517
+ mapErrorSeverityToESlint(ruleConfig.severity),
57518
+ ];
57519
+ }));
57520
+ const allRuleConfigs = Object.assign(Object.assign({}, basicRuleConfigs), compilerRuleConfigs);
57556
57521
  const plugin = {
57557
57522
  meta: {
57558
57523
  name: 'eslint-plugin-react-hooks',
57559
57524
  },
57560
- configs: {},
57561
57525
  rules,
57526
+ configs: {},
57562
57527
  };
57563
57528
  Object.assign(plugin.configs, {
57564
57529
  'recommended-legacy': {
57565
57530
  plugins: ['react-hooks'],
57566
- rules: ruleConfigs,
57531
+ rules: basicRuleConfigs,
57532
+ },
57533
+ 'recommended-latest-legacy': {
57534
+ plugins: ['react-hooks'],
57535
+ rules: allRuleConfigs,
57567
57536
  },
57568
57537
  'flat/recommended': [
57569
57538
  {
57570
57539
  plugins: {
57571
57540
  'react-hooks': plugin,
57572
57541
  },
57573
- rules: ruleConfigs,
57542
+ rules: basicRuleConfigs,
57574
57543
  },
57575
57544
  ],
57576
57545
  'recommended-latest': [
@@ -57578,13 +57547,17 @@ Object.assign(plugin.configs, {
57578
57547
  plugins: {
57579
57548
  'react-hooks': plugin,
57580
57549
  },
57581
- rules: ruleConfigs,
57550
+ rules: allRuleConfigs,
57551
+ },
57552
+ ],
57553
+ recommended: [
57554
+ {
57555
+ plugins: {
57556
+ 'react-hooks': plugin,
57557
+ },
57558
+ rules: basicRuleConfigs,
57582
57559
  },
57583
57560
  ],
57584
- recommended: {
57585
- plugins: ['react-hooks'],
57586
- rules: ruleConfigs,
57587
- },
57588
57561
  });
57589
57562
 
57590
57563
  module.exports = plugin;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "6.1.0",
4
+ "version": "6.1.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",
@@ -41,24 +41,22 @@
41
41
  "dependencies": {
42
42
  "@babel/core": "^7.24.4",
43
43
  "@babel/parser": "^7.24.4",
44
- "@babel/plugin-proposal-private-methods": "^7.18.6",
45
- "hermes-parser": "^0.25.1",
46
- "zod": "^3.22.4",
47
- "zod-validation-error": "^3.0.3"
44
+ "zod": "^3.22.4 || ^4.0.0",
45
+ "zod-validation-error": "^3.0.3 || ^4.0.0"
48
46
  },
49
47
  "devDependencies": {
50
48
  "@babel/eslint-parser": "^7.11.4",
51
49
  "@babel/preset-typescript": "^7.26.0",
52
50
  "@babel/types": "^7.19.0",
53
51
  "@tsconfig/strictest": "^2.0.5",
54
- "@typescript-eslint/parser-v2": "npm:@typescript-eslint/parser@^2.26.0",
55
- "@typescript-eslint/parser-v3": "npm:@typescript-eslint/parser@^3.10.0",
56
- "@typescript-eslint/parser-v4": "npm:@typescript-eslint/parser@^4.1.0",
57
- "@typescript-eslint/parser-v5": "npm:@typescript-eslint/parser@^5.62.0",
58
52
  "@types/eslint": "^8.56.12",
59
53
  "@types/estree": "^1.0.6",
60
54
  "@types/estree-jsx": "^1.0.5",
61
55
  "@types/node": "^20.2.5",
56
+ "@typescript-eslint/parser-v2": "npm:@typescript-eslint/parser@^2.26.0",
57
+ "@typescript-eslint/parser-v3": "npm:@typescript-eslint/parser@^3.10.0",
58
+ "@typescript-eslint/parser-v4": "npm:@typescript-eslint/parser@^4.1.0",
59
+ "@typescript-eslint/parser-v5": "npm:@typescript-eslint/parser@^5.62.0",
62
60
  "babel-eslint": "^10.0.3",
63
61
  "eslint-v7": "npm:eslint@^7.7.0",
64
62
  "eslint-v8": "npm:eslint@^8.57.1",
@@ -66,4 +64,4 @@
66
64
  "jest": "^29.5.0",
67
65
  "typescript": "^5.4.3"
68
66
  }
69
- }
67
+ }