@kazupon/eslint-config 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -63,7 +63,7 @@ export default defineConfig(
63
63
  )
64
64
  ```
65
65
 
66
- > [!IMPORTANT]
66
+ > [!IMPORTANT] <!-- eslint-disable-line markdown/no-missing-label-refs -->
67
67
  > Support flat configuration only, **not supported Legacy style (`.eslintrc`)**
68
68
 
69
69
  ### Lint with npm scripts `package.json`
@@ -125,7 +125,7 @@ The following built-in preset configurations are supported:
125
125
  | `javascript` | [`@eslint/js`](https://www.npmjs.com/package/@eslint/js) | no (built-in) |
126
126
  | `comments` | [`@eslint-community/eslint-plugin-eslint-comments`](https://www.npmjs.com/package/@eslint-community/eslint-plugin-eslint-comments) | no (built-in) |
127
127
  | `typescript` | [`typescript-eslint`](https://www.npmjs.com/package/typescript-eslint) | yes |
128
- | `imports` | [`eslint-plugin-import`](https://www.npmjs.com/package/eslint-plugin-import), [`eslint-plugin-unused-imports`](https://www.npmjs.com/package/eslint-plugin-unused-imports) | yes |
128
+ | `imports` | [`eslint-plugin-import`](https://www.npmjs.com/package/eslint-plugin-import), [`eslint-plugin-unused-imports`](https://www.npmjs.com/package/eslint-plugin-unused-imports), [`eslint-plugin-module-interop`](https://www.npmjs.com/package/eslint-plugin-module-interop) | yes |
129
129
  | `jsdoc` | [`eslint-plugin-jsdoc`](https://www.npmjs.com/package/eslint-plugin-jsdoc) | yes |
130
130
  | `regexp` | [`eslint-plugin-regexp`](https://www.npmjs.com/package/eslint-plugin-regexp) | yes |
131
131
  | `promise` | [`eslint-plugin-promise`](https://www.npmjs.com/package/eslint-plugin-promise) | yes |
package/dist/index.d.ts CHANGED
@@ -362,6 +362,21 @@ interface ImportsRules {
362
362
  * @see https://github.com/import-js/eslint-plugin-import/blob/v2.31.0/docs/rules/unambiguous.md
363
363
  */
364
364
  'import/unambiguous'?: Linter.RuleEntry<[]>;
365
+ /**
366
+ * disallow importing CommonJS modules
367
+ * @see https://ota-meshi.github.io/eslint-plugin-module-interop/rules/no-import-cjs.html
368
+ */
369
+ 'module-interop/no-import-cjs'?: Linter.RuleEntry<[]>;
370
+ /**
371
+ * disallow `require(esm)`
372
+ * @see https://ota-meshi.github.io/eslint-plugin-module-interop/rules/no-require-esm.html
373
+ */
374
+ 'module-interop/no-require-esm'?: Linter.RuleEntry<[]>;
375
+ /**
376
+ * enforce json imports to have the `{type: "json"}` attribute.
377
+ * @see https://ota-meshi.github.io/eslint-plugin-module-interop/rules/prefer-json-modules.html
378
+ */
379
+ 'module-interop/prefer-json-modules'?: Linter.RuleEntry<[]>;
365
380
  /**
366
381
  * Disallow unused variables
367
382
  * @see https://github.com/sweepline/eslint-plugin-unused-imports/blob/master/docs/rules/no-unused-imports.md
@@ -13932,6 +13947,11 @@ interface ImportsOptions {
13932
13947
  * @default false
13933
13948
  */
13934
13949
  typescript?: boolean;
13950
+ /**
13951
+ * use `eslint-plugin-module-interop`
13952
+ * @default true
13953
+ */
13954
+ interop?: boolean;
13935
13955
  }
13936
13956
  /**
13937
13957
  * `eslint-plugin-import-x`, `eslint-plugin-unused-imports` and overrides configuration options
@@ -14037,6 +14057,10 @@ interface MarkdownOptions {
14037
14057
  * @default true
14038
14058
  */
14039
14059
  fencedCodeBlocks?: boolean;
14060
+ /**
14061
+ * enable block extensions
14062
+ */
14063
+ blockExtensions?: string[];
14040
14064
  }
14041
14065
  /**
14042
14066
  * `@eslint/markdown` and overrides configuration options
@@ -14091,18 +14115,39 @@ interface TypeScriptOptions {
14091
14115
  parserOptions?: TypeScriptParserOptions;
14092
14116
  }
14093
14117
  /**
14094
- * @see https://typescript-eslint.io/getting-started/typed-linting
14118
+ * @see https://typescript-eslint.io/packages/parser/#configuration
14095
14119
  */
14096
14120
  interface TypeScriptParserOptions {
14097
- /**
14098
- * @see https://typescript-eslint.io/packages/parser#project
14099
- * @default true
14100
- */
14101
- project?: boolean | string | string[];
14102
- /**
14103
- * @see https://typescript-eslint.io/packages/parser#tsconfigrootdir
14104
- */
14121
+ cacheLifetime?: {
14122
+ glob?: number | 'Infinity';
14123
+ };
14124
+ disallowAutomaticSingleRunInference?: boolean;
14125
+ ecmaFeatures?: {
14126
+ jsx?: boolean;
14127
+ globalReturn?: boolean;
14128
+ };
14129
+ ecmaVersion?: number | 'latest';
14130
+ emitDecoratorMetadata?: boolean;
14131
+ experimentalDecorators?: boolean;
14132
+ isolatedDeclarations?: boolean;
14133
+ extraFileExtensions?: string[];
14134
+ jsDocParsingMode?: 'all' | 'none' | 'type-info';
14135
+ jsxFragmentName?: string | null;
14136
+ jsxPragma?: string | null;
14137
+ lib?: string[];
14138
+ programs?: undefined[];
14139
+ project?: string | string[] | boolean | null;
14140
+ projectFolderIgnoreList?: string[];
14141
+ projectService?: boolean | TypeScriptProjectServiceOptions;
14105
14142
  tsconfigRootDir?: string;
14143
+ warnOnUnsupportedTypeScriptVersion?: boolean;
14144
+ }
14145
+ /**
14146
+ * @see https://typescript-eslint.io/packages/parser/#projectservice
14147
+ */
14148
+ interface TypeScriptProjectServiceOptions {
14149
+ allowDefaultProject?: string[];
14150
+ defaultProject?: string;
14106
14151
  }
14107
14152
  /**
14108
14153
  * `typescript-eslint` and overrides configuration options
@@ -14279,4 +14324,4 @@ interface YmlOptions {
14279
14324
  declare function yml(options?: YmlOptions & OverridesOptions<YmlRules>): Promise<Linter.Config[]>;
14280
14325
  declare const yaml: typeof yml;
14281
14326
 
14282
- export { type CommentsOptions, type CommentsRules, type CssOptions, type CssRules, type ImportsOptions, type ImportsRules, type JavaScriptOptions, type JavascriptRules, type JsDocumentOptions, type JsdocRules, type JsoncOptions, type JsoncRules, type MarkdownOptions, type MarkdownRules, type OverridesOptions, type PrettierOptions, type PrettierRules, type PromiseOptions, type PromiseRules, type ReactOptions, type ReactRules, type RegexpOptions, type RegexpRules, type SvelteRules, type SvelteScriptOptions, type TomlOptions, type TomlRules, type TypeScriptOptions, type TypeScriptParserOptions, type TypescriptRules, type UnicornOptions, type UnicornRules, type VitestOptions, type VitestRules, type VueRules, type VueScriptOptions, type YmlOptions, type YmlRules, comments, css, defineConfig, imports, javascript, jsdoc, jsonc, markdown, md, prettier, promise, react, regexp, svelte, toml, typescript, unicorn, vitest, vue, yaml, yml };
14327
+ export { type CommentsOptions, type CommentsRules, type CssOptions, type CssRules, type ImportsOptions, type ImportsRules, type JavaScriptOptions, type JavascriptRules, type JsDocumentOptions, type JsdocRules, type JsoncOptions, type JsoncRules, type MarkdownOptions, type MarkdownRules, type OverridesOptions, type PrettierOptions, type PrettierRules, type PromiseOptions, type PromiseRules, type ReactOptions, type ReactRules, type RegexpOptions, type RegexpRules, type SvelteRules, type SvelteScriptOptions, type TomlOptions, type TomlRules, type TypeScriptOptions, type TypeScriptParserOptions, type TypeScriptProjectServiceOptions, type TypescriptRules, type UnicornOptions, type UnicornRules, type VitestOptions, type VitestRules, type VueRules, type VueScriptOptions, type YmlOptions, type YmlRules, comments, css, defineConfig, imports, javascript, jsdoc, jsonc, markdown, md, prettier, promise, react, regexp, svelte, toml, typescript, unicorn, vitest, vue, yaml, yml };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { FlatConfigComposer } from "eslint-flat-config-utils";
2
2
  import { interopDefault } from "@kazupon/jts-utils/module";
3
3
  import { isObject } from "@kazupon/jts-utils/object";
4
4
  import globals from "globals";
5
+ import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
5
6
 
6
7
  //#region src/config.ts
7
8
  function defineConfig(...configs) {
@@ -25,6 +26,7 @@ const GLOB_SVELTE = "**/*.svelte";
25
26
  const GLOB_MARKDOWN = "**/*.md";
26
27
  const GLOB_CSS = "**/*.css";
27
28
  const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
29
+ const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
28
30
  const GLOB_TESTS = [
29
31
  `**/test/**/*.${GLOB_SRC_EXT}`,
30
32
  `**/tests/**/*.${GLOB_SRC_EXT}`,
@@ -66,6 +68,7 @@ async function comments(options = {}) {
66
68
  const comments$1 = await loadPlugin("@eslint-community/eslint-plugin-eslint-comments");
67
69
  return [{
68
70
  name: "@eslint-community/eslint-comments/recommended",
71
+ ignores: [GLOB_MARKDOWN],
69
72
  plugins: { "@eslint-community/eslint-comments": comments$1 },
70
73
  rules: { ...comments$1.configs.recommended.rules }
71
74
  }, {
@@ -82,6 +85,7 @@ async function css(options = {}) {
82
85
  const customSyntax = !!options.customSyntax;
83
86
  const css$1 = await loadPlugin("@eslint/css");
84
87
  const core = {
88
+ name: "@eslint/css/recommended",
85
89
  files: [GLOB_CSS],
86
90
  language: "css/css",
87
91
  ...css$1.configs["recommended"]
@@ -110,20 +114,29 @@ const IMPORTS_FILES = [
110
114
  GLOB_TSX
111
115
  ];
112
116
  async function imports(options = {}) {
113
- const { rules: overrideRules = {} } = options;
114
- const unused = await loadPlugin(
115
- // eslint-disable-line @typescript-eslint/no-unsafe-assignment
116
- "eslint-plugin-unused-imports"
117
- );
117
+ const { rules: overrideRules = {}, interop = true } = options;
118
+ const unused = await loadPlugin("eslint-plugin-unused-imports");
118
119
  const imports$1 = await loadPlugin("eslint-plugin-import");
119
120
  const configs = [imports$1.flatConfigs.recommended];
120
121
  if (options.typescript) try {
121
122
  await loadPlugin("eslint-import-resolver-typescript");
122
123
  imports$1.flatConfigs.typescript.settings["import/resolver"]["typescript"] = true;
123
- configs.push(imports$1.flatConfigs.typescript);
124
+ configs.push({
125
+ name: "import/typescript",
126
+ ...imports$1.flatConfigs.typescript
127
+ });
124
128
  } catch (error) {
125
129
  throw new Error(`Not found eslint-import-resolver-typescript: ${error.message}`);
126
130
  }
131
+ if (interop) try {
132
+ const modInterop = await loadPlugin("eslint-plugin-module-interop");
133
+ configs.push({
134
+ name: "module-interop",
135
+ ...modInterop.configs.recommended
136
+ });
137
+ } catch (error) {
138
+ throw new Error(`Not found eslint-plugin-module-interop: ${error.message}`);
139
+ }
127
140
  configs.push({
128
141
  name: "unused-imports",
129
142
  plugins: { "unused-imports": unused },
@@ -159,10 +172,11 @@ async function javascript(options = {}) {
159
172
  const { rules: overrideRules = {} } = options;
160
173
  const js = await loadPlugin("@eslint/js");
161
174
  return [{
162
- name: "eslint/defaults/rules",
175
+ name: "@kazupon/javascript/markdown-block",
176
+ files: ["**/*.md/*.{js,cjs,mjs}"],
163
177
  ...js.configs.recommended
164
178
  }, {
165
- name: "@kazupon/javascript/@eslint/js",
179
+ name: "@kazupon/javascript/overrides",
166
180
  languageOptions: {
167
181
  ecmaVersion: 2022,
168
182
  globals: {
@@ -197,7 +211,10 @@ async function jsdoc(options = {}) {
197
211
  if (error) preset = `${preset}-error`;
198
212
  return preset;
199
213
  }
200
- return [jsdoc$1.configs[`flat/${resolvePreset()}`], {
214
+ return [{
215
+ ignores: [GLOB_MARKDOWN],
216
+ ...jsdoc$1.configs[`flat/${resolvePreset()}`]
217
+ }, {
201
218
  name: "@kazupon/jsdoc",
202
219
  rules: { ...overrideRules }
203
220
  }];
@@ -216,16 +233,20 @@ async function jsonc(options = {}) {
216
233
  const jsonc$1 = await loadPlugin("eslint-plugin-jsonc");
217
234
  const configs = [];
218
235
  for (const kind of kinds) if (kind) configs.push(...jsonc$1.configs[`flat/recommended-with-${kind}`].map((config, index) => {
219
- return config.name ? config : {
220
- name: `jsonc/flat/recommended-with-${kind}/${index}`,
221
- ...config
236
+ const mapped = {
237
+ ...config,
238
+ ignores: [GLOB_MARKDOWN]
222
239
  };
240
+ if (!config.name) mapped.name = `jsonc/flat/recommended-with-${kind}/${index}`;
241
+ return mapped;
223
242
  }));
224
243
  if (usePrettier) configs.push(...jsonc$1.configs["flat/prettier"].map((config, index) => {
225
- return config.name ? config : {
226
- name: `jsonc/flat/prettier/${index}`,
227
- ...config
244
+ const mapped = {
245
+ ...config,
246
+ ignores: [GLOB_MARKDOWN]
228
247
  };
248
+ if (!config.name) mapped.name = `jsonc/flat/prettier/${index}`;
249
+ return mapped;
229
250
  }));
230
251
  const overriddenConfig = {
231
252
  name: "@kazupon/jsonc",
@@ -322,19 +343,36 @@ function jsoncSort() {
322
343
  //#endregion
323
344
  //#region src/configs/markdown.ts
324
345
  async function markdown(options = {}) {
325
- const { rules: overrideRules = {} } = options;
346
+ const { rules: overrideRules = {}, files = [GLOB_MARKDOWN], blockExtensions = [] } = options;
326
347
  const language = options.language || "gfm";
327
- const fencedCodeBlocks = typeof options.fencedCodeBlocks === "boolean" ? options.fencedCodeBlocks : true;
328
348
  const markdown$1 = await loadPlugin("@eslint/markdown");
329
- const recommended = markdown$1.configs["recommended"][0];
349
+ const recommended = { ...markdown$1.configs["recommended"][0] };
350
+ const codeblocks = markdown$1.configs.processor[2];
330
351
  recommended.language = `markdown/${language}`;
331
352
  return [
332
353
  recommended,
333
- ...fencedCodeBlocks ? markdown$1.configs["processor"] : [],
354
+ {
355
+ name: "markdown/makedown-in-markdown",
356
+ files,
357
+ ignores: [`${GLOB_MARKDOWN}/**`],
358
+ processor: mergeProcessors([markdown$1.processors.markdown, processorPassThrough])
359
+ },
360
+ {
361
+ name: "makrdown/ignore-lint-blocks-in-typescript",
362
+ files: ["**/*.md/**"],
363
+ languageOptions: { parserOptions: {} }
364
+ },
334
365
  {
335
366
  name: "@kazupon/markdown",
336
- files: [GLOB_MARKDOWN],
337
- rules: { ...overrideRules }
367
+ files: [`${GLOB_MARKDOWN}/${GLOB_SRC}`, ...blockExtensions.map((ext) => `${GLOB_MARKDOWN}/**/*.${ext}`)],
368
+ languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
369
+ rules: {
370
+ ...codeblocks.rules,
371
+ "import/no-unresolved": "off",
372
+ "unused-imports/no-unused-vars": "off",
373
+ "@typescript-eslint/no-unused-vars": "off",
374
+ ...overrideRules
375
+ }
338
376
  }
339
377
  ];
340
378
  }
@@ -345,7 +383,10 @@ const md = markdown;
345
383
  async function prettier(options = {}) {
346
384
  const { rules: overrideRules = {} } = options;
347
385
  const prettier$1 = await loadPlugin("eslint-config-prettier");
348
- return [prettier$1, {
386
+ return [{
387
+ name: "config-prettier",
388
+ ...prettier$1
389
+ }, {
349
390
  name: "@kazupon/prettier",
350
391
  rules: { ...overrideRules }
351
392
  }];
@@ -405,6 +446,7 @@ async function regexp(options = {}) {
405
446
  const regexp$1 = await loadPlugin("eslint-plugin-regexp");
406
447
  return [{
407
448
  name: "regexp/flat/recommended",
449
+ ignores: [GLOB_MARKDOWN],
408
450
  ...regexp$1.configs["flat/recommended"]
409
451
  }, {
410
452
  name: "@kazupon/eslint-regexp",
@@ -434,7 +476,10 @@ async function svelte(options = {}) {
434
476
  ...parserOptions
435
477
  }
436
478
  };
437
- return [...svelte$1.configs["flat/recommended"], customConfig];
479
+ return [...svelte$1.configs["flat/recommended"].map((config) => ({
480
+ ...config,
481
+ ignores: [GLOB_MARKDOWN]
482
+ })), customConfig];
438
483
  }
439
484
 
440
485
  //#endregion
@@ -444,10 +489,12 @@ async function toml(options = {}) {
444
489
  const toml$1 = await loadPlugin("eslint-plugin-toml");
445
490
  const configs = [];
446
491
  configs.push(...toml$1.configs["flat/standard"].map((config, index) => {
447
- return config.name ? config : {
448
- name: `toml/flat/standard/${index}`,
449
- ...config
492
+ const mapped = {
493
+ ...config,
494
+ ignores: [GLOB_MARKDOWN]
450
495
  };
496
+ if (!config.name) mapped.name = `toml/flat/standard/${index}`;
497
+ return mapped;
451
498
  }));
452
499
  const overriddenConfig = {
453
500
  name: "@kazupon/toml",
@@ -466,11 +513,16 @@ async function typescript(options = {}) {
466
513
  const baseFiles = [
467
514
  GLOB_TS,
468
515
  GLOB_TSX,
469
- ...extraFileExtensions.map((ext) => `**/*${ext}`)
516
+ ...extraFileExtensions.map((ext) => `**/*.${ext}`)
470
517
  ];
471
518
  const files = [...options.files ?? [], ...baseFiles];
519
+ const extendedPreset = ts.configs.recommendedTypeChecked.map((config) => {
520
+ const mapped = { ...config };
521
+ if (config.files) mapped.files = [...config.files, `${GLOB_MARKDOWN}/**/${GLOB_TS}`];
522
+ return mapped;
523
+ });
472
524
  return [
473
- ...ts.configs.recommendedTypeChecked,
525
+ ...extendedPreset,
474
526
  {
475
527
  files: [
476
528
  GLOB_JS,
@@ -479,18 +531,25 @@ async function typescript(options = {}) {
479
531
  GLOB_JSON5,
480
532
  GLOB_JSONC,
481
533
  GLOB_YAML,
482
- GLOB_TOML
534
+ GLOB_TOML,
535
+ GLOB_MARKDOWN,
536
+ `${GLOB_MARKDOWN}/**`
483
537
  ],
484
538
  ...ts.configs.disableTypeChecked
485
539
  },
540
+ {
541
+ name: "@kazupon/typescipt/typescript-eslint/overrides-for-disable-type-checked",
542
+ rules: { ...ts.configs.disableTypeChecked.rules }
543
+ },
486
544
  {
487
545
  name: "@kazupon/typescipt/typescript-eslint",
488
546
  files,
489
547
  languageOptions: {
490
548
  parser: ts.parser,
491
549
  parserOptions: {
492
- extraFileExtensions: extraFileExtensions.map((ext) => `${ext}`),
550
+ extraFileExtensions: extraFileExtensions.map((ext) => `.${ext}`),
493
551
  sourceType: "module",
552
+ tsconfigRootDir: process.cwd(),
494
553
  ...parserOptions
495
554
  }
496
555
  },
@@ -560,7 +619,10 @@ async function vue(options = {}) {
560
619
  const vue$1 = await loadPlugin("eslint-plugin-vue");
561
620
  const vueParser = vue$1.configs["flat/base"][1]["languageOptions"]?.parser;
562
621
  const configs = [];
563
- configs.push(...vue$1.configs["flat/recommended"]);
622
+ configs.push(...vue$1.configs["flat/recommended"].map((config) => ({
623
+ ...config,
624
+ ignores: [GLOB_MARKDOWN]
625
+ })));
564
626
  if (options.composable) {
565
627
  const composable = await loadPlugin("eslint-plugin-vue-composable");
566
628
  const composableBase = { ...composable.configs["flat/recommended"][0] };
@@ -572,10 +634,12 @@ async function vue(options = {}) {
572
634
  const scopedCssMapped = scopedCss.configs["flat/recommended"].map(
573
635
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
574
636
  (config, index) => {
575
- return config.name ? config : {
576
- name: `vue/scoped-css/recommended/${index}`,
577
- ...config
637
+ const mapped = {
638
+ ...config,
639
+ ignores: [GLOB_MARKDOWN]
578
640
  };
641
+ if (!config.name) mapped.name = `vue/scoped-css/recommended/${index}`;
642
+ return mapped;
579
643
  }
580
644
  );
581
645
  configs.push(scopedCssMapped[0], scopedCssMapped[2]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kazupon/eslint-config",
3
3
  "description": "ESLint config for @kazupon",
4
- "version": "0.24.0",
4
+ "version": "0.26.0",
5
5
  "author": {
6
6
  "email": "kawakazu80@gmail.com",
7
7
  "name": "kazuya kawaguchi"
@@ -53,6 +53,7 @@
53
53
  "@eslint/js": "^9.22.0",
54
54
  "@kazupon/jts-utils": "^0.6.0",
55
55
  "eslint-flat-config-utils": "^2.0.1",
56
+ "eslint-merge-processors": "^2.0.0",
56
57
  "globals": "^16.0.0"
57
58
  },
58
59
  "peerDependencies": {
@@ -65,6 +66,7 @@
65
66
  "eslint-plugin-import": ">=2.31.0",
66
67
  "eslint-plugin-jsdoc": ">=48.5.0",
67
68
  "eslint-plugin-jsonc": ">=2.16.0",
69
+ "eslint-plugin-module-interop": ">=0.3.0",
68
70
  "eslint-plugin-promise": ">=6.4.0",
69
71
  "eslint-plugin-react": ">=7.35.0",
70
72
  "eslint-plugin-react-hooks": ">=5.2.0",
@@ -107,6 +109,9 @@
107
109
  "eslint-plugin-jsonc": {
108
110
  "optional": true
109
111
  },
112
+ "eslint-plugin-module-interop": {
113
+ "optional": true
114
+ },
110
115
  "eslint-plugin-promise": {
111
116
  "optional": true
112
117
  },
@@ -166,10 +171,11 @@
166
171
  "bumpp": "^10.1.0",
167
172
  "eslint": "^9.22.0",
168
173
  "eslint-config-prettier": "^10.1.1",
169
- "eslint-import-resolver-typescript": "^3.9.1",
174
+ "eslint-import-resolver-typescript": "^4.0.0",
170
175
  "eslint-plugin-import": "^2.31.0",
171
176
  "eslint-plugin-jsdoc": "^50.6.8",
172
177
  "eslint-plugin-jsonc": "^2.19.1",
178
+ "eslint-plugin-module-interop": "^0.3.0",
173
179
  "eslint-plugin-promise": "^7.2.1",
174
180
  "eslint-plugin-react": "^7.37.4",
175
181
  "eslint-plugin-react-hooks": "^5.2.0",