@fullstacksjs/eslint-config 13.8.2 → 13.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
@@ -51,7 +51,7 @@ You can fine-tune module detection by overriding it, the `defineConfig` function
51
51
  ```typescript
52
52
  interface Options {
53
53
  react?: boolean | { additionalEffectHooks?: string }; // controls react, react-hooks, jsx/a11y plugins
54
- typescript?: ParserOptions // https://typescript-eslint.io/packages/parser#configuration
54
+ typescript?: boolean | ParserOptions // https://typescript-eslint.io/packages/parser#configuration
55
55
  node?: boolean; // controls node plugin
56
56
  sort?: boolean; // controls perfectionist plugin
57
57
  strict?: boolean; // controls strict rules
package/cjs/index.d.ts CHANGED
@@ -93,7 +93,7 @@ export interface Options extends Linter.Config {
93
93
  * Controls [TypeScript plugin](https://www.npmjs.com/package/typescript-eslint).
94
94
  * @default true - If you have `typescript` in your dependencies.
95
95
  */
96
- typescript?: { projectService?: boolean | ProjectService; tsconfigRootDir?: string; cacheLifetime?: number };
96
+ typescript?: boolean | { projectService?: boolean | ProjectService; tsconfigRootDir?: string; cacheLifetime?: number };
97
97
  /**
98
98
  * Disables expensive rules.
99
99
  * @default false
@@ -111,7 +111,7 @@ export interface Options extends Linter.Config {
111
111
  gitignore?: string | false;
112
112
  /**
113
113
  * Controls regex plugin.
114
- * @default true
114
+ * @default { allowedCharacterRanges: ['all'] }
115
115
  */
116
116
  regex?: boolean | { allowedCharacterRanges: string[] };
117
117
  }
@@ -57,7 +57,7 @@ function base(options = {}) {
57
57
  skipComments: false
58
58
  }],
59
59
  'max-nested-callbacks': ['error', 7],
60
- 'max-params': ['error', 7],
60
+ 'max-params': ['error', 3],
61
61
  'max-statements': ['error', 40],
62
62
  'no-alert': 'error',
63
63
  'no-array-constructor': 'error',
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
 
7
7
  var _eslintPluginJest = _interopRequireDefault(require("eslint-plugin-jest"));
8
+ var _globals = _interopRequireDefault(require("globals"));
8
9
  var _globs = require("../utils/globs.js");
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
11
  /**
@@ -16,6 +17,11 @@ function jest() {
16
17
  plugins: {
17
18
  jest: _eslintPluginJest.default
18
19
  },
20
+ languageOptions: {
21
+ globals: {
22
+ ..._globals.default.jest
23
+ }
24
+ },
19
25
  rules: {
20
26
  'jest/consistent-test-it': 'off',
21
27
  'jest/expect-expect': 'off',
@@ -22,7 +22,7 @@ function next() {
22
22
  'next/no-before-interactive-script-outside-document': 'warn',
23
23
  'next/no-css-tags': 'warn',
24
24
  'next/no-document-import-in-page': 'warn',
25
- // 'next/no-duplicate-head': 'warn',
25
+ 'next/no-duplicate-head': 'warn',
26
26
  'next/no-head-element': 'warn',
27
27
  'next/no-head-import-in-document': 'warn',
28
28
  'next/no-html-link-for-pages': 'warn',
@@ -15,9 +15,6 @@ function playwright() {
15
15
  },
16
16
  files: _globs.globs.e2e,
17
17
  rules: {
18
- 'jest/no-standalone-expect': ['error', {
19
- additionalTestBlockFunctions: ['test.jestPlaywrightDebug', 'it.jestPlaywrightDebug', 'test.jestPlaywrightSkip', 'it.jestPlaywrightSkip', 'test.jestPlaywrightConfig', 'it.jestPlaywrightConfig']
20
- }],
21
18
  'playwright/expect-expect': 'error',
22
19
  'playwright/missing-playwright-await': 'error',
23
20
  'playwright/max-nested-describe': ['warn', {
@@ -39,6 +36,7 @@ function playwright() {
39
36
  'playwright/no-useless-await': 'error',
40
37
  'playwright/no-unsafe-references': 'warn',
41
38
  'playwright/no-useless-not': 'warn',
39
+ 'playwright/no-unused-locators': 'warn',
42
40
  'playwright/no-wait-for-navigation': 'warn',
43
41
  'playwright/no-wait-for-selector': 'warn',
44
42
  'playwright/no-wait-for-timeout': 'warn',
@@ -35,21 +35,21 @@ function prettier() {
35
35
  '@typescript-eslint/space-before-function-paren': 'off',
36
36
  '@typescript-eslint/space-infix-ops': 'off',
37
37
  '@typescript-eslint/type-annotation-spacing': 'off',
38
- 'react/jsx-child-element-spacing': 'off',
39
- 'react/jsx-closing-bracket-location': 'off',
40
- 'react/jsx-closing-tag-location': 'off',
41
- 'react/jsx-curly-newline': 'off',
42
- 'react/jsx-curly-spacing': 'off',
43
- 'react/jsx-equals-spacing': 'off',
44
- 'react/jsx-first-prop-new-line': 'off',
45
- 'react/jsx-indent': 'off',
46
- 'react/jsx-indent-props': 'off',
47
- 'react/jsx-max-props-per-line': 'off',
48
- 'react/jsx-newline': 'off',
49
- 'react/jsx-one-expression-per-line': 'off',
50
- 'react/jsx-props-no-multi-spaces': 'off',
51
- 'react/jsx-tag-spacing': 'off',
52
- 'react/jsx-wrap-multilines': 'off',
38
+ '@stylistic/jsx-child-element-spacing': 'off',
39
+ '@stylistic/jsx-closing-bracket-location': 'off',
40
+ '@stylistic/jsx-closing-tag-location': 'off',
41
+ '@stylistic/jsx-curly-newline': 'off',
42
+ '@stylistic/jsx-curly-spacing': 'off',
43
+ '@stylistic/jsx-equals-spacing': 'off',
44
+ '@stylistic/jsx-first-prop-new-line': 'off',
45
+ '@stylistic/jsx-indent': 'off',
46
+ '@stylistic/jsx-indent-props': 'off',
47
+ '@stylistic/jsx-max-props-per-line': 'off',
48
+ '@stylistic/jsx-newline': 'off',
49
+ '@stylistic/jsx-one-expression-per-line': 'off',
50
+ '@stylistic/jsx-props-no-multi-spaces': 'off',
51
+ '@stylistic/jsx-tag-spacing': 'off',
52
+ '@stylistic/jsx-wrap-multilines': 'off',
53
53
  'vue/html-self-closing': 'off',
54
54
  'vue/max-len': 'off',
55
55
  'vue/array-bracket-newline': 'off',
@@ -5,9 +5,10 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
 
7
7
  var _eslintPluginPromise = _interopRequireDefault(require("eslint-plugin-promise"));
8
+ var _conditions = require("../utils/conditions.js");
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
10
  /** @return { import('eslint').Linter.Config } */
10
- function promise() {
11
+ function promise(options = {}) {
11
12
  return {
12
13
  plugins: {
13
14
  promise: _eslintPluginPromise.default
@@ -26,8 +27,10 @@ function promise() {
26
27
  'promise/param-names': 'warn',
27
28
  'promise/prefer-await-to-callbacks': 'off',
28
29
  'promise/prefer-await-to-then': 'off',
30
+ 'promise/prefer-catch': (0, _conditions.strict)(options, 'warn'),
29
31
  'promise/valid-params': 'warn',
30
- 'promise/no-multiple-resolved': 'warn'
32
+ 'promise/no-multiple-resolved': 'warn',
33
+ 'promise/spec-only': 'warn'
31
34
  }
32
35
  };
33
36
  }
@@ -7,17 +7,28 @@ Object.defineProperty(exports, "__esModule", {
7
7
  var _eslintPlugin = _interopRequireDefault(require("@eslint-react/eslint-plugin"));
8
8
  var _eslintPluginJsxA11y = _interopRequireDefault(require("eslint-plugin-jsx-a11y"));
9
9
  var _eslintPluginReactHooks = _interopRequireDefault(require("eslint-plugin-react-hooks"));
10
+ var _typescriptEslint = require("typescript-eslint");
10
11
  var _conditions = require("../utils/conditions.js");
12
+ var _globs = require("../utils/globs.js");
11
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
14
  /** @return { import('eslint').Linter.Config } */
13
15
  function react(options = {}) {
14
16
  const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
15
17
  return {
18
+ files: [_globs.globs.js, _globs.globs.jsx, _globs.globs.ts, _globs.globs.tsx],
16
19
  plugins: {
17
20
  ..._eslintPlugin.default.configs.all.plugins,
18
21
  'react-hooks': _eslintPluginReactHooks.default,
19
22
  'jsx-a11y': _eslintPluginJsxA11y.default
20
23
  },
24
+ ...(0, _conditions.predicate)(projectService, {
25
+ languageOptions: {
26
+ parser: _typescriptEslint.parser,
27
+ parserOptions: {
28
+ ...options.typescript
29
+ }
30
+ }
31
+ }),
21
32
  settings: {
22
33
  'react': {
23
34
  pragma: 'React',
@@ -43,6 +54,7 @@ function react(options = {}) {
43
54
  '@eslint-react/dom/no-script-url': 'warn',
44
55
  '@eslint-react/dom/no-unsafe-iframe-sandbox': 'warn',
45
56
  '@eslint-react/dom/no-unsafe-target-blank': 'warn',
57
+ '@eslint-react/jsx-dollar': 'warn',
46
58
  '@eslint-react/jsx-key-before-spread': 'error',
47
59
  '@eslint-react/jsx-no-undef': 'off',
48
60
  '@eslint-react/jsx-no-iife': 'warn',
@@ -32,7 +32,7 @@ function storybook() {
32
32
  'storybook/no-title-property-in-meta': 'off',
33
33
  // Conflicts
34
34
  '@typescript-eslint/no-confusing-void-expression': 'off',
35
- 'react/jsx-no-useless-fragment': 'off',
35
+ '@eslint-react/no-useless-fragment': 'off',
36
36
  'react-hooks/rules-of-hooks': 'off'
37
37
  }
38
38
  };
@@ -13,31 +13,25 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
13
13
  * @param { import('../index.js').Options } options
14
14
  * @return { import('eslint').Linter.Config }
15
15
  */
16
+
16
17
  function tests(options = {}) {
17
18
  return {
19
+ files: [..._globs.globs.test, ..._globs.globs.e2e],
18
20
  plugins: {
19
21
  vitest: _eslintPlugin.default
20
22
  },
21
- files: [..._globs.globs.test, ..._globs.globs.e2e],
22
23
  languageOptions: {
23
24
  globals: {
24
- ..._globals.default['shared-node-browser'],
25
- ..._globals.default.jest
25
+ ..._globals.default['shared-node-browser']
26
26
  }
27
27
  },
28
28
  rules: {
29
- 'vitest/padding-around-after-all-blocks': 'warn',
30
- 'vitest/padding-around-after-each-blocks': 'warn',
31
- 'vitest/padding-around-before-all-blocks': 'warn',
32
- 'vitest/padding-around-before-each-blocks': 'warn',
33
- 'vitest/padding-around-describe-blocks': 'warn',
34
- 'vitest/padding-around-expect-groups': 'warn',
35
- 'vitest/padding-around-test-blocks': 'warn',
36
29
  'max-lines-per-function': 'off',
37
30
  'no-sparse-arrays': 'off',
38
31
  'no-empty-function': 'off',
32
+ 'vitest/padding-around-all': 'warn',
39
33
  ...(0, _conditions.predicate)(options.react, {
40
- 'react/jsx-no-constructed-context-values': 'off'
34
+ '@eslint-react/no-unstable-context-value': 'off'
41
35
  }),
42
36
  ...(0, _conditions.predicate)(options.typescript, {
43
37
  '@typescript-eslint/method-signature-style': 'off',
@@ -39,7 +39,7 @@ function typescript(options = {}) {
39
39
  '@typescript-eslint/camelcase': 'off',
40
40
  '@typescript-eslint/class-literal-property-style': ['error', 'getters'],
41
41
  '@typescript-eslint/consistent-generic-constructors': ['warn', 'constructor'],
42
- '@typescript-eslint/consistent-indexed-object-style': 'off',
42
+ '@typescript-eslint/consistent-indexed-object-style': 'warn',
43
43
  '@typescript-eslint/consistent-type-assertions': 'error',
44
44
  '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
45
45
  '@typescript-eslint/consistent-type-imports': ['warn', {
@@ -71,7 +71,7 @@ function typescript(options = {}) {
71
71
  '@typescript-eslint/no-empty-object-type': ['warn', {
72
72
  allowInterfaces: 'with-single-extends'
73
73
  }],
74
- '@typescript-eslint/no-explicit-any': 'off',
74
+ '@typescript-eslint/no-explicit-any': (0, _conditions.strict)(options, 'warn'),
75
75
  '@typescript-eslint/no-extra-non-null-assertion': 'error',
76
76
  '@typescript-eslint/no-extraneous-class': ['warn', {
77
77
  allowWithDecorator: true
@@ -105,12 +105,14 @@ function typescript(options = {}) {
105
105
  '@typescript-eslint/no-this-alias': 'error',
106
106
  '@typescript-eslint/no-type-alias': 'off',
107
107
  '@typescript-eslint/no-unnecessary-type-constraint': 'warn',
108
- '@typescript-eslint/no-unsafe-argument': 'off',
109
- '@typescript-eslint/no-unsafe-assignment': 'off',
110
- '@typescript-eslint/no-unsafe-call': 'off',
108
+ '@typescript-eslint/no-unsafe-argument': (0, _conditions.strict)(options, 'warn'),
109
+ '@typescript-eslint/no-unsafe-assignment': (0, _conditions.strict)(options, 'warn'),
110
+ '@typescript-eslint/no-unsafe-call': (0, _conditions.strict)(options, 'warn'),
111
111
  '@typescript-eslint/no-unsafe-declaration-merging': 'warn',
112
- '@typescript-eslint/no-unsafe-member-access': 'off',
113
- '@typescript-eslint/no-unsafe-return': 'off',
112
+ '@typescript-eslint/no-unsafe-member-access': (0, _conditions.strict)(options, ['warn', {
113
+ allowOptionalChaining: true
114
+ }]),
115
+ '@typescript-eslint/no-unsafe-return': (0, _conditions.strict)(options, 'warn'),
114
116
  '@typescript-eslint/no-untyped-public-signature': 'off',
115
117
  '@typescript-eslint/no-unused-expressions': 'error',
116
118
  '@typescript-eslint/no-unused-vars': ['warn', {
@@ -197,6 +199,7 @@ function typescript(options = {}) {
197
199
  '@typescript-eslint/no-unnecessary-type-conversion': 'error',
198
200
  '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
199
201
  '@typescript-eslint/no-unsafe-enum-comparison': 'warn',
202
+ '@typescript-eslint/no-unsafe-function-type': 'warn',
200
203
  '@typescript-eslint/no-unnecessary-condition': ['warn', {
201
204
  allowConstantLoopConditions: false
202
205
  }],
@@ -243,10 +246,6 @@ function typescript(options = {}) {
243
246
  'prefer-promise-reject-errors': 'off',
244
247
  'consistent-return': 'off'
245
248
  }),
246
- // open issues
247
- 'react/jsx-no-useless-fragment': 'off',
248
- // Need useless-fragment for JSX return type
249
-
250
249
  // Conflicts with @typescript-eslint
251
250
  'no-empty-function': 'off',
252
251
  'default-case': 'off',
@@ -95,11 +95,13 @@ function vitest() {
95
95
  'vitest/require-local-test-context-for-concurrent-snapshots': 'warn',
96
96
  'vitest/require-mock-type-parameters': 'off',
97
97
  'vitest/require-to-throw-message': 'warn',
98
- 'vitest/require-top-level-describe': 'warn',
98
+ 'vitest/require-top-level-describe': 'off',
99
99
  'vitest/valid-describe-callback': 'warn',
100
100
  'vitest/valid-expect': 'warn',
101
101
  'vitest/valid-expect-in-promise': 'warn',
102
- 'vitest/valid-title': 'warn',
102
+ 'vitest/valid-title': ['warn', {
103
+ allowArguments: true
104
+ }],
103
105
  'vitest/warn-todo': 'warn'
104
106
  }
105
107
  };
@@ -29,7 +29,7 @@ const globs = exports.globs = {
29
29
  html: '**/*.html',
30
30
  astro: '**/*.astro',
31
31
  graphql: '**/*.{gql,graphql}',
32
- storybook: ['**/*.stories.{js,jsx,ts,tsx}'],
32
+ storybook: ['**/*.stories.{js,mjs,cjs,jsx,ts,tsx}'],
33
33
  test: [`**/__tests__/*.${srcExt}`, `**/*.spec.${srcExt}`, `**/*.test.${srcExt}`],
34
34
  e2e: [`**/e2e/*.${srcExt}`]
35
35
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullstacksjs/eslint-config",
3
- "version": "13.8.2",
3
+ "version": "13.10.0",
4
4
  "license": "MIT",
5
5
  "author": "fullstacks <fullstacksjs@gmail.com>",
6
6
  "description": "fullstacks eslint config",
@@ -35,45 +35,46 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@eslint-react/eslint-plugin": "2.0.6",
39
- "@eslint/compat": "1.4.0",
40
- "@next/eslint-plugin-next": "15.5.4",
41
- "@stylistic/eslint-plugin": "5.4.0",
42
- "@vitest/eslint-plugin": "1.3.13",
38
+ "@eslint-react/eslint-plugin": "2.3.1",
39
+ "@eslint/compat": "1.4.1",
40
+ "@next/eslint-plugin-next": "16.0.1",
41
+ "@stylistic/eslint-plugin": "5.5.0",
42
+ "@vitest/eslint-plugin": "1.4.1",
43
43
  "deepmerge": "4.3.1",
44
- "eslint-plugin-better-tailwindcss": "3.7.9",
45
- "eslint-plugin-cypress": "5.1.1",
44
+ "eslint-plugin-better-tailwindcss": "3.7.10",
45
+ "eslint-plugin-cypress": "5.2.0",
46
46
  "eslint-plugin-import-x": "4.16.1",
47
47
  "eslint-plugin-jest": "29.0.1",
48
48
  "eslint-plugin-jsx-a11y": "6.10.2",
49
49
  "eslint-plugin-n": "17.23.1",
50
- "eslint-plugin-perfectionist": "4.15.0",
51
- "eslint-plugin-playwright": "2.2.2",
50
+ "eslint-plugin-perfectionist": "4.15.1",
51
+ "eslint-plugin-playwright": "2.3.0",
52
52
  "eslint-plugin-prettier": "5.5.4",
53
53
  "eslint-plugin-promise": "7.2.1",
54
- "eslint-plugin-react-hooks": "7.0.0",
54
+ "eslint-plugin-react-hooks": "7.0.1",
55
55
  "eslint-plugin-regexp": "2.10.0",
56
- "eslint-plugin-storybook": "0.12.0",
57
- "globals": "16.4.0",
56
+ "eslint-plugin-storybook": "10.0.6",
57
+ "globals": "16.5.0",
58
58
  "local-pkg": "1.1.2",
59
- "typescript-eslint": "8.44.1"
59
+ "typescript-eslint": "8.46.3"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@eslint/eslintrc": "3.3.1",
63
- "@eslint/js": "9.36.0",
64
- "@semantic-release/github": "11.0.6",
65
- "@semantic-release/npm": "12.0.2",
63
+ "@eslint/js": "9.39.1",
64
+ "@semantic-release/github": "12.0.1",
65
+ "@semantic-release/npm": "13.1.1",
66
66
  "@semantic-release/release-notes-generator": "14.1.0",
67
67
  "@types/eslint": "9.6.1",
68
- "cspell": "9.2.1",
69
- "eslint": "9.36.0",
68
+ "cspell": "9.3.0",
69
+ "eslint": "9.39.1",
70
70
  "husky": "9.1.7",
71
- "jest": "30.1.3",
72
- "lint-staged": "16.2.1",
71
+ "jest": "30.2.0",
72
+ "lint-staged": "16.2.6",
73
73
  "pinst": "3.0.0",
74
74
  "prettier": "3.6.2",
75
- "semantic-release": "24.2.9",
76
- "typescript": "5.9.2",
75
+ "semantic-release": "25.0.2",
76
+ "storybook": "10.0.6",
77
+ "typescript": "5.9.3",
77
78
  "unbuild": "3.6.1"
78
79
  },
79
80
  "peerDependencies": {
@@ -96,5 +97,9 @@
96
97
  "jest": {
97
98
  "optional": true
98
99
  }
100
+ },
101
+ "volta": {
102
+ "node": "22.20.0",
103
+ "npm": "11.6.2"
99
104
  }
100
105
  }
package/src/index.d.ts CHANGED
@@ -93,7 +93,7 @@ export interface Options extends Linter.Config {
93
93
  * Controls [TypeScript plugin](https://www.npmjs.com/package/typescript-eslint).
94
94
  * @default true - If you have `typescript` in your dependencies.
95
95
  */
