eslint-config-agent 3.0.4 → 3.1.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/CHANGELOG.md +158 -0
- package/README.md +592 -26
- package/configs/base-plugins.js +32 -0
- package/configs/config-files.js +19 -3
- package/configs/examples.js +12 -1
- package/configs/javascript.js +12 -4
- package/configs/length-rule-scope.js +27 -0
- package/configs/overrides.js +3 -14
- package/configs/test-files.js +40 -1
- package/configs/tsx.js +10 -0
- package/configs/typescript.js +44 -2
- package/exports/ddd.d.ts +10 -0
- package/exports/ddd.js +1 -3
- package/exports/incremental.d.ts +11 -0
- package/exports/incremental.js +39 -0
- package/exports/recommended-incremental.d.ts +11 -0
- package/exports/recommended-incremental.js +46 -0
- package/exports/recommended.d.ts +14 -0
- package/exports/recommended.js +110 -0
- package/exports/to-warnings.d.ts +20 -0
- package/exports/to-warnings.js +41 -0
- package/index.d.ts +18 -0
- package/index.js +883 -7
- package/package.json +46 -17
- package/plugins/index.js +6 -0
- package/rules/index.js +20 -22
- package/rules/no-inline-union-types/index.js +8 -6
- package/rules/no-process-env-properties/index.js +4 -4
- package/rules/no-record-literal-types/index.js +3 -3
- package/rules/plugin/import/index.js +41 -0
- package/rules/plugin/index.js +0 -2
- package/rules/plugin/n/index.js +16 -2
- package/rules/plugin/n/no-process-env/index.js +4 -4
- package/rules/plugin/react/index.js +150 -2
- package/rules/plugin/typescript-eslint/index.js +406 -0
- package/rules/require-spec-file-tsx/README.md +57 -0
- package/rules/require-spec-file-tsx/helpers.js +93 -0
- package/rules/require-spec-file-tsx/index.js +109 -0
- package/rules/plugin/jsx-a11y/index.js +0 -3
package/configs/base-plugins.js
CHANGED
|
@@ -46,6 +46,37 @@ export const basePluginsConfig = [
|
|
|
46
46
|
],
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
+
// Require spec files for .tsx/.jsx source files too.
|
|
50
|
+
//
|
|
51
|
+
// `ddd/require-spec-file` only inspects `.js`/`.ts` files, so React/Preact
|
|
52
|
+
// components — the code this config primarily targets — were silently exempt
|
|
53
|
+
// from the spec requirement. This custom rule covers the JSX extensions with
|
|
54
|
+
// the same heuristic, completing the "spec file for every source file"
|
|
55
|
+
// promise. Its excludePatterns mirror the JSX-relevant entries of the `ddd`
|
|
56
|
+
// list above (index/stories files are exempt; the error/exception file
|
|
57
|
+
// patterns are exempt; `.spec`/`.test` files are skipped by the rule
|
|
58
|
+
// itself).
|
|
59
|
+
{
|
|
60
|
+
rules: {
|
|
61
|
+
'custom/require-spec-file-tsx': [
|
|
62
|
+
'error',
|
|
63
|
+
{
|
|
64
|
+
excludePatterns: [
|
|
65
|
+
'**/index.tsx',
|
|
66
|
+
'**/index.jsx',
|
|
67
|
+
'**/*.stories.{tsx,jsx}',
|
|
68
|
+
// Mirror the ddd error/exception exemptions for JSX extensions so
|
|
69
|
+
// an error component (e.g. an error boundary) is not singled out
|
|
70
|
+
// for a spec file when its `.ts` equivalent is exempt.
|
|
71
|
+
'**/*-error.{tsx,jsx}',
|
|
72
|
+
'**/*.error.{tsx,jsx}',
|
|
73
|
+
'**/errors/**',
|
|
74
|
+
'**/exceptions/**',
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
49
80
|
// Disable DDD for config infrastructure files
|
|
50
81
|
{
|
|
51
82
|
files: [
|
|
@@ -60,6 +91,7 @@ export const basePluginsConfig = [
|
|
|
60
91
|
],
|
|
61
92
|
rules: {
|
|
62
93
|
'ddd/require-spec-file': 'off',
|
|
94
|
+
'custom/require-spec-file-tsx': 'off',
|
|
63
95
|
},
|
|
64
96
|
},
|
|
65
97
|
]
|
package/configs/config-files.js
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration for configuration files
|
|
3
3
|
* Allows hardcoded values and default exports in config files
|
|
4
|
+
*
|
|
5
|
+
* The `*.config.*` and `eslint.config.*` globs are recursive (they are
|
|
6
|
+
* prefixed with a globstar) so the relaxations also reach config files that
|
|
7
|
+
* live below the repo root — e.g. `apps/web/vite.config.ts` or
|
|
8
|
+
* `packages/ui/eslint.config.mjs` in a monorepo. Previously these used
|
|
9
|
+
* root-only globs (`*.config.{...}`), so a nested `eslint.config.mjs` /
|
|
10
|
+
* `vite.config.ts` silently escaped the config-file relaxations and got hit
|
|
11
|
+
* with `default/no-localhost`, `default/no-hardcoded-urls`, `max-lines`, etc.
|
|
12
|
+
* — the same asymmetry the `.mjs`/`.cjs` coverage fix addressed for the
|
|
13
|
+
* JavaScript rule set. This now mirrors the recursive-glob convention every
|
|
14
|
+
* other config block already uses.
|
|
15
|
+
*
|
|
16
|
+
* `index.js` is intentionally left root-scoped: broadening it to a recursive
|
|
17
|
+
* glob would relax these rules for every barrel/entry file in a consumer's
|
|
18
|
+
* source tree, masking real issues. Only files whose names mark them as
|
|
19
|
+
* configuration (`*.config.*`, `eslint.config.*`) are matched recursively.
|
|
4
20
|
*/
|
|
5
21
|
|
|
6
22
|
export const configFilesConfig = [
|
|
7
23
|
// Configuration files - allow hardcoded values for configuration purposes
|
|
8
24
|
{
|
|
9
25
|
files: [
|
|
10
|
-
'
|
|
11
|
-
'eslint.config.{js,ts}',
|
|
26
|
+
'**/*.config.{js,ts,mjs,cjs}',
|
|
27
|
+
'**/eslint.config.{js,ts,mjs,cjs}',
|
|
12
28
|
'index.js',
|
|
13
|
-
'**/configs/**/*.{js,ts}',
|
|
29
|
+
'**/configs/**/*.{js,ts,mjs,cjs}',
|
|
14
30
|
],
|
|
15
31
|
rules: {
|
|
16
32
|
'default/no-localhost': 'off',
|
package/configs/examples.js
CHANGED
|
@@ -45,7 +45,7 @@ const sharedRestrictedSyntax = [
|
|
|
45
45
|
message:
|
|
46
46
|
'Exporting from external libraries is not allowed. Only re-export from relative paths or scoped packages.',
|
|
47
47
|
},
|
|
48
|
-
allRules.
|
|
48
|
+
allRules.noProcessEnvironmentPropertiesConfig,
|
|
49
49
|
allRules.noExportSpecifiersConfig,
|
|
50
50
|
...allRules.noDefaultClassExportRules,
|
|
51
51
|
]
|
|
@@ -83,10 +83,21 @@ export const examplesConfig = [
|
|
|
83
83
|
// Relax file/function length limits for concise examples
|
|
84
84
|
'max-lines-per-function': 'off',
|
|
85
85
|
'max-lines': 'off',
|
|
86
|
+
// Example fixtures demonstrate rule behavior and use `console.log` as
|
|
87
|
+
// illustrative sample code, so the shared `no-console` ban does not apply.
|
|
88
|
+
'no-console': 'off',
|
|
86
89
|
// Examples don't need JSDoc
|
|
87
90
|
'jsdoc/require-jsdoc': 'off',
|
|
88
91
|
'jsdoc/require-param': 'off',
|
|
89
92
|
'jsdoc/require-returns': 'off',
|
|
90
93
|
},
|
|
91
94
|
},
|
|
95
|
+
{
|
|
96
|
+
// JavaScript example fixtures (the `.ts` block above only matches `.ts`).
|
|
97
|
+
// They likewise use `console.log` as sample code.
|
|
98
|
+
files: ['**/rules/**/examples/**/*.js'],
|
|
99
|
+
rules: {
|
|
100
|
+
'no-console': 'off',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
92
103
|
]
|
package/configs/javascript.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JavaScript File Configurations
|
|
3
3
|
*
|
|
4
|
-
* Handles all JavaScript (.js) file-specific rules.
|
|
4
|
+
* Handles all JavaScript (.js, .mjs, .cjs) file-specific rules.
|
|
5
5
|
* Plugin registration removed - all plugins registered globally in index.js.
|
|
6
|
+
*
|
|
7
|
+
* The ESM/CommonJS extensions (`.mjs`/`.cjs`) are linted with the same rule set
|
|
8
|
+
* as plain `.js`, mirroring how the TypeScript config covers `.mts`/`.cts`
|
|
9
|
+
* alongside `.ts`. Previously these were ignored here, so `.mjs`/`.cjs` source
|
|
10
|
+
* files silently escaped the package's signature `no-restricted-syntax`,
|
|
11
|
+
* `single-export`, and `required-exports` rules.
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
import globals from 'globals'
|
|
@@ -10,15 +16,13 @@ import globals from 'globals'
|
|
|
10
16
|
export const javascriptConfig = (sharedRules, sharedRestrictedSyntax) => [
|
|
11
17
|
// JavaScript files (not JSX)
|
|
12
18
|
{
|
|
13
|
-
files: ['**/*.js'],
|
|
19
|
+
files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
|
|
14
20
|
ignores: [
|
|
15
21
|
'**/node_modules/**',
|
|
16
22
|
'**/dist/**',
|
|
17
23
|
'**/build/**',
|
|
18
24
|
'pnpm-lock.yaml',
|
|
19
25
|
'**/*.umd.js',
|
|
20
|
-
'**/*.cjs',
|
|
21
|
-
'**/*.mjs',
|
|
22
26
|
'**/*.stories.{js,jsx,ts,tsx}',
|
|
23
27
|
'**/rules/**/index.js',
|
|
24
28
|
],
|
|
@@ -70,6 +74,10 @@ export const javascriptConfig = (sharedRules, sharedRestrictedSyntax) => [
|
|
|
70
74
|
},
|
|
71
75
|
rules: {
|
|
72
76
|
...sharedRules,
|
|
77
|
+
// Build/CI tooling under `scripts/` is a console program: printing to
|
|
78
|
+
// stdout is its job, so the shared `no-console` ban (aimed at leftover
|
|
79
|
+
// debugging in shipped source) does not apply here.
|
|
80
|
+
'no-console': 'off',
|
|
73
81
|
'no-restricted-syntax': ['error', ...sharedRestrictedSyntax],
|
|
74
82
|
},
|
|
75
83
|
},
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function/File Length Rule Scope
|
|
3
|
+
*
|
|
4
|
+
* `files`/`ignores` scope shared by the strict (error-level)
|
|
5
|
+
* `max-lines-per-function`/`max-lines` block in `configs/overrides.js` and the
|
|
6
|
+
* `recommended` preset's warn-level equivalent (`exports/recommended.js`).
|
|
7
|
+
* Extracted to its own module so the two can never drift apart — the preset
|
|
8
|
+
* only needs to relax the *severity*, not widen or narrow which files the
|
|
9
|
+
* rules apply to (tests, stories, config files, and this package's own
|
|
10
|
+
* `index.js` stay exempt either way).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const lengthRuleFileMatch = {
|
|
14
|
+
files: ['**/*.{ts,tsx,js,jsx}'],
|
|
15
|
+
ignores: [
|
|
16
|
+
'**/*.stories.{js,jsx,ts,tsx}',
|
|
17
|
+
'**/*.test.{js,jsx,ts,tsx}',
|
|
18
|
+
'**/*.spec.{js,jsx,ts,tsx}',
|
|
19
|
+
'**/test/**/*.{js,jsx,ts,tsx}',
|
|
20
|
+
'**/tests/**/*.{js,jsx,ts,tsx}',
|
|
21
|
+
'**/__tests__/**/*.{js,jsx,ts,tsx}',
|
|
22
|
+
'**/configs/**/*.{js,ts}',
|
|
23
|
+
'*.config.{js,ts}',
|
|
24
|
+
'eslint.config.{js,ts}',
|
|
25
|
+
'index.js',
|
|
26
|
+
],
|
|
27
|
+
}
|
package/configs/overrides.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import globals from 'globals'
|
|
9
9
|
import allRules from '../rules/index.js'
|
|
10
|
+
import { lengthRuleFileMatch } from './length-rule-scope.js'
|
|
10
11
|
|
|
11
12
|
export const overridesConfig = (
|
|
12
13
|
sharedRestrictedSyntax,
|
|
@@ -79,7 +80,7 @@ export const overridesConfig = (
|
|
|
79
80
|
'Type assertions with indexed access types like "as (typeof X)[number]" are not allowed. Use a named type instead.',
|
|
80
81
|
},
|
|
81
82
|
allRules.noTypeAssertionsConfig,
|
|
82
|
-
allRules.
|
|
83
|
+
allRules.noProcessEnvironmentPropertiesConfig,
|
|
83
84
|
allRules.noExportSpecifiersConfig,
|
|
84
85
|
],
|
|
85
86
|
},
|
|
@@ -87,19 +88,7 @@ export const overridesConfig = (
|
|
|
87
88
|
|
|
88
89
|
// Function and file length rules - strict error thresholds
|
|
89
90
|
{
|
|
90
|
-
|
|
91
|
-
ignores: [
|
|
92
|
-
'**/*.stories.{js,jsx,ts,tsx}',
|
|
93
|
-
'**/*.test.{js,jsx,ts,tsx}',
|
|
94
|
-
'**/*.spec.{js,jsx,ts,tsx}',
|
|
95
|
-
'**/test/**/*.{js,jsx,ts,tsx}',
|
|
96
|
-
'**/tests/**/*.{js,jsx,ts,tsx}',
|
|
97
|
-
'**/__tests__/**/*.{js,jsx,ts,tsx}',
|
|
98
|
-
'**/configs/**/*.{js,ts}',
|
|
99
|
-
'*.config.{js,ts}',
|
|
100
|
-
'eslint.config.{js,ts}',
|
|
101
|
-
'index.js',
|
|
102
|
-
],
|
|
91
|
+
...lengthRuleFileMatch,
|
|
103
92
|
rules: {
|
|
104
93
|
'max-lines-per-function': allRules.maxFunctionLinesError,
|
|
105
94
|
'max-lines': allRules.maxFileLinesError,
|
package/configs/test-files.js
CHANGED
|
@@ -58,7 +58,7 @@ const sharedRestrictedSyntax = [
|
|
|
58
58
|
message:
|
|
59
59
|
'Exporting from external libraries is not allowed. Only re-export from relative paths or scoped packages.',
|
|
60
60
|
},
|
|
61
|
-
allRules.
|
|
61
|
+
allRules.noProcessEnvironmentPropertiesConfig,
|
|
62
62
|
allRules.noExportSpecifiersConfig,
|
|
63
63
|
...allRules.noDefaultClassExportRules,
|
|
64
64
|
]
|
|
@@ -101,13 +101,49 @@ export const testFilesConfig = [
|
|
|
101
101
|
rules: {
|
|
102
102
|
'max-lines-per-function': 'off',
|
|
103
103
|
'max-lines': 'off', // Ignore file length limits in test and spec files
|
|
104
|
+
// The shared config bans bare `console.log` in shipped source, but test
|
|
105
|
+
// and rule-tester spec files use `console.log` legitimately to report
|
|
106
|
+
// progress and assertions (this package's own `*.test.js` runners do
|
|
107
|
+
// exactly that), and fixtures embed it as sample code. Keep the rule on
|
|
108
|
+
// for real source and off here so test logging is not flagged.
|
|
109
|
+
'no-console': 'off',
|
|
104
110
|
'default/no-localhost': ['error', { allowInTests: true }],
|
|
105
111
|
'default/no-hardcoded-urls': ['error', { allowInTests: true }],
|
|
106
112
|
'default/no-default-params': 'off', // Allow default parameters in test files for demonstration purposes
|
|
113
|
+
// Test and rule-tester spec files routinely embed source snippets inside
|
|
114
|
+
// string literals as fixtures (e.g. `code: 'const x = `${y}`'`), where a
|
|
115
|
+
// literal `${...}` is the intended payload, not a mis-quoted template.
|
|
116
|
+
// Keep no-template-curly-in-string on for real source but off here so the
|
|
117
|
+
// fixtures are not flagged.
|
|
118
|
+
'no-template-curly-in-string': 'off',
|
|
107
119
|
// Disable error plugin rules in test files
|
|
108
120
|
'error/no-generic-error': 'off',
|
|
109
121
|
'error/require-custom-error': 'off',
|
|
110
122
|
'error/no-throw-literal': 'off',
|
|
123
|
+
// Relax the noisy `eslint-plugin-security` heuristics for test code.
|
|
124
|
+
//
|
|
125
|
+
// These rules exist to harden *shipped* code against attacker-controlled
|
|
126
|
+
// input, but their detection is purely syntactic and fires constantly on
|
|
127
|
+
// perfectly safe test setup: a fixture path built from a temp dir
|
|
128
|
+
// (`detect-non-literal-fs-filename`), indexing a lookup table by a loop
|
|
129
|
+
// variable (`detect-object-injection`), compiling a pattern from a test
|
|
130
|
+
// input (`detect-non-literal-regexp`), spawning a helper binary in an
|
|
131
|
+
// integration test (`detect-child-process`), or `require`-ing a module
|
|
132
|
+
// resolved at runtime in a fixture loader (`detect-non-literal-require`).
|
|
133
|
+
// None of these are vulnerabilities in test files — the inputs are the
|
|
134
|
+
// test's own literals, not untrusted data, and the code never reaches
|
|
135
|
+
// production — so they are false positives that force adopters to litter
|
|
136
|
+
// specs with `eslint-disable` comments (this package's own
|
|
137
|
+
// `scripts/test-runner.js` already does exactly that). Turning them off
|
|
138
|
+
// for tests mirrors the `error/*` relaxations above; the genuinely
|
|
139
|
+
// value-adding security rules (`detect-unsafe-regex` for ReDoS,
|
|
140
|
+
// `detect-eval-with-expression`, `detect-buffer-noassert`, the timing and
|
|
141
|
+
// bidi-character checks) stay enabled everywhere.
|
|
142
|
+
'security/detect-non-literal-fs-filename': 'off',
|
|
143
|
+
'security/detect-object-injection': 'off',
|
|
144
|
+
'security/detect-non-literal-regexp': 'off',
|
|
145
|
+
'security/detect-child-process': 'off',
|
|
146
|
+
'security/detect-non-literal-require': 'off',
|
|
111
147
|
// Allow multiple exports in test files for testing import/export patterns
|
|
112
148
|
'no-restricted-syntax': [
|
|
113
149
|
'warn',
|
|
@@ -204,6 +240,9 @@ export const testFilesConfig = [
|
|
|
204
240
|
'jsdoc/require-jsdoc': 'off',
|
|
205
241
|
'jsdoc/require-param': 'off',
|
|
206
242
|
'jsdoc/require-returns': 'off',
|
|
243
|
+
// Spec files act as CLI test runners and legitimately call process.exit()
|
|
244
|
+
// to report pass/fail status — the unicorn rule is for library code only.
|
|
245
|
+
'unicorn/no-process-exit': 'off',
|
|
207
246
|
},
|
|
208
247
|
},
|
|
209
248
|
|
package/configs/tsx.js
CHANGED
|
@@ -30,9 +30,19 @@ export const tsxConfig = (
|
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
settings: {
|
|
33
|
+
react: {
|
|
34
|
+
version: 'detect',
|
|
35
|
+
},
|
|
33
36
|
'import/resolver': {
|
|
34
37
|
typescript: {},
|
|
35
38
|
},
|
|
39
|
+
// Tell eslint-plugin-import to parse TypeScript dependency files with the
|
|
40
|
+
// TS parser. Without this, the resolver finds the file but the plugin
|
|
41
|
+
// cannot read its imports/exports, so cross-file rules like
|
|
42
|
+
// import/no-cycle silently never fire on .ts/.tsx code.
|
|
43
|
+
'import/parsers': {
|
|
44
|
+
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
|
|
45
|
+
},
|
|
36
46
|
},
|
|
37
47
|
rules: {
|
|
38
48
|
...sharedRules,
|
package/configs/typescript.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript File Configurations
|
|
3
3
|
*
|
|
4
|
-
* Handles all TypeScript (.ts) file-specific rules.
|
|
4
|
+
* Handles all TypeScript (.ts, .mts, .cts) file-specific rules.
|
|
5
5
|
* Plugin registration removed - all plugins registered globally in index.js.
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ export const typescriptConfig = (
|
|
|
15
15
|
) => [
|
|
16
16
|
// TypeScript files - Base config
|
|
17
17
|
{
|
|
18
|
-
files: ['**/*.ts'],
|
|
18
|
+
files: ['**/*.ts', '**/*.mts', '**/*.cts'],
|
|
19
19
|
ignores: [
|
|
20
20
|
'**/node_modules/**',
|
|
21
21
|
'**/dist/**',
|
|
@@ -30,15 +30,57 @@ export const typescriptConfig = (
|
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
32
|
settings: {
|
|
33
|
+
react: {
|
|
34
|
+
version: 'detect',
|
|
35
|
+
},
|
|
33
36
|
'import/resolver': {
|
|
34
37
|
typescript: {},
|
|
35
38
|
},
|
|
39
|
+
// Tell eslint-plugin-import to parse TypeScript dependency files with the
|
|
40
|
+
// TS parser. Without this, the resolver finds the file but the plugin
|
|
41
|
+
// cannot read its imports/exports, so cross-file rules like
|
|
42
|
+
// import/no-cycle silently never fire on .ts/.tsx code.
|
|
43
|
+
'import/parsers': {
|
|
44
|
+
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
|
|
45
|
+
},
|
|
36
46
|
},
|
|
37
47
|
rules: {
|
|
38
48
|
...sharedRules,
|
|
39
49
|
...allRules.typescriptEslintRules,
|
|
40
50
|
'no-undef': 'off', // TypeScript handles this
|
|
51
|
+
'jsdoc/require-jsdoc': [
|
|
52
|
+
'error',
|
|
53
|
+
{
|
|
54
|
+
require: {
|
|
55
|
+
ClassDeclaration: true,
|
|
56
|
+
FunctionDeclaration: true,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
],
|
|
41
60
|
'custom/no-default-class-export': 'error',
|
|
61
|
+
// Require an explicit return type on every function, not just the
|
|
62
|
+
// exported ones `explicit-module-boundary-types` would cover. Inferred
|
|
63
|
+
// return types are computed bottom-up from the body, so a refactor deep
|
|
64
|
+
// inside a helper can silently widen or change what it returns — a `null`
|
|
65
|
+
// branch added here, a `Promise` introduced there — and nothing flags it
|
|
66
|
+
// until that drift surfaces far away at a call site (or type-checks fine
|
|
67
|
+
// and ships as a runtime bug). Writing the type down inverts the check:
|
|
68
|
+
// the function body is now verified against the contract the author
|
|
69
|
+
// declared, so the mistake fails at the function itself instead of
|
|
70
|
+
// leaking outward. This is exactly the shortcut an AI assistant takes
|
|
71
|
+
// when it emits a helper and lets inference "figure out" the return type,
|
|
72
|
+
// which puts it squarely in this config's explicit-over-clever,
|
|
73
|
+
// fail-locally stance. It is type-aware but cheap (it reads the function
|
|
74
|
+
// signature, no whole-program analysis) and is in neither
|
|
75
|
+
// `eslint:recommended` nor typescript-eslint's `strictTypeChecked` /
|
|
76
|
+
// `stylisticTypeChecked` presets this config extends, so it must be
|
|
77
|
+
// enabled explicitly — which is why `tools-view` re-adds it by hand on
|
|
78
|
+
// top of the base config. It is scoped to `.ts`/`.mts`/`.cts` (this
|
|
79
|
+
// file's `files`) and deliberately NOT applied to `.tsx`: requiring an
|
|
80
|
+
// explicit return type on every JSX component is high-noise for little
|
|
81
|
+
// gain, so React function components stay exempt, matching how
|
|
82
|
+
// `tools-view` enables it on `src/**/*.ts` only.
|
|
83
|
+
'@typescript-eslint/explicit-function-return-type': 'error',
|
|
42
84
|
'single-export/single-export': 'error',
|
|
43
85
|
'required-exports/required-exports': [
|
|
44
86
|
'error',
|
package/exports/ddd.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Linter } from 'eslint'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* DDD preset. The DDD rules (`require-spec-file`) now ship in the base config,
|
|
5
|
+
* so this entry point is equivalent to the default `eslint-config-agent`
|
|
6
|
+
* export and is kept for backward compatibility.
|
|
7
|
+
*/
|
|
8
|
+
declare const config: Linter.Config[]
|
|
9
|
+
|
|
10
|
+
export default config
|
package/exports/ddd.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Linter } from 'eslint'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Incremental adoption preset: the full `eslint-config-agent` ruleset with every
|
|
5
|
+
* error-level rule downgraded to a warning. `eslint` exits `0` so CI stays
|
|
6
|
+
* green while the complete backlog is still reported, letting a team burn it
|
|
7
|
+
* down before flipping back to errors.
|
|
8
|
+
*/
|
|
9
|
+
declare const config: Linter.Config[]
|
|
10
|
+
|
|
11
|
+
export default config
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incremental adoption preset.
|
|
3
|
+
*
|
|
4
|
+
* Dropping the full strict ruleset onto an existing codebase surfaces a large
|
|
5
|
+
* backlog of pre-existing violations at once, so `eslint` exits non-zero and CI
|
|
6
|
+
* goes red on the very first run. Teams then either give up or copy-paste a
|
|
7
|
+
* helper that rewrites every `error` rule to `warn` — the exact same block,
|
|
8
|
+
* repeated in every repo that adopts this config.
|
|
9
|
+
*
|
|
10
|
+
* This entry point ships that pattern so it no longer has to be copy-pasted:
|
|
11
|
+
*
|
|
12
|
+
* ```js
|
|
13
|
+
* import incremental from 'eslint-config-agent/incremental'
|
|
14
|
+
*
|
|
15
|
+
* export default incremental
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* `incremental` is the full `eslint-config-agent` ruleset with every
|
|
19
|
+
* error-level rule downgraded to a warning. `eslint` exits `0`, so `pnpm lint`
|
|
20
|
+
* (and CI) stays green, while the complete ruleset is still reported — letting a
|
|
21
|
+
* team burn the backlog down gradually and flip back to errors once it is clear.
|
|
22
|
+
*
|
|
23
|
+
* To enforce a rule as a hard error before the rest of the backlog is cleared,
|
|
24
|
+
* append your own override layer, which wins over the warned defaults:
|
|
25
|
+
*
|
|
26
|
+
* ```js
|
|
27
|
+
* import incremental from 'eslint-config-agent/incremental'
|
|
28
|
+
*
|
|
29
|
+
* export default [
|
|
30
|
+
* ...incremental,
|
|
31
|
+
* { rules: { eqeqeq: ['error', 'always'] } },
|
|
32
|
+
* ]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import config from '../index.js'
|
|
37
|
+
import { toWarnings } from './to-warnings.js'
|
|
38
|
+
|
|
39
|
+
export default config.map(toWarnings)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Linter } from 'eslint'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recommended + incremental preset: the `recommended` config with every
|
|
5
|
+
* surviving error-level rule downgraded to a warning. The gentlest on-ramp —
|
|
6
|
+
* the noisiest rules are off and everything else warns, so `eslint` exits `0`
|
|
7
|
+
* while the remaining backlog is still reported.
|
|
8
|
+
*/
|
|
9
|
+
declare const config: Linter.Config[]
|
|
10
|
+
|
|
11
|
+
export default config
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recommended + incremental (relaxed, warn-level) preset.
|
|
3
|
+
*
|
|
4
|
+
* The package already ships two adoption on-ramps, but each only solves half of
|
|
5
|
+
* what an existing codebase hits on the first lint run:
|
|
6
|
+
*
|
|
7
|
+
* - `recommended` turns the most divisive rules **off** (spec files, single
|
|
8
|
+
* export, custom `error/*`, optional chaining / nullish-coalescing bans,
|
|
9
|
+
* and so on) — but every remaining rule still reports as an **error**, so a
|
|
10
|
+
* real backlog still fails CI on the first run.
|
|
11
|
+
* - `incremental` keeps **every** rule reporting but downgrades them all to
|
|
12
|
+
* **warnings** — so CI stays green, yet the divisive rules keep firing as a
|
|
13
|
+
* wall of warnings on idiomatic TypeScript and React/Preact + Tailwind code.
|
|
14
|
+
*
|
|
15
|
+
* The gentlest possible on-ramp is the combination of the two: relax the
|
|
16
|
+
* divisive rules entirely *and* downgrade everything else to a warning. That is
|
|
17
|
+
* exactly this preset — the `recommended` config with every surviving
|
|
18
|
+
* error-level rule rewritten to `warn`:
|
|
19
|
+
*
|
|
20
|
+
* ```js
|
|
21
|
+
* import recommendedIncremental from 'eslint-config-agent/recommended-incremental'
|
|
22
|
+
*
|
|
23
|
+
* export default recommendedIncremental
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* `eslint` exits `0`, so `pnpm lint` (and CI) stays green, the noisiest rules
|
|
27
|
+
* are silent, and the remaining quality rules show up as warnings you can burn
|
|
28
|
+
* down before tightening back up.
|
|
29
|
+
*
|
|
30
|
+
* To enforce a rule as a hard error before the rest of the backlog is cleared,
|
|
31
|
+
* append your own override layer, which wins over the warned defaults:
|
|
32
|
+
*
|
|
33
|
+
* ```js
|
|
34
|
+
* import recommendedIncremental from 'eslint-config-agent/recommended-incremental'
|
|
35
|
+
*
|
|
36
|
+
* export default [
|
|
37
|
+
* ...recommendedIncremental,
|
|
38
|
+
* { rules: { eqeqeq: ['error', 'always'] } },
|
|
39
|
+
* ]
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import recommended from './recommended.js'
|
|
44
|
+
import { toWarnings } from './to-warnings.js'
|
|
45
|
+
|
|
46
|
+
export default recommended.map(toWarnings)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Linter } from 'eslint'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recommended (relaxed) preset: the default config with the most divisive rules
|
|
5
|
+
* turned off (spec files, single export, custom `error/*`, optional chaining /
|
|
6
|
+
* nullish-coalescing bans, and so on) for incremental adoption.
|
|
7
|
+
* `max-lines-per-function`/`max-lines` are downgraded to `warn` (same 70/100
|
|
8
|
+
* line thresholds as the strict default) so a real codebase's legacy long
|
|
9
|
+
* functions/files surface as backlog instead of failing CI. Every other
|
|
10
|
+
* surviving rule still reports as an error.
|
|
11
|
+
*/
|
|
12
|
+
declare const config: Linter.Config[]
|
|
13
|
+
|
|
14
|
+
export default config
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recommended (relaxed) preset.
|
|
3
|
+
*
|
|
4
|
+
* The default export is intentionally strict — it is tuned for greenfield
|
|
5
|
+
* projects that adopt every convention from day one (a spec file beside every
|
|
6
|
+
* source file, custom Error classes, no optional chaining / nullish
|
|
7
|
+
* coalescing, single export per module, and so on).
|
|
8
|
+
*
|
|
9
|
+
* Existing codebases usually cannot satisfy all of that at once, so they end
|
|
10
|
+
* up copying the same block of rule overrides into their own
|
|
11
|
+
* `eslint.config.js` just to get the config to load without a wall of errors.
|
|
12
|
+
*
|
|
13
|
+
* This preset bundles those common overrides so incremental adopters can opt
|
|
14
|
+
* into the core quality rules immediately while deferring the most opinionated
|
|
15
|
+
* ones:
|
|
16
|
+
*
|
|
17
|
+
* ```js
|
|
18
|
+
* import recommended from 'eslint-config-agent/recommended'
|
|
19
|
+
*
|
|
20
|
+
* export default recommended
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Re-enable any individual rule by appending your own override layer.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import config from '../index.js'
|
|
27
|
+
import { noProcessEnvironmentPropertiesConfig } from '../rules/no-process-env-properties/index.js'
|
|
28
|
+
import { errorOptions as maxFunctionLinesErrorOptions } from '../rules/max-function-lines/index.js'
|
|
29
|
+
import { errorOptions as maxFileLinesErrorOptions } from '../rules/max-file-lines/index.js'
|
|
30
|
+
import { lengthRuleFileMatch } from '../configs/length-rule-scope.js'
|
|
31
|
+
|
|
32
|
+
const relaxedOverrides = {
|
|
33
|
+
name: 'eslint-config-agent/recommended-overrides',
|
|
34
|
+
rules: {
|
|
35
|
+
// Don't require a `*.spec.*` file alongside every source file. The strict
|
|
36
|
+
// default splits this requirement across two rules: `ddd/require-spec-file`
|
|
37
|
+
// covers `.js`/`.ts` (the upstream `eslint-plugin-ddd` rule bails out on any
|
|
38
|
+
// other extension), and the bundled `custom/require-spec-file-tsx` covers
|
|
39
|
+
// `.tsx`/`.jsx` — i.e. the React/Preact components this config primarily
|
|
40
|
+
// targets. Relaxing only the first would still force a spec file beside
|
|
41
|
+
// every component, defeating the preset's purpose for its core audience, so
|
|
42
|
+
// both halves are disabled together here.
|
|
43
|
+
'ddd/require-spec-file': 'off',
|
|
44
|
+
'custom/require-spec-file-tsx': 'off',
|
|
45
|
+
// Allow multiple exports per module.
|
|
46
|
+
'single-export/single-export': 'off',
|
|
47
|
+
'required-exports/required-exports': 'off',
|
|
48
|
+
// Allow generic `Error` instead of mandating custom Error classes.
|
|
49
|
+
'error/no-generic-error': 'off',
|
|
50
|
+
'error/require-custom-error': 'off',
|
|
51
|
+
'error/no-literal-error-message': 'off',
|
|
52
|
+
// Don't require a JSDoc block on every exported function and class. The
|
|
53
|
+
// strict default enables `jsdoc/require-jsdoc` at `error` for every
|
|
54
|
+
// `FunctionDeclaration` and `ClassDeclaration` (see `index.js` and
|
|
55
|
+
// `configs/typescript.js`), so adopting the config on an existing codebase
|
|
56
|
+
// produces a wall of `Missing JSDoc comment` errors on day one. This is the
|
|
57
|
+
// third of the three highest-volume on-ramp rules the README calls out —
|
|
58
|
+
// alongside `ddd/require-spec-file` and `error/no-literal-error-message`,
|
|
59
|
+
// both already relaxed above — so relax it here to match the preset's
|
|
60
|
+
// stated incremental-adoption purpose. Only the "document everything"
|
|
61
|
+
// requirement is lifted: the jsdoc *content* rules (`check-param-names`,
|
|
62
|
+
// `require-returns`, ...) stay enabled, so any JSDoc that is actually
|
|
63
|
+
// written is still validated.
|
|
64
|
+
'jsdoc/require-jsdoc': 'off',
|
|
65
|
+
// Allow default parameter values.
|
|
66
|
+
'default/no-default-params': 'off',
|
|
67
|
+
// Allow `type` aliases, not just `interface` declarations.
|
|
68
|
+
'@typescript-eslint/consistent-type-definitions': 'off',
|
|
69
|
+
// Don't require a semantic `className` on every HTML element, and don't
|
|
70
|
+
// reject Tailwind-only class lists. The strict default enables
|
|
71
|
+
// `jsx-classname/require-classname` with `{ ignoreTailwind: true }`, which
|
|
72
|
+
// errors both on elements with no `className` and on elements whose
|
|
73
|
+
// `className` contains only Tailwind utilities (e.g.
|
|
74
|
+
// `<div className="flex gap-2" />`). That makes the config impossible to
|
|
75
|
+
// adopt incrementally in any React/Preact + Tailwind codebase — by far the
|
|
76
|
+
// most common modern setup — so relax it for the recommended preset.
|
|
77
|
+
'jsx-classname/require-classname': 'off',
|
|
78
|
+
// The most divisive layer: optional chaining (`?.`), nullish coalescing
|
|
79
|
+
// (`??`), type assertions, switch-default bans, and inline union/record
|
|
80
|
+
// type restrictions. Removing them lets idiomatic TypeScript through during
|
|
81
|
+
// adoption. The process.env guard (`no-process-env-properties`) is NOT in
|
|
82
|
+
// this group: scattered `process.env.FOO` access is a configuration smell
|
|
83
|
+
// regardless of adoption stage, so it is kept as the one surviving
|
|
84
|
+
// no-restricted-syntax check.
|
|
85
|
+
'no-restricted-syntax': ['error', noProcessEnvironmentPropertiesConfig],
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The strict default promotes function/file length to hard errors in its
|
|
90
|
+
// final override layer (`configs/overrides.js`'s "Function and file length
|
|
91
|
+
// rules" block) — at >70 lines per function and >100 lines per file — which
|
|
92
|
+
// blocks incremental adoption: an existing codebase pointing `recommended` at
|
|
93
|
+
// its real source tree still gets fatal errors on every long legacy
|
|
94
|
+
// function/file, exactly the "wall of errors" this preset exists to avoid
|
|
95
|
+
// (see issue #85). Downgrade both to `warn` while keeping the same 70/100
|
|
96
|
+
// thresholds — and the same file scope (`lengthRuleFileMatch`, shared with
|
|
97
|
+
// the strict block) — so the signal still surfaces in `eslint` output and the
|
|
98
|
+
// backlog can be burned down, but it no longer fails a CI run that treats
|
|
99
|
+
// errors as fatal. Consumers can re-enable these as errors with their own
|
|
100
|
+
// override layer once they are ready.
|
|
101
|
+
const lengthWarningOverrides = {
|
|
102
|
+
name: 'eslint-config-agent/recommended-length-warnings',
|
|
103
|
+
...lengthRuleFileMatch,
|
|
104
|
+
rules: {
|
|
105
|
+
'max-lines-per-function': ['warn', maxFunctionLinesErrorOptions],
|
|
106
|
+
'max-lines': ['warn', maxFileLinesErrorOptions],
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default [...config, relaxedOverrides, lengthWarningOverrides]
|