@sun-asterisk/sunlint 1.1.7 â 1.2.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/.sunlint.json +1 -1
- package/CHANGELOG.md +83 -0
- package/README.md +66 -4
- package/config/presets/all.json +125 -0
- package/config/presets/beginner.json +16 -8
- package/config/presets/ci.json +12 -4
- package/config/presets/maintainability.json +38 -0
- package/config/presets/performance.json +32 -0
- package/config/presets/quality.json +103 -0
- package/config/presets/recommended.json +36 -12
- package/config/presets/security.json +88 -0
- package/config/presets/strict.json +15 -5
- package/config/rules/rules-registry-generated.json +6312 -0
- package/config/rules-summary.json +1941 -0
- package/core/adapters/sunlint-rule-adapter.js +452 -0
- package/core/analysis-orchestrator.js +4 -4
- package/core/config-manager.js +28 -5
- package/core/rule-selection-service.js +52 -55
- package/docs/CONFIGURATION.md +111 -3
- package/docs/LANGUAGE-SPECIFIC-RULES.md +308 -0
- package/docs/README.md +3 -0
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +156 -0
- package/engines/eslint-engine.js +92 -2
- package/engines/heuristic-engine.js +8 -31
- package/origin-rules/common-en.md +1320 -0
- package/origin-rules/dart-en.md +289 -0
- package/origin-rules/java-en.md +60 -0
- package/origin-rules/kotlin-mobile-en.md +453 -0
- package/origin-rules/reactjs-en.md +102 -0
- package/origin-rules/security-en.md +1055 -0
- package/origin-rules/swift-en.md +449 -0
- package/origin-rules/typescript-en.md +136 -0
- package/package.json +6 -5
- package/scripts/copy-rules.js +86 -0
- package/rules/README.md +0 -252
- package/rules/common/C002_no_duplicate_code/analyzer.js +0 -65
- package/rules/common/C002_no_duplicate_code/config.json +0 -23
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +0 -418
- package/rules/common/C003_no_vague_abbreviations/config.json +0 -35
- package/rules/common/C006_function_naming/analyzer.js +0 -349
- package/rules/common/C006_function_naming/config.json +0 -86
- package/rules/common/C010_limit_block_nesting/analyzer.js +0 -389
- package/rules/common/C013_no_dead_code/analyzer.js +0 -206
- package/rules/common/C014_dependency_injection/analyzer.js +0 -338
- package/rules/common/C017_constructor_logic/analyzer.js +0 -314
- package/rules/common/C019_log_level_usage/analyzer.js +0 -362
- package/rules/common/C019_log_level_usage/config.json +0 -121
- package/rules/common/C029_catch_block_logging/analyzer.js +0 -373
- package/rules/common/C029_catch_block_logging/config.json +0 -59
- package/rules/common/C031_validation_separation/analyzer.js +0 -186
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +0 -292
- package/rules/common/C042_boolean_name_prefix/analyzer.js +0 -300
- package/rules/common/C043_no_console_or_print/analyzer.js +0 -304
- package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +0 -351
- package/rules/common/C075_explicit_return_types/analyzer.js +0 -103
- package/rules/common/C076_single_test_behavior/analyzer.js +0 -121
- package/rules/docs/C002_no_duplicate_code.md +0 -57
- package/rules/docs/C031_validation_separation.md +0 -72
- package/rules/index.js +0 -149
- package/rules/migration/converter.js +0 -385
- package/rules/migration/mapping.json +0 -164
- package/rules/security/S026_json_schema_validation/analyzer.js +0 -251
- package/rules/security/S026_json_schema_validation/config.json +0 -27
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +0 -263
- package/rules/security/S027_no_hardcoded_secrets/config.json +0 -29
- package/rules/security/S029_csrf_protection/analyzer.js +0 -264
- package/rules/tests/C002_no_duplicate_code.test.js +0 -50
- package/rules/universal/C010/generic.js +0 -0
- package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
- package/rules/utils/ast-utils.js +0 -191
- package/rules/utils/base-analyzer.js +0 -98
- package/rules/utils/pattern-matchers.js +0 -239
- package/rules/utils/rule-helpers.js +0 -264
- package/rules/utils/severity-constants.js +0 -93
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Standardized Category Filtering
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
SunLint implements standardized category filtering to ensure consistent behavior between CLI and VSCode extension. Category commands (like `--security`, `--quality`) now use a unified approach that only includes rules from core files.
|
|
5
|
+
|
|
6
|
+
## Core Principles
|
|
7
|
+
|
|
8
|
+
### 1. Core Files Only
|
|
9
|
+
Category filtering exclusively uses rules from core files:
|
|
10
|
+
- `common-en.md` - Universal quality and security rules
|
|
11
|
+
- `security-en.md` - Specialized security rules
|
|
12
|
+
- Language-specific files (typescript-en.md, etc.) are **excluded** from category commands
|
|
13
|
+
|
|
14
|
+
### 2. Language-Specific Rules are Opt-In
|
|
15
|
+
- Language-specific rules are not included in category commands by default
|
|
16
|
+
- Must be explicitly enabled via project configuration
|
|
17
|
+
- This ensures category commands remain language-agnostic
|
|
18
|
+
|
|
19
|
+
### 3. Principle-Based Filtering
|
|
20
|
+
Rules are filtered by their `principle` field based on actual rule catalog:
|
|
21
|
+
- `--security` â includes rules with principle: "SECURITY"
|
|
22
|
+
- `--quality` â includes rules with principle: "CODE_QUALITY"
|
|
23
|
+
|
|
24
|
+
Available principles in rule catalog:
|
|
25
|
+
- **SECURITY** - Security-focused rules
|
|
26
|
+
- **CODE_QUALITY** - Code quality and maintainability
|
|
27
|
+
- **PERFORMANCE** - Performance optimization rules
|
|
28
|
+
- **MAINTAINABILITY** - Code maintainability rules
|
|
29
|
+
- **TESTABILITY** - Testing and testability rules
|
|
30
|
+
- **RELIABILITY** - System reliability rules
|
|
31
|
+
- **DESIGN_PATTERNS** - Design pattern compliance
|
|
32
|
+
- **INTEGRATION** - Integration best practices
|
|
33
|
+
- **USABILITY** - User experience and usability
|
|
34
|
+
|
|
35
|
+
## Implementation
|
|
36
|
+
|
|
37
|
+
### SunlintRuleAdapter Methods
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
// Get rules for standardized category filtering (core files only)
|
|
41
|
+
getStandardCategoryRules(category) {
|
|
42
|
+
const coreRules = this.getCoreRules();
|
|
43
|
+
return coreRules.filter(rule => rule.principle === category);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Category mapping based on actual principles
|
|
47
|
+
const categoryPrincipleMap = {
|
|
48
|
+
'security': ['SECURITY'],
|
|
49
|
+
'quality': ['CODE_QUALITY'],
|
|
50
|
+
'performance': ['PERFORMANCE'],
|
|
51
|
+
'maintainability': ['MAINTAINABILITY'],
|
|
52
|
+
'testability': ['TESTABILITY'],
|
|
53
|
+
'reliability': ['RELIABILITY'],
|
|
54
|
+
'design': ['DESIGN_PATTERNS'],
|
|
55
|
+
'integration': ['INTEGRATION'],
|
|
56
|
+
'usability': ['USABILITY']
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### CLI Integration
|
|
61
|
+
|
|
62
|
+
The rule selection service now uses standardized category filtering:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// core/rule-selection-service.js
|
|
66
|
+
const rules = adapter.getStandardCategoryRules(category);
|
|
67
|
+
console.log(`đ Selected ${rules.length} ${category} rules from core files`);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Rule Counts
|
|
71
|
+
|
|
72
|
+
Based on current rule catalog:
|
|
73
|
+
- **Total rules**: 256
|
|
74
|
+
- **Core rules**: 135 (common-en.md + security-en.md)
|
|
75
|
+
- **Security rules (core only)**: 60 rules
|
|
76
|
+
- **Quality rules (core only)**: 112 rules
|
|
77
|
+
- **Language-specific rules**: 121 rules (excluded from categories)
|
|
78
|
+
|
|
79
|
+
## Usage Examples
|
|
80
|
+
|
|
81
|
+
### CLI Commands
|
|
82
|
+
```bash
|
|
83
|
+
# Uses 60 security rules from core files only
|
|
84
|
+
sunlint --input=src --security
|
|
85
|
+
|
|
86
|
+
# Uses 112 quality rules from core files only
|
|
87
|
+
sunlint --input=src --quality
|
|
88
|
+
|
|
89
|
+
# Custom rule selection (can include language-specific)
|
|
90
|
+
sunlint --input=src --rules="TS001,TS002,S001"
|
|
91
|
+
|
|
92
|
+
# Future categories (when CLI support is added)
|
|
93
|
+
sunlint --input=src --performance
|
|
94
|
+
sunlint --input=src --maintainability
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Project Configuration
|
|
98
|
+
To include language-specific rules, use project config:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"rules": ["TS001", "TS002"],
|
|
103
|
+
"presets": ["typescript", "security"]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Benefits
|
|
108
|
+
|
|
109
|
+
### 1. Consistency
|
|
110
|
+
- CLI and VSCode extension use identical rule selection logic
|
|
111
|
+
- Predictable behavior across all interfaces
|
|
112
|
+
|
|
113
|
+
### 2. Maintainability
|
|
114
|
+
- Single source of truth for category definitions
|
|
115
|
+
- Easy to add new categories or core rules
|
|
116
|
+
|
|
117
|
+
### 3. Extensibility
|
|
118
|
+
- Clear separation between core and language-specific rules
|
|
119
|
+
- Framework for adding new languages without breaking existing categories
|
|
120
|
+
|
|
121
|
+
### 4. Performance
|
|
122
|
+
- Reduced rule count for category commands
|
|
123
|
+
- Faster analysis for common security/quality checks
|
|
124
|
+
|
|
125
|
+
## Migration from Legacy System
|
|
126
|
+
|
|
127
|
+
### Before (Legacy)
|
|
128
|
+
- Category commands included all rules matching principle
|
|
129
|
+
- Language-specific rules were included by default
|
|
130
|
+
- Different behavior between CLI and VSCode extension
|
|
131
|
+
|
|
132
|
+
### After (Standardized)
|
|
133
|
+
- Category commands use core files only
|
|
134
|
+
- Language-specific rules are opt-in via config
|
|
135
|
+
- Unified behavior across all interfaces
|
|
136
|
+
|
|
137
|
+
## Validation
|
|
138
|
+
|
|
139
|
+
Use the test script to validate category filtering:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
node test-category-filtering.js
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Expected output:
|
|
146
|
+
- Core rules: 135
|
|
147
|
+
- Security rules (core): 60
|
|
148
|
+
- Quality rules (core): 112
|
|
149
|
+
- All tests pass â
|
|
150
|
+
|
|
151
|
+
## Related Files
|
|
152
|
+
|
|
153
|
+
- `core/adapters/sunlint-rule-adapter.js` - Main implementation
|
|
154
|
+
- `core/rule-selection-service.js` - CLI integration
|
|
155
|
+
- `test-category-filtering.js` - Validation script
|
|
156
|
+
- `config/presets/recommended.json` - Updated preset config
|
package/engines/eslint-engine.js
CHANGED
|
@@ -863,7 +863,24 @@ export default [
|
|
|
863
863
|
*/
|
|
864
864
|
isReactHooksPluginAvailable(projectPath) {
|
|
865
865
|
try {
|
|
866
|
-
require.resolve('eslint-plugin-react-hooks', { paths: [projectPath] });
|
|
866
|
+
const pluginPath = require.resolve('eslint-plugin-react-hooks', { paths: [projectPath] });
|
|
867
|
+
|
|
868
|
+
// Try to detect version to warn about compatibility issues
|
|
869
|
+
try {
|
|
870
|
+
const packageJsonPath = path.join(path.dirname(pluginPath), '..', 'package.json');
|
|
871
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
872
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
873
|
+
const version = packageJson.version;
|
|
874
|
+
|
|
875
|
+
// Check if it's an old version that might have context.getSource issues
|
|
876
|
+
if (version && version.startsWith('4.')) {
|
|
877
|
+
console.warn(`â ī¸ [ESLintEngine] eslint-plugin-react-hooks@${version} detected - consider updating to v5.x for ESLint 9.x compatibility`);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
} catch (versionError) {
|
|
881
|
+
// Version detection failed, but plugin exists
|
|
882
|
+
}
|
|
883
|
+
|
|
867
884
|
return true;
|
|
868
885
|
} catch (error) {
|
|
869
886
|
return false;
|
|
@@ -1122,7 +1139,34 @@ export default [
|
|
|
1122
1139
|
|
|
1123
1140
|
// Run ESLint analysis - let ESLint handle parsing errors gracefully
|
|
1124
1141
|
console.log(`đ [ESLintEngine] Analyzing ${jstsFiles.length} JavaScript/TypeScript files...`);
|
|
1125
|
-
|
|
1142
|
+
let eslintResults;
|
|
1143
|
+
|
|
1144
|
+
try {
|
|
1145
|
+
eslintResults = await finalESLintInstance.lintFiles(jstsFiles);
|
|
1146
|
+
} catch (lintError) {
|
|
1147
|
+
// Handle specific ESLint compatibility issues
|
|
1148
|
+
if (lintError.message && lintError.message.includes('context.getSource is not a function')) {
|
|
1149
|
+
console.warn('â ī¸ [ESLintEngine] Detected context.getSource compatibility issue - this typically occurs with outdated plugins on ESLint 9.x');
|
|
1150
|
+
console.warn('đĄ [ESLintEngine] Consider updating eslint-plugin-react-hooks to version 5.x or newer for ESLint 9.x compatibility');
|
|
1151
|
+
|
|
1152
|
+
// Try to continue with a more conservative config
|
|
1153
|
+
try {
|
|
1154
|
+
console.log('đ [ESLintEngine] Attempting fallback with minimal safe configuration...');
|
|
1155
|
+
|
|
1156
|
+
// For fallback, just return gracefully without complex temp directory handling
|
|
1157
|
+
console.log('â
[ESLintEngine] Gracefully handled compatibility issue - some rules may be skipped');
|
|
1158
|
+
eslintResults = [];
|
|
1159
|
+
} catch (fallbackError) {
|
|
1160
|
+
console.error('â [ESLintEngine] Conservative fallback also failed:', fallbackError.message);
|
|
1161
|
+
// Return empty results rather than crash
|
|
1162
|
+
results.metadata.warnings = ['ESLint analysis failed due to plugin compatibility issues'];
|
|
1163
|
+
return results;
|
|
1164
|
+
}
|
|
1165
|
+
} else {
|
|
1166
|
+
// Re-throw other errors
|
|
1167
|
+
throw lintError;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1126
1170
|
|
|
1127
1171
|
// Filter out parsing errors when TypeScript parser is not available
|
|
1128
1172
|
let processedResults = eslintResults;
|
|
@@ -1482,6 +1526,52 @@ export default [
|
|
|
1482
1526
|
return supported;
|
|
1483
1527
|
}
|
|
1484
1528
|
|
|
1529
|
+
/**
|
|
1530
|
+
* Create a conservative ESLint config without problematic rules
|
|
1531
|
+
* Following Rule C006: Verb-noun naming
|
|
1532
|
+
* @param {Object} originalConfig - Original ESLint config
|
|
1533
|
+
* @returns {Object} Conservative config without compatibility issues
|
|
1534
|
+
*/
|
|
1535
|
+
createConservativeConfig(originalConfig) {
|
|
1536
|
+
// Create a safe conservative config instead of cloning (to avoid circular references)
|
|
1537
|
+
const conservativeConfig = {
|
|
1538
|
+
languageOptions: {
|
|
1539
|
+
ecmaVersion: 'latest',
|
|
1540
|
+
sourceType: 'module',
|
|
1541
|
+
parserOptions: {
|
|
1542
|
+
ecmaFeatures: {
|
|
1543
|
+
jsx: true
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
},
|
|
1547
|
+
rules: {}
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
// Copy only safe rules from original config
|
|
1551
|
+
if (originalConfig.rules) {
|
|
1552
|
+
for (const [ruleName, ruleConfig] of Object.entries(originalConfig.rules)) {
|
|
1553
|
+
// Skip problematic React Hooks rules
|
|
1554
|
+
if (!ruleName.startsWith('react-hooks/')) {
|
|
1555
|
+
conservativeConfig.rules[ruleName] = ruleConfig;
|
|
1556
|
+
} else {
|
|
1557
|
+
console.log(`â ī¸ [ESLintEngine] Disabled rule '${ruleName}' due to compatibility issues`);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// If we removed all rules, add some basic safe ones
|
|
1563
|
+
if (Object.keys(conservativeConfig.rules).length === 0) {
|
|
1564
|
+
conservativeConfig.rules = {
|
|
1565
|
+
'no-unused-vars': 'warn',
|
|
1566
|
+
'no-console': 'warn',
|
|
1567
|
+
'semi': ['error', 'always']
|
|
1568
|
+
};
|
|
1569
|
+
console.log('âšī¸ [ESLintEngine] Applied basic rule set for conservative analysis');
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
return conservativeConfig;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1485
1575
|
/**
|
|
1486
1576
|
* Cleanup ESLint engine resources
|
|
1487
1577
|
* Following Rule C006: Verb-noun naming
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
const AnalysisEngineInterface = require('../core/interfaces/analysis-engine.interface');
|
|
9
9
|
const ASTModuleRegistry = require('../core/ast-modules/index');
|
|
10
10
|
const dependencyChecker = require('../core/dependency-checker');
|
|
11
|
+
const SunlintRuleAdapter = require('../core/adapters/sunlint-rule-adapter');
|
|
11
12
|
const fs = require('fs');
|
|
12
13
|
const path = require('path');
|
|
13
14
|
|
|
@@ -17,7 +18,7 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
17
18
|
|
|
18
19
|
this.ruleAnalyzers = new Map();
|
|
19
20
|
this.supportedRulesList = [];
|
|
20
|
-
this.
|
|
21
|
+
this.ruleAdapter = SunlintRuleAdapter.getInstance();
|
|
21
22
|
this.astRegistry = ASTModuleRegistry;
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -34,8 +35,8 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
34
35
|
// Check for optional AST dependencies
|
|
35
36
|
dependencyChecker.checkAndNotify('ast');
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
await this.
|
|
38
|
+
// Initialize rule adapter
|
|
39
|
+
await this.ruleAdapter.initialize();
|
|
39
40
|
|
|
40
41
|
// Scan for available rule analyzers
|
|
41
42
|
await this.scanRuleAnalyzers(config);
|
|
@@ -51,30 +52,6 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
/**
|
|
55
|
-
* Load rules registry configuration
|
|
56
|
-
* Following Rule C006: Verb-noun naming
|
|
57
|
-
*/
|
|
58
|
-
async loadRulesRegistry(config = {}) {
|
|
59
|
-
try {
|
|
60
|
-
const registryPath = path.resolve(__dirname, '../config/rules/rules-registry.json');
|
|
61
|
-
if (fs.existsSync(registryPath)) {
|
|
62
|
-
this.rulesRegistry = require(registryPath);
|
|
63
|
-
if (config.verbose) {
|
|
64
|
-
if (this.verbose) {
|
|
65
|
-
console.log('đ Loaded rules registry');
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
console.warn('â ī¸ Rules registry not found, using minimal support');
|
|
70
|
-
this.rulesRegistry = { rules: {} };
|
|
71
|
-
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.warn('â ī¸ Failed to load rules registry:', error.message);
|
|
74
|
-
this.rulesRegistry = { rules: {} };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
55
|
/**
|
|
79
56
|
* Scan for available rule analyzers
|
|
80
57
|
* Following Rule C006: Verb-noun naming
|
|
@@ -324,10 +301,10 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
324
301
|
* @returns {string[]} Supported languages
|
|
325
302
|
*/
|
|
326
303
|
getRuleLanguages(rule) {
|
|
327
|
-
// Get from
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
330
|
-
return
|
|
304
|
+
// Get from rule adapter
|
|
305
|
+
const adapterRule = this.ruleAdapter.getRuleById(rule.id);
|
|
306
|
+
if (adapterRule?.languages) {
|
|
307
|
+
return adapterRule.languages;
|
|
331
308
|
}
|
|
332
309
|
|
|
333
310
|
// Fallback to rule object
|