96
- typescript?: { projectService?: boolean | ProjectService; tsconfigRootDir?: string; cacheLifetime?: number };
96
+ typescript?: boolean | { projectService?: boolean | ProjectService; tsconfigRootDir?: string; cacheLifetime?: number };
97
97
  /**
98
98
  * Disables expensive rules.
99
99
  * @default false
@@ -111,7 +111,7 @@ export interface Options extends Linter.Config {
111
111
  gitignore?: string | false;
112
112
  /**
113
113
  * Controls regex plugin.
114
- * @default true
114
+ * @default { allowedCharacterRanges: ['all'] }
115
115
  */
116
116
  regex?: boolean | { allowedCharacterRanges: string[] };
117
117
  }
@@ -45,7 +45,7 @@ function base(options = {}) {
45
45
  'max-lines-per-function': ['error', 150],
46
46
  'max-lines': ['error', { max: 2500, skipBlankLines: false, skipComments: false }],
47
47
  'max-nested-callbacks': ['error', 7],
48
- 'max-params': ['error', 7],
48
+ 'max-params': ['error', 3],
49
49
  'max-statements': ['error', 40],
50
50
  'no-alert': 'error',
51
51
  'no-array-constructor': 'error',
@@ -1,4 +1,5 @@
1
1
  import plugin from 'eslint-plugin-jest';
2
+ import globals from 'globals';
2
3
 
3
4
  import { globs } from '../utils/globs.mjs';
4
5
 
@@ -9,6 +10,11 @@ function jest() {
9
10
  return {
10
11
  files: globs.test,
11
12
  plugins: { jest: plugin },
13
+ languageOptions: {
14
+ globals: {
15
+ ...globals.jest,
16
+ },
17
+ },
12
18
  rules: {
13
19
  'jest/consistent-test-it': 'off',
14
20
  'jest/expect-expect': 'off',
@@ -14,7 +14,7 @@ function next() {
14
14
  'next/no-before-interactive-script-outside-document': 'warn',
15
15
  'next/no-css-tags': 'warn',
16
16
  'next/no-document-import-in-page': 'warn',
17
- // 'next/no-duplicate-head': 'warn',
17
+ 'next/no-duplicate-head': 'warn',
18
18
  'next/no-head-element': 'warn',
19
19
  'next/no-head-import-in-document': 'warn',
20
20
  'next/no-html-link-for-pages': 'warn',
@@ -8,19 +8,6 @@ function playwright() {
8
8
  plugins: { playwright: plugin },
9
9
  files: globs.e2e,
10
10
  rules: {
11
- 'jest/no-standalone-expect': [
12
- 'error',
13
- {
14
- additionalTestBlockFunctions: [
15
- 'test.jestPlaywrightDebug',
16
- 'it.jestPlaywrightDebug',
17
- 'test.jestPlaywrightSkip',
18
- 'it.jestPlaywrightSkip',
19
- 'test.jestPlaywrightConfig',
20
- 'it.jestPlaywrightConfig',
21
- ],
22
- },
23
- ],
24
11
  'playwright/expect-expect': 'error',
25
12
  'playwright/missing-playwright-await': 'error',
26
13
  'playwright/max-nested-describe': ['warn', { max: 5 }],
@@ -40,6 +27,7 @@ function playwright() {
40
27
  'playwright/no-useless-await': 'error',
41
28
  'playwright/no-unsafe-references': 'warn',
42
29
  'playwright/no-useless-not': 'warn',
30
+ 'playwright/no-unused-locators': 'warn',
43
31
  'playwright/no-wait-for-navigation': 'warn',
44
32
  'playwright/no-wait-for-selector': 'warn',
45
33
  'playwright/no-wait-for-timeout': 'warn',
@@ -30,21 +30,21 @@ function prettier() {
30
30
  '@typescript-eslint/space-infix-ops': 'off',
31
31
  '@typescript-eslint/type-annotation-spacing': 'off',
32
32
 
33
- 'react/jsx-child-element-spacing': 'off',
34
- 'react/jsx-closing-bracket-location': 'off',
35
- 'react/jsx-closing-tag-location': 'off',
36
- 'react/jsx-curly-newline': 'off',
37
- 'react/jsx-curly-spacing': 'off',
38
- 'react/jsx-equals-spacing': 'off',
39
- 'react/jsx-first-prop-new-line': 'off',
40
- 'react/jsx-indent': 'off',
41
- 'react/jsx-indent-props': 'off',
42
- 'react/jsx-max-props-per-line': 'off',
43
- 'react/jsx-newline': 'off',
44
- 'react/jsx-one-expression-per-line': 'off',
45
- 'react/jsx-props-no-multi-spaces': 'off',
46
- 'react/jsx-tag-spacing': 'off',
47
- 'react/jsx-wrap-multilines': 'off',
33
+ '@stylistic/jsx-child-element-spacing': 'off',
34
+ '@stylistic/jsx-closing-bracket-location': 'off',
35
+ '@stylistic/jsx-closing-tag-location': 'off',
36
+ '@stylistic/jsx-curly-newline': 'off',
37
+ '@stylistic/jsx-curly-spacing': 'off',
38
+ '@stylistic/jsx-equals-spacing': 'off',
39
+ '@stylistic/jsx-first-prop-new-line': 'off',
40
+ '@stylistic/jsx-indent': 'off',
41
+ '@stylistic/jsx-indent-props': 'off',
42
+ '@stylistic/jsx-max-props-per-line': 'off',
43
+ '@stylistic/jsx-newline': 'off',
44
+ '@stylistic/jsx-one-expression-per-line': 'off',
45
+ '@stylistic/jsx-props-no-multi-spaces': 'off',
46
+ '@stylistic/jsx-tag-spacing': 'off',
47
+ '@stylistic/jsx-wrap-multilines': 'off',
48
48
 
49
49
  'vue/html-self-closing': 'off',
50
50
  'vue/max-len': 'off',
@@ -1,7 +1,9 @@
1
1
  import plugin from 'eslint-plugin-promise';
2
2
 
3
+ import { strict } from '../utils/conditions.mjs';
4
+
3
5
  /** @return { import('eslint').Linter.Config } */
4
- function promise() {
6
+ function promise(options = {}) {
5
7
  return {
6
8
  plugins: { promise: plugin },
7
9
  rules: {
@@ -18,8 +20,10 @@ function promise() {
18
20
  'promise/param-names': 'warn',
19
21
  'promise/prefer-await-to-callbacks': 'off',
20
22
  'promise/prefer-await-to-then': 'off',
23
+ 'promise/prefer-catch': strict(options, 'warn'),
21
24
  'promise/valid-params': 'warn',
22
25
  'promise/no-multiple-resolved': 'warn',
26
+ 'promise/spec-only': 'warn',
23
27
  },
24
28
  };
25
29
  }
@@ -1,19 +1,28 @@
1
1
  import reactPlugin from '@eslint-react/eslint-plugin';
2
2
  import a11yPlugin from 'eslint-plugin-jsx-a11y';
3
3
  import hooksPlugin from 'eslint-plugin-react-hooks';
4
+ import { parser } from 'typescript-eslint';
4
5
 
5
6
  import { predicate } from '../utils/conditions.mjs';
7
+ import { globs } from '../utils/globs.mjs';
6
8
 
7
9
  /** @return { import('eslint').Linter.Config } */
8
10
  function react(options = {}) {
9
11
  const projectService = options.typescript && options.typescript.tsconfigRootDir && options.typescript.projectService;
10
12
 
11
13
  return {
14
+ files: [globs.js, globs.jsx, globs.ts, globs.tsx],
12
15
  plugins: {
13
16
  ...reactPlugin.configs.all.plugins,
14
17
  'react-hooks': hooksPlugin,
15
18
  'jsx-a11y': a11yPlugin,
16
19
  },
20
+ ...predicate(projectService, {
21
+ languageOptions: {
22
+ parser,
23
+ parserOptions: { ...options.typescript },
24
+ },
25
+ }),
17
26
  settings: {
18
27
  'react': {
19
28
  pragma: 'React',
@@ -40,6 +49,7 @@ function react(options = {}) {
40
49
  '@eslint-react/dom/no-unsafe-iframe-sandbox': 'warn',
41
50
  '@eslint-react/dom/no-unsafe-target-blank': 'warn',
42
51
 
52
+ '@eslint-react/jsx-dollar': 'warn',
43
53
  '@eslint-react/jsx-key-before-spread': 'error',
44
54
  '@eslint-react/jsx-no-undef': 'off',
45
55
  '@eslint-react/jsx-no-iife': 'warn',
@@ -27,7 +27,7 @@ function storybook() {
27
27
 
28
28
  // Conflicts
29
29
  '@typescript-eslint/no-confusing-void-expression': 'off',
30
- 'react/jsx-no-useless-fragment': 'off',
30
+ '@eslint-react/no-useless-fragment': 'off',
31
31
  'react-hooks/rules-of-hooks': 'off',
32
32
  },
33
33
  };
@@ -8,28 +8,23 @@ import { globs } from '../utils/globs.mjs';
8
8
  * @param { import('..').Options } options
9
9
  * @return { import('eslint').Linter.Config }
10
10
  */
11
+
11
12
  function tests(options = {}) {
12
13
  return {
13
- plugins: { vitest: plugin },
14
14
  files: [...globs.test, ...globs.e2e],
15
+ plugins: { vitest: plugin },
15
16
  languageOptions: {
16
- globals: { ...globals['shared-node-browser'], ...globals.jest },
17
+ globals: { ...globals['shared-node-browser'] },
17
18
  },
18
19
  rules: {
19
- 'vitest/padding-around-after-all-blocks': 'warn',
20
- 'vitest/padding-around-after-each-blocks': 'warn',
21
- 'vitest/padding-around-before-all-blocks': 'warn',
22
- 'vitest/padding-around-before-each-blocks': 'warn',
23
- 'vitest/padding-around-describe-blocks': 'warn',
24
- 'vitest/padding-around-expect-groups': 'warn',
25
- 'vitest/padding-around-test-blocks': 'warn',
26
-
27
20
  'max-lines-per-function': 'off',
28
21
  'no-sparse-arrays': 'off',
29
22
  'no-empty-function': 'off',
30
23
 
24
+ 'vitest/padding-around-all': 'warn',
25
+
31
26
  ...predicate(options.react, {
32
- 'react/jsx-no-constructed-context-values': 'off',
27
+ '@eslint-react/no-unstable-context-value': 'off',
33
28
  }),
34
29
 
35
30
  ...predicate(options.typescript, {
@@ -1,6 +1,6 @@
1
1
  import { parser, plugin } from 'typescript-eslint';
2
2
 
3
- import { predicate } from '../utils/conditions.mjs';
3
+ import { predicate, strict } from '../utils/conditions.mjs';
4
4
  import { globs } from '../utils/globs.mjs';
5
5
  import { namingConvention } from '../utils/naming-convention.mjs';
6
6
 
@@ -37,7 +37,7 @@ function typescript(options = {}) {
37
37
  '@typescript-eslint/camelcase': 'off',
38
38
  '@typescript-eslint/class-literal-property-style': ['error', 'getters'],
39
39
  '@typescript-eslint/consistent-generic-constructors': ['warn', 'constructor'],
40
- '@typescript-eslint/consistent-indexed-object-style': 'off',
40
+ '@typescript-eslint/consistent-indexed-object-style': 'warn',
41
41
  '@typescript-eslint/consistent-type-assertions': 'error',
42
42
  '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
43
43
  '@typescript-eslint/consistent-type-imports': [
@@ -74,7 +74,7 @@ function typescript(options = {}) {
74
74
  '@typescript-eslint/no-dynamic-delete': 'error',
75
75
  '@typescript-eslint/no-empty-function': 'error',
76
76
  '@typescript-eslint/no-empty-object-type': ['warn', { allowInterfaces: 'with-single-extends' }],
77
- '@typescript-eslint/no-explicit-any': 'off',
77
+ '@typescript-eslint/no-explicit-any': strict(options, 'warn'),
78
78
  '@typescript-eslint/no-extra-non-null-assertion': 'error',
79
79
  '@typescript-eslint/no-extraneous-class': ['warn', { allowWithDecorator: true }],
80
80
  '@typescript-eslint/no-import-type-side-effects': 'warn',
@@ -96,12 +96,12 @@ function typescript(options = {}) {
96
96
  '@typescript-eslint/no-this-alias': 'error',
97
97
  '@typescript-eslint/no-type-alias': 'off',
98
98
  '@typescript-eslint/no-unnecessary-type-constraint': 'warn',
99
- '@typescript-eslint/no-unsafe-argument': 'off',
100
- '@typescript-eslint/no-unsafe-assignment': 'off',
101
- '@typescript-eslint/no-unsafe-call': 'off',
99
+ '@typescript-eslint/no-unsafe-argument': strict(options, 'warn'),
100
+ '@typescript-eslint/no-unsafe-assignment': strict(options, 'warn'),
101
+ '@typescript-eslint/no-unsafe-call': strict(options, 'warn'),
102
102
  '@typescript-eslint/no-unsafe-declaration-merging': 'warn',
103
- '@typescript-eslint/no-unsafe-member-access': 'off',
104
- '@typescript-eslint/no-unsafe-return': 'off',
103
+ '@typescript-eslint/no-unsafe-member-access': strict(options, ['warn', { allowOptionalChaining: true }]),
104
+ '@typescript-eslint/no-unsafe-return': strict(options, 'warn'),
105
105
  '@typescript-eslint/no-untyped-public-signature': 'off',
106
106
  '@typescript-eslint/no-unused-expressions': 'error',
107
107
  '@typescript-eslint/no-unused-vars': [
@@ -171,6 +171,7 @@ function typescript(options = {}) {
171
171
  '@typescript-eslint/no-unnecessary-type-conversion': 'error',
172
172
  '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
173
173
  '@typescript-eslint/no-unsafe-enum-comparison': 'warn',
174
+ '@typescript-eslint/no-unsafe-function-type': 'warn',
174
175
  '@typescript-eslint/no-unnecessary-condition': [
175
176
  'warn',
176
177
  {
@@ -215,9 +216,6 @@ function typescript(options = {}) {
215
216
  'consistent-return': 'off',
216
217
  }),
217
218
 
218
- // open issues
219
- 'react/jsx-no-useless-fragment': 'off', // Need useless-fragment for JSX return type
220
-
221
219
  // Conflicts with @typescript-eslint
222
220
  'no-empty-function': 'off',
223
221
  'default-case': 'off',
@@ -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
+
61
62
  'vitest/prefer-called-once': 'warn',
62
63
  'vitest/prefer-called-times': 'off',
63
64
  'vitest/prefer-called-with': 'warn',
@@ -88,11 +89,11 @@ function vitest() {
88
89
  'vitest/require-local-test-context-for-concurrent-snapshots': 'warn',
89
90
  'vitest/require-mock-type-parameters': 'off',
90
91
  'vitest/require-to-throw-message': 'warn',
91
- 'vitest/require-top-level-describe': 'warn',
92
+ 'vitest/require-top-level-describe': 'off',
92
93
  'vitest/valid-describe-callback': 'warn',
93
94
  'vitest/valid-expect': 'warn',
94
95
  'vitest/valid-expect-in-promise': 'warn',
95
- 'vitest/valid-title': 'warn',
96
+ 'vitest/valid-title': ['warn', { allowArguments: true }],
96
97
  'vitest/warn-todo': 'warn',
97
98
  },
98
99
  };
@@ -28,7 +28,7 @@ export const globs = {
28
28
  astro: '**/*.astro',
29
29
  graphql: '**/*.{gql,graphql}',
30
30
 
31
- storybook: ['**/*.stories.{js,jsx,ts,tsx}'],
31
+ storybook: ['**/*.stories.{js,mjs,cjs,jsx,ts,tsx}'],
32
32
 
33
33
  test: [`**/__tests__/*.${srcExt}`, `**/*.spec.${srcExt}`, `**/*.test.${srcExt}`],
34
34
  e2e: [`**/e2e/*.${srcExt}`],