@mrpalmer/eslint-config 2.1.0 → 2.2.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.
@@ -0,0 +1,8 @@
1
+
2
+ > @mrpalmer/eslint-config@2.2.0 prebuild
3
+ > rm -rf types
4
+
5
+
6
+ > @mrpalmer/eslint-config@2.2.0 build
7
+ > tsc
8
+
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @mrpalmer/eslint-config
2
2
 
3
+ ## 2.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - afbdd32: Replace `eslint-plugin-react` with `@eslint-react/eslint-plugin`
8
+
9
+ ### Patch Changes
10
+
11
+ - 1e43272: Update ESLint plugins
12
+ - 32711bf: Fix order of configs in "all"
13
+ - df14ce7: Export TypeScript types
14
+ - Updated dependencies [96a657e]
15
+ - @mrpalmer/eslint-plugin@1.0.1
16
+
3
17
  ## 2.1.0
4
18
 
5
19
  ### Minor Changes
package/configs/base.js CHANGED
@@ -227,6 +227,7 @@ export default config(
227
227
  'import-x/no-webpack-loader-syntax': 'error',
228
228
  'import-x/order': 'off',
229
229
  'import-x/prefer-default-export': 'off',
230
+ 'import-x/prefer-namespace-import': 'off',
230
231
  'import-x/unambiguous': 'off',
231
232
  },
