@etchteam/eslint-config 2.2.65 → 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.
@@ -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
@@ -1,4 +1 @@
1
- #!/usr/bin/env sh
2
- . "$(dirname -- "$0")/_/husky.sh"
3
-
4
1
  npx --no -- commitlint --edit ${1}
package/.husky/pre-commit CHANGED
@@ -1,4 +1 @@
1
- #!/usr/bin/env sh
2
- . "$(dirname -- "$0")/_/husky.sh"
3
-
4
1
  npx --no -- lint-staged
package/CHANGELOG.md CHANGED
@@ -1,6 +1,7 @@
1
- ## [2.2.65](https://github.com/etchteam/eslint/compare/v2.2.64...v2.2.65) (2025-06-23)
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 prettier from 3.5.3 to 3.6.0 ([6dd1320](https://github.com/etchteam/eslint/commit/6dd132014fd0e360ed5afd3ebe2bb469b78b6cf3))
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
- ```bash
14
- echo "module.exports = { extends: ['@etchteam'] };" > .eslintrc.cjs
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 "module.exports = { singleQuote: true };" > prettier.config.cjs
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 "module.exports = { singleQuote: true };" > prettier.config.cjs
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
@@ -1 +1 @@
1
- module.exports = { extends: ['@commitlint/config-conventional'] };
1
+ export default { extends: ['@commitlint/config-conventional'] };
@@ -1,3 +1,3 @@
1
- module.exports = {
1
+ export default {
2
2
  '*.{ts,tsx,js,jsx,yml,yaml,json}': 'eslint --fix',
3
3
  };
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@etchteam/eslint-config",
3
- "version": "2.2.65",
3
+ "version": "2.2.66",
4
4
  "description": "Etch's standard eslint config",
5
- "main": "src/index.js",
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
- "@typescript-eslint/eslint-plugin": "^7.10.0",
34
- "@typescript-eslint/parser": "^7.10.0",
35
- "eslint": ">=8.29.0",
36
- "eslint-config-next": "^15.0.0",
37
- "eslint-config-prettier": "^10.0.1",
38
- "eslint-plugin-import": "^2.29.0",
39
- "eslint-plugin-json": "^4.0.0",
40
- "eslint-plugin-jsx-a11y": "^6.8.0",
41
- "eslint-plugin-prettier": "^5.0.1",
42
- "eslint-plugin-react": "^7.33.2",
43
- "eslint-plugin-security": "^3.0.0",
44
- "eslint-plugin-storybook": "^9.0.0",
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.10.0",
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": ">=8.29.0",
58
+ "eslint": ">=9.0.0",
52
59
  "prettier": ">=3.0.0"
53
60
  }
54
61
  }
@@ -1,3 +1,3 @@
1
- module.exports = {
1
+ export default {
2
2
  singleQuote: true,
3
3
  };
package/release.config.js CHANGED
@@ -1,4 +1,4 @@
1
- module.exports = {
1
+ export default {
2
2
  branches: ['main'],
3
3
  plugins: [
4
4
  [
package/src/index.js CHANGED
@@ -1,72 +1,101 @@
1
- module.exports = {
2
- extends: [
3
- 'next/core-web-vitals',
4
- 'plugin:@typescript-eslint/recommended',
5
- 'plugin:storybook/recommended',
6
- 'plugin:security/recommended-legacy',
7
- 'plugin:import/recommended',
8
- 'plugin:import/typescript',
9
- 'plugin:prettier/recommended',
10
- 'plugin:jsx-a11y/strict',
11
- 'plugin:json/recommended-legacy',
12
- 'plugin:you-dont-need-lodash-underscore/compatible',
13
- 'plugin:yml/standard',
14
- 'plugin:yml/prettier',
15
- ],
16
- plugins: ['unused-imports'],
17
- parser: '@typescript-eslint/parser',
18
- rules: {
19
- 'no-unused-vars': 'off',
20
- '@typescript-eslint/no-unused-vars': 'error',
21
- '@typescript-eslint/no-explicit-any': 'warn',
22
- 'unused-imports/no-unused-imports': 'error',
23
- 'unused-imports/no-unused-vars': 'off',
24
- 'import/order': [
25
- 'error',
26
- {
27
- 'newlines-between': 'always',
28
- alphabetize: {
29
- order: 'asc',
30
- },
31
- pathGroups: [
32
- {
33
- pattern: '@/**',
34
- group: 'parent',
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
- 'prettier/prettier': [
40
- 'error',
41
- {
42
- singleQuote: true,
43
- },
44
- ],
45
- 'jsx-a11y/anchor-ambiguous-text': 'error',
46
- 'jsx-a11y/no-aria-hidden-on-focusable': 'error',
47
- 'security/detect-object-injection': 'off',
48
- 'react/forbid-elements': [
49
- 'error',
50
- {
51
- forbid: [
52
- { element: 'b', message: 'Do not use HTML for styling' },
53
- { element: 'i', message: 'Do not use HTML for styling' },
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
- 'react/jsx-no-useless-fragment': [
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;
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "test",
3
+ "version": "1.0.0",
4
+ "description": "Test JSON file",
5
+ "scripts": {
6
+ "test": "echo test"
7
+ }
8
+ }
@@ -0,0 +1,7 @@
1
+ name: test-config
2
+ version: 1.0.0
3
+ # Fixed indentation
4
+ description: Test YAML file
5
+ scripts:
6
+ test: echo test
7
+ build: echo build