@fullstacksjs/eslint-config 14.6.0 → 14.7.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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/cjs/modules/base.js +3 -1
  3. package/cjs/modules/cypress.js +3 -1
  4. package/cjs/modules/imports.js +3 -1
  5. package/cjs/modules/jest.js +3 -1
  6. package/cjs/modules/next.js +3 -1
  7. package/cjs/modules/node.js +4 -2
  8. package/cjs/modules/perfectionist.js +3 -1
  9. package/cjs/modules/playwright.js +3 -1
  10. package/cjs/modules/prettier.js +3 -7
  11. package/cjs/modules/promise.js +3 -1
  12. package/cjs/modules/react.js +45 -28
  13. package/cjs/modules/regex.js +8 -2
  14. package/cjs/modules/storybook.js +3 -1
  15. package/cjs/modules/stylistic.js +3 -1
  16. package/cjs/modules/tailwind.js +10 -3
  17. package/cjs/modules/tests.js +3 -1
  18. package/cjs/modules/typescript.js +4 -12
  19. package/cjs/modules/vitest.js +3 -2
  20. package/cjs/types/modules/react.d.ts +5 -0
  21. package/cjs/types/modules/regex.d.ts +1 -1
  22. package/cjs/types/modules/tailwind.d.ts +2 -9
  23. package/cjs/utils/nextAllowExportNames.js +7 -0
  24. package/cjs/utils/objectOrEmpty.js +14 -0
  25. package/package.json +13 -13
  26. package/src/modules/base.mjs +4 -1
  27. package/src/modules/cypress.mjs +4 -1
  28. package/src/modules/imports.mjs +3 -1
  29. package/src/modules/jest.mjs +3 -1
  30. package/src/modules/next.mjs +5 -1
  31. package/src/modules/node.mjs +5 -2
  32. package/src/modules/perfectionist.mjs +5 -1
  33. package/src/modules/playwright.mjs +4 -1
  34. package/src/modules/prettier.mjs +5 -7
  35. package/src/modules/promise.mjs +4 -1
  36. package/src/modules/react.mjs +48 -27
  37. package/src/modules/regex.mjs +10 -2
  38. package/src/modules/storybook.mjs +4 -1
  39. package/src/modules/stylistic.mjs +5 -1
  40. package/src/modules/tailwind.mjs +12 -4
  41. package/src/modules/tests.mjs +4 -1
  42. package/src/modules/typescript.mjs +3 -8
  43. package/src/modules/vitest.mjs +4 -2
  44. package/src/types/modules/react.d.ts +5 -0
  45. package/src/types/modules/regex.d.ts +1 -1
  46. package/src/types/modules/tailwind.d.ts +2 -9
  47. package/src/utils/nextAllowExportNames.mjs +17 -0
  48. package/src/utils/objectOrEmpty.mjs +8 -0
@@ -1,5 +1,10 @@
1
1
  import type { ConfigWithOverrides } from '..';
2
2
 
3
3
  interface ReactOptions extends ConfigWithOverrides {
4
+ version?: string;
5
+ importSource?: string;
6
+ compilationMode?: 'all' | 'annotation' | 'infer' | 'syntax'; // Use the same compilationMode as the React Compiler config for consistent analysis
7
+ polymorphicPropName?: string;
8
+ additionalStateHooks?: string;
4
9
  additionalEffectHooks?: string;
5
10
  }
@@ -1,5 +1,5 @@
1
1
  import type { ConfigWithOverrides } from '..';
2
2
 
3
3
  interface RegexOptions extends ConfigWithOverrides {
4
- allowedCharacterRanges: string[];
4
+ allowedCharacterRanges?: string[];
5
5
  }
@@ -1,18 +1,11 @@
1
1
  import type { ConfigWithOverrides } from '..';
2
2
 