232
233
  settings: {
package/configs/jest.js CHANGED
@@ -36,7 +36,9 @@ export default tseslint.config(
36
36
  name: 'mrpalmer/jest',
37
37
 
38
38
  rules: {
39
- 'react/display-name': 'off', // we don't need a display name in test files
39
+ // we don't need a display name in test files
40
+ '@eslint-react/no-missing-component-display-name': 'off',
41
+ '@eslint-react/no-missing-context-display-name': 'off',
40
42
 
41
43
  'jest/consistent-test-it': 'off',
42
44
  'jest/max-expects': 'off',
@@ -61,6 +63,7 @@ export default tseslint.config(
61
63
  'jest/prefer-called-with': 'error',
62
64
  'jest/prefer-comparison-matcher': 'warn',
63
65
  'jest/prefer-each': 'warn',
66
+ 'jest/prefer-ending-with-an-expect': 'warn',
64
67
  'jest/prefer-equality-matcher': 'warn',
65
68
  'jest/prefer-expect-assertions': 'off',
66
69
  'jest/prefer-expect-resolves': 'off',
@@ -82,6 +85,7 @@ export default tseslint.config(
82
85
  ...(hasTestingLibrary
83
86
  ? {
84
87
  'testing-library/consistent-data-testid': 'off',
88
+ 'testing-library/no-test-id-queries': 'warn',
85
89
  'testing-library/prefer-explicit-assert': 'warn',
86
90
  'testing-library/prefer-implicit-assert': 'off',
87
91
  'testing-library/prefer-query-matchers': 'off',
package/configs/react.js CHANGED
@@ -1,8 +1,9 @@
1
+ import pluginReact from '@eslint-react/eslint-plugin'
1
2
  import pluginJsxA11y from 'eslint-plugin-jsx-a11y'
2
- import pluginReact from 'eslint-plugin-react'
3
3
  import pluginReactHooks from 'eslint-plugin-react-hooks'
4
4
  import globals from 'globals'
5
5
  import tseslint from 'typescript-eslint'
6
+ import * as deprecated from '../utils/deprecated.js'
6
7
  import {
7
8
  getAllDependencies,
8
9
  getMinimumSupportedVersion,
@@ -13,19 +14,18 @@ const oldestSupportedReactVersion = '16.5.2'
13
14
  const allDeps = getAllDependencies()
14
15
  const minimumSupportedReactVersion =
15
16
  getMinimumSupportedVersion(allDeps, 'react') ?? oldestSupportedReactVersion
16
- const hasPropTypes = Object.hasOwn(allDeps, 'prop-types')
17
17
 
18
- // jsx-a11y/label-has-for is deprecated but still defined in the recommended config
19
- delete pluginJsxA11y.flatConfigs.recommended.rules['jsx-a11y/label-has-for']
18
+ const jsxA11yRecommended = deprecated.remove(
19
+ pluginJsxA11y.flatConfigs.recommended,
20
+ // jsx-a11y/label-has-for is deprecated but still defined in the recommended config
21
+ ['jsx-a11y/label-has-for']
22
+ )
20
23
 
21
24
  export default tseslint.config(
22
25
  {
23
26
  extends: [
24
- {
25
- name: 'react/recommended',
26
- ...pluginReact.configs.flat.recommended,
27
- },
28
- pluginJsxA11y.flatConfigs.recommended,
27
+ pluginReact.configs.recommended,
28
+ jsxA11yRecommended,
29
29
  {
30
30
  name: 'react-hooks/recommended',
31
31
  plugins: {
@@ -42,113 +42,75 @@ export default tseslint.config(
42
42
  },
43
43
  name: 'mrpalmer/react',
44
44
  rules: {
45
- 'react/boolean-prop-naming': 'off',
46
- 'react/button-has-type': 'off',
47
- 'react/checked-requires-onchange-or-readonly': 'error',
48
- 'react/default-props-match-prop-types': hasPropTypes ? 'error' : 'off',
49
- 'react/destructuring-assignment': 'off',
50
- 'react/forbid-component-props': 'off',
51
- 'react/forbid-dom-props': 'off',
52
- 'react/forbid-elements': 'off',
53
- 'react/forbid-foreign-prop-types': hasPropTypes ? 'error' : 'off',
54
- 'react/forbid-prop-types': 'off',
55
- 'react/forward-ref-uses-ref': 'error',
56
- 'react/function-component-definition': 'off',
57
- 'react/hook-use-state': 'off',
58
- 'react/iframe-missing-sandbox': 'warn',
59
- 'react/jsx-boolean-value': 'off',
60
- 'react/jsx-child-element-spacing': 'warn',
61
- 'react/jsx-closing-bracket-location': 'off',
62
- 'react/jsx-closing-tag-location': 'off',
63
- 'react/jsx-curly-brace-presence': [
64
- 'warn',
65
- { children: 'ignore', propElementValues: 'always', props: 'never' },
66
- ],
67
- 'react/jsx-curly-newline': 'off',
68
- 'react/jsx-curly-spacing': 'off',
69
- 'react/jsx-equals-spacing': 'off',
70
- 'react/jsx-filename-extension': ['error', { extensions: ['.js'] }],
71
- 'react/jsx-first-prop-new-line': 'off',
72
- 'react/jsx-fragments': 'off',
73
- 'react/jsx-handler-names': 'off',
74
- 'react/jsx-indent': 'off',
75
- 'react/jsx-indent-props': 'off',
76
- 'react/jsx-max-depth': 'off',
77
- 'react/jsx-max-props-per-line': 'off',
78
- 'react/jsx-newline': 'off',
79
- 'react/jsx-no-bind': 'off',
80
- 'react/jsx-no-constructed-context-values': 'off',
81
- 'react/jsx-no-leaked-render': 'off',
82
- 'react/jsx-no-literals': 'off',
83
- 'react/jsx-no-script-url': 'error',
84
- 'react/jsx-no-useless-fragment': 'warn',
85
- 'react/jsx-one-expression-per-line': 'off',
86
- 'react/jsx-pascal-case': 'error',
87
- 'react/jsx-props-no-multi-spaces': 'off',
88
- 'react/jsx-props-no-spread-multi': 'warn',
89
- 'react/jsx-props-no-spreading': 'off',
90
- 'react/jsx-sort-props': 'off',
91
- 'react/jsx-tag-spacing': 'off',
92
- 'react/jsx-wrap-multilines': 'off',
93
- 'react/no-access-state-in-setstate': 'error',
94
- 'react/no-adjacent-inline-elements': 'off',
95
- 'react/no-array-index-key': 'off', // sometimes you don't care about the issues, or they don't apply
96
- 'react/no-arrow-function-lifecycle': 'error',
97
- 'react/no-danger': 'off',
98
- 'react/no-did-mount-set-state': 'error',
99
- 'react/no-did-update-set-state': 'error',
100
- 'react/no-invalid-html-attribute': 'error',
101
- 'react/no-multi-comp': 'off',
102
- 'react/no-namespace': 'error',
103
- 'react/no-object-type-as-default-prop': 'warn',
104
- 'react/no-redundant-should-component-update': 'error',
105
- 'react/no-set-state': 'off',
106
- 'react/no-this-in-sfc': 'error',
107
- 'react/no-typos': 'error',
108
- 'react/no-unescaped-entities': 'warn',
109
- 'react/no-unsafe': 'warn', // if you need it there should be a comment explaining why
110
- 'react/no-unstable-nested-components': ['error', { allowAsProps: true }],
111
- 'react/no-unused-class-component-methods': 'error',
112
- 'react/no-unused-prop-types': hasPropTypes ? 'error' : 'off',
113
- 'react/no-unused-state': 'error',
114
- 'react/no-will-update-set-state': 'error',
115
- 'react/prefer-es6-class': 'off',
116
- 'react/prefer-exact-props': 'off',
117
- 'react/prefer-read-only-props': 'off',
118
- 'react/prefer-stateless-function': 'off',
119
- 'react/prop-types': hasPropTypes ? 'error' : 'off',
120
- 'react/require-default-props': 'off', // sometimes the default value is undefined so that's fine...
121
- 'react/require-optimization': 'off',
122
- 'react/self-closing-comp': 'error',
123
- 'react/sort-comp': 'off',
124
- 'react/sort-default-props': 'off',
125
- 'react/sort-prop-types': 'off',
126
- 'react/state-in-constructor': 'off',
127
- 'react/static-property-placement': 'off',
128
- 'react/style-prop-object': 'error',
129
- 'react/void-dom-elements-no-children': 'error',
130
-
131
45
  'jsx-a11y/lang': 'error',
132
46
  'jsx-a11y/no-aria-hidden-on-focusable': 'off',
133
47
  'jsx-a11y/no-autofocus': 'off',
134
48
  'jsx-a11y/prefer-tag-over-role': 'off',
135
49
  'jsx-a11y/tabindex-no-positive': 'warn',
50
+
51
+ '@eslint-react/avoid-shorthand-boolean': 'off',
52
+ '@eslint-react/avoid-shorthand-fragment': 'off',
53
+ '@eslint-react/jsx-no-iife': 'warn',
54
+ '@eslint-react/jsx-no-undef': 'error',
55
+ '@eslint-react/no-children-prop': 'warn',
56
+ '@eslint-react/no-class-component': 'warn',
57
+ '@eslint-react/no-complex-conditional-rendering': 'warn',
58
+ '@eslint-react/no-leaked-conditional-rendering': 'off', // will be enabled for typescript files below
59
+ '@eslint-react/no-missing-component-display-name': 'warn',
60
+ '@eslint-react/no-missing-context-display-name': 'warn',
61
+ '@eslint-react/no-useless-fragment': 'warn',
62
+ '@eslint-react/prefer-destructuring-assignment': 'warn',
63
+ '@eslint-react/prefer-react-namespace-import': 'warn',
64
+ '@eslint-react/prefer-read-only-props': 'off', // may be enabled for typescript files below
65
+ '@eslint-react/prefer-shorthand-boolean': 'warn',
66
+ '@eslint-react/prefer-shorthand-fragment': 'warn',
67
+
68
+ '@eslint-react/debug/class-component': 'off',
69
+ '@eslint-react/debug/function-component': 'off',
70
+ '@eslint-react/debug/hook': 'off',
71
+ '@eslint-react/debug/is-from-react': 'off',
72
+ '@eslint-react/debug/jsx': 'off',
73
+ '@eslint-react/debug/react-hooks': 'off',
74
+
75
+ '@eslint-react/dom/no-children-in-void-dom-elements': 'error',
76
+ '@eslint-react/dom/no-unknown-property': 'error',
77
+
78
+ '@eslint-react/hooks-extra/no-direct-set-state-in-use-layout-effect':
79
+ 'warn',
80
+ '@eslint-react/hooks-extra/no-unnecessary-use-callback': 'warn',
81
+ '@eslint-react/hooks-extra/no-unnecessary-use-memo': 'warn',
82
+
83
+ '@eslint-react/naming-convention/component-name': 'warn',
84
+ '@eslint-react/naming-convention/filename': 'off', // this needs to be configured per project
85
+ '@eslint-react/naming-convention/filename-extension': [
86
+ 'warn',
87
+ 'as-needed',
88
+ ],
89
+ '@eslint-react/naming-convention/use-state': 'off',
90
+
91
+ // @eslint-react/eslint-plugin marks their rules as deprecated in jsdoc,
92
+ // but not in the rule's metadata.
93
+ ...deprecated.disable('@eslint-react', [
94
+ 'ensure-forward-ref-using-ref',
95
+ 'no-complicated-conditional-rendering',
96
+ 'no-duplicate-jsx-props',
97
+ 'no-nested-components',
98
+ 'use-jsx-vars',
99
+ 'hooks-extra/ensure-custom-hooks-using-other-hooks',
100
+ 'hooks-extra/ensure-use-callback-has-non-empty-deps',
101
+ 'hooks-extra/ensure-use-memo-has-non-empty-deps',
102
+ 'hooks-extra/no-redundant-custom-hook',
103
+ 'hooks-extra/no-useless-custom-hooks',
104
+ ]),
136
105
  },
137
106
  settings: {
138
- react: {
107
+ 'react-x': {
139
108
  version: minimumSupportedReactVersion,
140
109
  },
141
110
  },
142
111
  },
143
112
  {
144
113
  files: ['**/*.ts?(x)'],
145
- name: 'mrpalmer/react/typescript',
146
- rules: {
147
- 'react/jsx-filename-extension': [
148
- 'error',
149
- { extensions: ['.ts', '.tsx'] },
150
- ],
151
- 'react/prop-types': 'off',
152
- },
114
+ ...pluginReact.configs['recommended-type-checked'],
153
115
  }
154
116
  )
@@ -130,6 +130,7 @@ export default tseslint.config({
130
130
  '@typescript-eslint/no-unnecessary-parameter-property-assignment': 'warn',
131
131
  '@typescript-eslint/no-unnecessary-qualifier': 'warn',
132
132
  '@typescript-eslint/no-unnecessary-type-arguments': 'warn',
133
+ '@typescript-eslint/no-unnecessary-type-conversion': 'warn',
133
134
  '@typescript-eslint/no-unsafe-type-assertion': 'error',
134
135
  '@typescript-eslint/no-useless-empty-export': 'error',
135
136
  '@typescript-eslint/parameter-properties': [
@@ -148,7 +149,6 @@ export default tseslint.config({
148
149
  ],
149
150
  '@typescript-eslint/strict-boolean-expressions': 'off',
150
151
  '@typescript-eslint/switch-exhaustiveness-check': 'error',
151
- '@typescript-eslint/typedef': 'off',
152
152
  },
153
153
  settings: {
154
154
  'import-x/resolver-next': [
package/index.js CHANGED
@@ -6,7 +6,7 @@ import react from './configs/react.js'
6
6
  import typescript from './configs/typescript.js'
7
7
 
8
8
  const configs = {
9
- all: [...base, ...react, ...jest, ...typescript],
9
+ all: [...base, ...typescript, ...react, ...jest],
10
10
  base,
11
11
  jest,
12
12
  react,
package/package.json CHANGED
@@ -1,11 +1,21 @@
1
1
  {
2
2
  "name": "@mrpalmer/eslint-config",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Mike Palmer's personal ESLint rules",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./index.js",
10
+ "types": "./types/index.d.ts"
11
+ },
12
+ "./package.json": "./package.json"
13
+ },
7
14
  "main": "index.js",
15
+ "types": "types/index.d.ts",
8
16
  "scripts": {
17
+ "prebuild": "rm -rf types",
18
+ "build": "tsc",
9
19
  "check-config": "run-p check-config:*",
10
20
  "check-config:jest": "cd test && validate-config -f component.test.js",
11
21
  "check-config:jest-ts": "cd test && validate-config -f component.test.ts",
@@ -15,21 +25,20 @@
15
25
  "validate": "npm run check-config"
16
26
  },
17
27
  "dependencies": {
18
- "@eslint/js": "^9.20.0",
19
- "@mrpalmer/eslint-plugin": "^1.0.0",
20
- "@types/eslint__js": "^8.42.3",
21
- "eslint-import-resolver-typescript": "^4.3.4",
22
- "eslint-plugin-import-x": "^4.11.1",
23
- "eslint-plugin-jest": "^28.11.0",
28
+ "@eslint-react/eslint-plugin": "^1.52.3",
29
+ "@eslint/js": "^9.31.0",
30
+ "@mrpalmer/eslint-plugin": "^1.0.1",
31
+ "eslint-import-resolver-typescript": "^4.4.4",
32
+ "eslint-plugin-import-x": "^4.16.1",
33
+ "eslint-plugin-jest": "^29.0.1",
24
34
  "eslint-plugin-jest-dom": "^5.5.0",
25
35
  "eslint-plugin-jsx-a11y": "^6.10.2",
26
- "eslint-plugin-react": "^7.37.4",
27
- "eslint-plugin-react-hooks": "^5.1.0",
28
- "eslint-plugin-testing-library": "^7.1.1",
29
- "globals": "^15.14.0",
36
+ "eslint-plugin-react-hooks": "^5.2.0",
37
+ "eslint-plugin-testing-library": "^7.5.4",
38
+ "globals": "^16.3.0",
30
39
  "read-package-up": "^11.0.0",
31
- "semver": "^7.3.2",
32
- "typescript-eslint": "^8.23.0"
40
+ "semver": "^7.7.2",
41
+ "typescript-eslint": "^8.36.0"
33
42
  },
34
43
  "peerDependencies": {
35
44
  "@testing-library/dom": "*",
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "declaration": true,
6
+ "declarationDir": "./types",
7
+ "emitDeclarationOnly": true
8
+ },
9
+ "include": ["index.js"]
10
+ }
package/turbo.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": ["//"],
3
+ "tasks": {
4
+ "build": {
5
+ "outputs": ["types/**"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").FlatConfig.ConfigArray;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").FlatConfig.ConfigArray;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").FlatConfig.ConfigArray;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").FlatConfig.ConfigArray;
2
+ export default _default;
@@ -0,0 +1,20 @@
1
+ declare namespace _default {
2
+ export { config };
3
+ export { configs };
4
+ export { globals };
5
+ }
6
+ export default _default;
7
+ import { config } from 'typescript-eslint';
8
+ export namespace configs {
9
+ export let all: import("@typescript-eslint/utils/ts-eslint").FlatConfig.Config[];
10
+ export { base };
11
+ export { jest };
12
+ export { react };
13
+ export { typescript };
14
+ }
15
+ import globals from 'globals';
16
+ import base from './configs/base.js';
17
+ import jest from './configs/jest.js';
18
+ import react from './configs/react.js';
19
+ import typescript from './configs/typescript.js';
20
+ export { config, globals };
@@ -0,0 +1,4 @@
1
+ export function remove(config: any, ruleNames: any): any;
2
+ export function disable(pluginName: any, ruleNames: any): {
3
+ [k: string]: any;
4
+ };
@@ -0,0 +1,14 @@
1
+ /** @typedef {Record<string, string>} Dependencies */
2
+ /**
3
+ * Get all dependencies from the current project
4
+ * @returns {Dependencies}
5
+ */
6
+ export function getAllDependencies(): Dependencies;
7
+ /**
8
+ * Get the installed version of a dependency
9
+ * @param {Dependencies} allDeps
10
+ * @param {string} depName
11
+ * @returns {string | undefined}
12
+ */
13
+ export function getMinimumSupportedVersion(allDeps: Dependencies, depName: string): string | undefined;
14
+ export type Dependencies = Record<string, string>;
@@ -0,0 +1,19 @@
1
+ export function remove(config, ruleNames) {
2
+ if (!config || !config.rules) {
3
+ return config
4
+ }
5
+
6
+ for (const ruleName of ruleNames) {
7
+ if (Object.hasOwn(config.rules, ruleName)) {
8
+ delete config.rules[ruleName]
9
+ }
10
+ }
11
+
12
+ return config
13
+ }
14
+
15
+ export function disable(pluginName, ruleNames) {
16
+ return Object.fromEntries(
17
+ ruleNames.map((ruleName) => [`${pluginName}/${ruleName}`, 'off'])
18
+ )
19
+ }