@etchteam/eslint-config 2.2.201 → 2.6.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/AGENTS.md ADDED
@@ -0,0 +1,154 @@
1
+ # AGENTS.md
2
+
3
+ This file provides guidance to AI Agents when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is `@etchteam/eslint-config`, a shareable ESLint configuration package used by [Etch](https://etch.co). It provides modular, composable ESLint configurations for JavaScript, TypeScript, React, Angular, Next.js, Preact, Web Components, Node.js, and NestJS projects using ESLint 9's flat config format.
8
+
9
+ ## Development Commands
10
+
11
+ ### Linting
12
+ ```bash
13
+ # Lint the source code
14
+ npx eslint src
15
+
16
+ # Lint with auto-fix
17
+ npx eslint src --fix
18
+
19
+ # Test the config against test files (should produce errors)
20
+ npx eslint test-files/
21
+ ```
22
+
23
+ ### Release
24
+ ```bash
25
+ # Create a new release (runs semantic-release)
26
+ npm run release
27
+ ```
28
+
29
+ Note: There are no unit tests in this project. Testing is done by running ESLint against the `test-files/` directory, which should intentionally produce linting errors to verify the config rules work.
30
+
31
+ ## Architecture
32
+
33
+ ### Modular Config Structure
34
+
35
+ The configuration is split into composable modules:
36
+
37
+ ```
38
+ src/
39
+ ├── index.mjs # Default export (full config) + named exports
40
+ ├── base.mjs # Core: JS, TS, security, imports, prettier
41
+ ├── configs/
42
+ │ ├── json.mjs # JSON file linting
43
+ │ ├── yaml.mjs # YAML file linting
44
+ │ ├── storybook.mjs # Storybook linting
45
+ │ ├── react.mjs # React + jsx-a11y
46
+ │ └── environments/
47
+ │ ├── nextjs.mjs # Next.js (base + react + Next.js rules)
48
+ │ ├── nodejs.mjs # Node.js (base, no React)
49
+ │ ├── angular.mjs # Angular (base + angular-eslint)
50
+ │ ├── preact.mjs # Preact (base + react modified)
51
+ │ ├── web-components.mjs # Lit/Web Components
52
+ │ └── nestjs.mjs # NestJS (base + nestjs rules)
53
+ ├── utils/
54
+ │ └── fixup.mjs # Shared fixupPluginRules helper
55
+ └── types.d.ts # TypeScript definitions
56
+ ```
57
+
58
+ ### Config Composition
59
+
60
+ **Default export** (`src/index.mjs`): Backwards-compatible full config = `base + json + yaml + storybook + react`
61
+
62
+ **Named exports** for composition:
63
+ - `base`, `json`, `yaml`, `storybook`, `react` - Individual modules
64
+ - `nodejs`, `nextjs`, `preact`, `angular`, `webComponents`, `nestjs` - Self-contained environment configs
65
+
66
+ **Package.json exports map** provides direct imports:
67
+ - `@etchteam/eslint-config` - Default (full config)
68
+ - `@etchteam/eslint-config/base` - Base only
69
+ - `@etchteam/eslint-config/nextjs` - Next.js environment
70
+ - etc.
71
+
72
+ ### ESLint 9 Flat Config
73
+
74
+ This config uses ESLint 9's flat config format exclusively:
75
+
76
+ - **Compatibility layer**: `src/utils/fixup.mjs` wraps plugins that don't support flat config yet (import, jsx-a11y, you-dont-need-lodash-underscore, react)
77
+ - **Native flat config plugins**: unused-imports, typescript-eslint, security, yml, storybook, json
78
+ - **Parser configuration**: TypeScript ESLint parser in `languageOptions`
79
+
80
+ ### Dependencies
81
+
82
+ **Core dependencies** (always installed):
83
+ - `@eslint/compat`, `@eslint/js`, `typescript-eslint`
84
+ - `eslint-plugin-security`, `eslint-plugin-import`, `eslint-plugin-unused-imports`
85
+ - `eslint-plugin-prettier`, `eslint-config-prettier`
86
+ - `eslint-plugin-json`, `eslint-plugin-yml`, `eslint-plugin-storybook`
87
+ - `eslint-import-resolver-typescript`, `globals`
88
+
89
+ **Optional dependencies** (for environment-specific configs):
90
+ - `eslint-plugin-react`, `eslint-plugin-jsx-a11y` - React/Preact/Next.js
91
+ - `@next/eslint-plugin-next`, `eslint-plugin-react-hooks` - Next.js
92
+ - `angular-eslint` - Angular
93
+ - `eslint-plugin-lit` - Web Components
94
+ - `@darraghor/eslint-plugin-nestjs-typed` - NestJS
95
+
96
+ ### Key Rules
97
+
98
+ - **Unused imports**: Enforced via `eslint-plugin-unused-imports`
99
+ - **Import ordering**: Alphabetical with newlines between groups, `@/` paths treated as parent group
100
+ - **TypeScript**: `no-explicit-any` is warning (not error), unused vars are errors
101
+ - **React**: Forbids `<b>` and `<i>` elements, enforces read-only props, no useless fragments
102
+ - **Accessibility**: Includes extended jsx-a11y rules beyond the preset
103
+ - **Security**: Uses recommended config with `detect-object-injection` disabled
104
+ - **Prettier**: Single quotes enforced, integrated via `eslint-plugin-prettier`
105
+
106
+ ## Git Workflow
107
+
108
+ ### Commit Messages
109
+
110
+ This repo uses [Conventional Commits](https://www.conventionalcommits.org/) enforced by commitlint:
111
+ - Format: `type(scope): description`
112
+ - Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
113
+ - Validated by husky pre-commit hook running commitlint
114
+
115
+ ### Semantic Release
116
+
117
+ - Automatic versioning and publishing via semantic-release
118
+ - Runs on push to `main` branch via `.github/workflows/publish.yml`
119
+ - Release configuration in `release.config.js`
120
+ - Generates CHANGELOG.md automatically
121
+ - Publishes to npm with provenance
122
+
123
+ ### Git Hooks
124
+
125
+ Husky hooks are configured in `.husky/`:
126
+ - **pre-commit**: Runs `lint-staged` which executes `eslint --fix` on staged files matching `*.{ts,tsx,js,jsx,yml,yaml,json}`
127
+ - **commit-msg**: Validates commit messages with commitlint
128
+
129
+ Note: `HUSKY=0` environment variable disables hooks in CI.
130
+
131
+ ## CI/CD
132
+
133
+ ### CI Pipeline (`.github/workflows/ci.yml`)
134
+ - Runs on pull requests
135
+ - Tests against Node.js 18, 20, 22
136
+ - Lints source code with `npx eslint src`
137
+ - Validates config against `test-files/` (expects violations to prove rules work)
138
+
139
+ ### Publish Pipeline (`.github/workflows/publish.yml`)
140
+ - Runs on push to `main`
141
+ - Uses semantic-release to determine version, generate changelog, and publish
142
+ - Requires `NPM_TOKEN` secret for publishing
143
+
144
+ ## Test Strategy
145
+
146
+ This package uses a unique testing approach:
147
+ - `test-files/` directory contains intentionally badly-formatted code
148
+ - CI runs ESLint against these files and expects failures
149
+ - If ESLint passes on test files, the CI fails (proves rules aren't working)
150
+ - This validates that the config actually enforces the expected rules
151
+
152
+ ## Mergify Configuration
153
+
154
+ Auto-merge is configured in `.github/mergify.yml` for Dependabot PRs that pass CI.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,3 @@
1
- ## [2.2.201](https://github.com/etchteam/eslint/compare/v2.2.200...v2.2.201) (2026-01-06)
1
+ ## 2.6.0 (2026-01-28)
2
2
 
3
-
4
- ### Bug Fixes
5
-
6
- * bump @typescript-eslint/parser from 8.51.0 to 8.52.0 ([5810ff2](https://github.com/etchteam/eslint/commit/5810ff2f6bbdabe90146ed0d46feafa6d0273679))
3
+ * feat: upgrade to node 24 and set up node in publish ([0b5c3a4](https://github.com/etchteam/eslint/commit/0b5c3a4))
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
package/README.md CHANGED
@@ -20,9 +20,103 @@ import etchConfig from '@etchteam/eslint-config';
20
20
  export default etchConfig;
21
21
  ```
22
22
 
23
- ### With lint-staged
23
+ ## Environment-Specific Configs
24
24
 
25
- #### New project
25
+ For projects that don't need the full config, use environment-specific imports to reduce dependencies:
26
+
27
+ ### Next.js
28
+
29
+ ```javascript
30
+ import nextjs from '@etchteam/eslint-config/nextjs';
31
+
32
+ export default nextjs;
33
+ ```
34
+
35
+ ### Node.js / Express
36
+
37
+ ```javascript
38
+ import nodejs from '@etchteam/eslint-config/nodejs';
39
+
40
+ export default nodejs;
41
+ ```
42
+
43
+ ### Angular
44
+
45
+ ```javascript
46
+ import angular from '@etchteam/eslint-config/angular';
47
+
48
+ export default angular;
49
+ ```
50
+
51
+ ### Preact
52
+
53
+ ```javascript
54
+ import preact from '@etchteam/eslint-config/preact';
55
+
56
+ export default preact;
57
+ ```
58
+
59
+ ### Web Components (Lit)
60
+
61
+ ```javascript
62
+ import webComponents from '@etchteam/eslint-config/web-components';
63
+
64
+ export default webComponents;
65
+ ```
66
+
67
+ ### NestJS
68
+
69
+ ```javascript
70
+ import nestjs from '@etchteam/eslint-config/nestjs';
71
+
72
+ export default nestjs;
73
+ ```
74
+
75
+ ## Composable Configs
76
+
77
+ Build custom configs by combining individual modules:
78
+
79
+ ```javascript
80
+ import { base, json, yaml, react } from '@etchteam/eslint-config';
81
+
82
+ export default [
83
+ ...base,
84
+ ...json,
85
+ ...yaml,
86
+ ...react,
87
+ {
88
+ // Your custom overrides
89
+ rules: {
90
+ 'react/prefer-read-only-props': 'warn',
91
+ },
92
+ },
93
+ ];
94
+ ```
95
+
96
+ ### Available Modules
97
+
98
+ | Module | Description |
99
+ |--------|-------------|
100
+ | `base` | Core rules: JS, TypeScript, security, imports, prettier |
101
+ | `json` | JSON file linting |
102
+ | `yaml` | YAML file linting |
103
+ | `storybook` | Storybook best practices |
104
+ | `react` | React + JSX accessibility |
105
+
106
+ ### Environment Configs (Self-Contained)
107
+
108
+ | Config | Includes |
109
+ |--------|----------|
110
+ | `nextjs` | base + json + yaml + storybook + react + Next.js rules |
111
+ | `nodejs` | base + json + yaml + Node.js globals |
112
+ | `angular` | base + json + yaml + storybook + Angular rules |
113
+ | `preact` | base + json + yaml + storybook + react (Preact settings) |
114
+ | `web-components` | base + json + yaml + storybook + Lit rules |
115
+ | `nestjs` | base + json + yaml + NestJS rules + Jest globals |
116
+
117
+ ## With lint-staged
118
+
119
+ ### New project
26
120
 
27
121
  Run the following:
28
122
 
@@ -37,7 +131,7 @@ echo "npx --no-install -- lint-staged" > .husky/pre-commit
37
131
 
38
132
  ```
39
133
 
40
- #### Existing project with husky and lint staged
134
+ ### Existing project with husky and lint staged
41
135
 
42
136
  Add the following to your lint-staged config:
43
137
 
@@ -108,4 +202,4 @@ ESLint 9 uses flat config by default, so your existing npm scripts should work w
108
202
  - **Flat config format** - More explicit and performant
109
203
  - **ESLint 9 compatibility** - Latest features and fixes
110
204
  - **Updated plugins** - All plugins updated to latest versions
111
- - **Reduced compatibility layer** - Only 3 plugins need compatibility wrappers
205
+ - **Modular configs** - Import only what you need for your environment
package/package.json CHANGED
@@ -1,18 +1,30 @@
1
1
  {
2
2
  "name": "@etchteam/eslint-config",
3
- "version": "2.2.201",
3
+ "version": "2.6.0",
4
4
  "description": "Etch's standard eslint config",
5
5
  "type": "module",
6
6
  "main": "src/index.mjs",
7
7
  "exports": {
8
- ".": "./src/index.mjs"
8
+ ".": "./src/index.mjs",
9
+ "./base": "./src/base.mjs",
10
+ "./json": "./src/configs/json.mjs",
11
+ "./yaml": "./src/configs/yaml.mjs",
12
+ "./storybook": "./src/configs/storybook.mjs",
13
+ "./react": "./src/configs/react.mjs",
14
+ "./nodejs": "./src/configs/environments/nodejs.mjs",
15
+ "./nextjs": "./src/configs/environments/nextjs.mjs",
16
+ "./preact": "./src/configs/environments/preact.mjs",
17
+ "./angular": "./src/configs/environments/angular.mjs",
18
+ "./web-components": "./src/configs/environments/web-components.mjs",
19
+ "./nestjs": "./src/configs/environments/nestjs.mjs",
20
+ "./package.json": "./package.json"
9
21
  },
10
22
  "scripts": {
11
23
  "test": "echo \"Error: no test specified\" && exit 1",
12
24
  "release": "semantic-release"
13
25
  },
14
26
  "engines": {
15
- "node": "^18 || ^20 || ^22"
27
+ "node": "^20 || ^22 || ^24"
16
28
  },
17
29
  "repository": {
18
30
  "type": "git",
@@ -34,28 +46,38 @@
34
46
  "lint-staged": "^16.0.0"
35
47
  },
36
48
  "dependencies": {
37
- "@eslint/compat": "^1.3.0",
49
+ "@eslint/compat": "^2.0.1",
38
50
  "@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": "^16.0.0",
43
51
  "eslint-config-prettier": "^10.1.5",
52
+ "eslint-import-resolver-typescript": "^4.4.4",
44
53
  "eslint-plugin-import": "^2.32.0",
45
54
  "eslint-plugin-json": "^4.0.1",
46
- "eslint-plugin-jsx-a11y": "^6.10.2",
47
55
  "eslint-plugin-prettier": "^5.5.0",
48
- "eslint-plugin-react": "^7.37.5",
49
56
  "eslint-plugin-security": "^3.0.1",
50
57
  "eslint-plugin-storybook": "^10.0.1",
51
58
  "eslint-plugin-unused-imports": "^4.1.3",
52
- "eslint-plugin-yml": "^1.18.0",
59
+ "eslint-plugin-yml": "^3.0.0",
53
60
  "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0",
54
- "prettier": ">=3.0.0",
61
+ "globals": "^16.0.0",
55
62
  "typescript-eslint": "^8.35.0"
56
63
  },
64
+ "optionalDependencies": {
65
+ "@darraghor/eslint-plugin-nestjs-typed": "^6.0.0",
66
+ "@next/eslint-plugin-next": "^15.0.0",
67
+ "angular-eslint": "^19.0.0",
68
+ "eslint-plugin-jsx-a11y": "^6.10.2",
69
+ "eslint-plugin-lit": "^1.15.0",
70
+ "eslint-plugin-react": "^7.37.5",
71
+ "eslint-plugin-react-hooks": "^5.0.0"
72
+ },
57
73
  "peerDependencies": {
58
74
  "eslint": ">=9.0.0",
59
- "prettier": ">=3.0.0"
75
+ "prettier": ">=3.0.0",
76
+ "typescript": ">=4.8.4"
77
+ },
78
+ "peerDependenciesMeta": {
79
+ "typescript": {
80
+ "optional": true
81
+ }
60
82
  }
61
83
  }
package/src/base.mjs ADDED
@@ -0,0 +1,70 @@
1
+ import js from '@eslint/js';
2
+ import importPlugin from 'eslint-plugin-import';
3
+ import prettier from 'eslint-plugin-prettier/recommended';
4
+ import security from 'eslint-plugin-security';
5
+ import unusedImports from 'eslint-plugin-unused-imports';
6
+ import youDontNeedLodash from 'eslint-plugin-you-dont-need-lodash-underscore';
7
+ import tseslint from 'typescript-eslint';
8
+
9
+ import { fixupPluginRules } from './utils/fixup.mjs';
10
+
11
+ /**
12
+ * Base ESLint configuration for all projects.
13
+ * Includes: JavaScript, TypeScript, security, import ordering, prettier, and common rules.
14
+ * Does NOT include: React, JSX accessibility, JSON, YAML, or Storybook configs.
15
+ */
16
+ export default [
17
+ js.configs.recommended,
18
+ ...tseslint.configs.recommended,
19
+ security.configs.recommended,
20
+ {
21
+ files: ['**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'],
22
+ plugins: {
23
+ 'unused-imports': unusedImports,
24
+ import: fixupPluginRules(importPlugin),
25
+ 'you-dont-need-lodash-underscore': fixupPluginRules(youDontNeedLodash),
26
+ },
27
+ languageOptions: {
28
+ parser: tseslint.parser,
29
+ ecmaVersion: 'latest',
30
+ sourceType: 'module',
31
+ },
32
+ rules: {
33
+ 'no-unused-vars': 'off',
34
+ '@typescript-eslint/no-unused-vars': 'error',
35
+ '@typescript-eslint/no-explicit-any': 'warn',
36
+ 'unused-imports/no-unused-imports': 'error',
37
+ 'unused-imports/no-unused-vars': 'off',
38
+ 'import/order': [
39
+ 'error',
40
+ {
41
+ 'newlines-between': 'always',
42
+ alphabetize: {
43
+ order: 'asc',
44
+ },
45
+ pathGroups: [
46
+ {
47
+ pattern: '@/**',
48
+ group: 'parent',
49
+ },
50
+ ],
51
+ },
52
+ ],
53
+ 'prettier/prettier': [
54
+ 'error',
55
+ {
56
+ singleQuote: true,
57
+ },
58
+ ],
59
+ 'security/detect-object-injection': 'off',
60
+ 'spaced-comment': 'error',
61
+ },
62
+ settings: {
63
+ 'import/resolver': {
64
+ typescript: true,
65
+ node: true,
66
+ },
67
+ },
68
+ },
69
+ prettier,
70
+ ];
@@ -0,0 +1,53 @@
1
+ import angular from 'angular-eslint';
2
+
3
+ import base from '../../base.mjs';
4
+ import json from '../json.mjs';
5
+ import storybook from '../storybook.mjs';
6
+ import yaml from '../yaml.mjs';
7
+
8
+ /**
9
+ * Angular ESLint configuration.
10
+ * Includes: base + JSON + YAML + Storybook + Angular rules
11
+ *
12
+ * Usage:
13
+ * ```js
14
+ * import angular from '@etchteam/eslint-config/angular';
15
+ * export default angular;
16
+ * ```
17
+ */
18
+ export default [
19
+ ...base,
20
+ ...json,
21
+ ...yaml,
22
+ ...storybook,
23
+ {
24
+ files: ['**/*.ts'],
25
+ extends: [...angular.configs.tsRecommended],
26
+ processor: angular.processInlineTemplates,
27
+ rules: {
28
+ '@angular-eslint/directive-selector': [
29
+ 'error',
30
+ {
31
+ type: 'attribute',
32
+ prefix: 'app',
33
+ style: 'camelCase',
34
+ },
35
+ ],
36
+ '@angular-eslint/component-selector': [
37
+ 'error',
38
+ {
39
+ type: 'element',
40
+ prefix: 'app',
41
+ style: 'kebab-case',
42
+ },
43
+ ],
44
+ },
45
+ },
46
+ {
47
+ files: ['**/*.html'],
48
+ extends: [
49
+ ...angular.configs.templateRecommended,
50
+ ...angular.configs.templateAccessibility,
51
+ ],
52
+ },
53
+ ];
@@ -0,0 +1,31 @@
1
+ import nestjs from '@darraghor/eslint-plugin-nestjs-typed';
2
+ import globals from 'globals';
3
+
4
+ import base from '../../base.mjs';
5
+ import json from '../json.mjs';
6
+ import yaml from '../yaml.mjs';
7
+
8
+ /**
9
+ * NestJS ESLint configuration.
10
+ * Includes: base + JSON + YAML + NestJS rules + Node.js/Jest globals
11
+ *
12
+ * Usage:
13
+ * ```js
14
+ * import nestjs from '@etchteam/eslint-config/nestjs';
15
+ * export default nestjs;
16
+ * ```
17
+ */
18
+ export default [
19
+ ...base,
20
+ ...json,
21
+ ...yaml,
22
+ {
23
+ languageOptions: {
24
+ globals: {
25
+ ...globals.node,
26
+ ...globals.jest,
27
+ },
28
+ },
29
+ },
30
+ nestjs.configs.flatRecommended,
31
+ ];
@@ -0,0 +1,40 @@
1
+ import nextPlugin from '@next/eslint-plugin-next';
2
+ import reactHooks from 'eslint-plugin-react-hooks';
3
+
4
+ import base from '../../base.mjs';
5
+ import json from '../json.mjs';
6
+ import react from '../react.mjs';
7
+ import storybook from '../storybook.mjs';
8
+ import yaml from '../yaml.mjs';
9
+
10
+ /**
11
+ * Next.js ESLint configuration.
12
+ * Includes: base + JSON + YAML + Storybook + React + Next.js rules
13
+ *
14
+ * Usage:
15
+ * ```js
16
+ * import nextjs from '@etchteam/eslint-config/nextjs';
17
+ * export default nextjs;
18
+ * ```
19
+ */
20
+ export default [
21
+ ...base,
22
+ ...json,
23
+ ...yaml,
24
+ ...storybook,
25
+ ...react,
26
+ {
27
+ plugins: {
28
+ '@next/next': nextPlugin,
29
+ 'react-hooks': reactHooks,
30
+ },
31
+ rules: {
32
+ ...nextPlugin.configs.recommended.rules,
33
+ ...nextPlugin.configs['core-web-vitals'].rules,
34
+ ...reactHooks.configs.recommended.rules,
35
+ 'import/no-anonymous-default-export': 'warn',
36
+ 'react/react-in-jsx-scope': 'off',
37
+ 'react/prop-types': 'off',
38
+ },
39
+ },
40
+ ];
@@ -0,0 +1,27 @@
1
+ import globals from 'globals';
2
+
3
+ import base from '../../base.mjs';
4
+ import json from '../json.mjs';
5
+ import yaml from '../yaml.mjs';
6
+
7
+ /**
8
+ * Node.js backend ESLint configuration.
9
+ * Includes: base + JSON + YAML + Node.js globals
10
+ * Does NOT include: React, Storybook
11
+ *
12
+ * Usage:
13
+ * ```js
14
+ * import nodejs from '@etchteam/eslint-config/nodejs';
15
+ * export default nodejs;
16
+ * ```
17
+ */
18
+ export default [
19
+ ...base,
20
+ ...json,
21
+ ...yaml,
22
+ {
23
+ languageOptions: {
24
+ globals: globals.node,
25
+ },
26
+ },
27
+ ];
@@ -0,0 +1,35 @@
1
+ import base from '../../base.mjs';
2
+ import json from '../json.mjs';
3
+ import react from '../react.mjs';
4
+ import storybook from '../storybook.mjs';
5
+ import yaml from '../yaml.mjs';
6
+
7
+ /**
8
+ * Preact ESLint configuration.
9
+ * Includes: base + JSON + YAML + Storybook + React (modified for Preact)
10
+ *
11
+ * Usage:
12
+ * ```js
13
+ * import preact from '@etchteam/eslint-config/preact';
14
+ * export default preact;
15
+ * ```
16
+ */
17
+ export default [
18
+ ...base,
19
+ ...json,
20
+ ...yaml,
21
+ ...storybook,
22
+ ...react,
23
+ {
24
+ settings: {
25
+ react: {
26
+ pragma: 'h',
27
+ version: 'detect',
28
+ },
29
+ },
30
+ rules: {
31
+ 'react/prop-types': 'off',
32
+ 'react/react-in-jsx-scope': 'off',
33
+ },
34
+ },
35
+ ];
@@ -0,0 +1,24 @@
1
+ import lit from 'eslint-plugin-lit';
2
+
3
+ import base from '../../base.mjs';
4
+ import json from '../json.mjs';
5
+ import storybook from '../storybook.mjs';
6
+ import yaml from '../yaml.mjs';
7
+
8
+ /**
9
+ * Web Components (Lit) ESLint configuration.
10
+ * Includes: base + JSON + YAML + Storybook + Lit rules
11
+ *
12
+ * Usage:
13
+ * ```js
14
+ * import webComponents from '@etchteam/eslint-config/web-components';
15
+ * export default webComponents;
16
+ * ```
17
+ */
18
+ export default [
19
+ ...base,
20
+ ...json,
21
+ ...yaml,
22
+ ...storybook,
23
+ lit.configs['flat/recommended'],
24
+ ];
@@ -0,0 +1,11 @@
1
+ import json from 'eslint-plugin-json';
2
+
3
+ /**
4
+ * JSON file linting configuration.
5
+ */
6
+ export default [
7
+ {
8
+ files: ['**/*.json'],
9
+ ...json.configs.recommended,
10
+ },
11
+ ];
@@ -0,0 +1,42 @@
1
+ import jsxA11y from 'eslint-plugin-jsx-a11y';
2
+ import react from 'eslint-plugin-react';
3
+
4
+ import { fixupPluginRules } from '../utils/fixup.mjs';
5
+
6
+ /**
7
+ * React and JSX accessibility linting configuration.
8
+ */
9
+ export default [
10
+ {
11
+ files: ['**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'],
12
+ plugins: {
13
+ react: fixupPluginRules(react),
14
+ 'jsx-a11y': fixupPluginRules(jsxA11y),
15
+ },
16
+ rules: {
17
+ 'jsx-a11y/anchor-ambiguous-text': 'error',
18
+ 'jsx-a11y/no-aria-hidden-on-focusable': 'error',
19
+ 'react/forbid-elements': [
20
+ 'error',
21
+ {
22
+ forbid: [
23
+ { element: 'b', message: 'Do not use HTML for styling' },
24
+ { element: 'i', message: 'Do not use HTML for styling' },
25
+ ],
26
+ },
27
+ ],
28
+ 'react/jsx-no-useless-fragment': [
29
+ 'error',
30
+ {
31
+ allowExpressions: true,
32
+ },
33
+ ],
34
+ 'react/prefer-read-only-props': 'error',
35
+ },
36
+ settings: {
37
+ react: {
38
+ version: 'detect',
39
+ },
40
+ },
41
+ },
42
+ ];
@@ -0,0 +1,6 @@
1
+ import storybook from 'eslint-plugin-storybook';
2
+
3
+ /**
4
+ * Storybook linting configuration.
5
+ */
6
+ export default storybook.configs['flat/recommended'];
@@ -0,0 +1,6 @@
1
+ import yml from 'eslint-plugin-yml';
2
+
3
+ /**
4
+ * YAML file linting configuration.
5
+ */
6
+ export default yml.configs['flat/recommended'];
package/src/index.mjs CHANGED
@@ -1,101 +1,36 @@
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';
1
+ import base from './base.mjs';
2
+ import json from './configs/json.mjs';
3
+ import reactConfig from './configs/react.mjs';
4
+ import storybook from './configs/storybook.mjs';
5
+ import yaml from './configs/yaml.mjs';
14
6
 
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,
7
+ // Named exports for composable configs
8
+ export { default as base } from './base.mjs';
9
+ export { default as json } from './configs/json.mjs';
10
+ export { default as react } from './configs/react.mjs';
11
+ export { default as storybook } from './configs/storybook.mjs';
12
+ export { default as yaml } from './configs/yaml.mjs';
29
13
 
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',
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,
94
- },
95
- react: {
96
- version: 'detect',
97
- },
98
- },
99
- },
100
- prettier, // Prettier recommended config
101
- ];
14
+ /**
15
+ * Default export - Full ESLint configuration (backwards compatible)
16
+ * Includes: base + JSON + YAML + Storybook + React
17
+ *
18
+ * Usage:
19
+ * ```js
20
+ * import etchConfig from '@etchteam/eslint-config';
21
+ * export default etchConfig;
22
+ * ```
23
+ *
24
+ * For environment-specific or composable usage, use named exports:
25
+ * ```js
26
+ * import { base, react } from '@etchteam/eslint-config';
27
+ * export default [...base, ...react];
28
+ * ```
29
+ *
30
+ * Or import specific environment configs:
31
+ * ```js
32
+ * import nextjs from '@etchteam/eslint-config/nextjs';
33
+ * export default nextjs;
34
+ * ```
35
+ */
36
+ export default [...base, ...json, ...yaml, ...storybook, ...reactConfig];
package/src/types.d.ts ADDED
@@ -0,0 +1,72 @@
1
+ import type { Linter } from 'eslint';
2
+
3
+ type FlatConfigArray = Linter.Config[];
4
+
5
+ /**
6
+ * Base ESLint configuration for all projects.
7
+ * Includes: JavaScript, TypeScript, security, import ordering, prettier, and common rules.
8
+ */
9
+ export declare const base: FlatConfigArray;
10
+
11
+ /**
12
+ * JSON file linting configuration.
13
+ */
14
+ export declare const json: FlatConfigArray;
15
+
16
+ /**
17
+ * YAML file linting configuration.
18
+ */
19
+ export declare const yaml: FlatConfigArray;
20
+
21
+ /**
22
+ * Storybook linting configuration.
23
+ */
24
+ export declare const storybook: FlatConfigArray;
25
+
26
+ /**
27
+ * React and JSX accessibility linting configuration.
28
+ */
29
+ export declare const react: FlatConfigArray;
30
+
31
+ /**
32
+ * Node.js backend ESLint configuration.
33
+ * Includes: base + JSON + YAML + Node.js globals
34
+ */
35
+ export declare const nodejs: FlatConfigArray;
36
+
37
+ /**
38
+ * Next.js ESLint configuration.
39
+ * Includes: base + JSON + YAML + Storybook + React + Next.js rules
40
+ */
41
+ export declare const nextjs: FlatConfigArray;
42
+
43
+ /**
44
+ * Preact ESLint configuration.
45
+ * Includes: base + JSON + YAML + Storybook + React (modified for Preact)
46
+ */
47
+ export declare const preact: FlatConfigArray;
48
+
49
+ /**
50
+ * Angular ESLint configuration.
51
+ * Includes: base + JSON + YAML + Storybook + Angular rules
52
+ */
53
+ export declare const angular: FlatConfigArray;
54
+
55
+ /**
56
+ * Web Components (Lit) ESLint configuration.
57
+ * Includes: base + JSON + YAML + Storybook + Lit rules
58
+ */
59
+ export declare const webComponents: FlatConfigArray;
60
+
61
+ /**
62
+ * NestJS ESLint configuration.
63
+ * Includes: base + JSON + YAML + NestJS rules + Node.js/Jest globals
64
+ */
65
+ export declare const nestjs: FlatConfigArray;
66
+
67
+ /**
68
+ * Default export - Full ESLint configuration (backwards compatible)
69
+ * Includes: base + JSON + YAML + Storybook + React
70
+ */
71
+ declare const config: FlatConfigArray;
72
+ export default config;
@@ -0,0 +1,21 @@
1
+ import { fixupPluginRules } from '@eslint/compat';
2
+
3
+ /**
4
+ * Wraps plugins that don't yet support ESLint 9 flat config natively.
5
+ * This provides a centralized place to manage compatibility wrappers.
6
+ */
7
+ export { fixupPluginRules };
8
+
9
+ /**
10
+ * Helper to wrap multiple plugins at once
11
+ * @param {Record<string, object>} plugins - Object mapping plugin names to plugin modules
12
+ * @returns {Record<string, object>} - Object with wrapped plugins
13
+ */
14
+ export function fixupPlugins(plugins) {
15
+ return Object.fromEntries(
16
+ Object.entries(plugins).map(([name, plugin]) => [
17
+ name,
18
+ fixupPluginRules(plugin),
19
+ ]),
20
+ );
21
+ }