@codfish/eslint-config 13.0.0 → 13.1.1

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,38 @@
1
+ export default tseslintConfig;
2
+ export const rules: {
3
+ '@typescript-eslint/no-unused-vars': (string | {
4
+ ignoreRestSiblings: boolean;
5
+ })[];
6
+ '@typescript-eslint/no-empty-function': string;
7
+ '@typescript-eslint/naming-convention': (string | {
8
+ selector: string[];
9
+ format: string[];
10
+ custom: {
11
+ regex: string;
12
+ match: boolean;
13
+ };
14
+ })[];
15
+ '@typescript-eslint/ban-ts-comment': (string | {
16
+ 'ts-ignore': string;
17
+ 'ts-expect-error': string;
18
+ 'ts-nocheck': string;
19
+ })[];
20
+ '@typescript-eslint/no-restricted-types': (string | {
21
+ types: {
22
+ 'React.FC': {
23
+ message: string;
24
+ };
25
+ 'React.FunctionComponent': {
26
+ message: string;
27
+ };
28
+ };
29
+ })[];
30
+ } | {
31
+ '@typescript-eslint/no-unused-vars'?: never;
32
+ '@typescript-eslint/no-empty-function'?: never;
33
+ '@typescript-eslint/naming-convention'?: never;
34
+ '@typescript-eslint/ban-ts-comment'?: never;
35
+ '@typescript-eslint/no-restricted-types'?: never;
36
+ };
37
+ declare const tseslintConfig: import("eslint").Linter.Config[];
38
+ //# sourceMappingURL=typescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../rules/typescript.js"],"names":[],"mappings":";AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCO;AA9CP,8BACa,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CACsC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=react-integration.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-integration.spec.d.ts","sourceRoot":"","sources":["../../../tests/integration/react-integration.spec.js"],"names":[],"mappings":""}
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Get the version of a dependency from the consumer's package.json.
3
+ * Returns the major version as a string (e.g. '18', '19'), or null if not found.
4
+ */
5
+ export function getDepVersion(dep: any): string | null;
1
6
  export function hasLocalConfig(moduleName: any, searchOptions?: {}): boolean;
2
7
  export function hasDep(props: any): boolean;
3
8
  export function hasDevDep(props: any): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.js"],"names":[],"mappings":"AAyBA,6EAKC;AAfgC,4CAA+D;AAA/D,+CAA+D;AAA/D,gDAA+D;AAMzF,8CAA8E;AAE9E,yDAAmE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.js"],"names":[],"mappings":"AAyBA;;;GAGG;AACH,uDAKC;AAED,6EAKC;AA1BgC,4CAA+D;AAA/D,+CAA+D;AAA/D,gDAA+D;AAMzF,8CAA8E;AAE9E,yDAAmE"}
package/index.js CHANGED
@@ -8,14 +8,13 @@ import prettierConfig from 'eslint-plugin-prettier/recommended';
8
8
  import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
9
9
  import ymlPlugin from 'eslint-plugin-yml';
10
10
  import globals from 'globals';
11
- import tseslint from 'typescript-eslint';
12
11
 
13
12
  import prettierBuiltInConfig from './prettier.js';
14
13
  import configFilesConfig from './rules/config-files.js';
15
14
  import reactConfig from './rules/react.js';
16
15
  import testConfig from './rules/tests.js';
16
+ import tseslintConfig, { rules as tsRules } from './rules/typescript.js';
17
17
  import { hasLocalConfig, ifAnyDep } from './utils.js';
18
-
19
18
  const useBuiltinPrettierConfig = !hasLocalConfig('prettier');
20
19
 