3
- interface TailwindOptionsBase extends ConfigWithOverrides {
4
- callees?: string[];
5
- variables?: string[];
6
- attributes?: string[];
7
- tags?: string[];
8
- }
9
-
10
- interface TailwindOptionsWithEntryPoint extends TailwindOptionsBase {
3
+ interface TailwindOptionsWithEntryPoint extends ConfigWithOverrides {
11
4
  entryPoint: string;
12
5
  tailwindConfig?: string;
13
6
  }
14
7
 
15
- interface TailwindOptionsWithConfig extends TailwindOptionsBase {
8
+ interface TailwindOptionsWithConfig extends ConfigWithOverrides {
16
9
  entryPoint?: string;
17
10
  tailwindConfig: string;
18
11
  }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.nextAllowExportNames = void 0;
7
+ const nextAllowExportNames = exports.nextAllowExportNames = ['experimental_ppr', 'dynamic', 'dynamicParams', 'revalidate', 'fetchCache', 'runtime', 'preferredRegion', 'maxDuration', 'metadata', 'generateMetadata', 'viewport', 'generateViewport', 'generateImageMetadata', 'generateSitemaps', 'generateStaticParams'];
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.objectOrEmpty = objectOrEmpty;
7
+ /**
8
+ * @template T
9
+ * @param {T | null | undefined} value
10
+ * @returns {T | {}}
11
+ */
12
+ function objectOrEmpty(value) {
13
+ return typeof value === 'object' && value !== null ? value : {};
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullstacksjs/eslint-config",
3
- "version": "14.6.0",
3
+ "version": "14.7.0",
4
4
  "license": "MIT",
5
5
  "author": "fullstacks <fullstacksjs@gmail.com>",
6
6
  "description": "fullstacks eslint config",
@@ -16,7 +16,7 @@
16
16
  "src",
17
17
  "cjs"
18
18
  ],
19
- "packageManager": "npm@11.13.0",
19
+ "packageManager": "npm@11.16.0",
20
20
  "scripts": {
21
21
  "lint": "eslint .",
22
22
  "spell": "cspell ./* --no-progress",
@@ -38,11 +38,11 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@eslint-react/eslint-plugin": "5.8.3",
41
+ "@eslint-react/eslint-plugin": "5.8.16",
42
42
  "@eslint/compat": "2.1.0",
43
- "@next/eslint-plugin-next": "16.2.6",
43
+ "@next/eslint-plugin-next": "16.2.7",
44
44
  "@stylistic/eslint-plugin": "5.10.0",
45
- "@vitest/eslint-plugin": "1.6.17",
45
+ "@vitest/eslint-plugin": "1.6.19",
46
46
  "deepmerge": "4.3.1",
47
47
  "eslint-flat-config-utils": "3.2.0",
48
48
  "eslint-plugin-better-tailwindcss": "4.5.0",
@@ -53,14 +53,14 @@
53
53
  "eslint-plugin-n": "18.0.1",
54
54
  "eslint-plugin-perfectionist": "5.9.0",
55
55
  "eslint-plugin-playwright": "2.10.4",
56
- "eslint-plugin-prettier": "5.5.5",
56
+ "eslint-plugin-prettier": "5.5.6",
57
57
  "eslint-plugin-promise": "7.3.0",
58
- "eslint-plugin-react-hooks": "7.1.1",
58
+ "eslint-plugin-react-refresh": "0.5.2",
59
59
  "eslint-plugin-regexp": "3.1.0",
60
- "eslint-plugin-storybook": "10.4.0",
60
+ "eslint-plugin-storybook": "10.4.2",
61
61
  "globals": "17.6.0",
62
62
  "local-pkg": "1.2.1",
63
- "typescript-eslint": "8.59.4"
63
+ "typescript-eslint": "8.61.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@eslint/eslintrc": "3.3.5",
@@ -69,15 +69,15 @@
69
69
  "@semantic-release/npm": "13.1.5",
70
70
  "@semantic-release/release-notes-generator": "14.1.1",
71
71
  "@types/eslint": "9.6.1",
72
- "cspell": "10.0.0",
73
- "eslint": "10.4.0",
72
+ "cspell": "10.0.1",
73
+ "eslint": "10.4.1",
74
74
  "husky": "9.1.7",
75
75
  "jest": "30.4.2",
76
- "lint-staged": "17.0.5",
76
+ "lint-staged": "17.0.7",
77
77
  "pinst": "3.0.0",
78
78
  "prettier": "3.8.3",
79
79
  "semantic-release": "25.0.3",
80
- "storybook": "10.4.0",
80
+ "storybook": "10.4.2",
81
81
  "typescript": "6.0.3",
82
82
  "unbuild": "3.6.1"
83
83
  },
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import globals from 'globals';
3
3
 
4
4
  import { strict } from '../utils/conditions.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { import('eslint').Linter.Config }
9
10
  */
10
11
  function base(options = {}) {
12
+ const overrides = objectOrEmpty(options.base.overrides);
13
+
11
14
  const baseConfig = {
12
15
  name: 'base',
13
16
  languageOptions: {
@@ -197,7 +200,7 @@ function base(options = {}) {
197
200
  },
198
201
  };
199
202
 
200
- return mergeConfigs(baseConfig, options.base.overrides ?? {});
203
+ return mergeConfigs(baseConfig, overrides);
201
204
  }
202
205
 
203
206
  export default base;
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-cypress';
3
3
 
4
4
  import { globs } from '../utils/globs.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { import('eslint').Linter.Config }
9
10
  */
10
11
  function cypress(options = {}) {
12
+ const overrides = objectOrEmpty(options.cypress.overrides);
13
+
11
14
  const cypressConfig = {
12
15
  name: 'cypress',
13
16
  files: globs.e2e,
@@ -26,7 +29,7 @@ function cypress(options = {}) {
26
29
  },
27
30
  };
28
31
 
29
- return mergeConfigs(cypressConfig, options.cypress.overrides ?? {});
32
+ return mergeConfigs(cypressConfig, overrides);
30
33
  }
31
34
 
32
35
  export default cypress;
@@ -2,6 +2,7 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-import-x';
3
3
 
4
4
  import { predicate } from '../utils/conditions.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  const tsExtensions = ['.ts', '.tsx', '.cts', '.mts', '.ctsx', '.mtsx'];
7
8
  const jsExtensions = ['.mjs', '.js', '.jsx', '.cjs'];
@@ -13,6 +14,7 @@ const allExtensions = [...jsExtensions, ...tsExtensions];
13
14
  */
14
15
  function imports(options = {}) {
15
16
  const isObject = typeof options.import === 'object';
17
+ const overrides = objectOrEmpty(options.import.overrides);
16
18
 
17
19
  const importsConfig = {
18
20
  name: 'imports',
@@ -106,7 +108,7 @@ function imports(options = {}) {
106
108
  },
107
109
  };
108
110
 
109
- return mergeConfigs(importsConfig, options.import.overrides ?? {});
111
+ return mergeConfigs(importsConfig, overrides);
110
112
  }
111
113
 
112
114
  export default imports;
@@ -4,12 +4,14 @@ import globals from 'globals';
4
4
 
5
5
  import { predicate } from '../utils/conditions.mjs';
6
6
  import { globs } from '../utils/globs.mjs';
7
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
7
8
 
8
9
  /**
9
10
  * @param { import('../types').Options } options
10
11
  * @return { import('eslint').Linter.Config } */
11
12
  function jest(options = {}) {
12
13
  const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
14
+ const overrides = objectOrEmpty(options.jest.overrides);
13
15
 
14
16
  const jestConfig = {
15
17
  name: 'jest',
@@ -86,7 +88,7 @@ function jest(options = {}) {
86
88
  },
87
89
  };
88
90
 
89
- return mergeConfigs(jestConfig, options.jest.overrides ?? {});
91
+ return mergeConfigs(jestConfig, overrides);
90
92
  }
91
93
 
92
94
  export default jest;
@@ -1,11 +1,15 @@
1
1
  import plugin from '@next/eslint-plugin-next';
2
2
  import { mergeConfigs } from 'eslint-flat-config-utils';
3
3
 
4
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
+
4
6
  /**
5
7
  * @param { import('../types').Options } options
6
8
  * @return { import('eslint').Linter.Config }
7
9
  */
8
10
  function next(options = {}) {
11
+ const overrides = objectOrEmpty(options.next.overrides);
12
+
9
13
  const nextConfig = {
10
14
  name: 'next',
11
15
  plugins: { next: plugin },
@@ -34,7 +38,7 @@ function next(options = {}) {
34
38
  },
35
39
  };
36
40
 
37
- return mergeConfigs(nextConfig, options.next.overrides ?? {});
41
+ return mergeConfigs(nextConfig, overrides);
38
42
  }
39
43
 
40
44
  export default next;
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-n';
3
3
 
4
4
  import { strict } from '../utils/conditions.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { import('eslint').Linter.Config }
9
10
  */
10
11
  function node(options = {}) {
12
+ const overrides = objectOrEmpty(options.node.overrides);
13
+
11
14
  const nodeConfig = {
12
15
  name: 'node',
13
16
  plugins: { n: plugin },
@@ -30,7 +33,7 @@ function node(options = {}) {
30
33
  'n/no-sync': strict(options, 'warn'),
31
34
  'n/no-top-level-await': 'off',
32
35
  'n/no-unpublished-bin': 'warn',
33
- 'n/no-unpublished-import': 'warn',
36
+ 'n/no-unpublished-import': 'off',
34
37
  'n/no-unpublished-require': 'warn',
35
38
  'n/no-unsupported-features/es-builtins': 'off', // Nice but not a general rule
36
39
  'n/no-unsupported-features/es-syntax': 'off', // Nice but not a general rule
@@ -58,7 +61,7 @@ function node(options = {}) {
58
61
  },
59
62
  };
60
63
 
61
- return mergeConfigs(nodeConfig, options.node.overrides ?? {});
64
+ return mergeConfigs(nodeConfig, overrides);
62
65
  }
63
66
 
64
67
  export default node;
@@ -1,11 +1,15 @@
1
1
  import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-perfectionist';
3
3
 
4
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
+
4
6
  /**
5
7
  * @param { import('../types').Options } options
6
8
  * @return { Promise<import('eslint').Linter.Config> }
7
9
  */
8
10
  function perfectionist(options = {}) {
11
+ const overrides = objectOrEmpty(options.sort.overrides);
12
+
9
13
  const perfectionistConfig = {
10
14
  name: 'perfectionist',
11
15
  plugins: { perfectionist: plugin },
@@ -72,7 +76,7 @@ function perfectionist(options = {}) {
72
76
  },
73
77
  };
74
78
 
75
- return mergeConfigs(perfectionistConfig, options.sort.overrides ?? {});
79
+ return mergeConfigs(perfectionistConfig, overrides);
76
80
  }
77
81
 
78
82
  export default perfectionist;
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-playwright';
3
3
 
4
4
  import { globs } from '../utils/globs.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { Promise<import('eslint').Linter.Config> }
9
10
  */
10
11
  function playwright(options = {}) {
12
+ const overrides = objectOrEmpty(options.playwright.overrides);
13
+
11
14
  const playwrightConfig = {
12
15
  name: 'playwright',
13
16
  plugins: { playwright: plugin },
@@ -74,7 +77,7 @@ function playwright(options = {}) {
74
77
  },
75
78
  };
76
79
 
77
- return mergeConfigs(playwrightConfig, options.playwright.overrides ?? {});
80
+ return mergeConfigs(playwrightConfig, overrides);
78
81
  }
79
82
 
80
83
  export default playwright;
@@ -1,11 +1,15 @@
1
1
  import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-prettier';
3
3
 
4
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
+
4
6
  /**
5
7
  * @param { import('../types').Options } options
6
8
  * @return { Promise<import('eslint').Linter.Config> }
7
9
  */
8
10
  function prettier(options = {}) {
11
+ const overrides = objectOrEmpty(options.prettier.overrides);
12
+
9
13
  const prettierConfig = {
10
14
  name: 'prettier',
11
15
  plugins: { prettier: plugin },
@@ -13,24 +17,20 @@ function prettier(options = {}) {
13
17
  'prettier/prettier': 'error',
14
18
 
15
19
  'curly': 'off',
16
- 'brace-style': 'off',
17
20
  'no-unexpected-multiline': 'off',
18
21
 
19
22
  '@typescript-eslint/lines-around-comment': 'off',
20
23
  '@typescript-eslint/quotes': 'off',
21
24
  '@typescript-eslint/block-spacing': 'off',
22
- '@typescript-eslint/brace-style': 'off',
23
25
  '@typescript-eslint/comma-dangle': 'off',
24
26
  '@typescript-eslint/comma-spacing': 'off',
25
27
  '@typescript-eslint/func-call-spacing': 'off',
26
28
  '@typescript-eslint/indent': 'off',
27
- '@typescript-eslint/key-spacing': 'off',
28
29
  '@typescript-eslint/keyword-spacing': 'off',
29
30
  '@typescript-eslint/member-delimiter-style': 'off',
30
31
  '@typescript-eslint/no-extra-parens': 'off',
31
32
  '@typescript-eslint/no-extra-semi': 'off',
32
33
  '@typescript-eslint/semi': 'off',
33
- '@typescript-eslint/space-before-blocks': 'off',
34
34
  '@typescript-eslint/space-before-function-paren': 'off',
35
35
  '@typescript-eslint/space-infix-ops': 'off',
36
36
  '@typescript-eslint/type-annotation-spacing': 'off',
@@ -42,12 +42,10 @@ function prettier(options = {}) {
42
42
  '@stylistic/jsx-curly-spacing': 'off',
43
43
  '@stylistic/jsx-equals-spacing': 'off',
44
44
  '@stylistic/jsx-first-prop-new-line': 'off',
45
- '@stylistic/jsx-indent': 'off',
46
45
  '@stylistic/jsx-indent-props': 'off',
47
46
  '@stylistic/jsx-max-props-per-line': 'off',
48
47
  '@stylistic/jsx-newline': 'off',
49
48
  '@stylistic/jsx-one-expression-per-line': 'off',
50
- '@stylistic/jsx-props-no-multi-spaces': 'off',
51
49
  '@stylistic/jsx-tag-spacing': 'off',
52
50
  '@stylistic/jsx-wrap-multilines': 'off',
53
51
 
@@ -93,7 +91,7 @@ function prettier(options = {}) {
93
91
  },
94
92
  };
95
93
 
96
- return mergeConfigs(prettierConfig, options.prettier.overrides ?? {});
94
+ return mergeConfigs(prettierConfig, overrides);
97
95
  }
98
96
 
99
97
  export default prettier;
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-promise';
3
3
 
4
4
  import { strict } from '../utils/conditions.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { Promise<import('eslint').Linter.Config> }
9
10
  */
10
11
  function promise(options = {}) {
12
+ const overrides = objectOrEmpty(options.promise.overrides);
13
+
11
14
  const promiseConfig = {
12
15
  name: 'promise',
13
16
  plugins: { promise: plugin },
@@ -32,7 +35,7 @@ function promise(options = {}) {
32
35
  },
33
36
  };
34
37
 
35
- return mergeConfigs(promiseConfig, options.promise.overrides ?? {});
38
+ return mergeConfigs(promiseConfig, overrides);
36
39
  }
37
40
 
38
41
  export default promise;
@@ -1,11 +1,14 @@
1
1
  import reactPlugin from '@eslint-react/eslint-plugin';
2
2
  import { mergeConfigs } from 'eslint-flat-config-utils';
3
3
  import a11yPlugin from 'eslint-plugin-jsx-a11y';
4
- import hooksPlugin from 'eslint-plugin-react-hooks';
4
+ import { reactRefresh } from 'eslint-plugin-react-refresh';
5
+ import { isPackageExists } from 'local-pkg';
5
6
  import { parser } from 'typescript-eslint';
6
7
 
7
8
  import { predicate, strict } from '../utils/conditions.mjs';
8
9
  import { globs } from '../utils/globs.mjs';
10
+ import { nextAllowExportNames } from '../utils/nextAllowExportNames.mjs';
11
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
9
12
 
10
13
  /**
11
14
  * @param { import('../types').Options } options
@@ -13,14 +16,16 @@ import { globs } from '../utils/globs.mjs';
13
16
  */
14
17
  function react(options = {}) {
15
18
  const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
19
+ const isObject = typeof options.react === 'object';
20
+ const overrides = objectOrEmpty(options.react.overrides);
16
21
 
17
22
  const reactConfig = {
18
23
  name: 'react',
19
24
  files: [globs.js, globs.jsx, globs.ts, globs.tsx],
20
25
  plugins: {
21
26
  ...reactPlugin.configs.all.plugins,
22
- 'react-hooks': hooksPlugin,
23
27
  'jsx-a11y': a11yPlugin,
28
+ 'react-refresh': reactRefresh.plugin,
24
29
  },
25
30
  ...predicate(projectService, {
26
31
  languageOptions: {
@@ -29,12 +34,25 @@ function react(options = {}) {
29
34
  },
30
35
  }),
31
36
  settings: {
32
- 'react': {
33
- pragma: 'React',
34
- version: 'detect',
35
- },
36
- 'react-hooks': {
37
- additionalEffectHooks: options.react.additionalEffectHooks,
37
+ 'react-x': {
38
+ ...predicate(isObject && 'version' in options.react, {
39
+ version: options.react.version,
40
+ }),
41
+ ...predicate(isObject && 'importSource' in options.react, {
42
+ importSource: options.react.importSource,
43
+ }),
44
+ ...predicate(isObject && 'compilationMode' in options.react, {
45
+ compilationMode: options.react.compilationMode,
46
+ }),
47
+ ...predicate(isObject && 'polymorphicPropName' in options.react, {
48
+ polymorphicPropName: options.react.polymorphicPropName,
49
+ }),
50
+ ...predicate(isObject && 'additionalStateHooks' in options.react, {
51
+ additionalStateHooks: options.react.additionalStateHooks,
52
+ }),
53
+ ...predicate(isObject && 'additionalEffectHooks' in options.react, {
54
+ additionalEffectHooks: options.react.additionalEffectHooks,
55
+ }),
38
56
  },
39
57
  },
40
58
  rules: {
@@ -118,24 +136,18 @@ function react(options = {}) {
118
136
 
119
137
  '@eslint-react/rsc-function-definition': 'error',
120
138
 
121
- 'react-hooks/rules-of-hooks': 'error',
122
- 'react-hooks/exhaustive-deps': 'warn',
123
-
124
- 'react-hooks/config': 'error',
125
- 'react-hooks/error-boundaries': 'error',
126
- 'react-hooks/component-hook-factories': 'error',
127
- 'react-hooks/gating': 'error',
128
- 'react-hooks/globals': 'error',
129
- 'react-hooks/immutability': 'error',
130
- 'react-hooks/preserve-manual-memoization': 'error',
131
- 'react-hooks/purity': 'error',
132
- 'react-hooks/refs': 'error',
133
- 'react-hooks/set-state-in-effect': strict('error'),
134
- 'react-hooks/set-state-in-render': 'error',
135
- 'react-hooks/static-components': strict('error'),
136
- 'react-hooks/unsupported-syntax': 'warn',
137
- 'react-hooks/use-memo': 'error',
138
- 'react-hooks/incompatible-library': 'warn',
139
+ '@eslint-react/rules-of-hooks': 'error',
140
+ '@eslint-react/exhaustive-deps': 'error',
141
+ '@eslint-react/error-boundaries': 'error',
142
+ '@eslint-react/globals': 'error',
143
+ '@eslint-react/immutability': 'error',
144
+ '@eslint-react/purity': 'error',
145
+ '@eslint-react/refs': 'error',
146
+ '@eslint-react/set-state-in-effect': strict('error'),
147
+ '@eslint-react/set-state-in-render': 'error',
148
+ '@eslint-react/static-components': strict('error'),
149
+ '@eslint-react/unsupported-syntax': 'error',
150
+ '@eslint-react/use-memo': 'error',
139
151
 
140
152
  'jsx-a11y/alt-text': 'warn',
141
153
  'jsx-a11y/anchor-has-content': 'error',
@@ -173,10 +185,19 @@ function react(options = {}) {
173
185
  'jsx-a11y/tabindex-no-positive': 'warn',
174
186
  'jsx-a11y/anchor-ambiguous-text': 'off',
175
187
  'jsx-a11y/prefer-tag-over-role': 'off',
188
+
189
+ 'react-refresh/only-export-components': [
190
+ 'error',
191
+ {
192
+ allowExportNames: isPackageExists('next') ? nextAllowExportNames : [],
193
+
194
+ allowConstantExport: isPackageExists('vite'),
195
+ },
196
+ ],
176
197
  },
177
198
  };
178
199
 
179
- return mergeConfigs(reactConfig, options.react.overrides ?? {});
200
+ return mergeConfigs(reactConfig, overrides);
180
201
  }
181
202
 
182
203
  export default react;
@@ -1,17 +1,25 @@
1
1
  import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import * as plugin from 'eslint-plugin-regexp';
3
3
 
4
+ import { predicate } from '../utils/conditions.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
6
+
4
7
  /**
5
8
  * @param { import('../types').Options } options
6
9
  * @return { Promise<import('eslint').Linter.Config> }
7
10
  */
8
11
  function regex(options = {}) {
12
+ const isObject = typeof options.regex === 'object';
13
+ const overrides = objectOrEmpty(options.regex.overrides);
14
+
9
15
  const regexConfig = {
10
16
  name: 'regex',
11
17
  plugins: { regexp: plugin },
12
18
  settings: {
13
19
  regexp: {
14
- allowedCharacterRanges: options.regex.allowedCharacterRanges,
20
+ ...predicate(isObject && 'allowedCharacterRanges' in options.regex, {
21
+ allowedCharacterRanges: options.regex.allowedCharacterRanges,
22
+ }),
15
23
  },
16
24
  },
17
25
  rules: {
@@ -104,7 +112,7 @@ function regex(options = {}) {
104
112
  },
105
113
  };
106
114
 
107
- return mergeConfigs(regexConfig, options.regex.overrides ?? {});
115
+ return mergeConfigs(regexConfig, overrides);
108
116
  }
109
117
 
110
118
  export default regex;
@@ -2,12 +2,15 @@ import { mergeConfigs } from 'eslint-flat-config-utils';
2
2
  import plugin from 'eslint-plugin-storybook';
3
3
 
4
4
  import { globs } from '../utils/globs.mjs';
5
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('../types').Options } options
8
9
  * @return { Promise<import('eslint').Linter.Config> }
9
10
  */
10
11
  function storybook(options = {}) {
12
+ const overrides = objectOrEmpty(options.storybook.overrides);
13
+
11
14
  const storybookConfig = {
12
15
  name: 'storybook',
13
16
  files: globs.storybook,
@@ -38,7 +41,7 @@ function storybook(options = {}) {
38
41
  },
39
42
  };
40
43
 
41
- return mergeConfigs(storybookConfig, options.storybook.overrides ?? {});
44
+ return mergeConfigs(storybookConfig, overrides);
42
45
  }
43
46
 
44
47
  export default storybook;
@@ -1,11 +1,15 @@
1
1
  import stylisticPlugin from '@stylistic/eslint-plugin';
2
2
  import { mergeConfigs } from 'eslint-flat-config-utils';
3
3
 
4
+ import { objectOrEmpty } from '../utils/objectOrEmpty.mjs';
5
+
4
6
  /**
5
7
  * @param { import('../types').Options } options
6
8
  * @return { Promise<import('eslint').Linter.Config> }
7
9
  */
8
10
  function stylistic(options = {}) {
11
+ const overrides = objectOrEmpty(options.stylistic.overrides);
12
+
9
13
  const stylisticConfig = {
10
14
  name: 'stylistic',
11
15
  plugins: { '@stylistic': stylisticPlugin },
@@ -44,7 +48,7 @@ function stylistic(options = {}) {
44
48
  ],
45
49
  },
46
50
  };
47
- return mergeConfigs(stylisticConfig, options.stylistic.overrides ?? {});
51
+ return mergeConfigs(stylisticConfig, overrides);
48
52
  }
49
53
 
50
54
  export default stylistic;