@sun-asterisk/sunlint 1.2.1 → 1.3.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 +40 -1
- package/CONTRIBUTING.md +533 -70
- package/README.md +16 -2
- package/config/engines/engines-enhanced.json +86 -0
- package/config/engines/semantic-config.json +114 -0
- package/config/eslint-rule-mapping.json +50 -38
- package/config/rule-analysis-strategies.js +18 -2
- package/config/rules/enhanced-rules-registry.json +2503 -0
- package/config/rules/rules-registry-generated.json +785 -837
- package/core/adapters/sunlint-rule-adapter.js +25 -30
- package/core/analysis-orchestrator.js +42 -2
- package/core/categories.js +52 -0
- package/core/category-constants.js +39 -0
- package/core/cli-action-handler.js +32 -5
- package/core/config-manager.js +111 -0
- package/core/config-merger.js +61 -0
- package/core/constants/categories.js +168 -0
- package/core/constants/defaults.js +165 -0
- package/core/constants/engines.js +185 -0
- package/core/constants/index.js +30 -0
- package/core/constants/rules.js +215 -0
- package/core/file-targeting-service.js +128 -7
- package/core/interfaces/rule-plugin.interface.js +207 -0
- package/core/plugin-manager.js +448 -0
- package/core/rule-selection-service.js +42 -15
- package/core/semantic-engine.js +560 -0
- package/core/semantic-rule-base.js +433 -0
- package/core/unified-rule-registry.js +484 -0
- package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
- package/engines/core/base-engine.js +249 -0
- package/engines/engine-factory.js +275 -0
- package/engines/eslint-engine.js +180 -30
- package/engines/heuristic-engine.js +513 -56
- package/integrations/eslint/plugin/index.js +27 -27
- package/package.json +11 -6
- 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-smart-pipeline.js +755 -0
- package/rules/common/C029_catch_block_logging/analyzer.js +141 -0
- package/rules/common/C029_catch_block_logging/config.json +59 -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/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -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 +162 -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/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/category-manager.js +150 -0
- package/scripts/generate-rules-registry.js +88 -0
- package/scripts/generate_insights.js +188 -0
- package/scripts/migrate-rule-registry.js +157 -0
- package/scripts/validate-system.js +48 -0
- package/.sunlint.json +0 -35
- package/config/README.md +0 -88
- package/config/engines/eslint-rule-mapping.json +0 -74
- package/config/testing/test-s005-working.ts +0 -22
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -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
- /package/{config/schemas/sunlint-schema.json → rules/universal/C010/generic.js} +0 -0
- /package/{core/multi-rule-runner.js → rules/universal/C010/tree-sitter-analyzer.js} +0 -0
package/CONTRIBUTING.md
CHANGED
|
@@ -49,74 +49,357 @@ When contributing to Sun Lint, please follow these coding rules:
|
|
|
49
49
|
|
|
50
50
|
## 🔧 **Development Workflow**
|
|
51
51
|
|
|
52
|
-
### **
|
|
52
|
+
### **SunLint Architecture Overview**
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
SunLint uses a **multi-engine architecture** with rule mapping system:
|
|
55
|
+
|
|
56
|
+
- **Heuristic Engine**: Pattern-based analysis using AST (Abstract Syntax Tree)
|
|
57
|
+
- **ESLint Engine**: JavaScript/TypeScript linting using ESLint rules
|
|
58
|
+
- **OpenAI Engine**: AI-powered code analysis
|
|
59
|
+
|
|
60
|
+
**Rule Configuration Files:**
|
|
61
|
+
- `rules/` - Unified rule registry (auto-generated from origin-rules)
|
|
62
|
+
- `config/eslint-rule-mapping.json` - ESLint engine rule mappings
|
|
63
|
+
- `origin-rules/` - Original rule definitions (markdown format)
|
|
64
|
+
|
|
65
|
+
### **Adding a New Rule (Current Process)**
|
|
66
|
+
|
|
67
|
+
#### **Step 1: Choose Rule Implementation Approach**
|
|
68
|
+
|
|
69
|
+
**Option A: ESLint Engine Rule (Recommended for JS/TS)**
|
|
70
|
+
For JavaScript/TypeScript rules that can use existing ESLint rules:
|
|
71
|
+
|
|
72
|
+
1. **Add to ESLint mapping**: Edit `config/eslint-rule-mapping.json`
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"C042": ["no-magic-numbers", "custom/no-hardcoded-values"]
|
|
76
|
+
}
|
|
59
77
|
```
|
|
60
78
|
|
|
61
|
-
2. **
|
|
79
|
+
2. **Create custom ESLint rule** (if needed): `integrations/eslint/plugin/rules/no-hardcoded-values.js`
|
|
80
|
+
|
|
81
|
+
**Option B: Heuristic Engine Rule (Universal)**
|
|
82
|
+
For language-agnostic rules or complex pattern analysis:
|
|
83
|
+
|
|
84
|
+
1. **Create rule class**: `custom-rules/c042-no-hardcoded-config.js`
|
|
85
|
+
|
|
86
|
+
#### **Step 2: Implement Rule Logic**
|
|
87
|
+
|
|
88
|
+
**For ESLint Engine Rules:**
|
|
62
89
|
```javascript
|
|
63
|
-
// rules/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
// integrations/eslint/plugin/rules/no-hardcoded-values.js
|
|
91
|
+
module.exports = {
|
|
92
|
+
meta: {
|
|
93
|
+
type: 'problem',
|
|
94
|
+
docs: { description: 'Detect hardcoded configuration values' },
|
|
95
|
+
schema: []
|
|
96
|
+
},
|
|
97
|
+
create(context) {
|
|
98
|
+
return {
|
|
99
|
+
VariableDeclaration(node) {
|
|
100
|
+
// Rule C005: Single responsibility - detect hardcoded values
|
|
101
|
+
if (this.isHardcodedConfig(node)) {
|
|
102
|
+
context.report({
|
|
103
|
+
node,
|
|
104
|
+
message: 'Avoid hardcoded configuration values'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**For Heuristic Engine Rules:**
|
|
114
|
+
```javascript
|
|
115
|
+
// custom-rules/c042-no-hardcoded-config.js
|
|
116
|
+
const SemanticRuleBase = require('../core/semantic-rule-base');
|
|
117
|
+
|
|
118
|
+
class NoHardcodedConfigRule extends SemanticRuleBase {
|
|
119
|
+
constructor() {
|
|
120
|
+
super('C042', 'No Hardcoded Configuration Values');
|
|
68
121
|
}
|
|
69
122
|
|
|
70
|
-
|
|
123
|
+
analyze(node, context) {
|
|
124
|
+
// Rule C005: Single responsibility - focus only on hardcoded config detection
|
|
125
|
+
if (this.isHardcodedConfigValue(node)) {
|
|
126
|
+
return this.createViolation(node, 'Hardcoded configuration value detected');
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
isHardcodedConfigValue(node) {
|
|
71
132
|
// Rule C031: Keep validation logic separate
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
133
|
+
const configPatterns = /^(API_URL|DATABASE_URL|MAX_|MIN_|TIMEOUT|PORT)/;
|
|
134
|
+
return node.type === 'VariableDeclaration' &&
|
|
135
|
+
configPatterns.test(node.declarations[0]?.id?.name);
|
|
75
136
|
}
|
|
76
137
|
}
|
|
77
138
|
|
|
78
|
-
module.exports =
|
|
139
|
+
module.exports = NoHardcodedConfigRule;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### **Step 3: Update Rule Registry**
|
|
143
|
+
|
|
144
|
+
Add rule definition to origin rules:
|
|
145
|
+
```markdown
|
|
146
|
+
<!-- origin-rules/common-en.md -->
|
|
147
|
+
## C042: No Hardcoded Configuration Values
|
|
148
|
+
|
|
149
|
+
**Category**: Maintainability
|
|
150
|
+
**Severity**: Warning
|
|
151
|
+
|
|
152
|
+
**Description**: Avoid hardcoding configuration values in business logic
|
|
153
|
+
|
|
154
|
+
**Examples**:
|
|
155
|
+
❌ Bad:
|
|
156
|
+
```javascript
|
|
157
|
+
const API_URL = "https://api.example.com";
|
|
158
|
+
const MAX_RETRIES = 5;
|
|
79
159
|
```
|
|
80
160
|
|
|
81
|
-
|
|
161
|
+
✅ Good:
|
|
162
|
+
```javascript
|
|
163
|
+
const API_URL = process.env.API_URL;
|
|
164
|
+
const MAX_RETRIES = parseInt(process.env.MAX_RETRIES || '3');
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### **Step 4: Add Tests**
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
// test/rules/c042.test.js
|
|
171
|
+
const { testRule } = require('../test-utils');
|
|
172
|
+
|
|
173
|
+
describe('Rule C042: No Hardcoded Configuration Values', () => {
|
|
174
|
+
testRule('C042', {
|
|
175
|
+
valid: [
|
|
176
|
+
'const apiUrl = process.env.API_URL;',
|
|
177
|
+
'const config = loadConfig();'
|
|
178
|
+
],
|
|
179
|
+
invalid: [
|
|
180
|
+
'const API_URL = "https://api.example.com";',
|
|
181
|
+
'const MAX_RETRIES = 5;'
|
|
182
|
+
]
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### **Step 5: Test Your Rule**
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Test with specific engine
|
|
191
|
+
node cli.js --rule=C042 --engine=eslint --input=test/fixtures
|
|
192
|
+
node cli.js --rule=C042 --engine=heuristic --input=test/fixtures
|
|
193
|
+
|
|
194
|
+
# Test rule behavior
|
|
195
|
+
node cli.js --rule=C042 --input=test/fixtures --verbose
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### **Engine-Specific Development**
|
|
199
|
+
|
|
200
|
+
#### **Heuristic Engine Rules**
|
|
201
|
+
|
|
202
|
+
For custom pattern-based analysis:
|
|
203
|
+
|
|
204
|
+
1. **Create Rule Class**:
|
|
205
|
+
```javascript
|
|
206
|
+
// rules/custom/your-rule.js
|
|
207
|
+
const HeuristicRuleBase = require('../../core/heuristic-rule-base');
|
|
208
|
+
|
|
209
|
+
class YourCustomRule extends HeuristicRuleBase {
|
|
210
|
+
constructor() {
|
|
211
|
+
super('CXXX', 'Your Rule Name');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
analyze(node, context) {
|
|
215
|
+
// Your analysis logic
|
|
216
|
+
// Return violation or null
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
2. **Add to Registry**:
|
|
82
222
|
```json
|
|
83
|
-
// rules/quality/c042-new-rule/config.json
|
|
84
223
|
{
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
224
|
+
"CXXX": {
|
|
225
|
+
"engineMappings": {
|
|
226
|
+
"heuristic": {
|
|
227
|
+
"implementation": "custom/your-rule",
|
|
228
|
+
"supportedLanguages": ["typescript", "javascript"]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
92
232
|
}
|
|
93
233
|
```
|
|
94
234
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
235
|
+
#### **ESLint Engine Rules**
|
|
236
|
+
|
|
237
|
+
For JavaScript/TypeScript linting:
|
|
238
|
+
|
|
239
|
+
1. **Use Existing ESLint Rules**:
|
|
240
|
+
```json
|
|
98
241
|
{
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
242
|
+
"CXXX": {
|
|
243
|
+
"engineMappings": {
|
|
244
|
+
"eslint": {
|
|
245
|
+
"rules": ["no-console", "prefer-const"],
|
|
246
|
+
"config": {
|
|
247
|
+
"no-console": ["error"],
|
|
248
|
+
"prefer-const": ["warn"]
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
106
252
|
}
|
|
107
253
|
}
|
|
108
254
|
```
|
|
109
255
|
|
|
110
|
-
|
|
256
|
+
2. **Create Custom ESLint Rule** (advanced):
|
|
111
257
|
```javascript
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
258
|
+
// eslint-custom-rules/your-rule.js
|
|
259
|
+
module.exports = {
|
|
260
|
+
meta: {
|
|
261
|
+
type: 'problem',
|
|
262
|
+
docs: { description: 'Your rule description' }
|
|
263
|
+
},
|
|
264
|
+
create(context) {
|
|
265
|
+
return {
|
|
266
|
+
FunctionDeclaration(node) {
|
|
267
|
+
// Your ESLint rule logic
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### **OpenAI Engine Rules**
|
|
275
|
+
|
|
276
|
+
For AI-powered analysis:
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"CXXX": {
|
|
281
|
+
"engineMappings": {
|
|
282
|
+
"openai": {
|
|
283
|
+
"prompt": "Analyze code for specific pattern or anti-pattern",
|
|
284
|
+
"examples": [
|
|
285
|
+
"// Bad example",
|
|
286
|
+
"// Good example"
|
|
287
|
+
],
|
|
288
|
+
"temperature": 0.1,
|
|
289
|
+
"maxTokens": 500
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
115
294
|
```
|
|
116
295
|
|
|
117
296
|
### **Adding a New Security Rule**
|
|
118
297
|
|
|
119
|
-
Same process
|
|
298
|
+
Same process as above, just use `"category": "security"` in the rule definition.
|
|
299
|
+
|
|
300
|
+
### **Testing Your New Rule**
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Test all engines with your new rule
|
|
304
|
+
node cli.js --rule=C042 --input=test/fixtures --format=json
|
|
305
|
+
|
|
306
|
+
# Test specific engine
|
|
307
|
+
node cli.js --rule=C042 --engine=heuristic --input=test/fixtures
|
|
308
|
+
node cli.js --rule=C042 --engine=eslint --input=test/fixtures
|
|
309
|
+
node cli.js --rule=C042 --engine=openai --input=test/fixtures
|
|
310
|
+
|
|
311
|
+
# Validate rule registry
|
|
312
|
+
node validate-system.js
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### **Rule Definition Schema**
|
|
316
|
+
|
|
317
|
+
Complete schema for rule definitions:
|
|
318
|
+
|
|
319
|
+
```json
|
|
320
|
+
{
|
|
321
|
+
"CXXX": {
|
|
322
|
+
"id": "CXXX", // Required: Rule ID
|
|
323
|
+
"title": "Rule Title", // Required: Human-readable title
|
|
324
|
+
"description": "Detailed description", // Required: Rule description
|
|
325
|
+
"severity": "error|warning|info", // Required: Severity level
|
|
326
|
+
"category": "quality|security|performance|maintainability", // Required
|
|
327
|
+
"tags": ["tag1", "tag2"], // Optional: Tags for filtering
|
|
328
|
+
"languages": ["typescript", "javascript"], // Optional: Supported languages
|
|
329
|
+
"engineMappings": { // Required: Engine configurations
|
|
330
|
+
"heuristic": {
|
|
331
|
+
"implementation": "custom/rule-name",
|
|
332
|
+
"supportedLanguages": ["typescript"],
|
|
333
|
+
"astTargets": ["FunctionDeclaration"]
|
|
334
|
+
},
|
|
335
|
+
"eslint": {
|
|
336
|
+
"rules": ["eslint-rule-name"],
|
|
337
|
+
"config": { "rule-option": true }
|
|
338
|
+
},
|
|
339
|
+
"openai": {
|
|
340
|
+
"prompt": "AI analysis prompt",
|
|
341
|
+
"examples": ["code example"],
|
|
342
|
+
"temperature": 0.1
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
"analysisStrategy": { // Optional: Analysis metadata
|
|
346
|
+
"type": "ast|regex|semantic",
|
|
347
|
+
"patterns": ["pattern1"],
|
|
348
|
+
"astTargets": ["NodeType"],
|
|
349
|
+
"heuristics": ["detection-method"]
|
|
350
|
+
},
|
|
351
|
+
"metadata": { // Optional: Additional metadata
|
|
352
|
+
"author": "Developer Name",
|
|
353
|
+
"created": "2025-08-07",
|
|
354
|
+
"updated": "2025-08-07",
|
|
355
|
+
"version": "1.0.0"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### **Architecture Deep Dive**
|
|
362
|
+
|
|
363
|
+
#### **Unified Rule Registry**
|
|
364
|
+
- **Location**: `rules/` (auto-generated from origin-rules)
|
|
365
|
+
- **Source**: `origin-rules/` (markdown files)
|
|
366
|
+
- **ESLint Mappings**: `config/eslint-rule-mapping.json`
|
|
367
|
+
- **Loader**: `core/unified-rule-registry.js`
|
|
368
|
+
|
|
369
|
+
#### **Engine Architecture**
|
|
370
|
+
```
|
|
371
|
+
┌─────────────────────────────────────────┐
|
|
372
|
+
│ SunLint CLI │
|
|
373
|
+
├─────────────────────────────────────────┤
|
|
374
|
+
│ Analysis Orchestrator │
|
|
375
|
+
│ (Strict Engine Mode Support) │
|
|
376
|
+
├─────────────────────────────────────────┤
|
|
377
|
+
│ ┌─────────────┬─────────────┬─────────┐ │
|
|
378
|
+
│ │ Heuristic │ ESLint │ OpenAI │ │
|
|
379
|
+
│ │ Engine │ Engine │ Engine │ │
|
|
380
|
+
│ │ (244 rules) │ (57 rules) │(256 all)│ │
|
|
381
|
+
│ └─────────────┴─────────────┴─────────┘ │
|
|
382
|
+
├─────────────────────────────────────────┤
|
|
383
|
+
│ Rule Configuration │
|
|
384
|
+
│ ┌─────────────┬─────────────────────────┐ │
|
|
385
|
+
│ │ ESLint │ Unified Registry │ │
|
|
386
|
+
│ │ Mappings │ (Generated Rules) │ │
|
|
387
|
+
│ │ (.json) │ (origin-rules) │ │
|
|
388
|
+
│ └─────────────┴─────────────────────────┘ │
|
|
389
|
+
└─────────────────────────────────────────┘
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### **How Engines Load Rules**
|
|
393
|
+
1. **Initialization**: Each engine calls `getInstance()` from unified registry
|
|
394
|
+
2. **Rule Loading**: Registry loads rules from auto-generated `rules/` directory
|
|
395
|
+
3. **ESLint Mapping**: ESLint engine loads rule mappings from `config/eslint-rule-mapping.json`
|
|
396
|
+
4. **Engine Filtering**: Each engine filters rules based on their capabilities
|
|
397
|
+
5. **Analysis**: Engines analyze code using their specific rule implementations
|
|
398
|
+
|
|
399
|
+
**Key Features:**
|
|
400
|
+
- ✅ **Strict Engine Mode**: `--engine=eslint` only runs ESLint, skips unsupported rules
|
|
401
|
+
- ✅ **Fallback Mode**: Auto-engine selection with fallback (ESLint → Heuristic → OpenAI)
|
|
402
|
+
- ✅ **Rule Skipping**: Graceful handling of unsupported rules by specific engines
|
|
120
403
|
|
|
121
404
|
## 🧪 **Testing**
|
|
122
405
|
|
|
@@ -125,25 +408,50 @@ Same process but in `rules/security/` directory with `security` category.
|
|
|
125
408
|
npm test
|
|
126
409
|
```
|
|
127
410
|
|
|
128
|
-
### **
|
|
411
|
+
### **Test Rule Registry System**
|
|
129
412
|
```bash
|
|
130
|
-
#
|
|
131
|
-
|
|
413
|
+
# Validate unified rule registry
|
|
414
|
+
node validate-system.js
|
|
132
415
|
|
|
133
|
-
#
|
|
134
|
-
npm run test:
|
|
416
|
+
# Check rule loading for each engine
|
|
417
|
+
npm run test:engines
|
|
418
|
+
```
|
|
135
419
|
|
|
136
|
-
|
|
137
|
-
|
|
420
|
+
### **Test Specific Rules**
|
|
421
|
+
```bash
|
|
422
|
+
# Test specific rule with all engines
|
|
423
|
+
node cli.js --rule=C042 --input=test/fixtures
|
|
138
424
|
|
|
139
|
-
# Test
|
|
140
|
-
|
|
425
|
+
# Test with specific engine
|
|
426
|
+
node cli.js --rule=C042 --engine=heuristic --input=test/fixtures
|
|
427
|
+
node cli.js --rule=C042 --engine=eslint --input=test/fixtures
|
|
428
|
+
node cli.js --rule=C042 --engine=openai --input=test/fixtures
|
|
429
|
+
|
|
430
|
+
# Test multiple rules
|
|
431
|
+
node cli.js --rule=C006,C019,C042 --input=test/fixtures
|
|
141
432
|
```
|
|
142
433
|
|
|
143
|
-
### **Test
|
|
434
|
+
### **Test Rule Development**
|
|
144
435
|
```bash
|
|
145
|
-
#
|
|
146
|
-
|
|
436
|
+
# Create test fixtures
|
|
437
|
+
mkdir -p test/fixtures/c042
|
|
438
|
+
echo 'const API_URL = "https://api.example.com";' > test/fixtures/c042/invalid.ts
|
|
439
|
+
echo 'const apiUrl = process.env.API_URL;' > test/fixtures/c042/valid.ts
|
|
440
|
+
|
|
441
|
+
# Test your rule
|
|
442
|
+
node cli.js --rule=C042 --input=test/fixtures/c042 --format=json
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### **Integration Testing**
|
|
446
|
+
```bash
|
|
447
|
+
# Test all engines work together
|
|
448
|
+
npm run test:integration
|
|
449
|
+
|
|
450
|
+
# Test rule registry loading
|
|
451
|
+
npm run test:registry
|
|
452
|
+
|
|
453
|
+
# Performance testing
|
|
454
|
+
npm run test:performance
|
|
147
455
|
```
|
|
148
456
|
|
|
149
457
|
## 📊 **Code Review Process**
|
|
@@ -158,13 +466,16 @@ node cli.js --rule=C042 --input=test/fixtures --format=eslint
|
|
|
158
466
|
|
|
159
467
|
2. **Submit Pull Request**
|
|
160
468
|
- Clear title and description
|
|
161
|
-
- Reference related issues
|
|
469
|
+
- Reference related issues
|
|
162
470
|
- Include test results
|
|
163
471
|
- Follow template
|
|
472
|
+
- **NEW**: Validate rule registry with `node validate-system.js`
|
|
164
473
|
|
|
165
474
|
3. **Review Criteria**
|
|
166
475
|
- Code quality (follows our own rules!)
|
|
167
|
-
-
|
|
476
|
+
- Rule properly defined in `enhanced-rules-registry.json`
|
|
477
|
+
- All engines can load the rule correctly
|
|
478
|
+
- Test coverage for all supported engines
|
|
168
479
|
- Documentation completeness
|
|
169
480
|
- Performance impact
|
|
170
481
|
- Backward compatibility
|
|
@@ -174,32 +485,88 @@ node cli.js --rule=C042 --input=test/fixtures --format=eslint
|
|
|
174
485
|
### **Update Documentation**
|
|
175
486
|
When adding features:
|
|
176
487
|
- Update `README.md`
|
|
177
|
-
- Add rule documentation
|
|
488
|
+
- Add rule to `enhanced-rules-registry.json` (this is your main documentation!)
|
|
178
489
|
- Update configuration examples
|
|
179
490
|
- Add usage examples
|
|
491
|
+
- Update `RULE_MIGRATION_SUMMARY.md` if changing rule system
|
|
180
492
|
|
|
181
493
|
### **Rule Documentation Template**
|
|
182
|
-
```markdown
|
|
183
|
-
## Rule C042: New Rule Name
|
|
184
494
|
|
|
185
|
-
|
|
186
|
-
**Severity**: Error
|
|
187
|
-
**Languages**: TypeScript, Dart, Kotlin
|
|
495
|
+
All rule documentation is now centralized in `enhanced-rules-registry.json`:
|
|
188
496
|
|
|
189
|
-
|
|
190
|
-
|
|
497
|
+
```json
|
|
498
|
+
{
|
|
499
|
+
"C042": {
|
|
500
|
+
"title": "Clear, descriptive rule title",
|
|
501
|
+
"description": "Detailed explanation of what the rule checks, why it matters, and how to fix violations. Follow Rule C015 (domain language) - use clear business terms.",
|
|
502
|
+
"examples": {
|
|
503
|
+
"invalid": [
|
|
504
|
+
"// Bad example that violates the rule",
|
|
505
|
+
"const API_URL = 'https://hardcoded-url.com';"
|
|
506
|
+
],
|
|
507
|
+
"valid": [
|
|
508
|
+
"// Good example that follows the rule",
|
|
509
|
+
"const apiUrl = process.env.API_URL;"
|
|
510
|
+
]
|
|
511
|
+
},
|
|
512
|
+
"fixSuggestions": [
|
|
513
|
+
"Move configuration to environment variables",
|
|
514
|
+
"Use a configuration management system",
|
|
515
|
+
"Extract constants to a separate config file"
|
|
516
|
+
],
|
|
517
|
+
"relatedRules": ["C031", "C034"]
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
```
|
|
191
521
|
|
|
192
|
-
###
|
|
522
|
+
### **Engine-Specific Documentation**
|
|
193
523
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
524
|
+
#### **Heuristic Engine Rules**
|
|
525
|
+
Document custom analysis patterns:
|
|
526
|
+
```json
|
|
527
|
+
{
|
|
528
|
+
"analysisStrategy": {
|
|
529
|
+
"type": "ast",
|
|
530
|
+
"description": "Analyzes AST nodes for hardcoded configuration patterns",
|
|
531
|
+
"astTargets": ["VariableDeclaration", "PropertyAssignment"],
|
|
532
|
+
"patterns": ["literal-values-in-config-context"],
|
|
533
|
+
"complexity": "O(n) where n is number of variable declarations"
|
|
534
|
+
}
|
|
535
|
+
}
|
|
197
536
|
```
|
|
198
537
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
538
|
+
#### **ESLint Engine Rules**
|
|
539
|
+
Document ESLint rule mappings:
|
|
540
|
+
```json
|
|
541
|
+
{
|
|
542
|
+
"engineMappings": {
|
|
543
|
+
"eslint": {
|
|
544
|
+
"rules": ["no-magic-numbers"],
|
|
545
|
+
"rationale": "ESLint's no-magic-numbers rule catches hardcoded values",
|
|
546
|
+
"limitations": "May have false positives for legitimate constants",
|
|
547
|
+
"customConfig": {
|
|
548
|
+
"no-magic-numbers": ["error", { "ignore": [0, 1, -1] }]
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
202
553
|
```
|
|
554
|
+
|
|
555
|
+
#### **OpenAI Engine Rules**
|
|
556
|
+
Document AI prompts and examples:
|
|
557
|
+
```json
|
|
558
|
+
{
|
|
559
|
+
"engineMappings": {
|
|
560
|
+
"openai": {
|
|
561
|
+
"prompt": "Identify hardcoded configuration values that should be externalized to environment variables or config files",
|
|
562
|
+
"context": "Look for URLs, timeouts, limits, and other configuration that might change between environments",
|
|
563
|
+
"examples": [
|
|
564
|
+
"❌ const API_URL = 'https://api.example.com';",
|
|
565
|
+
"✅ const API_URL = process.env.API_URL || 'https://default-api.com';"
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
203
570
|
```
|
|
204
571
|
|
|
205
572
|
## 🐛 **Bug Reports**
|
|
@@ -210,6 +577,49 @@ When reporting bugs:
|
|
|
210
577
|
3. Provide sample code
|
|
211
578
|
4. Include environment details
|
|
212
579
|
5. Include sunlint output
|
|
580
|
+
6. **NEW**: Run `node validate-system.js` and include output
|
|
581
|
+
|
|
582
|
+
## 🔧 **Troubleshooting**
|
|
583
|
+
|
|
584
|
+
### **Common Issues**
|
|
585
|
+
|
|
586
|
+
#### **Rule Not Loading**
|
|
587
|
+
```bash
|
|
588
|
+
# Check if rule exists in registry
|
|
589
|
+
node -e "const registry = require('./core/unified-rule-registry'); registry.getInstance().initialize().then(() => console.log('Rule C042:', registry.getInstance().rules.has('C042')))"
|
|
590
|
+
|
|
591
|
+
# Validate registry syntax
|
|
592
|
+
node validate-system.js
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
#### **Engine Not Finding Rule**
|
|
596
|
+
```bash
|
|
597
|
+
# Check engine-specific mapping
|
|
598
|
+
node -e "const registry = require('./core/unified-rule-registry'); registry.getInstance().initialize().then(r => { const rule = r.rules.get('C042'); console.log('ESLint mapping:', rule?.engineMappings?.eslint); })"
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
#### **Rule Registry Errors**
|
|
602
|
+
```bash
|
|
603
|
+
# Common issues:
|
|
604
|
+
# 1. JSON syntax errors in enhanced-rules-registry.json
|
|
605
|
+
# 2. Missing required fields (id, title, description, severity, category)
|
|
606
|
+
# 3. Invalid engine mapping structure
|
|
607
|
+
|
|
608
|
+
# Validate JSON syntax
|
|
609
|
+
node -c config/enhanced-rules-registry.json
|
|
610
|
+
|
|
611
|
+
# Check required fields
|
|
612
|
+
node validate-system.js
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### **Performance Issues**
|
|
616
|
+
```bash
|
|
617
|
+
# Profile rule loading
|
|
618
|
+
node --prof cli.js --rule=C042 --input=large-project/
|
|
619
|
+
|
|
620
|
+
# Check memory usage
|
|
621
|
+
node --inspect cli.js --rule=C042 --input=test/fixtures/
|
|
622
|
+
```
|
|
213
623
|
|
|
214
624
|
## 💡 **Feature Requests**
|
|
215
625
|
|
|
@@ -220,6 +630,59 @@ For new features:
|
|
|
220
630
|
4. Consider implementation complexity
|
|
221
631
|
5. Think about backward compatibility
|
|
222
632
|
|
|
633
|
+
## 📋 **Quick Reference**
|
|
634
|
+
|
|
635
|
+
### **Essential Commands**
|
|
636
|
+
```bash
|
|
637
|
+
# Add ESLint engine rule mapping
|
|
638
|
+
vim config/eslint-rule-mapping.json
|
|
639
|
+
|
|
640
|
+
# Create custom heuristic rule
|
|
641
|
+
vim custom-rules/c042-rule-name.js
|
|
642
|
+
|
|
643
|
+
# Add rule documentation
|
|
644
|
+
vim origin-rules/common-en.md
|
|
645
|
+
|
|
646
|
+
# Test new rule with specific engine
|
|
647
|
+
node cli.js --rule=CXXX --engine=eslint --input=test/fixtures
|
|
648
|
+
node cli.js --rule=CXXX --engine=heuristic --input=test/fixtures
|
|
649
|
+
|
|
650
|
+
# Test strict engine mode (no fallback)
|
|
651
|
+
node cli.js --rule=CXXX --engine=eslint --input=test/fixtures
|
|
652
|
+
|
|
653
|
+
# Test fallback mode (auto engine selection)
|
|
654
|
+
node cli.js --rule=CXXX --input=test/fixtures
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### **Key Files**
|
|
658
|
+
- `config/eslint-rule-mapping.json` - **ESLint engine rule mappings**
|
|
659
|
+
- `origin-rules/` - **Original rule definitions** (markdown format)
|
|
660
|
+
- `rules/` - **Generated rule registry** (auto-generated)
|
|
661
|
+
- `core/unified-rule-registry.js` - Rule registry loader
|
|
662
|
+
- `engines/heuristic-engine.js` - Custom pattern analysis
|
|
663
|
+
- `engines/eslint-engine.js` - JavaScript/TypeScript linting
|
|
664
|
+
- `engines/openai-engine.js` - AI-powered analysis
|
|
665
|
+
- `integrations/eslint/plugin/` - Custom ESLint rules
|
|
666
|
+
- `custom-rules/` - Heuristic engine custom rules
|
|
667
|
+
|
|
668
|
+
### **Rule Development Checklist**
|
|
669
|
+
- [ ] Choose appropriate engine (ESLint for JS/TS, Heuristic for universal)
|
|
670
|
+
- [ ] Add ESLint mapping to `config/eslint-rule-mapping.json` (if using ESLint engine)
|
|
671
|
+
- [ ] Create custom rule implementation (if needed)
|
|
672
|
+
- [ ] Add rule definition to `origin-rules/` (markdown format)
|
|
673
|
+
- [ ] Add test cases and examples
|
|
674
|
+
- [ ] Test with `node cli.js --rule=CXXX --input=test/fixtures`
|
|
675
|
+
- [ ] Test engine-specific behavior (`--engine=eslint`, `--engine=heuristic`)
|
|
676
|
+
- [ ] Update documentation if needed
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
**🚀 Ready to contribute? Start by choosing your engine and editing the appropriate mapping file!**
|
|
681
|
+
|
|
682
|
+
**For ESLint rules**: Edit `config/eslint-rule-mapping.json`
|
|
683
|
+
**For Heuristic rules**: Create files in `custom-rules/`
|
|
684
|
+
**For documentation**: Add to `origin-rules/` markdown files
|
|
685
|
+
|
|
223
686
|
## 🤝 **Community**
|
|
224
687
|
|
|
225
688
|
- **Discord**: [Sun Engineering Discord](https://discord.gg/sun-engineering)
|