21
20
  /**
@@ -34,7 +33,7 @@ export default defineConfig([
34
33
 
35
34
  files: ['**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'],
36
35
 
37
- extends: [js.configs.recommended, tseslint.configs.recommended],
36
+ extends: [js.configs.recommended, ...tseslintConfig],
38
37
 
39
38
  plugins: {
40
39
  'simple-import-sort': simpleImportSortPlugin,
@@ -43,6 +42,9 @@ export default defineConfig([
43
42
  languageOptions: {
44
43
  ecmaVersion: 'latest',
45
44
  sourceType: 'module',
45
+ parserOptions: {
46
+ ecmaFeatures: { jsx: true },
47
+ },
46
48
  globals: {
47
49
  ...globals.browser,
48
50
  ...globals.node,
@@ -54,8 +56,10 @@ export default defineConfig([
54
56
  // Error handling rules to enforce using the Error object
55
57
  'no-throw-literal': 'error',
56
58
  'prefer-promise-reject-errors': 'error',
59
+ 'no-unused-vars': ['error', { ignoreRestSiblings: true }],
60
+ 'no-empty-function': 'off',
57
61
 
58
- // Asynchronous functions that dont use await might not need to be asynchronous functions
62
+ // Asynchronous functions that don't use await might not need to be asynchronous functions
59
63
  // Usually result of refactoring, leads to misunderstanding/misusage
60
64
  'require-await': 'error',
61
65
 
@@ -85,44 +89,6 @@ export default defineConfig([
85
89
  'simple-import-sort/exports': 'error',
86
90
  'sort-imports': 'off',
87
91
 
88
- // Allows destructuring of rest properties even if they are unused
89
- '@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }],
90
- '@typescript-eslint/no-empty-function': 'off',
91
- '@typescript-eslint/naming-convention': [
92
- 'error',
93
- {
94
- selector: ['interface', 'typeAlias'],
95
- format: ['PascalCase'],
96
- custom: {
97
- regex: '^I[A-Z]', // prevent prefixing interfaces and type alias declarations with "I"
98
- match: false,
99
- },
100
- },
101
- ],
102
- '@typescript-eslint/ban-ts-comment': [
103
- 'error',
104
- {
105
- // If you need to use a ts comment, make sure you have a description.
106
- 'ts-ignore': 'allow-with-description',
107
- 'ts-expect-error': 'allow-with-description',
108
- 'ts-nocheck': 'allow-with-description',
109
- },
110
- ],
111
-
112
- '@typescript-eslint/no-restricted-types': [
113
- 'error',
114
- {
115
- types: {
116
- 'React.FC': {
117
- message: 'Useless and has some drawbacks, see https://github.com/facebook/create-react-app/pull/8177',
118
- },
119
- 'React.FunctionComponent': {
120
- message: 'Useless and has some drawbacks, see https://github.com/facebook/create-react-app/pull/8177',
121
- },
122
- },
123
- },
124
- ],
125
-
126
92
  // 1. Encouraging `lodash-es` imports per file
127
93
  // lodash imports should use `lodash-es` package and should be imported per file.
128
94
  // E.G: `import get from "lodash-es/get"`
@@ -170,6 +136,9 @@ export default defineConfig([
170
136
  ],
171
137
  },
172
138
  ],
139
+
140
+ // TypeScript rules (empty object when typescript is not installed)
141
+ ...tsRules,
173
142
  },
174
143
  },
175
144
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codfish/eslint-config",
3
- "version": "13.0.0",
3
+ "version": "13.1.1",
4
4
  "description": "Modern ESLint configuration with TypeScript, React, and testing framework support.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -54,40 +54,40 @@
54
54
  "prepare": "husky"
55
55
  },
56
56
  "dependencies": {
57
- "@commitlint/cli": "^20.4.1",
58
- "@commitlint/config-conventional": "^20.4.1",
57
+ "@commitlint/cli": "^20.4.2",
58
+ "@commitlint/config-conventional": "^20.4.2",
59
59
  "@eslint/js": "^10.0.0",
60
60
  "@eslint/json": "^1.0.1",
61
61
  "@eslint/markdown": "^7.5.1",
62
- "@html-eslint/eslint-plugin": "^0.55.0",
63
- "@html-eslint/parser": "^0.55.0",
62
+ "@html-eslint/eslint-plugin": "^0.57.1",
63
+ "@html-eslint/parser": "^0.57.1",
64
64
  "@next/eslint-plugin-next": "^16.1.6",
65
65
  "@tanstack/eslint-plugin-query": "^5.91.4",
66
66
  "@vitest/eslint-plugin": "^1.6.9",
67
67
  "cosmiconfig": "^9.0.0",
68
68
  "eslint-config-prettier": "^10.1.8",
69
- "eslint-plugin-jest": "^29.14.0",
69
+ "eslint-plugin-jest": "^29.15.0",
70
70
  "eslint-plugin-jsx-a11y": "^6.10.2",
71
71
  "eslint-plugin-prettier": "^5.5.5",
72
72
  "eslint-plugin-react": "^7.37.5",
73
73
  "eslint-plugin-react-hooks": "^7.0.1",
74
- "eslint-plugin-react-refresh": "^0.5.0",
74
+ "eslint-plugin-react-refresh": "^0.5.2",
75
75
  "eslint-plugin-simple-import-sort": "^12.1.1",
76
- "eslint-plugin-testing-library": "^7.15.4",
77
- "eslint-plugin-yml": "^3.1.2",
76
+ "eslint-plugin-testing-library": "^7.16.0",
77
+ "eslint-plugin-yml": "^3.3.0",
78
78
  "globals": "^17.3.0",
79
79
  "lodash.has": "^4.5.2",
80
80
  "prettier": ">= 3",
81
81
  "read-package-up": "^12.0.0",
82
- "typescript-eslint": "^8.55.0"
82
+ "typescript-eslint": "^8.56.1"
83
83
  },
84
84
  "devDependencies": {
85
- "@types/node": "^25.2.3",
85
+ "@types/node": "^25.3.3",
86
86
  "@vitest/coverage-v8": "^4.0.18",
87
- "doctoc": "^2.2.1",
88
- "eslint": "^10.0.0",
87
+ "doctoc": "^2.3.0",
88
+ "eslint": "^10.0.2",
89
89
  "husky": "^9.1.7",
90
- "lint-staged": "^16.1.6",
90
+ "lint-staged": "^16.3.0",
91
91
  "typescript": "^5.9.2",
92
92
  "vitest": "^4.0.18"
93
93
  },
@@ -128,6 +128,6 @@
128
128
  ]
129
129
  },
130
130
  "volta": {
131
- "node": "24.13.0"
131
+ "node": "24.14.0"
132
132
  }
133
133
  }
package/rules/react.js CHANGED
@@ -7,7 +7,7 @@ import reactHooks from 'eslint-plugin-react-hooks';
7
7
  import reactRefresh from 'eslint-plugin-react-refresh';
8
8
  import globals from 'globals';
9
9
 
10
- import { ifAnyDep } from '../utils.js';
10
+ import { getDepVersion, ifAnyDep } from '../utils.js';
11
11
 
12
12
  /**
13
13
  * React ESLint configuration. Includes React, React Hooks, and JSX accessibility rules.
@@ -41,7 +41,9 @@ export default defineConfig([
41
41
 
42
42
  settings: {
43
43
  react: {
44
- version: 'detect',
44
+ // Avoid 'detect' — it uses context.getFilename() which was removed in ESLint 10.
45
+ // Read the major version from the consumer's package.json instead.
46
+ version: getDepVersion('react') || 'detect',
45
47
  },
46
48
  },
47
49
 
@@ -0,0 +1,56 @@
1
+ import { hasAnyDep } from '../utils.js';
2
+
3
+ /**
4
+ * TypeScript ESLint configuration. Dynamically loads typescript-eslint
5
+ * only when typescript is installed in the consuming project.
6
+ *
7
+ * - https://typescript-eslint.io/
8
+ */
9
+ const hasTypeScript = hasAnyDep('typescript');
10
+ const tseslintConfig =
11
+ /** @type {import('eslint').Linter.Config[]} */
12
+ (hasTypeScript ? [(await import('typescript-eslint')).configs.recommended] : []);
13
+
14
+ export default tseslintConfig;
15
+
16
+ export const rules = hasTypeScript
17
+ ? {
18
+ // Allows destructuring of rest properties even if they are unused
19
+ '@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }],
20
+ '@typescript-eslint/no-empty-function': 'off',
21
+ '@typescript-eslint/naming-convention': [
22
+ 'error',
23
+ {
24
+ selector: ['interface', 'typeAlias'],
25
+ format: ['PascalCase'],
26
+ custom: {
27
+ regex: '^I[A-Z]', // prevent prefixing interfaces and type alias declarations with "I"
28
+ match: false,
29
+ },
30
+ },
31
+ ],
32
+ '@typescript-eslint/ban-ts-comment': [
33
+ 'error',
34
+ {
35
+ // If you need to use a ts comment, make sure you have a description.
36
+ 'ts-ignore': 'allow-with-description',
37
+ 'ts-expect-error': 'allow-with-description',
38
+ 'ts-nocheck': 'allow-with-description',
39
+ },
40
+ ],
41
+
42
+ '@typescript-eslint/no-restricted-types': [
43
+ 'error',
44
+ {
45
+ types: {
46
+ 'React.FC': {
47
+ message: 'Useless and has some drawbacks, see https://github.com/facebook/create-react-app/pull/8177',
48
+ },
49
+ 'React.FunctionComponent': {
50
+ message: 'Useless and has some drawbacks, see https://github.com/facebook/create-react-app/pull/8177',
51
+ },
52
+ },
53
+ },
54
+ ],
55
+ }
56
+ : {};
package/utils.js CHANGED
@@ -23,6 +23,17 @@ export const hasAnyDep = args => [hasDep, hasDevDep, hasPeerDep].some(fn => fn(a
23
23
 
24
24
  export const ifAnyDep = (deps, t, f) => (hasAnyDep([deps].flat()) ? t : f);
25
25
 
26
+ /**
27
+ * Get the version of a dependency from the consumer's package.json.
28
+ * Returns the major version as a string (e.g. '18', '19'), or null if not found.
29
+ */
30
+ export function getDepVersion(dep) {
31
+ const spec = pkg?.dependencies?.[dep] || pkg?.devDependencies?.[dep] || pkg?.peerDependencies?.[dep];
32
+ if (!spec) return null;
33
+ const match = spec.match(/\d+/);
34
+ return match ? match[0] : null;
35
+ }
36
+
26
37
  export function hasLocalConfig(moduleName, searchOptions = {}) {
27
38
  const explorerSync = cosmiconfigSync(moduleName, searchOptions);
28
39
  const result = explorerSync.search(pkgPath || './');