@sun-asterisk/sunlint 1.2.0 → 1.2.2
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/config/rule-analysis-strategies.js +18 -2
- package/engines/eslint-engine.js +9 -11
- package/engines/heuristic-engine.js +63 -31
- package/package.json +2 -1
- package/rules/README.md +252 -0
- package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
- package/rules/common/C002_no_duplicate_code/config.json +23 -0
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
- package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
- package/rules/common/C006_function_naming/analyzer.js +504 -0
- package/rules/common/C006_function_naming/config.json +86 -0
- package/rules/common/C006_function_naming/smart-analyzer.js +503 -0
- package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
- package/rules/common/C012_command_query_separation/analyzer.js +481 -0
- package/rules/common/C012_command_query_separation/ast-analyzer.js +495 -0
- package/rules/common/C013_no_dead_code/analyzer.js +206 -0
- package/rules/common/C014_dependency_injection/analyzer.js +338 -0
- package/rules/common/C017_constructor_logic/analyzer.js +314 -0
- package/rules/common/C019_log_level_usage/analyzer.js +362 -0
- package/rules/common/C019_log_level_usage/config.json +121 -0
- package/rules/common/C029_catch_block_logging/analyzer-backup.js +426 -0
- package/rules/common/C029_catch_block_logging/analyzer-fixed.js +130 -0
- package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +487 -0
- package/rules/common/C029_catch_block_logging/analyzer-simple.js +110 -0
- package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +755 -0
- package/rules/common/C029_catch_block_logging/analyzer.js +129 -0
- package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +441 -0
- package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +127 -0
- package/rules/common/C029_catch_block_logging/ast-analyzer.js +133 -0
- package/rules/common/C029_catch_block_logging/cfg-analyzer.js +408 -0
- package/rules/common/C029_catch_block_logging/config.json +59 -0
- package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +454 -0
- package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +700 -0
- package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +568 -0
- package/rules/common/C029_catch_block_logging/semantic-analyzer.js +459 -0
- package/rules/common/C031_validation_separation/analyzer.js +186 -0
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
- package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +296 -0
- package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
- package/rules/common/C043_no_console_or_print/analyzer.js +431 -0
- package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +590 -0
- package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
- package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
- package/rules/docs/C002_no_duplicate_code.md +57 -0
- package/rules/docs/C031_validation_separation.md +72 -0
- package/rules/index.js +155 -0
- package/rules/migration/converter.js +385 -0
- package/rules/migration/mapping.json +164 -0
- package/rules/parser/constants.js +31 -0
- package/rules/parser/file-config.js +80 -0
- package/rules/parser/rule-parser-simple.js +305 -0
- package/rules/parser/rule-parser.js +527 -0
- package/rules/security/S015_insecure_tls_certificate/analyzer.js +150 -0
- package/rules/security/S015_insecure_tls_certificate/ast-analyzer.js +237 -0
- package/rules/security/S023_no_json_injection/analyzer.js +278 -0
- package/rules/security/S023_no_json_injection/ast-analyzer.js +359 -0
- package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
- package/rules/security/S026_json_schema_validation/config.json +27 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +436 -0
- package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
- package/rules/security/S029_csrf_protection/analyzer.js +330 -0
- package/rules/tests/C002_no_duplicate_code.test.js +50 -0
- package/rules/universal/C010/generic.js +0 -0
- package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
- package/rules/utils/ast-utils.js +191 -0
- package/rules/utils/base-analyzer.js +98 -0
- package/rules/utils/pattern-matchers.js +239 -0
- package/rules/utils/rule-helpers.js +264 -0
- package/rules/utils/severity-constants.js +93 -0
- package/scripts/generate_insights.js +188 -0
- package/scripts/merge-reports.js +0 -424
- package/scripts/test-scripts/README.md +0 -22
- package/scripts/test-scripts/test-c041-comparison.js +0 -114
- package/scripts/test-scripts/test-c041-eslint.js +0 -67
- package/scripts/test-scripts/test-eslint-rules.js +0 -146
- package/scripts/test-scripts/test-real-world.js +0 -44
- package/scripts/test-scripts/test-rules-on-real-projects.js +0 -86
|
@@ -12,9 +12,9 @@ module.exports = {
|
|
|
12
12
|
accuracy: { ast: 95, regex: 75 }
|
|
13
13
|
},
|
|
14
14
|
'C012': {
|
|
15
|
-
reason: '
|
|
15
|
+
reason: 'Command Query Separation requires function behavior analysis',
|
|
16
16
|
methods: ['ast', 'regex'],
|
|
17
|
-
accuracy: { ast:
|
|
17
|
+
accuracy: { ast: 95, regex: 80 }
|
|
18
18
|
},
|
|
19
19
|
'C015': {
|
|
20
20
|
reason: 'Function parameter counting benefits from AST',
|
|
@@ -25,6 +25,16 @@ module.exports = {
|
|
|
25
25
|
reason: 'Constructor logic analysis needs AST context',
|
|
26
26
|
methods: ['ast', 'regex'],
|
|
27
27
|
accuracy: { ast: 90, regex: 70 }
|
|
28
|
+
},
|
|
29
|
+
'S015': {
|
|
30
|
+
reason: 'TLS certificate validation requires AST context analysis',
|
|
31
|
+
methods: ['ast', 'regex'],
|
|
32
|
+
accuracy: { ast: 95, regex: 80 }
|
|
33
|
+
},
|
|
34
|
+
'S023': {
|
|
35
|
+
reason: 'JSON injection detection requires AST context analysis',
|
|
36
|
+
methods: ['ast', 'regex'],
|
|
37
|
+
accuracy: { ast: 95, regex: 60 }
|
|
28
38
|
}
|
|
29
39
|
},
|
|
30
40
|
|
|
@@ -55,6 +65,12 @@ module.exports = {
|
|
|
55
65
|
strategy: 'ast-primary-regex-fallback',
|
|
56
66
|
accuracy: { ast: 90, regex: 75, combined: 95 }
|
|
57
67
|
},
|
|
68
|
+
'C041': {
|
|
69
|
+
reason: 'Hardcoded secrets need AST literal analysis like ESLint',
|
|
70
|
+
methods: ['ast', 'regex'],
|
|
71
|
+
strategy: 'ast-primary-regex-fallback',
|
|
72
|
+
accuracy: { ast: 95, regex: 70, combined: 95 }
|
|
73
|
+
},
|
|
58
74
|
'C047': {
|
|
59
75
|
reason: 'Retry logic detection needs pattern + structure',
|
|
60
76
|
methods: ['regex', 'ast'],
|
package/engines/eslint-engine.js
CHANGED
|
@@ -359,14 +359,10 @@ class ESLintEngine extends AnalysisEngineInterface {
|
|
|
359
359
|
console.warn(`⚠️ [ESLintEngine] Skipped ${skippedRules.typescript.length} TypeScript ESLint rules - plugin not available`);
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
//
|
|
362
|
+
// Use only SunLint analysis config (filteredRules) - do not merge with project rules
|
|
363
363
|
const mergedConfig = {
|
|
364
|
-
...baseConfig,
|
|
365
364
|
...eslintConfig,
|
|
366
|
-
rules:
|
|
367
|
-
...baseConfig.rules,
|
|
368
|
-
...filteredRules
|
|
369
|
-
}
|
|
365
|
+
rules: filteredRules // Only use SunLint specified rules
|
|
370
366
|
};
|
|
371
367
|
|
|
372
368
|
// Create temporary config file in project directory
|
|
@@ -384,10 +380,7 @@ class ESLintEngine extends AnalysisEngineInterface {
|
|
|
384
380
|
}
|
|
385
381
|
}
|
|
386
382
|
},
|
|
387
|
-
rules:
|
|
388
|
-
...baseConfig.rules,
|
|
389
|
-
...filteredRules
|
|
390
|
-
}
|
|
383
|
+
rules: filteredRules // Only use SunLint specified rules
|
|
391
384
|
};
|
|
392
385
|
|
|
393
386
|
const configContent = `// Temporary flat config generated by SunLint
|
|
@@ -408,7 +401,7 @@ export default [
|
|
|
408
401
|
}
|
|
409
402
|
}
|
|
410
403
|
},
|
|
411
|
-
rules: ${JSON.stringify(
|
|
404
|
+
rules: ${JSON.stringify(filteredRules, null, 2)}
|
|
412
405
|
}
|
|
413
406
|
];
|
|
414
407
|
`;
|
|
@@ -1453,6 +1446,11 @@ export default [
|
|
|
1453
1446
|
};
|
|
1454
1447
|
|
|
1455
1448
|
for (const message of eslintResult.messages) {
|
|
1449
|
+
// Only process custom/ rules (SunLint rules) - ignore project-specific rules and inline directives
|
|
1450
|
+
if (!message.ruleId || !message.ruleId.startsWith('custom/')) {
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1456
1454
|
const violation = {
|
|
1457
1455
|
ruleId: this.mapESLintRuleToSunLint(message.ruleId, originalRules),
|
|
1458
1456
|
message: message.message,
|
|
@@ -81,43 +81,67 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
81
81
|
|
|
82
82
|
for (const ruleFolder of ruleFolders) {
|
|
83
83
|
const ruleId = this.extractRuleIdFromFolder(ruleFolder);
|
|
84
|
-
const analyzerPath = path.join(categoryPath, ruleFolder, 'analyzer.js');
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
// Priority 1: Check for AST analyzer (enhanced accuracy)
|
|
86
|
+
const astAnalyzerPath = path.join(categoryPath, ruleFolder, 'ast-analyzer.js');
|
|
87
|
+
const regexAnalyzerPath = path.join(categoryPath, ruleFolder, 'analyzer.js');
|
|
88
|
+
|
|
89
|
+
let selectedAnalyzer = null;
|
|
90
|
+
let analyzerPath = null;
|
|
91
|
+
let analyzerType = 'regex';
|
|
92
|
+
|
|
93
|
+
// Try AST analyzer first
|
|
94
|
+
if (fs.existsSync(astAnalyzerPath)) {
|
|
87
95
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// It's an analyzer instance with analyze method
|
|
105
|
-
this.ruleAnalyzers.set(ruleId, {
|
|
106
|
-
path: analyzerPath,
|
|
107
|
-
instance: analyzer,
|
|
108
|
-
folder: ruleFolder,
|
|
109
|
-
category: categoryFolder,
|
|
110
|
-
type: 'instance'
|
|
111
|
-
});
|
|
112
|
-
this.supportedRulesList.push(ruleId);
|
|
113
|
-
} else {
|
|
114
|
-
console.warn(`⚠️ Analyzer for ${ruleId} has unsupported format:`, typeof analyzer);
|
|
115
|
-
}
|
|
116
|
-
|
|
96
|
+
const analyzerModule = require(astAnalyzerPath);
|
|
97
|
+
selectedAnalyzer = analyzerModule.default || analyzerModule;
|
|
98
|
+
analyzerPath = astAnalyzerPath;
|
|
99
|
+
analyzerType = 'ast';
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.debug(`AST analyzer for ${ruleId} failed to load, falling back to regex:`, error.message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Fallback to regex analyzer
|
|
106
|
+
if (!selectedAnalyzer && fs.existsSync(regexAnalyzerPath)) {
|
|
107
|
+
try {
|
|
108
|
+
const analyzerModule = require(regexAnalyzerPath);
|
|
109
|
+
selectedAnalyzer = analyzerModule.default || analyzerModule;
|
|
110
|
+
analyzerPath = regexAnalyzerPath;
|
|
111
|
+
analyzerType = 'regex';
|
|
117
112
|
} catch (error) {
|
|
118
113
|
console.warn(`⚠️ Failed to load analyzer for ${ruleId}:`, error.message);
|
|
119
114
|
}
|
|
120
115
|
}
|
|
116
|
+
|
|
117
|
+
if (selectedAnalyzer) {
|
|
118
|
+
// Check if it's a class constructor, instance, or factory function
|
|
119
|
+
if (typeof selectedAnalyzer === 'function') {
|
|
120
|
+
// It's a class constructor
|
|
121
|
+
this.ruleAnalyzers.set(ruleId, {
|
|
122
|
+
path: analyzerPath,
|
|
123
|
+
class: selectedAnalyzer,
|
|
124
|
+
folder: ruleFolder,
|
|
125
|
+
category: categoryFolder,
|
|
126
|
+
type: 'class',
|
|
127
|
+
analyzerType: analyzerType // 'ast' or 'regex'
|
|
128
|
+
});
|
|
129
|
+
this.supportedRulesList.push(ruleId);
|
|
130
|
+
} else if (selectedAnalyzer && typeof selectedAnalyzer === 'object' && selectedAnalyzer.analyze) {
|
|
131
|
+
// It's an analyzer instance with analyze method
|
|
132
|
+
this.ruleAnalyzers.set(ruleId, {
|
|
133
|
+
path: analyzerPath,
|
|
134
|
+
instance: selectedAnalyzer,
|
|
135
|
+
folder: ruleFolder,
|
|
136
|
+
category: categoryFolder,
|
|
137
|
+
type: 'instance',
|
|
138
|
+
analyzerType: analyzerType // 'ast' or 'regex'
|
|
139
|
+
});
|
|
140
|
+
this.supportedRulesList.push(ruleId);
|
|
141
|
+
} else {
|
|
142
|
+
console.warn(`⚠️ Analyzer for ${ruleId} has unsupported format:`, typeof selectedAnalyzer);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
121
145
|
}
|
|
122
146
|
}
|
|
123
147
|
|
|
@@ -304,11 +328,19 @@ class HeuristicEngine extends AnalysisEngineInterface {
|
|
|
304
328
|
// Get from rule adapter
|
|
305
329
|
const adapterRule = this.ruleAdapter.getRuleById(rule.id);
|
|
306
330
|
if (adapterRule?.languages) {
|
|
331
|
+
// If rule supports 'All languages', return all available languages
|
|
332
|
+
if (adapterRule.languages.includes('All languages')) {
|
|
333
|
+
return ['typescript', 'javascript', 'java', 'python', 'ruby', 'php', 'dart', 'kotlin', 'swift'];
|
|
334
|
+
}
|
|
307
335
|
return adapterRule.languages;
|
|
308
336
|
}
|
|
309
337
|
|
|
310
338
|
// Fallback to rule object
|
|
311
339
|
if (rule.languages) {
|
|
340
|
+
// If rule supports 'All languages', return all available languages
|
|
341
|
+
if (rule.languages.includes('All languages')) {
|
|
342
|
+
return ['typescript', 'javascript', 'java', 'python', 'ruby', 'php', 'dart', 'kotlin', 'swift'];
|
|
343
|
+
}
|
|
312
344
|
return rule.languages;
|
|
313
345
|
}
|
|
314
346
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sun-asterisk/sunlint",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"config/",
|
|
75
75
|
"engines/",
|
|
76
76
|
"integrations/",
|
|
77
|
+
"rules/",
|
|
77
78
|
"scripts/",
|
|
78
79
|
"docs/",
|
|
79
80
|
".sunlint.json",
|
package/rules/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# SunLint Heuristic Rules System
|
|
2
|
+
|
|
3
|
+
Enhanced heuristic rules engine with organized rule categories and migration support.
|
|
4
|
+
|
|
5
|
+
## 📁 Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
rules/
|
|
9
|
+
├── # SunLint Heuristic Rules Structure
|
|
10
|
+
|
|
11
|
+
## 📁 Clean Rule Organization
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
rules/
|
|
15
|
+
├── 📚 docs/ # Rule documentation
|
|
16
|
+
│ ├── C002_no_duplicate_code.md
|
|
17
|
+
│ └── C031_validation_separation.md
|
|
18
|
+
├── 🧪 tests/ # Rule unit tests
|
|
19
|
+
│ └── C002_no_duplicate_code.test.js
|
|
20
|
+
├── 🛠️ utils/ # Shared utilities
|
|
21
|
+
│ ├── ast-utils.js # AST parsing helpers
|
|
22
|
+
│ ├── pattern-matchers.js # Pattern matching utilities
|
|
23
|
+
│ └── rule-helpers.js # Rule helper functions
|
|
24
|
+
├── 🔹 common/ # C-series rules (Common standards)
|
|
25
|
+
│ ├── C002_no_duplicate_code/
|
|
26
|
+
│ │ ├── analyzer.js # 🔍 Core analysis logic
|
|
27
|
+
│ │ └── config.json # ⚙️ Rule configuration
|
|
28
|
+
│ ├── C006_function_naming/
|
|
29
|
+
│ ├── C019_log_level_usage/
|
|
30
|
+
│ ├── C029_catch_block_logging/
|
|
31
|
+
│ └── C031_validation_separation/
|
|
32
|
+
├── 🔒 security/ # S-series rules (Security standards)
|
|
33
|
+
└── 📘 typescript/ # T-series rules (TypeScript specific)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## ✅ Key Improvements
|
|
37
|
+
|
|
38
|
+
### **1. Clean Rule Folders**
|
|
39
|
+
- **Before**: `README.md`, `test.js`, `analyzer.js`, `config.json` mixed together
|
|
40
|
+
- **After**: Only **core files** in rule folders (`analyzer.js`, `config.json`)
|
|
41
|
+
|
|
42
|
+
### **2. Centralized Documentation**
|
|
43
|
+
- **Before**: README scattered in each rule folder
|
|
44
|
+
- **After**: All docs in `rules/docs/[RuleId].md`
|
|
45
|
+
|
|
46
|
+
### **3. Centralized Testing**
|
|
47
|
+
- **Before**: `test.js` in each rule folder
|
|
48
|
+
- **After**: All tests in `rules/tests/[RuleId].test.js`
|
|
49
|
+
|
|
50
|
+
### **4. Correct Categorization**
|
|
51
|
+
- **Before**: ❌ `rules/coding/` (incorrect - C ≠ Coding)
|
|
52
|
+
- **After**: ✅ `rules/common/` (correct - C = Common)
|
|
53
|
+
|
|
54
|
+
## 🔍 Rule Analyzer Structure
|
|
55
|
+
|
|
56
|
+
Each rule analyzer follows a clean structure:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
// rules/common/C019_log_level_usage/analyzer.js
|
|
60
|
+
class C019Analyzer {
|
|
61
|
+
constructor() {
|
|
62
|
+
this.ruleId = 'C019';
|
|
63
|
+
this.ruleName = 'Log Level Usage';
|
|
64
|
+
// ...
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async analyze(files, language, config) {
|
|
68
|
+
// Core analysis logic only
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
// rules/common/C019_log_level_usage/config.json
|
|
75
|
+
{
|
|
76
|
+
"ruleId": "C019",
|
|
77
|
+
"name": "Log Level Usage",
|
|
78
|
+
"description": "Don't use error level for non-critical issues",
|
|
79
|
+
"severity": "warning",
|
|
80
|
+
"languages": ["typescript", "javascript", "dart"]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 🚀 Benefits
|
|
85
|
+
|
|
86
|
+
1. **Clean Separation**: Core logic separated from docs/tests
|
|
87
|
+
2. **Easy Maintenance**: Find docs/tests in centralized locations
|
|
88
|
+
3. **Correct Semantics**: C = Common (not Coding)
|
|
89
|
+
4. **Scalable**: Easy to add new rules/categories
|
|
90
|
+
5. **Engine Compatible**: Heuristic engine auto-discovers all rules
|
|
91
|
+
|
|
92
|
+
## 📊 Migration Summary
|
|
93
|
+
|
|
94
|
+
| **Aspect** | **Before** | **After** |
|
|
95
|
+
|------------|------------|-----------|
|
|
96
|
+
| **Rule Folders** | Mixed content | Core only (`analyzer.js`, `config.json`) |
|
|
97
|
+
| **Documentation** | Scattered | Centralized in `docs/` |
|
|
98
|
+
| **Tests** | Scattered | Centralized in `tests/` |
|
|
99
|
+
| **Categories** | ❌ `coding/` | ✅ `common/` |
|
|
100
|
+
| **Structure** | Flat | Nested by category |
|
|
101
|
+
| **Discoverable Rules** | 0 (broken) | 5 (working) |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
*Rules structure cleaned and optimized for maintainability! 🎉*
|
|
105
|
+
├── index.js # Rule registry and loader
|
|
106
|
+
├── common/ # 🛠️ Shared utilities
|
|
107
|
+
│ ├── ast-utils.js # AST parsing utilities
|
|
108
|
+
│ ├── pattern-matchers.js # Common pattern matching
|
|
109
|
+
│ └── rule-helpers.js # Rule development helpers
|
|
110
|
+
├── coding/ # 🔹 C-series: Coding standards (4 → expanding)
|
|
111
|
+
│ ├── C006_function_naming/ # Function naming conventions
|
|
112
|
+
│ ├── C019_log_level_usage/ # Log level usage patterns
|
|
113
|
+
│ ├── C029_catch_block_logging/ # Exception logging standards
|
|
114
|
+
│ └── C031_validation_separation/ # Input validation separation
|
|
115
|
+
├── security/ # 🔒 S-series: Security rules (0 → 49 planned)
|
|
116
|
+
│ └── (ready for migration from ESLint)
|
|
117
|
+
├── typescript/ # 📘 T-series: TypeScript rules (0 → 10 planned)
|
|
118
|
+
│ └── (ready for migration from ESLint)
|
|
119
|
+
└── migration/ # 🔄 ESLint → Heuristic migration
|
|
120
|
+
├── mapping.json # Rule mapping configuration
|
|
121
|
+
├── converter.js # Auto-migration tool
|
|
122
|
+
└── compatibility.js # Compatibility layer
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 🎯 Current Status
|
|
126
|
+
|
|
127
|
+
### ✅ **Active Heuristic Rules (4)**
|
|
128
|
+
| Rule ID | Name | Type | Status |
|
|
129
|
+
|---------|------|------|--------|
|
|
130
|
+
| **C006** | Function Naming | Coding | ✅ Production |
|
|
131
|
+
| **C019** | Log Level Usage | Coding | ✅ Production |
|
|
132
|
+
| **C029** | Catch Block Logging | Coding | ✅ Production |
|
|
133
|
+
| **C031** | Validation Separation | Coding | ✅ Production |
|
|
134
|
+
|
|
135
|
+
### 🚀 **Migration Pipeline (77 rules)**
|
|
136
|
+
| Category | ESLint Rules | Heuristic Target | Status |
|
|
137
|
+
|----------|--------------|------------------|--------|
|
|
138
|
+
| **Coding** | 22 rules | rules/coding/ | 🔄 Ready for migration |
|
|
139
|
+
| **Security** | 49 rules | rules/security/ | 🔄 Ready for migration |
|
|
140
|
+
| **TypeScript** | 10 rules | rules/typescript/ | 🔄 Ready for migration |
|
|
141
|
+
|
|
142
|
+
## 🛠️ Rule Development
|
|
143
|
+
|
|
144
|
+
### **Heuristic Rule Structure**
|
|
145
|
+
Each rule follows this standard structure:
|
|
146
|
+
```
|
|
147
|
+
rules/{category}/{RULE_ID}/
|
|
148
|
+
├── analyzer.js # Core heuristic logic
|
|
149
|
+
├── config.json # Rule configuration
|
|
150
|
+
├── test.js # Rule-specific tests
|
|
151
|
+
└── README.md # Rule documentation
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### **Rule Development Helpers**
|
|
155
|
+
Use shared utilities in `rules/common/`:
|
|
156
|
+
- `ast-utils.js` - AST traversal and analysis
|
|
157
|
+
- `pattern-matchers.js` - Common code pattern detection
|
|
158
|
+
- `rule-helpers.js` - Rule configuration and reporting
|
|
159
|
+
|
|
160
|
+
### **Example: Adding New Rule**
|
|
161
|
+
```bash
|
|
162
|
+
# Create new coding rule
|
|
163
|
+
mkdir rules/coding/C045_new_rule/
|
|
164
|
+
cd rules/coding/C045_new_rule/
|
|
165
|
+
|
|
166
|
+
# Create rule files
|
|
167
|
+
touch analyzer.js config.json test.js README.md
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 🔄 Migration Process
|
|
171
|
+
|
|
172
|
+
### **ESLint → Heuristic Migration**
|
|
173
|
+
|
|
174
|
+
1. **Mapping**: Define rule equivalencies in `migration/mapping.json`
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"eslint": "c006-function-name-verb-noun",
|
|
178
|
+
"heuristic": "C006_function_naming",
|
|
179
|
+
"compatibility": "partial",
|
|
180
|
+
"migration_priority": "high"
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
2. **Conversion**: Use `migration/converter.js` for automated migration
|
|
185
|
+
```bash
|
|
186
|
+
node rules/migration/converter.js --rule=C006 --target=heuristic
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
3. **Testing**: Validate against existing ESLint rule behavior
|
|
190
|
+
```bash
|
|
191
|
+
node rules/migration/compatibility.js --test=C006
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 🚀 Future Expansion
|
|
195
|
+
|
|
196
|
+
### **Phase 2A: Security Rules Migration**
|
|
197
|
+
Target: Migrate 49 security rules to heuristic engine
|
|
198
|
+
- Priority: S001, S003, S012 (critical security)
|
|
199
|
+
- Timeline: After ESLint deprecation decision
|
|
200
|
+
|
|
201
|
+
### **Phase 2B: TypeScript Rules Migration**
|
|
202
|
+
Target: Migrate 10 TypeScript rules to heuristic engine
|
|
203
|
+
- Priority: T002, T003, T004 (interface standards)
|
|
204
|
+
- Timeline: Post security migration
|
|
205
|
+
|
|
206
|
+
### **Phase 3: Advanced Heuristics**
|
|
207
|
+
- Multi-file analysis capabilities
|
|
208
|
+
- Cross-language rule support
|
|
209
|
+
- AI-assisted pattern detection
|
|
210
|
+
|
|
211
|
+
## 📊 Engine Comparison
|
|
212
|
+
|
|
213
|
+
| Feature | ESLint Engine | Heuristic Engine | Status |
|
|
214
|
+
|---------|---------------|------------------|--------|
|
|
215
|
+
| **Rules Count** | 81 rules | 4 → 81 rules | 🔄 Migration |
|
|
216
|
+
| **Performance** | AST heavy | Pattern optimized | 🚀 Faster |
|
|
217
|
+
| **Languages** | JS/TS only | Multi-language | 🌟 Flexible |
|
|
218
|
+
| **Customization** | Limited | Full control | ✅ Better |
|
|
219
|
+
| **Maintenance** | ESLint dependent | Self-contained | 🛡️ Stable |
|
|
220
|
+
|
|
221
|
+
## 🎯 Integration
|
|
222
|
+
|
|
223
|
+
### **Engine Loading**
|
|
224
|
+
The heuristic engine automatically loads rules from this structure:
|
|
225
|
+
```javascript
|
|
226
|
+
// core/analysis-orchestrator.js
|
|
227
|
+
const heuristicRules = require('../rules/index.js');
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### **Rule Registry**
|
|
231
|
+
All rules are registered in `rules/index.js`:
|
|
232
|
+
```javascript
|
|
233
|
+
module.exports = {
|
|
234
|
+
coding: {
|
|
235
|
+
C006: require('./coding/C006_function_naming/analyzer.js'),
|
|
236
|
+
C019: require('./coding/C019_log_level_usage/analyzer.js'),
|
|
237
|
+
// ...
|
|
238
|
+
},
|
|
239
|
+
security: {
|
|
240
|
+
// Ready for S-series rules
|
|
241
|
+
},
|
|
242
|
+
typescript: {
|
|
243
|
+
// Ready for T-series rules
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
**🏗️ Architecture**: Scalable, organized, migration-ready
|
|
251
|
+
**🎯 Goal**: 81 heuristic rules (ESLint independence)
|
|
252
|
+
**🚀 Status**: 4 active, 77 ready for migration
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C002_no_duplicate_code - Heuristic Rule Analyzer
|
|
3
|
+
* Category: coding
|
|
4
|
+
*
|
|
5
|
+
* TODO: Migrate logic from ESLint rule
|
|
6
|
+
* ESLint rule: integrations/eslint/plugin/rules/coding/c002-no_duplicate_code.js
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const ts = require('typescript');
|
|
10
|
+
const { PatternMatcher } = require('../../utils/pattern-matchers');
|
|
11
|
+
const { RuleHelper } = require('../../utils/rule-helpers');
|
|
12
|
+
|
|
13
|
+
class C002_no_duplicate_codeAnalyzer {
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.patternMatcher = new PatternMatcher();
|
|
17
|
+
this.helper = new RuleHelper();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Analyze code content for rule violations
|
|
22
|
+
* @param {string} content - File content
|
|
23
|
+
* @param {string} filePath - File path
|
|
24
|
+
* @param {Object} context - Analysis context
|
|
25
|
+
* @returns {Array} Array of violations
|
|
26
|
+
*/
|
|
27
|
+
analyze(content, filePath, context = {}) {
|
|
28
|
+
const violations = [];
|
|
29
|
+
|
|
30
|
+
// TODO: Implement heuristic analysis logic
|
|
31
|
+
// This should replicate the ESLint rule behavior using pattern matching
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Example pattern-based analysis
|
|
35
|
+
// const patterns = this.getViolationPatterns();
|
|
36
|
+
// const matches = this.patternMatcher.findMatches(content, patterns);
|
|
37
|
+
//
|
|
38
|
+
// matches.forEach(match => {
|
|
39
|
+
// violations.push(this.helper.createViolation({
|
|
40
|
+
// ruleId: 'C002_no_duplicate_code',
|
|
41
|
+
// message: 'Rule violation detected',
|
|
42
|
+
// line: match.line,
|
|
43
|
+
// column: match.column,
|
|
44
|
+
// severity: 'error'
|
|
45
|
+
// }));
|
|
46
|
+
// });
|
|
47
|
+
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.warn(`Error analyzing ${filePath} with C002_no_duplicate_code:`, error.message);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return violations;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get violation patterns for this rule
|
|
57
|
+
* @returns {Array} Array of patterns to match
|
|
58
|
+
*/
|
|
59
|
+
getViolationPatterns() {
|
|
60
|
+
// TODO: Define patterns based on ESLint rule logic
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = C002_no_duplicate_codeAnalyzer;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "C002_no_duplicate_code",
|
|
3
|
+
"name": "C002_no_duplicate_code",
|
|
4
|
+
"category": "coding",
|
|
5
|
+
"description": "C002_no_duplicate_code heuristic rule - migrated from ESLint",
|
|
6
|
+
"severity": "error",
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"migration": {
|
|
9
|
+
"from_eslint": "c002-no-duplicate-code",
|
|
10
|
+
"compatibility": "partial",
|
|
11
|
+
"status": "pending"
|
|
12
|
+
},
|
|
13
|
+
"patterns": {
|
|
14
|
+
"include": [
|
|
15
|
+
"**/*.js",
|
|
16
|
+
"**/*.ts"
|
|
17
|
+
],
|
|
18
|
+
"exclude": [
|
|
19
|
+
"**/*.test.*",
|
|
20
|
+
"**/*.spec.*"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|