@fullstacksjs/eslint-config 11.9.0 → 11.10.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
@@ -16,9 +16,11 @@
16
16
  $ npm install --save-dev @fullstacksjs/eslint-config eslint prettier
17
17
  ```
18
18
 
19
+ ⚡️ That's it, you don't need to install any eslint-plugin! If you already have some plugins installed, please remove them.
20
+
19
21
  ## Usage
20
22
 
21
- To use the configuration, all you need is to export the generated config by the `defineConfig` function. The configuration reads the metadata from your root `package.json` file and automatically adds the rules and plugins that are needed.
23
+ To use the configuration, all you need is to export the generated config by the `defineConfig` function. It automatically enables required plugins with **Auto Module Detection**.
22
24
 
23
25
  ### ESM
24
26
 
@@ -36,7 +38,13 @@ const { defineConfig } = require('@fullstacksjs/eslint-config');
36
38
  module.exports = defineConfig();
37
39
  ```
38
40
 
39
- ## Modules API
41
+ ## How Module Detection Works
42
+
43
+ Automatic module detection enables ESLint plugins based on the dependencies listed in your `package.json`. It scans your project to identify which tools you're using, and then activates the corresponding ESLint plugins accordingly.
44
+
45
+ For example, if your `package.json` includes `vitest` as a dependency, the configuration will automatically enable `eslint-plugin-vitest` for you. (You don't need to install the plugin itself)
46
+
47
+ ### Modules API
40
48
 
41
49
  You can fine-tune module detection by overriding it, the `defineConfig` function accepts options as its first argument to control enabled modules.
42
50
 
@@ -69,7 +77,7 @@ interface Options {
69
77
  }
70
78
  ```
71
79
 
72
- ## Extra configuration
80
+ ## What if I want to add my one rules
73
81
 
74
82
  You can pass any number of arbitrary custom config overrides to `defineConfig` function:
75
83
 
@@ -93,11 +101,25 @@ export default defineConfig(
93
101
  })
94
102
  ```
95
103
 
96
- ## Next.JS Warning
104
+ ## What If I Want to Use a Plugin That Isn't Supported?
105
+
106
+ You can still use any ESLint plugin, even if it's not supported by automatic detection. Simply install the plugin manually and add it to the `defineConfig`. There are no limitations.
107
+
108
+ ```js
109
+ import { defineConfig } from '@fullstacksjs/eslint-config';
110
+ import pluginVue from 'eslint-plugin-vue';
111
+
112
+ export default defineConfig(
113
+ { typescript: true },
114
+ ...pluginVue.configs['flat/recommended']
115
+ )
116
+ ```
117
+
118
+ ## I'm Getting a Next.js Warning: Plugin Was Not Detected
97
119
 
98
- **Question**: I'm getting "The Next.js plugin was not detected in your ESLint" warning.
120
+ This configuration includes built-in support for [Next.js](https://nextjs.org). The warning you're seeing from Next.js is misleading—it simply checks whether the plugin is explicitly listed in your package.json.
99
121
 
100
- **Answer**: This plugin has built-in support for Next.js. The warning from Next.js is misleading—Next.js simply checks `package.json` to see if the plugin is listed. You can safely ignore the warning or update your lint script from `next lint` to `eslint`.
122
+ You can safely ignore this warning. Alternatively, you can update your lint script from next lint to eslint to avoid it entirely.
101
123
 
102
124
  ## Speed Optimization!
103
125
 
@@ -41,7 +41,22 @@ function imports(options = {}) {
41
41
  },
42
42
  rules: {
43
43
  'import/consistent-type-specifier-style': ['warn', 'prefer-top-level'],
44
- // 'import/extensions': ['error', 'ignorePackages', ignorePackages: true, js: opt, jsx: opt, mjs: opt, cjs: opt, ...(options.typescript && { ts: opt, tsx: opt, mts: opt, cts: opt, }), ], FIXME: This rule is broken!
44
+ /*
45
+ * FIXME: This rule is broken!
46
+ const opt = options.esm ? 'always' : 'never';
47
+ 'import/extensions': [
48
+ 'error',
49
+ opt,
50
+ {
51
+ ignorePackages: true,
52
+ js: opt,
53
+ jsx: opt,
54
+ mjs: opt,
55
+ cjs: opt,
56
+ ...(options.typescript && { ts: opt, tsx: opt, mts: opt, cts: opt }),
57
+ },
58
+ ],
59
+ */
45
60
  'import/first': 'error',
46
61
  'import/newline-after-import': 'warn',
47
62
  'import/no-absolute-path': 'error',
@@ -24,17 +24,20 @@ function react() {
24
24
  },
25
25
  rules: {
26
26
  '@eslint-react/dom/no-children-in-void-dom-elements': 'warn',
27
- '@eslint-react/dom/no-dangerously-set-innerhtml': 'off',
28
27
  '@eslint-react/dom/no-dangerously-set-innerhtml-with-children': 'error',
28
+ '@eslint-react/dom/no-dangerously-set-innerhtml': 'off',
29
29
  '@eslint-react/dom/no-find-dom-node': 'error',
30
+ '@eslint-react/dom/no-flush-sync': 'off',
31
+ '@eslint-react/dom/no-hydrate': 'warn',
30
32
  '@eslint-react/dom/no-missing-button-type': 'warn',
31
33
  '@eslint-react/dom/no-missing-iframe-sandbox': 'warn',
32
34
  '@eslint-react/dom/no-namespace': 'error',
33
35
  '@eslint-react/dom/no-render-return-value': 'error',
36
+ '@eslint-react/dom/no-render': 'warn',
34
37
  '@eslint-react/dom/no-script-url': 'warn',
35
38
  '@eslint-react/dom/no-unsafe-iframe-sandbox': 'warn',
36
39
  '@eslint-react/dom/no-unsafe-target-blank': 'warn',
37
- '@eslint-react/ensure-forward-ref-using-ref': 'warn',
40
+ '@eslint-react/ensure-forward-ref-using-ref': 'off',
38
41
  '@eslint-react/no-access-state-in-setstate': 'error',
39
42
  '@eslint-react/no-array-index-key': 'warn',
40
43
  '@eslint-react/no-children-count': 'warn',
@@ -52,8 +55,9 @@ function react() {
52
55
  '@eslint-react/no-direct-mutation-state': 'error',
53
56
  '@eslint-react/no-duplicate-key': 'error',
54
57
  '@eslint-react/no-implicit-key': 'error',
58
+ '@eslint-react/no-missing-context-display-name': 'off',
55
59
  '@eslint-react/no-missing-key': 'error',
56
- '@eslint-react/no-nested-components': 'warn',
60
+ '@eslint-react/no-nested-component-definitions': 'warn',
57
61
  '@eslint-react/no-redundant-should-component-update': 'error',
58
62
  '@eslint-react/no-set-state-in-component-did-mount': 'warn',
59
63
  '@eslint-react/no-set-state-in-component-did-update': 'warn',
@@ -66,6 +70,7 @@ function react() {
66
70
  '@eslint-react/no-unstable-default-props': 'error',
67
71
  '@eslint-react/no-unused-class-component-members': 'warn',
68
72
  '@eslint-react/no-unused-state': 'warn',
73
+ '@eslint-react/no-useless-forward-ref': 'warn',
69
74
  '@eslint-react/no-useless-fragment': 'warn',
70
75
  '@eslint-react/prefer-destructuring-assignment': 'warn',
71
76
  '@eslint-react/prefer-shorthand-boolean': 'warn',
@@ -75,11 +80,12 @@ function react() {
75
80
  '@eslint-react/hooks-extra/prefer-use-state-lazy-initialization': 'warn',
76
81
  '@eslint-react/hooks-extra/no-useless-custom-hooks': 'warn',
77
82
  '@eslint-react/naming-convention/component-name': 'warn',
78
- '@eslint-react/naming-convention/filename': 'off',
83
+ '@eslint-react/naming-convention/context-name': 'warn',
79
84
  '@eslint-react/naming-convention/filename-extension': ['error', {
80
85
  allow: 'always',
81
86
  extensions: ['.jsx', '.tsx']
82
87
  }],
88
+ '@eslint-react/naming-convention/filename': 'off',
83
89
  '@eslint-react/naming-convention/use-state': 'off',
84
90
  'react-hooks/exhaustive-deps': 'warn',
85
91
  'react-hooks/rules-of-hooks': 'error',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullstacksjs/eslint-config",
3
- "version": "11.9.0",
3
+ "version": "11.10.0",
4
4
  "license": "MIT",
5
5
  "author": "fullstacks <fullstacksjs@gmail.com>",
6
6
  "description": "fullstacks eslint config",
@@ -34,22 +34,22 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@eslint-react/eslint-plugin": "1.28.0",
38
- "@next/eslint-plugin-next": "15.1.7",
39
- "@stylistic/eslint-plugin": "4.1.0",
37
+ "@eslint-react/eslint-plugin": "1.37.3",
38
+ "@next/eslint-plugin-next": "15.2.3",
39
+ "@stylistic/eslint-plugin": "4.2.0",
40
40
  "deepmerge": "4.3.1",
41
- "eslint-plugin-cypress": "4.1.0",
42
- "eslint-plugin-import-x": "4.6.1",
41
+ "eslint-plugin-cypress": "4.2.0",
42
+ "eslint-plugin-import-x": "4.9.1",
43
43
  "eslint-plugin-jest": "28.11.0",
44
44
  "eslint-plugin-jest-formatting": "3.1.0",
45
45
  "eslint-plugin-jsx-a11y": "6.10.2",
46
- "eslint-plugin-n": "17.15.1",
47
- "eslint-plugin-perfectionist": "4.9.0",
46
+ "eslint-plugin-n": "17.16.2",
47
+ "eslint-plugin-perfectionist": "4.10.1",
48
48
  "eslint-plugin-playwright": "2.2.0",
49
49
  "eslint-plugin-prettier": "5.2.3",
50
50
  "eslint-plugin-promise": "7.2.1",
51
- "eslint-plugin-react-hooks": "5.1.0",
52
- "eslint-plugin-storybook": "0.11.3",
51
+ "eslint-plugin-react-hooks": "5.2.0",
52
+ "eslint-plugin-storybook": "0.11.6",
53
53
  "eslint-plugin-tailwindcss": "3.18.0",
54
54
  "eslint-plugin-vitest": "0.5.4",
55
55
  "globals": "16.0.0",
@@ -57,14 +57,14 @@
57
57
  "typescript-eslint": "8.27.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@eslint/eslintrc": "3.3.0",
61
- "@eslint/js": "9.22.0",
60
+ "@eslint/eslintrc": "3.3.1",
61
+ "@eslint/js": "9.23.0",
62
62
  "@semantic-release/github": "11.0.1",
63
63
  "@semantic-release/npm": "12.0.1",
64
64
  "@semantic-release/release-notes-generator": "14.0.3",
65
65
  "@types/eslint": "9.6.1",
66
66
  "cspell": "8.17.5",
67
- "eslint": "9.22.0",
67
+ "eslint": "9.23.0",
68
68
  "husky": "9.1.7",
69
69
  "jest": "29.7.0",
70
70
  "lint-staged": "15.5.0",
@@ -77,7 +77,7 @@
77
77
  },
78
78
  "peerDependencies": {
79
79
  "cypress": ">=8",
80
- "eslint": "^9",
80
+ "eslint": ">=9.22",
81
81
  "prettier": "3",
82
82
  "react": ">=16",
83
83
  "typescript": ">=4.7"
@@ -32,7 +32,22 @@ function imports(options = {}) {
32
32
 
33
33
  rules: {
34
34
  'import/consistent-type-specifier-style': ['warn', 'prefer-top-level'],
35
- // 'import/extensions': ['error', 'ignorePackages', ignorePackages: true, js: opt, jsx: opt, mjs: opt, cjs: opt, ...(options.typescript && { ts: opt, tsx: opt, mts: opt, cts: opt, }), ], FIXME: This rule is broken!
35
+ /*
36
+ * FIXME: This rule is broken!
37
+ const opt = options.esm ? 'always' : 'never';
38
+ 'import/extensions': [
39
+ 'error',
40
+ opt,
41
+ {
42
+ ignorePackages: true,
43
+ js: opt,
44
+ jsx: opt,
45
+ mjs: opt,
46
+ cjs: opt,
47
+ ...(options.typescript && { ts: opt, tsx: opt, mts: opt, cts: opt }),
48
+ },
49
+ ],
50
+ */
36
51
  'import/first': 'error',
37
52
  'import/newline-after-import': 'warn',
38
53
  'import/no-absolute-path': 'error',
@@ -18,18 +18,20 @@ function react() {
18
18
  },
19
19
  rules: {
20
20
  '@eslint-react/dom/no-children-in-void-dom-elements': 'warn',
21
- '@eslint-react/dom/no-dangerously-set-innerhtml': 'off',
22
21
  '@eslint-react/dom/no-dangerously-set-innerhtml-with-children': 'error',
22
+ '@eslint-react/dom/no-dangerously-set-innerhtml': 'off',
23
23
  '@eslint-react/dom/no-find-dom-node': 'error',
24
+ '@eslint-react/dom/no-flush-sync': 'off',
25
+ '@eslint-react/dom/no-hydrate': 'warn',
24
26
  '@eslint-react/dom/no-missing-button-type': 'warn',
25
27
  '@eslint-react/dom/no-missing-iframe-sandbox': 'warn',
26
28
  '@eslint-react/dom/no-namespace': 'error',
27
29
  '@eslint-react/dom/no-render-return-value': 'error',
30
+ '@eslint-react/dom/no-render': 'warn',
28
31
  '@eslint-react/dom/no-script-url': 'warn',
29
32
  '@eslint-react/dom/no-unsafe-iframe-sandbox': 'warn',
30
33
  '@eslint-react/dom/no-unsafe-target-blank': 'warn',
31
-
32
- '@eslint-react/ensure-forward-ref-using-ref': 'warn',
34
+ '@eslint-react/ensure-forward-ref-using-ref': 'off',
33
35
  '@eslint-react/no-access-state-in-setstate': 'error',
34
36
  '@eslint-react/no-array-index-key': 'warn',
35
37
  '@eslint-react/no-children-count': 'warn',
@@ -47,8 +49,9 @@ function react() {
47
49
  '@eslint-react/no-direct-mutation-state': 'error',
48
50
  '@eslint-react/no-duplicate-key': 'error',
49
51
  '@eslint-react/no-implicit-key': 'error',
52
+ '@eslint-react/no-missing-context-display-name': 'off',
50
53
  '@eslint-react/no-missing-key': 'error',
51
- '@eslint-react/no-nested-components': 'warn',
54
+ '@eslint-react/no-nested-component-definitions': 'warn',
52
55
  '@eslint-react/no-redundant-should-component-update': 'error',
53
56
  '@eslint-react/no-set-state-in-component-did-mount': 'warn',
54
57
  '@eslint-react/no-set-state-in-component-did-update': 'warn',
@@ -61,6 +64,7 @@ function react() {
61
64
  '@eslint-react/no-unstable-default-props': 'error',
62
65
  '@eslint-react/no-unused-class-component-members': 'warn',
63
66
  '@eslint-react/no-unused-state': 'warn',
67
+ '@eslint-react/no-useless-forward-ref': 'warn',
64
68
  '@eslint-react/no-useless-fragment': 'warn',
65
69
  '@eslint-react/prefer-destructuring-assignment': 'warn',
66
70
  '@eslint-react/prefer-shorthand-boolean': 'warn',
@@ -72,8 +76,9 @@ function react() {
72
76
  '@eslint-react/hooks-extra/no-useless-custom-hooks': 'warn',
73
77
 
74
78
  '@eslint-react/naming-convention/component-name': 'warn',
75
- '@eslint-react/naming-convention/filename': 'off',
79
+ '@eslint-react/naming-convention/context-name': 'warn',
76
80
  '@eslint-react/naming-convention/filename-extension': ['error', { allow: 'always', extensions: ['.jsx', '.tsx'] }],
81
+ '@eslint-react/naming-convention/filename': 'off',
77
82
  '@eslint-react/naming-convention/use-state': 'off',
78
83
 
79
84
  'react-hooks/exhaustive-deps': 'warn',