@etchteam/eslint-config 2.2.64 → 2.2.66
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/.github/workflows/ci.yml +14 -1
- package/.husky/commit-msg +0 -3
- package/.husky/pre-commit +0 -3
- package/CHANGELOG.md +3 -2
- package/README.md +42 -5
- package/commitlint.config.js +1 -1
- package/lint-staged.config.js +1 -1
- package/package.json +24 -17
- package/prettier.config.js +1 -1
- package/release.config.js +1 -1
- package/src/index.js +96 -67
- package/test-files/test.js +31 -0
- package/test-files/test.json +8 -0
- package/test-files/test.yml +7 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -18,4 +18,17 @@ jobs:
|
|
|
18
18
|
node-version: ${{ matrix.version }}
|
|
19
19
|
cache: npm
|
|
20
20
|
- run: npm ci --no-audit --no-fund --prefer-offline
|
|
21
|
-
- run: npx --no-install eslint
|
|
21
|
+
- run: npx --no-install eslint src
|
|
22
|
+
- name: Test ESLint config against test files (expects failures)
|
|
23
|
+
run: |
|
|
24
|
+
set +e # Don't exit on failure
|
|
25
|
+
npx eslint test-files/ --format=compact
|
|
26
|
+
exit_code=$?
|
|
27
|
+
echo "ESLint exit code: $exit_code"
|
|
28
|
+
if [ $exit_code -eq 0 ]; then
|
|
29
|
+
echo "❌ Test files should have ESLint violations but none were found"
|
|
30
|
+
exit 1
|
|
31
|
+
else
|
|
32
|
+
echo "✅ Test files correctly show ESLint violations"
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
package/.husky/commit-msg
CHANGED
package/.husky/pre-commit
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
## [2.2.
|
|
1
|
+
## [2.2.66](https://github.com/etchteam/eslint/compare/v2.2.65...v2.2.66) (2025-06-25)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
* bump
|
|
6
|
+
* bump brace-expansion in the npm_and_yarn group ([218251f](https://github.com/etchteam/eslint/commit/218251ffa71da214d526b5abf49f8eb0ecaed06c))
|
|
7
|
+
* use module syntax for release config ([563f620](https://github.com/etchteam/eslint/commit/563f620abfdd057c0bd045b3f112b87d9c4e4617))
|
package/README.md
CHANGED
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
The eslint config that we use at [Etch](https://etch.co)
|
|
4
4
|
|
|
5
|
+
**⚠️ Version 1.0.0+ requires ESLint 9** - See [migration guide](#migrating-from-eslint-8) below for upgrading.
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
npm i -D eslint prettier @etchteam/eslint-config
|
|
10
|
+
npm i -D eslint@^9.0.0 prettier @etchteam/eslint-config
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## Usage
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
Create an `eslint.config.js` file in your project root:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import etchConfig from '@etchteam/eslint-config';
|
|
19
|
+
|
|
20
|
+
export default etchConfig;
|
|
15
21
|
```
|
|
16
22
|
|
|
17
23
|
### With lint-staged
|
|
@@ -50,7 +56,7 @@ echo "{ \"editor.formatOnSave\": false, \"editor.codeActionsOnSave\": { \"source
|
|
|
50
56
|
|
|
51
57
|
# The VSCode prettier extension doesn't read the eslint config, so specific
|
|
52
58
|
# prettier overrides need to go in a prettier config for format on save
|
|
53
|
-
echo "
|
|
59
|
+
echo "export default { singleQuote: true };" > prettier.config.js
|
|
54
60
|
|
|
55
61
|
```
|
|
56
62
|
|
|
@@ -70,5 +76,36 @@ Run the following:
|
|
|
70
76
|
```bash
|
|
71
77
|
# The VSCode prettier extension doesn't read the eslint config, so specific
|
|
72
78
|
# prettier overrides need to go in a prettier config for format on save
|
|
73
|
-
echo "
|
|
79
|
+
echo "export default { singleQuote: true };" > prettier.config.js
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Migrating from ESLint 8
|
|
83
|
+
|
|
84
|
+
If you're upgrading from ESLint 8, follow these steps:
|
|
85
|
+
|
|
86
|
+
### 1. Update Dependencies
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install eslint@^9.0.0 @etchteam/eslint-config@^1.0.0
|
|
74
90
|
```
|
|
91
|
+
|
|
92
|
+
### 2. Replace Configuration
|
|
93
|
+
|
|
94
|
+
Remove your old `.eslintrc.*` files and create a new `eslint.config.js`:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
import etchConfig from '@etchteam/eslint-config';
|
|
98
|
+
|
|
99
|
+
export default etchConfig;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. Update Scripts (if needed)
|
|
103
|
+
|
|
104
|
+
ESLint 9 uses flat config by default, so your existing npm scripts should work without changes.
|
|
105
|
+
|
|
106
|
+
### What's Changed
|
|
107
|
+
|
|
108
|
+
- **Flat config format** - More explicit and performant
|
|
109
|
+
- **ESLint 9 compatibility** - Latest features and fixes
|
|
110
|
+
- **Updated plugins** - All plugins updated to latest versions
|
|
111
|
+
- **Reduced compatibility layer** - Only 3 plugins need compatibility wrappers
|
package/commitlint.config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export default { extends: ['@commitlint/config-conventional'] };
|
package/lint-staged.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etchteam/eslint-config",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.66",
|
|
4
4
|
"description": "Etch's standard eslint config",
|
|
5
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "eslint.config.mjs",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./eslint.config.mjs"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
12
|
"release": "semantic-release"
|
|
@@ -30,25 +34,28 @@
|
|
|
30
34
|
"lint-staged": "^16.0.0"
|
|
31
35
|
},
|
|
32
36
|
"dependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"@
|
|
35
|
-
"eslint": "
|
|
36
|
-
"eslint
|
|
37
|
-
"eslint
|
|
38
|
-
"eslint-
|
|
39
|
-
"eslint-
|
|
40
|
-
"eslint-plugin-
|
|
41
|
-
"eslint-plugin-
|
|
42
|
-
"eslint-plugin-
|
|
43
|
-
"eslint-plugin-
|
|
44
|
-
"eslint-plugin-
|
|
37
|
+
"@eslint/compat": "^1.3.0",
|
|
38
|
+
"@eslint/js": "^9.29.0",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.35.0",
|
|
41
|
+
"eslint": ">=9.0.0",
|
|
42
|
+
"eslint-config-next": "^15.3.4",
|
|
43
|
+
"eslint-config-prettier": "^10.1.5",
|
|
44
|
+
"eslint-plugin-import": "^2.32.0",
|
|
45
|
+
"eslint-plugin-json": "^4.0.1",
|
|
46
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
47
|
+
"eslint-plugin-prettier": "^5.5.0",
|
|
48
|
+
"eslint-plugin-react": "^7.37.5",
|
|
49
|
+
"eslint-plugin-security": "^3.0.1",
|
|
50
|
+
"eslint-plugin-storybook": "^9.0.13",
|
|
45
51
|
"eslint-plugin-unused-imports": "^4.1.3",
|
|
46
|
-
"eslint-plugin-yml": "^1.
|
|
52
|
+
"eslint-plugin-yml": "^1.18.0",
|
|
47
53
|
"eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0",
|
|
48
|
-
"prettier": ">=3.0.0"
|
|
54
|
+
"prettier": ">=3.0.0",
|
|
55
|
+
"typescript-eslint": "^8.35.0"
|
|
49
56
|
},
|
|
50
57
|
"peerDependencies": {
|
|
51
|
-
"eslint": ">=
|
|
58
|
+
"eslint": ">=9.0.0",
|
|
52
59
|
"prettier": ">=3.0.0"
|
|
53
60
|
}
|
|
54
61
|
}
|
package/prettier.config.js
CHANGED
package/release.config.js
CHANGED
package/src/index.js
CHANGED
|
@@ -1,72 +1,101 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import { fixupPluginRules } from '@eslint/compat';
|
|
2
|
+
import js from '@eslint/js';
|
|
3
|
+
import importPlugin from 'eslint-plugin-import';
|
|
4
|
+
import json from 'eslint-plugin-json';
|
|
5
|
+
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
6
|
+
import prettier from 'eslint-plugin-prettier/recommended';
|
|
7
|
+
import react from 'eslint-plugin-react';
|
|
8
|
+
import security from 'eslint-plugin-security';
|
|
9
|
+
import storybook from 'eslint-plugin-storybook';
|
|
10
|
+
import unusedImports from 'eslint-plugin-unused-imports';
|
|
11
|
+
import yml from 'eslint-plugin-yml';
|
|
12
|
+
import youDontNeedLodash from 'eslint-plugin-you-dont-need-lodash-underscore';
|
|
13
|
+
import tseslint from 'typescript-eslint';
|
|
14
|
+
|
|
15
|
+
export default [
|
|
16
|
+
js.configs.recommended,
|
|
17
|
+
...tseslint.configs.recommended,
|
|
18
|
+
security.configs.recommended,
|
|
19
|
+
...yml.configs['flat/recommended'],
|
|
20
|
+
...storybook.configs['flat/recommended'],
|
|
21
|
+
{
|
|
22
|
+
files: ['**/*.json'],
|
|
23
|
+
...json.configs.recommended,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
plugins: {
|
|
27
|
+
// Plugins with native flat config support
|
|
28
|
+
'unused-imports': unusedImports,
|
|
29
|
+
|
|
30
|
+
// Plugins requiring compatibility layer
|
|
31
|
+
import: fixupPluginRules(importPlugin),
|
|
32
|
+
'jsx-a11y': fixupPluginRules(jsxA11y),
|
|
33
|
+
'you-dont-need-lodash-underscore': fixupPluginRules(youDontNeedLodash),
|
|
34
|
+
react: fixupPluginRules(react),
|
|
35
|
+
},
|
|
36
|
+
languageOptions: {
|
|
37
|
+
parser: tseslint.parser,
|
|
38
|
+
ecmaVersion: 'latest',
|
|
39
|
+
sourceType: 'module',
|
|
40
|
+
},
|
|
41
|
+
rules: {
|
|
42
|
+
// Migrate existing rules from src/index.js
|
|
43
|
+
'no-unused-vars': 'off',
|
|
44
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
45
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
46
|
+
'unused-imports/no-unused-imports': 'error',
|
|
47
|
+
'unused-imports/no-unused-vars': 'off',
|
|
48
|
+
'import/order': [
|
|
49
|
+
'error',
|
|
50
|
+
{
|
|
51
|
+
'newlines-between': 'always',
|
|
52
|
+
alphabetize: {
|
|
53
|
+
order: 'asc',
|
|
35
54
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
pathGroups: [
|
|
56
|
+
{
|
|
57
|
+
pattern: '@/**',
|
|
58
|
+
group: 'parent',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
'prettier/prettier': [
|
|
64
|
+
'error',
|
|
65
|
+
{
|
|
66
|
+
singleQuote: true,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
'jsx-a11y/anchor-ambiguous-text': 'error',
|
|
70
|
+
'jsx-a11y/no-aria-hidden-on-focusable': 'error',
|
|
71
|
+
'security/detect-object-injection': 'off',
|
|
72
|
+
'react/forbid-elements': [
|
|
73
|
+
'error',
|
|
74
|
+
{
|
|
75
|
+
forbid: [
|
|
76
|
+
{ element: 'b', message: 'Do not use HTML for styling' },
|
|
77
|
+
{ element: 'i', message: 'Do not use HTML for styling' },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
'react/jsx-no-useless-fragment': [
|
|
82
|
+
'error',
|
|
83
|
+
{
|
|
84
|
+
allowExpressions: true,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
'react/prefer-read-only-props': 'error',
|
|
88
|
+
'spaced-comment': 'error',
|
|
89
|
+
},
|
|
90
|
+
settings: {
|
|
91
|
+
'import/resolver': {
|
|
92
|
+
typescript: true,
|
|
93
|
+
node: true,
|
|
55
94
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
'error',
|
|
59
|
-
{
|
|
60
|
-
allowExpressions: true,
|
|
95
|
+
react: {
|
|
96
|
+
version: 'detect',
|
|
61
97
|
},
|
|
62
|
-
],
|
|
63
|
-
'react/prefer-read-only-props': 'error',
|
|
64
|
-
'spaced-comment': 'error',
|
|
65
|
-
},
|
|
66
|
-
settings: {
|
|
67
|
-
'import/resolver': {
|
|
68
|
-
typescript: true,
|
|
69
|
-
node: true,
|
|
70
98
|
},
|
|
71
99
|
},
|
|
72
|
-
|
|
100
|
+
prettier, // Prettier recommended config
|
|
101
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Test file to validate ESLint configuration
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
// Test unused imports (should be caught)
|
|
6
|
+
|
|
7
|
+
// Test unused variables
|
|
8
|
+
const unusedVar = 'test';
|
|
9
|
+
|
|
10
|
+
// Test React component with accessibility and other rules
|
|
11
|
+
const TestComponent = () => {
|
|
12
|
+
const [count, setCount] = useState(0);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div>
|
|
16
|
+
{/* Test anchor without proper text */}
|
|
17
|
+
<a href="/test">click here</a>
|
|
18
|
+
|
|
19
|
+
{/* Test useless fragment */}
|
|
20
|
+
<span>text</span>
|
|
21
|
+
|
|
22
|
+
{/* Test HTML styling elements */}
|
|
23
|
+
<b>Bold text</b>
|
|
24
|
+
<i>Italic text</i>
|
|
25
|
+
|
|
26
|
+
<button onClick={() => setCount(count + 1)}>Count: {count}</button>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default TestComponent;
|