@fullstacksjs/eslint-config 13.13.3 → 14.0.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
@@ -30,6 +30,7 @@ import { defineConfig } from '@fullstacksjs/eslint-config';
30
30
  export default defineConfig({
31
31
  typescript: {
32
32
  tsconfigRootDir: import.meta.dirname, // Recommended when using TypeScript
33
+ }
33
34
  });
34
35
  ```
35
36
 
@@ -182,7 +183,7 @@ import/no-deprecated
182
183
 
183
184
  ```js
184
185
  export default defineConfig({
185
- disableExpensiveRules: !process.env.CI || !process.env.HUSKY // Or anywhere you want
186
+ disableExpensiveRules: !process.env.CI || !process.env.HUSKY, // Or anywhere you want
186
187
  prettier: false // So you should run the formatter explicitly.
187
188
  });
188
189
  ```
@@ -6,12 +6,14 @@ Object.defineProperty(exports, "__esModule", {
6
6
 
7
7
  var _eslintPluginJest = _interopRequireDefault(require("eslint-plugin-jest"));
8
8
  var _globals = _interopRequireDefault(require("globals"));
9
+ var _conditions = require("../utils/conditions.js");
9
10
  var _globs = require("../utils/globs.js");
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
12
  /**
12
13
  * @param { import('../index.js').Options } options
13
14
  * @return { import('eslint').Linter.Config } */
14
- function jest() {
15
+ function jest(options = {}) {
16
+ const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
15
17
  return {
16
18
  files: _globs.globs.test,
17
19
  plugins: {
@@ -37,6 +39,10 @@ function jest() {
37
39
  'jest/no-done-callback': 'warn',
38
40
  'jest/no-expect-resolves': 'off',
39
41
  'jest/no-export': 'error',
42
+ ...(0, _conditions.predicate)(projectService, {
43
+ 'jest/no-error-equal': 'error',
44
+ 'jest/no-unnecessary-assertion': 'warn'
45
+ }),
40
46
  'jest/no-hooks': 'off',
41
47
  'jest/no-interpolation-in-snapshots': 'error',
42
48
  'jest/no-jasmine-globals': 'off',
@@ -60,6 +66,7 @@ function jest() {
60
66
  'jest/prefer-inline-snapshots': 'off',
61
67
  'jest/prefer-lowercase-title': 'off',
62
68
  'jest/prefer-mock-promise-shorthand': 'warn',
69
+ 'jest/prefer-mock-return-shorthand': 'warn',
63
70
  'jest/prefer-snapshot-hint': 'warn',
64
71
  'jest/prefer-spy-on': 'off',
65
72
  'jest/prefer-strict-equal': 'off',
@@ -48,8 +48,10 @@ function node(options = {}) {
48
48
  // Nice but not a general rule
49
49
  'n/prefer-global/buffer': 'warn',
50
50
  'n/prefer-global/console': 'warn',
51
+ 'n/prefer-global/crypto': 'warn',
51
52
  'n/prefer-global/text-decoder': 'warn',
52
53
  'n/prefer-global/text-encoder': 'warn',
54
+ 'n/prefer-global/timers': 'warn',
53
55
  'n/prefer-global/url-search-params': 'warn',
54
56
  'n/prefer-global/url': 'warn',
55
57
  'n/prefer-node-protocol': 'warn',
@@ -15,6 +15,7 @@ function playwright() {
15
15
  },
16
16
  files: _globs.globs.e2e,
17
17
  rules: {
18
+ 'playwright/consistent-spacing-between-blocks': 'warn',
18
19
  'playwright/expect-expect': 'error',
19
20
  'playwright/missing-playwright-await': 'error',
20
21
  'playwright/max-nested-describe': ['warn', {
@@ -79,9 +79,7 @@ function react(options = {}) {
79
79
  '@eslint-react/no-create-ref': 'error',
80
80
  '@eslint-react/no-direct-mutation-state': 'error',
81
81
  '@eslint-react/no-duplicate-key': 'error',
82
- '@eslint-react/no-default-props': 'warn',
83
82
  '@eslint-react/no-forward-ref': 'warn',
84
- '@eslint-react/no-implicit-key': 'error',
85
83
  '@eslint-react/no-missing-context-display-name': 'warn',
86
84
  '@eslint-react/no-missing-key': 'error',
87
85
  '@eslint-react/no-misused-capture-owner-stack': 'error',
@@ -91,7 +89,6 @@ function react(options = {}) {
91
89
  '@eslint-react/no-set-state-in-component-did-mount': 'warn',
92
90
  '@eslint-react/no-set-state-in-component-did-update': 'warn',
93
91
  '@eslint-react/no-set-state-in-component-will-update': 'warn',
94
- '@eslint-react/no-string-refs': 'error',
95
92
  '@eslint-react/dom/no-string-style-prop': 'error',
96
93
  '@eslint-react/no-unsafe-component-will-mount': 'warn',
97
94
  '@eslint-react/no-unsafe-component-will-receive-props': 'warn',
@@ -101,6 +98,7 @@ function react(options = {}) {
101
98
  '@eslint-react/no-unused-class-component-members': 'warn',
102
99
  '@eslint-react/no-unused-state': 'warn',
103
100
  ...(0, _conditions.predicate)(projectService, {
101
+ '@eslint-react/no-implicit-key': 'error',
104
102
  '@eslint-react/no-unused-props': 'warn'
105
103
  }),
106
104
  '@eslint-react/no-useless-forward-ref': 'off',
@@ -112,19 +110,20 @@ function react(options = {}) {
112
110
  '@eslint-react/no-unnecessary-key': 'warn',
113
111
  '@eslint-react/prefer-use-state-lazy-initialization': 'warn',
114
112
  '@eslint-react/prefer-destructuring-assignment': 'warn',
115
- '@eslint-react/hooks-extra/no-direct-set-state-in-use-effect': 'warn',
113
+ '@eslint-react/hooks-extra/no-direct-set-state-in-use-effect': 'off',
116
114
  '@eslint-react/naming-convention/component-name': 'warn',
117
115
  '@eslint-react/naming-convention/context-name': 'warn',
118
- '@eslint-react/naming-convention/filename-extension': ['error', {
119
- allow: 'always',
120
- extensions: ['.jsx', '.tsx']
116
+ '@eslint-react/naming-convention/id-name': 'warn',
117
+ '@eslint-react/naming-convention/ref-name': 'warn',
118
+ '@eslint-react/naming-convention/use-state': ['warn', {
119
+ enforceAssignment: true,
120
+ enforceSetterName: false
121
121
  }],
122
- '@eslint-react/naming-convention/filename': 'off',
123
- '@eslint-react/naming-convention/use-state': 'off',
124
122
  '@eslint-react/web-api/no-leaked-timeout': 'error',
125
123
  '@eslint-react/web-api/no-leaked-event-listener': 'error',
126
124
  '@eslint-react/web-api/no-leaked-interval': 'error',
127
125
  '@eslint-react/web-api/no-leaked-resize-observer': 'error',
126
+ '@eslint-react/rsc/function-definition': 'error',
128
127
  'react-hooks/rules-of-hooks': 'error',
129
128
  'react-hooks/exhaustive-deps': 'warn',
130
129
  'react-hooks/config': 'error',
@@ -28,6 +28,7 @@ async function tailwind(options = {}) {
28
28
  'better-tailwindcss/no-deprecated-classes': 'warn',
29
29
  'better-tailwindcss/no-conflicting-classes': 'error',
30
30
  'better-tailwindcss/no-unnecessary-whitespace': 'warn',
31
+ 'better-tailwindcss/enforce-canonical-classes': 'warn',
31
32
  'better-tailwindcss/enforce-consistent-class-order': 'warn',
32
33
  'better-tailwindcss/enforce-consistent-variable-syntax': 'error',
33
34
  'better-tailwindcss/enforce-shorthand-classes': 'warn',
@@ -128,8 +128,7 @@ function typescript(options = {}) {
128
128
  classes: true
129
129
  }],
130
130
  '@typescript-eslint/no-useless-constructor': 'error',
131
- '@typescript-eslint/no-useless-default-assignment': 'off',
132
- // Re-enable after fix https://github.com/typescript-eslint/typescript-eslint/issues/11849
131
+ '@typescript-eslint/no-useless-default-assignment': 'warn',
133
132
  '@typescript-eslint/no-useless-empty-export': 'warn',
134
133
  '@typescript-eslint/parameter-properties': 'off',
135
134
  '@typescript-eslint/prefer-as-const': 'warn',
@@ -65,6 +65,7 @@ function vitest() {
65
65
  'vitest/no-standalone-expect': 'warn',
66
66
  'vitest/no-test-prefixes': 'warn',
67
67
  'vitest/no-test-return-statement': 'warn',
68
+ 'vitest/no-unneeded-async-expect-function': 'warn',
68
69
  'vitest/prefer-called-once': 'warn',
69
70
  'vitest/prefer-called-times': 'off',
70
71
  'vitest/prefer-called-with': 'warn',
@@ -79,6 +80,7 @@ function vitest() {
79
80
  'vitest/prefer-importing-vitest-globals': 'off',
80
81
  'vitest/prefer-lowercase-title': 'warn',
81
82
  'vitest/prefer-mock-promise-shorthand': 'warn',
83
+ 'vitest/prefer-mock-return-shorthand': 'warn',
82
84
  'vitest/prefer-snapshot-hint': 'warn',
83
85
  'vitest/prefer-spy-on': 'warn',
84
86
  'vitest/prefer-strict-boolean-matchers': 'off',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullstacksjs/eslint-config",
3
- "version": "13.13.3",
3
+ "version": "14.0.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.7.0",
19
+ "packageManager": "npm@11.10.0",
20
20
  "scripts": {
21
21
  "lint": "eslint .",
22
22
  "spell": "cspell ./* --no-progress",
@@ -37,54 +37,55 @@
37
37
  }
38
38
  },
39
39
  "dependencies": {
40
- "@eslint-react/eslint-plugin": "2.3.13",
41
- "@eslint/compat": "2.0.0",
42
- "@next/eslint-plugin-next": "16.0.10",
43
- "@stylistic/eslint-plugin": "5.6.1",
44
- "@vitest/eslint-plugin": "1.5.2",
40
+ "@eslint-react/eslint-plugin": "2.13.0",
41
+ "@eslint/compat": "2.0.2",
42
+ "@next/eslint-plugin-next": "16.1.6",
43
+ "@stylistic/eslint-plugin": "5.8.0",
44
+ "@vitest/eslint-plugin": "1.6.9",
45
45
  "deepmerge": "4.3.1",
46
- "eslint-plugin-better-tailwindcss": "3.8.0",
47
- "eslint-plugin-cypress": "5.2.0",
46
+ "eslint-plugin-better-tailwindcss": "4.3.0",
47
+ "eslint-plugin-cypress": "5.3.0",
48
48
  "eslint-plugin-import-x": "4.16.1",
49
- "eslint-plugin-jest": "29.5.0",
49
+ "eslint-plugin-jest": "29.15.0",
50
50
  "eslint-plugin-jsx-a11y": "6.10.2",
51
- "eslint-plugin-n": "17.23.1",
52
- "eslint-plugin-perfectionist": "5.0.0",
53
- "eslint-plugin-playwright": "2.4.0",
54
- "eslint-plugin-prettier": "5.5.4",
51
+ "eslint-plugin-n": "17.24.0",
52
+ "eslint-plugin-perfectionist": "5.5.0",
53
+ "eslint-plugin-playwright": "2.5.1",
54
+ "eslint-plugin-prettier": "5.5.5",
55
55
  "eslint-plugin-promise": "7.2.1",
56
56
  "eslint-plugin-react-hooks": "7.0.1",
57
- "eslint-plugin-regexp": "2.10.0",
58
- "eslint-plugin-storybook": "10.1.10",
59
- "globals": "16.5.0",
57
+ "eslint-plugin-regexp": "3.0.0",
58
+ "eslint-plugin-storybook": "10.2.9",
59
+ "globals": "17.3.0",
60
60
  "local-pkg": "1.1.2",
61
- "typescript-eslint": "8.50.0"
61
+ "typescript-eslint": "8.56.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@eslint/eslintrc": "3.3.3",
65
65
  "@eslint/js": "9.39.2",
66
- "@semantic-release/github": "12.0.2",
67
- "@semantic-release/npm": "13.1.3",
66
+ "@semantic-release/github": "12.0.6",
67
+ "@semantic-release/npm": "13.1.4",
68
68
  "@semantic-release/release-notes-generator": "14.1.0",
69
69
  "@types/eslint": "9.6.1",
70
- "cspell": "9.4.0",
70
+ "cspell": "9.6.4",
71
71
  "eslint": "9.39.2",
72
72
  "husky": "9.1.7",
73
73
  "jest": "30.2.0",
74
74
  "lint-staged": "16.2.7",
75
75
  "pinst": "3.0.0",
76
- "prettier": "3.7.4",
77
- "semantic-release": "25.0.2",
78
- "storybook": "10.1.10",
76
+ "prettier": "3.8.1",
77
+ "semantic-release": "25.0.3",
78
+ "storybook": "10.2.9",
79
79
  "typescript": "5.9.3",
80
80
  "unbuild": "3.6.1"
81
81
  },
82
82
  "peerDependencies": {
83
83
  "cypress": ">=8",
84
- "eslint": ">=9.22",
85
- "prettier": "3",
86
- "react": ">=16",
87
- "typescript": ">=4.7"
84
+ "eslint": ">=9.38",
85
+ "prettier": ">=3",
86
+ "react": ">=18",
87
+ "tailwindcss": ">=3.3.0",
88
+ "typescript": ">=5"
88
89
  },
89
90
  "peerDependenciesMeta": {
90
91
  "typescript": {
@@ -1,12 +1,15 @@
1
1
  import plugin from 'eslint-plugin-jest';
2
2
  import globals from 'globals';
3
3
 
4
+ import { predicate } from '../utils/conditions.mjs';
4
5
  import { globs } from '../utils/globs.mjs';
5
6
 
6
7
  /**
7
8
  * @param { import('..').Options } options
8
9
  * @return { import('eslint').Linter.Config } */
9
- function jest() {
10
+ function jest(options = {}) {
11
+ const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
12
+
10
13
  return {
11
14
  files: globs.test,
12
15
  plugins: { jest: plugin },
@@ -28,6 +31,10 @@ function jest() {
28
31
  'jest/no-done-callback': 'warn',
29
32
  'jest/no-expect-resolves': 'off',
30
33
  'jest/no-export': 'error',
34
+ ...predicate(projectService, {
35
+ 'jest/no-error-equal': 'error',
36
+ 'jest/no-unnecessary-assertion': 'warn',
37
+ }),
31
38
  'jest/no-hooks': 'off',
32
39
  'jest/no-interpolation-in-snapshots': 'error',
33
40
  'jest/no-jasmine-globals': 'off',
@@ -49,6 +56,7 @@ function jest() {
49
56
  'jest/prefer-inline-snapshots': 'off',
50
57
  'jest/prefer-lowercase-title': 'off',
51
58
  'jest/prefer-mock-promise-shorthand': 'warn',
59
+ 'jest/prefer-mock-return-shorthand': 'warn',
52
60
  'jest/prefer-snapshot-hint': 'warn',
53
61
  'jest/prefer-spy-on': 'off',
54
62
  'jest/prefer-strict-equal': 'off',
@@ -35,8 +35,10 @@ function node(options = {}) {
35
35
  'n/no-unsupported-features/node-builtins': 'off', // Nice but not a general rule
36
36
  'n/prefer-global/buffer': 'warn',
37
37
  'n/prefer-global/console': 'warn',
38
+ 'n/prefer-global/crypto': 'warn',
38
39
  'n/prefer-global/text-decoder': 'warn',
39
40
  'n/prefer-global/text-encoder': 'warn',
41
+ 'n/prefer-global/timers': 'warn',
40
42
  'n/prefer-global/url-search-params': 'warn',
41
43
  'n/prefer-global/url': 'warn',
42
44
  'n/prefer-node-protocol': 'warn',
@@ -8,6 +8,7 @@ function playwright() {
8
8
  plugins: { playwright: plugin },
9
9
  files: globs.e2e,
10
10
  rules: {
11
+ 'playwright/consistent-spacing-between-blocks': 'warn',
11
12
  'playwright/expect-expect': 'error',
12
13
  'playwright/missing-playwright-await': 'error',
13
14
  'playwright/max-nested-describe': ['warn', { max: 5 }],
@@ -75,9 +75,7 @@ function react(options = {}) {
75
75
  '@eslint-react/no-create-ref': 'error',
76
76
  '@eslint-react/no-direct-mutation-state': 'error',
77
77
  '@eslint-react/no-duplicate-key': 'error',
78
- '@eslint-react/no-default-props': 'warn',
79
78
  '@eslint-react/no-forward-ref': 'warn',
80
- '@eslint-react/no-implicit-key': 'error',
81
79
  '@eslint-react/no-missing-context-display-name': 'warn',
82
80
  '@eslint-react/no-missing-key': 'error',
83
81
  '@eslint-react/no-misused-capture-owner-stack': 'error',
@@ -87,7 +85,6 @@ function react(options = {}) {
87
85
  '@eslint-react/no-set-state-in-component-did-mount': 'warn',
88
86
  '@eslint-react/no-set-state-in-component-did-update': 'warn',
89
87
  '@eslint-react/no-set-state-in-component-will-update': 'warn',
90
- '@eslint-react/no-string-refs': 'error',
91
88
  '@eslint-react/dom/no-string-style-prop': 'error',
92
89
  '@eslint-react/no-unsafe-component-will-mount': 'warn',
93
90
  '@eslint-react/no-unsafe-component-will-receive-props': 'warn',
@@ -97,6 +94,7 @@ function react(options = {}) {
97
94
  '@eslint-react/no-unused-class-component-members': 'warn',
98
95
  '@eslint-react/no-unused-state': 'warn',
99
96
  ...predicate(projectService, {
97
+ '@eslint-react/no-implicit-key': 'error',
100
98
  '@eslint-react/no-unused-props': 'warn',
101
99
  }),
102
100
  '@eslint-react/no-useless-forward-ref': 'off',
@@ -110,19 +108,27 @@ function react(options = {}) {
110
108
  '@eslint-react/prefer-use-state-lazy-initialization': 'warn',
111
109
  '@eslint-react/prefer-destructuring-assignment': 'warn',
112
110
 
113
- '@eslint-react/hooks-extra/no-direct-set-state-in-use-effect': 'warn',
111
+ '@eslint-react/hooks-extra/no-direct-set-state-in-use-effect': 'off',
114
112
 
115
113
  '@eslint-react/naming-convention/component-name': 'warn',
116
114
  '@eslint-react/naming-convention/context-name': 'warn',
117
- '@eslint-react/naming-convention/filename-extension': ['error', { allow: 'always', extensions: ['.jsx', '.tsx'] }],
118
- '@eslint-react/naming-convention/filename': 'off',
119
- '@eslint-react/naming-convention/use-state': 'off',
115
+ '@eslint-react/naming-convention/id-name': 'warn',
116
+ '@eslint-react/naming-convention/ref-name': 'warn',
117
+ '@eslint-react/naming-convention/use-state': [
118
+ 'warn',
119
+ {
120
+ enforceAssignment: true,
121
+ enforceSetterName: false,
122
+ },
123
+ ],
120
124
 
121
125
  '@eslint-react/web-api/no-leaked-timeout': 'error',
122
126
  '@eslint-react/web-api/no-leaked-event-listener': 'error',
123
127
  '@eslint-react/web-api/no-leaked-interval': 'error',
124
128
  '@eslint-react/web-api/no-leaked-resize-observer': 'error',
125
129
 
130
+ '@eslint-react/rsc/function-definition': 'error',
131
+
126
132
  'react-hooks/rules-of-hooks': 'error',
127
133
  'react-hooks/exhaustive-deps': 'warn',
128
134
 
@@ -20,6 +20,7 @@ async function tailwind(options = {}) {
20
20
  'better-tailwindcss/no-deprecated-classes': 'warn',
21
21
  'better-tailwindcss/no-conflicting-classes': 'error',
22
22
  'better-tailwindcss/no-unnecessary-whitespace': 'warn',
23
+ 'better-tailwindcss/enforce-canonical-classes': 'warn',
23
24
  'better-tailwindcss/enforce-consistent-class-order': 'warn',
24
25
  'better-tailwindcss/enforce-consistent-variable-syntax': 'error',
25
26
  'better-tailwindcss/enforce-shorthand-classes': 'warn',
@@ -117,7 +117,7 @@ function typescript(options = {}) {
117
117
  ],
118
118
  '@typescript-eslint/no-use-before-define': ['error', { functions: false, classes: true }],
119
119
  '@typescript-eslint/no-useless-constructor': 'error',
120
- '@typescript-eslint/no-useless-default-assignment': 'off', // Re-enable after fix https://github.com/typescript-eslint/typescript-eslint/issues/11849
120
+ '@typescript-eslint/no-useless-default-assignment': 'warn',
121
121
  '@typescript-eslint/no-useless-empty-export': 'warn',
122
122
  '@typescript-eslint/parameter-properties': 'off',
123
123
  '@typescript-eslint/prefer-as-const': 'warn',
@@ -58,6 +58,7 @@ function vitest() {
58
58
  'vitest/no-standalone-expect': 'warn',
59
59
  'vitest/no-test-prefixes': 'warn',
60
60
  'vitest/no-test-return-statement': 'warn',
61
+ 'vitest/no-unneeded-async-expect-function': 'warn',
61
62
 
62
63
  'vitest/prefer-called-once': 'warn',
63
64
  'vitest/prefer-called-times': 'off',
@@ -73,6 +74,7 @@ function vitest() {
73
74
  'vitest/prefer-importing-vitest-globals': 'off',
74
75
  'vitest/prefer-lowercase-title': 'warn',
75
76
  'vitest/prefer-mock-promise-shorthand': 'warn',
77
+ 'vitest/prefer-mock-return-shorthand': 'warn',
76
78
  'vitest/prefer-snapshot-hint': 'warn',
77
79
  'vitest/prefer-spy-on': 'warn',
78
80
  'vitest/prefer-strict-boolean-matchers': 'off',