@dmitryrechkin/eslint-standard 1.4.2 → 1.4.4
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/README.md +128 -728
- package/eslint.config.mjs +43 -5
- package/package.json +27 -15
- package/src/cli/index.mjs +4 -4
- package/src/cli/setup-aggressive-cleanup.mjs +97 -0
- package/docs/AUTO_INSTALL.md +0 -50
- package/docs/COMPLEXITY_RULES.md +0 -200
package/eslint.config.mjs
CHANGED
|
@@ -18,7 +18,10 @@ import unicornPlugin from 'eslint-plugin-unicorn';
|
|
|
18
18
|
import noSecretsPlugin from 'eslint-plugin-no-secrets';
|
|
19
19
|
import regexpPlugin from 'eslint-plugin-regexp';
|
|
20
20
|
import functionalPlugin from 'eslint-plugin-functional';
|
|
21
|
-
|
|
21
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
22
|
+
import prettierConfig from 'eslint-config-prettier';
|
|
23
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
24
|
+
import prettierPlugin from 'eslint-plugin-prettier';
|
|
22
25
|
export default function ({
|
|
23
26
|
tsconfigPath = './tsconfig.json',
|
|
24
27
|
ignores = [],
|
|
@@ -30,8 +33,10 @@ export default function ({
|
|
|
30
33
|
{
|
|
31
34
|
ignores: ['node_modules/**', 'dist/**', ...ignores],
|
|
32
35
|
},
|
|
36
|
+
// Add Prettier integration
|
|
37
|
+
prettierConfig,
|
|
33
38
|
{
|
|
34
|
-
files: ['**/*.{js,
|
|
39
|
+
files: ['**/*.{js,ts}', ...files], // Exclude jsx, tsx, and astro files from main config
|
|
35
40
|
languageOptions: {
|
|
36
41
|
parser: tsParser,
|
|
37
42
|
parserOptions: {
|
|
@@ -59,6 +64,7 @@ export default function ({
|
|
|
59
64
|
'no-secrets': noSecretsPlugin,
|
|
60
65
|
'regexp': regexpPlugin,
|
|
61
66
|
'functional': functionalPlugin,
|
|
67
|
+
'prettier': prettierPlugin,
|
|
62
68
|
...plugins,
|
|
63
69
|
},
|
|
64
70
|
settings: {
|
|
@@ -73,6 +79,11 @@ export default function ({
|
|
|
73
79
|
'import/extensions': ['.js', '.jsx', '.ts', '.tsx'],
|
|
74
80
|
},
|
|
75
81
|
rules: {
|
|
82
|
+
// Prettier integration
|
|
83
|
+
'prettier/prettier': 'error',
|
|
84
|
+
// Disable rules that conflict with prettier
|
|
85
|
+
'switch-case-brace/switch-case-brace-style': 'off',
|
|
86
|
+
|
|
76
87
|
// Original @dmitryrechkin/eslint-standard rules
|
|
77
88
|
'@typescript-eslint/explicit-function-return-type': 'error',
|
|
78
89
|
'@typescript-eslint/no-explicit-any': 'error', // Ban 'any' type for type safety
|
|
@@ -540,7 +551,7 @@ export default function ({
|
|
|
540
551
|
devDependencies: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/test/**', '**/tests/**', '**/__tests__/**']
|
|
541
552
|
}],
|
|
542
553
|
'import/no-mutable-exports': 'error',
|
|
543
|
-
'import/no-unused-modules': 'off', // Disabled
|
|
554
|
+
// 'import/no-unused-modules': 'off', // Disabled - incompatible with flat config, requires legacy .eslintrc
|
|
544
555
|
'import/unambiguous': 'off',
|
|
545
556
|
'import/no-commonjs': 'off',
|
|
546
557
|
'import/no-amd': 'error',
|
|
@@ -780,12 +791,39 @@ export default function ({
|
|
|
780
791
|
'unicorn/prevent-abbreviations': 'off', // Allow abbreviations for domain-specific terms
|
|
781
792
|
|
|
782
793
|
// Allow custom rules to be added
|
|
783
|
-
...rules
|
|
794
|
+
...rules
|
|
784
795
|
},
|
|
785
796
|
},
|
|
797
|
+
// Prettier config for TypeScript/JavaScript files with Allman brace style
|
|
798
|
+
{
|
|
799
|
+
files: ['**/*.{tsx,jsx,ts,js}'],
|
|
800
|
+
rules: {
|
|
801
|
+
'prettier/prettier': [
|
|
802
|
+
'error',
|
|
803
|
+
{
|
|
804
|
+
parser: 'typescript',
|
|
805
|
+
plugins: ['prettier-plugin-brace-style'],
|
|
806
|
+
braceStyle: 'allman'
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
// Prettier config for Astro files
|
|
812
|
+
{
|
|
813
|
+
files: ['**/*.astro'],
|
|
814
|
+
rules: {
|
|
815
|
+
'prettier/prettier': [
|
|
816
|
+
'error',
|
|
817
|
+
{
|
|
818
|
+
parser: 'astro',
|
|
819
|
+
plugins: ['prettier-plugin-astro']
|
|
820
|
+
}
|
|
821
|
+
]
|
|
822
|
+
}
|
|
823
|
+
},
|
|
786
824
|
// Test file specific overrides
|
|
787
825
|
{
|
|
788
|
-
files: ['**/*.test.{js,
|
|
826
|
+
files: ['**/*.test.{js,ts}', '**/*.spec.{js,ts}', '**/tests/**/*.{js,ts}'],
|
|
789
827
|
ignores: ['**/tests/fixtures/**/*'], // Don't apply test overrides to fixture files
|
|
790
828
|
rules: {
|
|
791
829
|
// Disable function scoping rule for test helpers
|
package/package.json
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dmitryrechkin/eslint-standard",
|
|
3
3
|
"description": "This package provides a shared ESLint configuration which includes TypeScript support and a set of specific linting rules designed to ensure high-quality and consistent code style across projects.",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.4",
|
|
5
5
|
"main": "eslint.config.mjs",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./eslint.config.mjs"
|
|
8
|
+
},
|
|
6
9
|
"bin": {
|
|
7
10
|
"eslint-standard": "./src/cli/index.mjs"
|
|
8
11
|
},
|
|
9
12
|
"files": [
|
|
10
13
|
"eslint.config.mjs",
|
|
11
14
|
"src/",
|
|
12
|
-
"docs/",
|
|
13
15
|
"README.md",
|
|
14
16
|
"LICENSE"
|
|
15
17
|
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"postinstall": "node src/cli/postinstall.mjs",
|
|
18
20
|
"package:publish": "npm publish --access public",
|
|
19
|
-
"test": "node tests/test-all-rules.
|
|
20
|
-
"test:all": "node tests/test-all-rules.
|
|
21
|
-
"test:formatting": "node tests/test-runner.
|
|
22
|
-
"test:
|
|
23
|
-
"test:
|
|
24
|
-
"test:
|
|
25
|
-
"test:
|
|
26
|
-
"test:
|
|
27
|
-
"test:
|
|
28
|
-
"test:
|
|
29
|
-
"test:
|
|
21
|
+
"test": "node tests/test-all-rules.mjs",
|
|
22
|
+
"test:all": "node tests/test-all-rules.mjs",
|
|
23
|
+
"test:formatting": "node tests/test-runner.mjs",
|
|
24
|
+
"test:simple": "node tests/simple-test.mjs",
|
|
25
|
+
"test:debug": "node tests/debug-test.mjs",
|
|
26
|
+
"test:complexity": "node tests/test-complexity-rules.mjs",
|
|
27
|
+
"test:safety": "node tests/test-safety-rules.mjs",
|
|
28
|
+
"test:security": "node tests/test-security-rules.mjs",
|
|
29
|
+
"test:sonarjs": "node tests/test-sonarjs-rules.mjs",
|
|
30
|
+
"test:unicorn": "node tests/test-unicorn-rules.mjs",
|
|
31
|
+
"test:switch-case": "node tests/test-switch-case-simple.mjs",
|
|
32
|
+
"test:cli": "node tests/test-cli.mjs",
|
|
33
|
+
"test:install": "node tests/test-install-simulation.mjs"
|
|
30
34
|
},
|
|
31
35
|
"keywords": [],
|
|
32
36
|
"author": "",
|
|
@@ -36,6 +40,7 @@
|
|
|
36
40
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
37
41
|
"@typescript-eslint/parser": "^8.0.0",
|
|
38
42
|
"eslint": "^9.0.0",
|
|
43
|
+
"eslint-config-prettier": "^10.0.0",
|
|
39
44
|
"eslint-plugin-functional": "^7.0.0",
|
|
40
45
|
"eslint-plugin-import": "^2.0.0",
|
|
41
46
|
"eslint-import-resolver-typescript": "^3.0.0",
|
|
@@ -43,19 +48,23 @@
|
|
|
43
48
|
"eslint-plugin-jsx-a11y": "^6.0.0",
|
|
44
49
|
"eslint-plugin-no-secrets": "^1.0.0",
|
|
45
50
|
"eslint-plugin-perfectionist": "^4.0.0",
|
|
51
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
46
52
|
"eslint-plugin-promise": "^7.0.0",
|
|
47
53
|
"eslint-plugin-regexp": "^2.0.0",
|
|
48
54
|
"eslint-plugin-security": "^3.0.0",
|
|
49
55
|
"eslint-plugin-simple-import-sort": "^12.0.0",
|
|
50
56
|
"eslint-plugin-sonarjs": "^3.0.0",
|
|
51
57
|
"eslint-plugin-unicorn": "^56.0.0",
|
|
52
|
-
"eslint-plugin-unused-imports": "^4.0.0"
|
|
58
|
+
"eslint-plugin-unused-imports": "^4.0.0",
|
|
59
|
+
"prettier-plugin-astro": "^0.14.0",
|
|
60
|
+
"prettier-plugin-brace-style": "^0.8.0"
|
|
53
61
|
},
|
|
54
62
|
"devDependencies": {
|
|
55
63
|
"@stylistic/eslint-plugin": "^5.2.2",
|
|
56
64
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
57
65
|
"@typescript-eslint/parser": "^8.38.0",
|
|
58
66
|
"eslint": "^9.32.0",
|
|
67
|
+
"eslint-config-prettier": "^10.1.8",
|
|
59
68
|
"eslint-plugin-functional": "^7.3.0",
|
|
60
69
|
"eslint-plugin-import": "^2.32.0",
|
|
61
70
|
"eslint-import-resolver-typescript": "^3.6.3",
|
|
@@ -63,12 +72,15 @@
|
|
|
63
72
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
64
73
|
"eslint-plugin-no-secrets": "^1.1.2",
|
|
65
74
|
"eslint-plugin-perfectionist": "^4.15.0",
|
|
75
|
+
"eslint-plugin-prettier": "^5.5.3",
|
|
66
76
|
"eslint-plugin-promise": "^7.2.1",
|
|
67
77
|
"eslint-plugin-regexp": "^2.9.0",
|
|
68
78
|
"eslint-plugin-security": "^3.0.1",
|
|
69
79
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
70
80
|
"eslint-plugin-sonarjs": "^3.0.4",
|
|
71
81
|
"eslint-plugin-unicorn": "^56.0.1",
|
|
72
|
-
"eslint-plugin-unused-imports": "^4.1.4"
|
|
82
|
+
"eslint-plugin-unused-imports": "^4.1.4",
|
|
83
|
+
"prettier-plugin-astro": "^0.14.1",
|
|
84
|
+
"prettier-plugin-brace-style": "^0.8.1"
|
|
73
85
|
}
|
|
74
86
|
}
|
package/src/cli/index.mjs
CHANGED
|
@@ -20,10 +20,10 @@ Usage:
|
|
|
20
20
|
npx @dmitryrechkin/eslint-standard <command>
|
|
21
21
|
|
|
22
22
|
Commands:
|
|
23
|
-
install-deps
|
|
24
|
-
check-deps
|
|
25
|
-
check-deps --install
|
|
26
|
-
help
|
|
23
|
+
install-deps Install all peer dependencies
|
|
24
|
+
check-deps Check if all peer dependencies are installed
|
|
25
|
+
check-deps --install Auto-install missing dependencies if any
|
|
26
|
+
help Show this help message
|
|
27
27
|
|
|
28
28
|
Examples:
|
|
29
29
|
npx @dmitryrechkin/eslint-standard install-deps
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file CLI Setup for Aggressive Unused Code Detection
|
|
5
|
+
*
|
|
6
|
+
* This CLI tool helps set up aggressive unused code detection and cleanup
|
|
7
|
+
* in your project with external tools and optimal configurations.
|
|
8
|
+
*
|
|
9
|
+
* @author PageFast Team
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { setupAggressiveCleanup } from '../configs/external-tools-setup.mjs';
|
|
14
|
+
|
|
15
|
+
// Simple command line argument parsing (avoiding external dependencies)
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const options = {
|
|
18
|
+
global: args.includes('--global') || args.includes('-g'),
|
|
19
|
+
packageManager: args.find((arg, i) => (args[i-1] === '--package-manager' || args[i-1] === '-p')) || 'npm',
|
|
20
|
+
dryRun: args.includes('--dry-run'),
|
|
21
|
+
help: args.includes('--help') || args.includes('-h')
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Main CLI program for setting up aggressive cleanup
|
|
26
|
+
*/
|
|
27
|
+
async function main()
|
|
28
|
+
{
|
|
29
|
+
try
|
|
30
|
+
{
|
|
31
|
+
if (options.help)
|
|
32
|
+
{
|
|
33
|
+
console.log(`
|
|
34
|
+
@dmitryrechkin/eslint-standard - Aggressive Cleanup Setup
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
npx @dmitryrechkin/eslint-standard setup-aggressive-cleanup [options]
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
-g, --global Install cleanup tools globally
|
|
41
|
+
-p, --package-manager <type> Package manager to use (npm, pnpm, yarn)
|
|
42
|
+
--dry-run Show what would be done without making changes
|
|
43
|
+
-h, --help Show this help message
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
npx @dmitryrechkin/eslint-standard setup-aggressive-cleanup
|
|
47
|
+
npx @dmitryrechkin/eslint-standard setup-aggressive-cleanup --global
|
|
48
|
+
npx @dmitryrechkin/eslint-standard setup-aggressive-cleanup -p pnpm
|
|
49
|
+
npx @dmitryrechkin/eslint-standard setup-aggressive-cleanup --dry-run
|
|
50
|
+
`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (options.dryRun)
|
|
55
|
+
{
|
|
56
|
+
console.log('🔍 DRY RUN - Would perform the following actions:\n');
|
|
57
|
+
console.log('1. Install external cleanup tools:');
|
|
58
|
+
console.log(' - ts-prune (find unused exports)');
|
|
59
|
+
console.log(' - unimported (find unused files)');
|
|
60
|
+
console.log(' - knip (advanced dead code elimination)');
|
|
61
|
+
console.log(' - depcheck (find unused dependencies)');
|
|
62
|
+
console.log(' - ts-remove-unused (remove unused imports)');
|
|
63
|
+
console.log('\n2. Add cleanup scripts to package.json');
|
|
64
|
+
console.log('\n3. Create optimal tsconfig.json for unused code detection');
|
|
65
|
+
console.log('\n4. Create knip.json configuration');
|
|
66
|
+
console.log('\nRun without --dry-run to actually perform setup.');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await setupAggressiveCleanup({
|
|
71
|
+
packageManager: options.packageManager,
|
|
72
|
+
globalTools: options.global
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log('\n🎉 Setup complete! Next steps:');
|
|
76
|
+
console.log('\n1. Enable aggressive cleanup in your ESLint config:');
|
|
77
|
+
console.log(' ```javascript');
|
|
78
|
+
console.log(' import baseConfig from "@dmitryrechkin/eslint-standard";');
|
|
79
|
+
console.log(' export default baseConfig({');
|
|
80
|
+
console.log(' aggressiveCleanup: true // 🔥 Enable aggressive mode');
|
|
81
|
+
console.log(' });');
|
|
82
|
+
console.log(' ```');
|
|
83
|
+
console.log('\n2. Run cleanup check:');
|
|
84
|
+
console.log(' npm run cleanup:check');
|
|
85
|
+
console.log('\n3. Review and fix issues:');
|
|
86
|
+
console.log(' npm run cleanup:fix');
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
catch (error)
|
|
90
|
+
{
|
|
91
|
+
console.error('\n❌ Setup failed:', error.message);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Run the main function
|
|
97
|
+
main();
|
package/docs/AUTO_INSTALL.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Auto-Installation Options
|
|
2
|
-
|
|
3
|
-
## Manual Installation (Default - Recommended)
|
|
4
|
-
|
|
5
|
-
By default, peer dependencies are NOT auto-installed. After installing the package, run:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx @dmitryrechkin/eslint-standard check-deps --install
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Environment Variable Control
|
|
12
|
-
|
|
13
|
-
You can control the installation behavior using environment variables:
|
|
14
|
-
|
|
15
|
-
### Enable Auto-Install
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# One-time auto-install
|
|
19
|
-
ESLINT_STANDARD_AUTO_INSTALL=true npm install @dmitryrechkin/eslint-standard
|
|
20
|
-
|
|
21
|
-
# Or add to .npmrc for project
|
|
22
|
-
echo "ESLINT_STANDARD_AUTO_INSTALL=true" >> .npmrc
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Disable All Postinstall Messages
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# Skip all postinstall scripts
|
|
29
|
-
ESLINT_STANDARD_SKIP_INSTALL=true npm install @dmitryrechkin/eslint-standard
|
|
30
|
-
|
|
31
|
-
# Or globally
|
|
32
|
-
npm install --ignore-scripts
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## CI/CD Environments
|
|
36
|
-
|
|
37
|
-
The postinstall script automatically detects CI environments and skips execution to avoid issues.
|
|
38
|
-
|
|
39
|
-
## Security Considerations
|
|
40
|
-
|
|
41
|
-
- Auto-installation is **opt-in only** via environment variable
|
|
42
|
-
- Respects npm's `--ignore-scripts` flag
|
|
43
|
-
- Skips in CI environments
|
|
44
|
-
- Never modifies files without user consent
|
|
45
|
-
|
|
46
|
-
## Best Practices
|
|
47
|
-
|
|
48
|
-
1. **Development**: Use `check-deps --install` for quick setup
|
|
49
|
-
2. **Production**: Explicitly install peer dependencies in package.json
|
|
50
|
-
3. **CI/CD**: Add peer dependencies to your package.json for reproducible builds
|
package/docs/COMPLEXITY_RULES.md
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
# Built-in Complexity Rules
|
|
2
|
-
|
|
3
|
-
`@dmitryrechkin/eslint-standard` includes industry-standard complexity rules by default to ensure code maintainability and readability. These rules help detect code quality issues like deep nesting, large functions, and violations of SOLID principles.
|
|
4
|
-
|
|
5
|
-
## Available Rules
|
|
6
|
-
|
|
7
|
-
### 1. Cyclomatic Complexity
|
|
8
|
-
```javascript
|
|
9
|
-
'complexity': ['error', 10]
|
|
10
|
-
```
|
|
11
|
-
- Limits the number of linearly independent paths through a function
|
|
12
|
-
- Default: 10 (strict mode: 5)
|
|
13
|
-
- Helps identify functions that are doing too much
|
|
14
|
-
|
|
15
|
-
### 2. Function Length
|
|
16
|
-
```javascript
|
|
17
|
-
'max-lines-per-function': ['error', {
|
|
18
|
-
max: 100,
|
|
19
|
-
skipBlankLines: true,
|
|
20
|
-
skipComments: true
|
|
21
|
-
}]
|
|
22
|
-
```
|
|
23
|
-
- Limits function length to 100 lines (pragmatic for complex business logic)
|
|
24
|
-
- Encourages reasonably sized, focused functions
|
|
25
|
-
- Balances Single Responsibility with real-world needs
|
|
26
|
-
|
|
27
|
-
### 3. Maximum Statements
|
|
28
|
-
```javascript
|
|
29
|
-
'max-statements': ['error', 20]
|
|
30
|
-
```
|
|
31
|
-
- Limits the number of statements in a function
|
|
32
|
-
- Default: 20 (strict mode: 10)
|
|
33
|
-
- Forces decomposition of complex logic
|
|
34
|
-
|
|
35
|
-
### 4. Nesting Depth
|
|
36
|
-
```javascript
|
|
37
|
-
'max-depth': ['error', { max: 3 }]
|
|
38
|
-
```
|
|
39
|
-
- Limits block nesting to 3 levels (strict mode: 2)
|
|
40
|
-
- Prevents deeply nested if/else chains
|
|
41
|
-
- Encourages early returns and guard clauses
|
|
42
|
-
|
|
43
|
-
### 5. Callback Nesting
|
|
44
|
-
```javascript
|
|
45
|
-
'max-nested-callbacks': ['error', 3]
|
|
46
|
-
```
|
|
47
|
-
- Limits callback nesting depth
|
|
48
|
-
- Encourages use of async/await or promises
|
|
49
|
-
- Prevents "callback hell"
|
|
50
|
-
|
|
51
|
-
### 6. Parameter Count
|
|
52
|
-
```javascript
|
|
53
|
-
'max-params': ['error', 4]
|
|
54
|
-
```
|
|
55
|
-
- Limits function parameters to 4 (strict mode: 3)
|
|
56
|
-
- Encourages parameter objects for complex functions
|
|
57
|
-
- Improves function signatures
|
|
58
|
-
|
|
59
|
-
### 7. File Size
|
|
60
|
-
```javascript
|
|
61
|
-
'max-lines': ['warn', {
|
|
62
|
-
max: 300,
|
|
63
|
-
skipBlankLines: true,
|
|
64
|
-
skipComments: true
|
|
65
|
-
}]
|
|
66
|
-
```
|
|
67
|
-
- Warns when files exceed 300 lines
|
|
68
|
-
- Encourages modular code organization
|
|
69
|
-
- Helps maintain Single Responsibility for modules
|
|
70
|
-
|
|
71
|
-
## Customizing Rules
|
|
72
|
-
|
|
73
|
-
The complexity rules are included by default. You can customize them by overriding specific rules:
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
import eslintStandard from '@dmitryrechkin/eslint-standard';
|
|
77
|
-
|
|
78
|
-
export default eslintStandard({
|
|
79
|
-
tsconfigPath: './tsconfig.json',
|
|
80
|
-
rules: {
|
|
81
|
-
// Make complexity stricter
|
|
82
|
-
'complexity': ['error', 8],
|
|
83
|
-
'max-lines-per-function': ['error', { max: 40 }],
|
|
84
|
-
'max-depth': ['error', { max: 2 }],
|
|
85
|
-
|
|
86
|
-
// Or relax for legacy code
|
|
87
|
-
'complexity': ['warn', 15],
|
|
88
|
-
'max-lines-per-function': ['warn', { max: 100 }],
|
|
89
|
-
|
|
90
|
-
// Or disable specific rules
|
|
91
|
-
'max-lines': 'off'
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Examples of Violations
|
|
97
|
-
|
|
98
|
-
### 1. High Cyclomatic Complexity
|
|
99
|
-
```typescript
|
|
100
|
-
// ❌ BAD: Complexity > 10
|
|
101
|
-
function processOrder(order: Order): Result {
|
|
102
|
-
if (order.status === 'pending') {
|
|
103
|
-
if (order.payment) {
|
|
104
|
-
if (order.payment.method === 'credit') {
|
|
105
|
-
if (order.payment.verified) {
|
|
106
|
-
// ... more conditions
|
|
107
|
-
}
|
|
108
|
-
} else if (order.payment.method === 'debit') {
|
|
109
|
-
// ... more branches
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} else if (order.status === 'processing') {
|
|
113
|
-
// ... more branches
|
|
114
|
-
}
|
|
115
|
-
// Total complexity: 15+
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ✅ GOOD: Break into smaller functions
|
|
119
|
-
function processOrder(order: Order): Result {
|
|
120
|
-
if (!isOrderReady(order)) {
|
|
121
|
-
return { error: 'Order not ready' };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const payment = processPayment(order.payment);
|
|
125
|
-
if (!payment.success) {
|
|
126
|
-
return { error: payment.error };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return completeOrder(order, payment);
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### 2. Deep Nesting
|
|
134
|
-
```typescript
|
|
135
|
-
// ❌ BAD: Nesting depth > 3
|
|
136
|
-
function validateData(data: any): boolean {
|
|
137
|
-
if (data) {
|
|
138
|
-
if (data.user) {
|
|
139
|
-
if (data.user.profile) {
|
|
140
|
-
if (data.user.profile.email) {
|
|
141
|
-
return validateEmail(data.user.profile.email);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ✅ GOOD: Use early returns
|
|
150
|
-
function validateData(data: any): boolean {
|
|
151
|
-
if (!data?.user?.profile?.email) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
return validateEmail(data.user.profile.email);
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 3. Long Functions
|
|
159
|
-
```typescript
|
|
160
|
-
// ❌ BAD: Function > 50 lines
|
|
161
|
-
function generateReport(data: Data): Report {
|
|
162
|
-
// 100+ lines of code doing multiple things:
|
|
163
|
-
// - Data validation
|
|
164
|
-
// - Data transformation
|
|
165
|
-
// - Calculations
|
|
166
|
-
// - Formatting
|
|
167
|
-
// - File generation
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ✅ GOOD: Split into focused functions
|
|
171
|
-
function generateReport(data: Data): Report {
|
|
172
|
-
const validatedData = validateReportData(data);
|
|
173
|
-
const transformedData = transformReportData(validatedData);
|
|
174
|
-
const calculations = calculateReportMetrics(transformedData);
|
|
175
|
-
const formatted = formatReportData(calculations);
|
|
176
|
-
return createReportFile(formatted);
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Benefits
|
|
181
|
-
|
|
182
|
-
1. **Improved Readability**: Smaller functions are easier to understand
|
|
183
|
-
2. **Better Testability**: Simple functions are easier to test
|
|
184
|
-
3. **Reduced Bugs**: Less complex code has fewer places for bugs to hide
|
|
185
|
-
4. **Easier Maintenance**: Changes are localized to smaller units
|
|
186
|
-
5. **Team Collaboration**: Consistent complexity limits across the codebase
|
|
187
|
-
|
|
188
|
-
## Migration Strategy
|
|
189
|
-
|
|
190
|
-
1. **Start with Warnings**: Use `warn` instead of `error` initially
|
|
191
|
-
2. **Fix Incrementally**: Address the worst violations first
|
|
192
|
-
3. **Set Realistic Goals**: Gradually tighten limits over time
|
|
193
|
-
4. **Document Exceptions**: Use `eslint-disable` comments sparingly with explanations
|
|
194
|
-
|
|
195
|
-
## Related Tools
|
|
196
|
-
|
|
197
|
-
- **SonarQube**: For comprehensive code quality metrics
|
|
198
|
-
- **CodeClimate**: For tracking technical debt
|
|
199
|
-
- **Lizard**: For cyclomatic complexity analysis
|
|
200
|
-
- **JSComplexity**: Visual complexity reports
|