@sun-asterisk/sunlint 1.2.2 ā 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/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 +171 -19
- package/engines/heuristic-engine.js +511 -78
- package/integrations/eslint/plugin/index.js +27 -27
- package/package.json +10 -6
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
- package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
- 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/index.js +7 -0
- package/scripts/category-manager.js +150 -0
- package/scripts/generate-rules-registry.js +88 -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/schemas/sunlint-schema.json +0 -0
- package/config/testing/test-s005-working.ts +0 -22
- package/core/multi-rule-runner.js +0 -0
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -0
- package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
- package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
- package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
- package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
- package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
- package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
- package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
- package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
- package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
- package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
- package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
- package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"knownRetryFunctions": [
|
|
3
|
+
"axios.get",
|
|
4
|
+
"axios.post",
|
|
5
|
+
"axios.put",
|
|
6
|
+
"axios.delete",
|
|
7
|
+
"axios.patch",
|
|
8
|
+
"axios.request",
|
|
9
|
+
"axios.head",
|
|
10
|
+
"axios.options",
|
|
11
|
+
|
|
12
|
+
"useQuery",
|
|
13
|
+
"useMutation",
|
|
14
|
+
"useInfiniteQuery",
|
|
15
|
+
"queryClient.fetchQuery",
|
|
16
|
+
"queryClient.prefetchQuery",
|
|
17
|
+
|
|
18
|
+
"apolloClient.query",
|
|
19
|
+
"apolloClient.mutate",
|
|
20
|
+
"apolloClient.watchQuery",
|
|
21
|
+
"useLazyQuery",
|
|
22
|
+
|
|
23
|
+
"apiService.get",
|
|
24
|
+
"apiService.post",
|
|
25
|
+
"apiService.put",
|
|
26
|
+
"apiService.delete",
|
|
27
|
+
"apiService.patch",
|
|
28
|
+
"httpClient.get",
|
|
29
|
+
"httpClient.post",
|
|
30
|
+
"httpClient.request",
|
|
31
|
+
|
|
32
|
+
"retryAsync",
|
|
33
|
+
"withRetry",
|
|
34
|
+
"retry",
|
|
35
|
+
"p-retry",
|
|
36
|
+
"exponentialBackoff",
|
|
37
|
+
"retryPromise",
|
|
38
|
+
|
|
39
|
+
"fetch",
|
|
40
|
+
"fetch-retry",
|
|
41
|
+
"node-fetch",
|
|
42
|
+
"got",
|
|
43
|
+
"superagent",
|
|
44
|
+
"request-promise"
|
|
45
|
+
],
|
|
46
|
+
|
|
47
|
+
"layerPatterns": {
|
|
48
|
+
"ui": ["component", "view", "page", "modal", "form", "screen", "widget", "/ui/", "/components/"],
|
|
49
|
+
"usecase": ["usecase", "use-case", "usecases", "service", "business", "/usecases/", "/services/"],
|
|
50
|
+
"repository": ["repository", "repo", "dao", "store", "persistence", "/repositories/", "/data/"],
|
|
51
|
+
"api": ["api", "client", "adapter", "gateway", "connector", "/api/", "/clients/", "/gateways/"]
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
"retryDetectionPatterns": {
|
|
55
|
+
"exceptionRetry": {
|
|
56
|
+
"description": "Detect retry logic in try-catch blocks",
|
|
57
|
+
"enabled": true
|
|
58
|
+
},
|
|
59
|
+
"emptyDataRetry": {
|
|
60
|
+
"description": "Detect retry logic when data is empty/null",
|
|
61
|
+
"enabled": true
|
|
62
|
+
},
|
|
63
|
+
"knownRetryConflict": {
|
|
64
|
+
"description": "Detect manual retry conflicting with built-in retry",
|
|
65
|
+
"enabled": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
"_description": "Configuration for Symbol-Based Analysis of retry functions using ts-morph",
|
|
70
|
+
"_usage": "Add functions that have built-in retry mechanisms to avoid false positives"
|
|
71
|
+
}
|
package/rules/index.js
CHANGED
|
@@ -15,6 +15,13 @@ const path = require('path');
|
|
|
15
15
|
*/
|
|
16
16
|
function loadRule(category, ruleId) {
|
|
17
17
|
try {
|
|
18
|
+
// Special case for C047: Use semantic analyzer by default
|
|
19
|
+
if (ruleId === 'C047_no_duplicate_retry_logic') {
|
|
20
|
+
const semanticPath = path.join(__dirname, category, ruleId, 'c047-semantic-rule.js');
|
|
21
|
+
console.log(`š¬ Loading C047 semantic analyzer: ${semanticPath}`);
|
|
22
|
+
return require(semanticPath);
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
const rulePath = path.join(__dirname, category, ruleId, 'analyzer.js');
|
|
19
26
|
return require(rulePath);
|
|
20
27
|
} catch (error) {
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SunLint Category Management CLI
|
|
5
|
+
* Utility for managing categories and principles
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node scripts/category-manager.js list
|
|
9
|
+
* node scripts/category-manager.js add <category> <principle> <description>
|
|
10
|
+
* node scripts/category-manager.js validate
|
|
11
|
+
* node scripts/category-manager.js stats
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const {
|
|
16
|
+
getValidCategories,
|
|
17
|
+
getCategoryPrinciples,
|
|
18
|
+
getCategoryDescription,
|
|
19
|
+
getCategoryStats,
|
|
20
|
+
isValidCategory,
|
|
21
|
+
addCategoryMapping
|
|
22
|
+
} = require('../core/constants/categories');
|
|
23
|
+
|
|
24
|
+
const command = process.argv[2];
|
|
25
|
+
|
|
26
|
+
switch (command) {
|
|
27
|
+
case 'list':
|
|
28
|
+
listCategories();
|
|
29
|
+
break;
|
|
30
|
+
|
|
31
|
+
case 'validate':
|
|
32
|
+
validateCategories();
|
|
33
|
+
break;
|
|
34
|
+
|
|
35
|
+
case 'stats':
|
|
36
|
+
showStats();
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case 'add':
|
|
40
|
+
addCategory(process.argv[3], process.argv[4], process.argv[5]);
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
case 'check':
|
|
44
|
+
checkCategory(process.argv[3]);
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
showHelp();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function listCategories() {
|
|
52
|
+
console.log('š SunLint Categories & Principles\n');
|
|
53
|
+
|
|
54
|
+
const categories = getValidCategories();
|
|
55
|
+
categories.forEach(category => {
|
|
56
|
+
const principles = getCategoryPrinciples(category);
|
|
57
|
+
const description = getCategoryDescription(category);
|
|
58
|
+
|
|
59
|
+
console.log(`š·ļø ${category.toUpperCase()}`);
|
|
60
|
+
console.log(` Principles: ${principles.join(', ')}`);
|
|
61
|
+
console.log(` Description: ${description}`);
|
|
62
|
+
console.log('');
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function validateCategories() {
|
|
67
|
+
console.log('š Validating Category System\n');
|
|
68
|
+
|
|
69
|
+
const stats = getCategoryStats();
|
|
70
|
+
console.log(`ā
Total Categories: ${stats.totalCategories}`);
|
|
71
|
+
console.log(`ā
Total Principles: ${stats.totalPrinciples}`);
|
|
72
|
+
|
|
73
|
+
// Check for missing principles
|
|
74
|
+
const allPrinciples = Object.values(SUNLINT_PRINCIPLES);
|
|
75
|
+
const mappedPrinciples = Object.values(CATEGORY_PRINCIPLE_MAP).flat();
|
|
76
|
+
|
|
77
|
+
const missingPrinciples = allPrinciples.filter(p => !mappedPrinciples.includes(p));
|
|
78
|
+
|
|
79
|
+
if (missingPrinciples.length > 0) {
|
|
80
|
+
console.log(`ā ļø Unmapped Principles: ${missingPrinciples.join(', ')}`);
|
|
81
|
+
} else {
|
|
82
|
+
console.log('ā
All principles mapped to categories');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('\nš Category Mapping:');
|
|
86
|
+
Object.entries(CATEGORY_PRINCIPLE_MAP).forEach(([category, principles]) => {
|
|
87
|
+
console.log(` ${category} -> ${principles.join(', ')}`);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function showStats() {
|
|
92
|
+
const stats = getCategoryStats();
|
|
93
|
+
console.log('š Category Statistics\n');
|
|
94
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function addCategory(category, principle, description) {
|
|
98
|
+
if (!category || !principle || !description) {
|
|
99
|
+
console.error('ā Usage: add <category> <principle> <description>');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(`š Adding category: ${category}`);
|
|
104
|
+
console.log(` Principle: ${principle}`);
|
|
105
|
+
console.log(` Description: ${description}`);
|
|
106
|
+
console.log('\nā ļø This would require updating category-constants.js manually');
|
|
107
|
+
console.log(' Add the following to CATEGORY_PRINCIPLE_MAP:');
|
|
108
|
+
console.log(` '${category.toLowerCase()}': ['${principle.toUpperCase()}'],`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function checkCategory(category) {
|
|
112
|
+
if (!category) {
|
|
113
|
+
console.error('ā Usage: check <category>');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log(`š Checking category: ${category}\n`);
|
|
118
|
+
|
|
119
|
+
const isValid = isValidCategory(category);
|
|
120
|
+
console.log(`Valid: ${isValid ? 'ā
' : 'ā'}`);
|
|
121
|
+
|
|
122
|
+
if (isValid) {
|
|
123
|
+
const principles = getCategoryPrinciples(category);
|
|
124
|
+
const description = getCategoryDescription(category);
|
|
125
|
+
|
|
126
|
+
console.log(`Principles: ${principles.join(', ')}`);
|
|
127
|
+
console.log(`Description: ${description}`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`Valid categories: ${getValidCategories().join(', ')}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function showHelp() {
|
|
134
|
+
console.log(`
|
|
135
|
+
š ļø SunLint Category Manager
|
|
136
|
+
|
|
137
|
+
Commands:
|
|
138
|
+
list Show all categories and their principles
|
|
139
|
+
validate Validate the category system consistency
|
|
140
|
+
stats Show category statistics
|
|
141
|
+
check Check if a specific category is valid
|
|
142
|
+
add Add a new category (manual step required)
|
|
143
|
+
|
|
144
|
+
Examples:
|
|
145
|
+
node scripts/category-manager.js list
|
|
146
|
+
node scripts/category-manager.js check security
|
|
147
|
+
node scripts/category-manager.js validate
|
|
148
|
+
node scripts/category-manager.js add accessibility ACCESSIBILITY "Accessibility guidelines"
|
|
149
|
+
`);
|
|
150
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { SimpleRuleParser } = require('../rules/parser/rule-parser-simple');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generate rules registry from origin-rules
|
|
9
|
+
* This script creates config/rules/rules-registry-generated.json
|
|
10
|
+
* from all *-en.md files in origin-rules/ directory
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
console.log('š Generating rules registry from origin-rules...');
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const parser = new SimpleRuleParser();
|
|
17
|
+
const originRulesDir = path.join(__dirname, '..', 'origin-rules');
|
|
18
|
+
const targetPath = path.join(__dirname, '..', 'config', 'rules', 'rules-registry-generated.json');
|
|
19
|
+
|
|
20
|
+
console.log(`Source: ${originRulesDir}`);
|
|
21
|
+
console.log(`Target: ${targetPath}`);
|
|
22
|
+
|
|
23
|
+
// Parse all rules from origin-rules
|
|
24
|
+
const allRules = parser.parseAllRules(originRulesDir);
|
|
25
|
+
|
|
26
|
+
if (allRules.length === 0) {
|
|
27
|
+
console.error('ā No rules found in origin-rules directory');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Convert to registry format
|
|
32
|
+
const registry = {
|
|
33
|
+
rules: {}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
allRules.forEach(rule => {
|
|
37
|
+
if (rule.id) {
|
|
38
|
+
registry.rules[rule.id] = {
|
|
39
|
+
name: rule.title || `${rule.id} Rule`,
|
|
40
|
+
description: rule.description || 'No description available',
|
|
41
|
+
category: rule.category || 'quality',
|
|
42
|
+
severity: rule.severity || 'major',
|
|
43
|
+
languages: rule.language ? [rule.language] : ['All languages'],
|
|
44
|
+
version: rule.version || '1.0.0',
|
|
45
|
+
status: rule.status || 'draft',
|
|
46
|
+
tags: [rule.category || 'quality', 'readability', 'code-quality'],
|
|
47
|
+
tools: rule.tools || [],
|
|
48
|
+
framework: rule.framework || 'All',
|
|
49
|
+
principles: rule.principles || []
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Ensure target directory exists
|
|
55
|
+
const targetDir = path.dirname(targetPath);
|
|
56
|
+
if (!fs.existsSync(targetDir)) {
|
|
57
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Write registry file
|
|
61
|
+
fs.writeFileSync(targetPath, JSON.stringify(registry, null, 2), 'utf8');
|
|
62
|
+
|
|
63
|
+
const rulesCount = Object.keys(registry.rules).length;
|
|
64
|
+
const fileSize = (fs.statSync(targetPath).size / 1024).toFixed(1);
|
|
65
|
+
|
|
66
|
+
console.log(`ā
Generated registry with ${rulesCount} rules`);
|
|
67
|
+
console.log(`š File: ${targetPath} (${fileSize} KB)`);
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('š Rules by category:');
|
|
70
|
+
|
|
71
|
+
// Stats by category
|
|
72
|
+
const categories = {};
|
|
73
|
+
Object.values(registry.rules).forEach(rule => {
|
|
74
|
+
const cat = rule.category || 'unknown';
|
|
75
|
+
categories[cat] = (categories[cat] || 0) + 1;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
Object.entries(categories)
|
|
79
|
+
.sort(([,a], [,b]) => b - a)
|
|
80
|
+
.forEach(([category, count]) => {
|
|
81
|
+
console.log(` ${category}: ${count} rules`);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('ā Error generating registry:', error.message);
|
|
86
|
+
console.error(error.stack);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Rule Registry Migration Script
|
|
5
|
+
* Merges all rule mappings into Unified Rule Registry
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
console.log('š RULE REGISTRY MIGRATION');
|
|
12
|
+
console.log('='.repeat(50));
|
|
13
|
+
|
|
14
|
+
// Load existing data
|
|
15
|
+
const rulesRegistry = JSON.parse(fs.readFileSync('./config/rules/rules-registry.json', 'utf8'));
|
|
16
|
+
const eslintMapping = JSON.parse(fs.readFileSync('./config/eslint-rule-mapping.json', 'utf8'));
|
|
17
|
+
const engineMapping = JSON.parse(fs.readFileSync('./config/engines/eslint-rule-mapping.json', 'utf8'));
|
|
18
|
+
const strategies = require('./config/rule-analysis-strategies.js');
|
|
19
|
+
|
|
20
|
+
// Current unified registry
|
|
21
|
+
const { UnifiedRuleRegistry } = require('./core/unified-rule-registry.js');
|
|
22
|
+
const registry = new UnifiedRuleRegistry();
|
|
23
|
+
|
|
24
|
+
async function migrateRuleData() {
|
|
25
|
+
console.log('š„ Loading current unified registry...');
|
|
26
|
+
await registry.initialize({ verbose: true });
|
|
27
|
+
|
|
28
|
+
console.log('š Analyzing missing rules...');
|
|
29
|
+
|
|
30
|
+
// Get all rule IDs from different sources
|
|
31
|
+
const registryRules = Object.keys(rulesRegistry.rules || {});
|
|
32
|
+
const eslintRules = Object.keys(eslintMapping.mappings || {});
|
|
33
|
+
const engineRules = Object.keys(engineMapping || {});
|
|
34
|
+
|
|
35
|
+
// Find missing rules in unified registry
|
|
36
|
+
const missingFromEslint = eslintRules.filter(ruleId =>
|
|
37
|
+
!registryRules.includes(ruleId)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
console.log(`š Found ${missingFromEslint.length} rules missing from registry:`,
|
|
41
|
+
missingFromEslint.slice(0, 10).join(', '));
|
|
42
|
+
|
|
43
|
+
// Extend unified registry with missing rules
|
|
44
|
+
const enhancedRegistry = { ...rulesRegistry };
|
|
45
|
+
|
|
46
|
+
missingFromEslint.forEach(ruleId => {
|
|
47
|
+
console.log(`ā Adding missing rule: ${ruleId}`);
|
|
48
|
+
|
|
49
|
+
enhancedRegistry.rules[ruleId] = {
|
|
50
|
+
id: ruleId,
|
|
51
|
+
name: `Rule ${ruleId}`, // Will be improved
|
|
52
|
+
description: `Auto-migrated rule ${ruleId} from ESLint mapping`,
|
|
53
|
+
category: inferCategory(ruleId),
|
|
54
|
+
severity: 'warning',
|
|
55
|
+
languages: ['typescript', 'javascript'],
|
|
56
|
+
version: '1.0.0',
|
|
57
|
+
status: 'migrated',
|
|
58
|
+
tags: ['migrated'],
|
|
59
|
+
|
|
60
|
+
// ESLint engine mapping
|
|
61
|
+
engineMappings: {
|
|
62
|
+
eslint: eslintMapping.mappings[ruleId] || []
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// Analysis strategy
|
|
66
|
+
strategy: {
|
|
67
|
+
preferred: inferStrategy(ruleId),
|
|
68
|
+
fallbacks: ['regex'],
|
|
69
|
+
accuracy: {}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Add missing engine mappings
|
|
75
|
+
console.log('š§ Adding engine mappings...');
|
|
76
|
+
Object.entries(engineMapping).forEach(([ruleId, eslintRules]) => {
|
|
77
|
+
if (enhancedRegistry.rules[ruleId]) {
|
|
78
|
+
enhancedRegistry.rules[ruleId].engineMappings = enhancedRegistry.rules[ruleId].engineMappings || {};
|
|
79
|
+
enhancedRegistry.rules[ruleId].engineMappings.eslint = eslintRules;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Add analysis strategies
|
|
84
|
+
console.log('š Adding analysis strategies...');
|
|
85
|
+
Object.entries(strategies.astPreferred || {}).forEach(([ruleId, config]) => {
|
|
86
|
+
if (enhancedRegistry.rules[ruleId]) {
|
|
87
|
+
enhancedRegistry.rules[ruleId].strategy = {
|
|
88
|
+
preferred: 'ast',
|
|
89
|
+
fallbacks: config.methods || ['regex'],
|
|
90
|
+
accuracy: config.accuracy || {}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
Object.entries(strategies.regexOptimal || {}).forEach(([ruleId, config]) => {
|
|
96
|
+
if (enhancedRegistry.rules[ruleId]) {
|
|
97
|
+
enhancedRegistry.rules[ruleId].strategy = {
|
|
98
|
+
preferred: 'regex',
|
|
99
|
+
fallbacks: config.methods || [],
|
|
100
|
+
accuracy: config.accuracy || {}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
console.log('š¾ Saving enhanced registry...');
|
|
106
|
+
|
|
107
|
+
// Save enhanced registry
|
|
108
|
+
fs.writeFileSync(
|
|
109
|
+
'./config/rules/enhanced-rules-registry.json',
|
|
110
|
+
JSON.stringify(enhancedRegistry, null, 2)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
console.log(`ā
Enhanced registry saved with ${Object.keys(enhancedRegistry.rules).length} rules`);
|
|
114
|
+
|
|
115
|
+
// Generate migration summary
|
|
116
|
+
const summary = {
|
|
117
|
+
originalRules: registryRules.length,
|
|
118
|
+
migratedRules: missingFromEslint.length,
|
|
119
|
+
totalRules: Object.keys(enhancedRegistry.rules).length,
|
|
120
|
+
eslintMappings: Object.keys(eslintMapping.mappings).length,
|
|
121
|
+
engineMappings: Object.keys(engineMapping).length
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
fs.writeFileSync(
|
|
125
|
+
'./migration-summary.json',
|
|
126
|
+
JSON.stringify(summary, null, 2)
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
console.log('š Migration summary:', summary);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Helper functions
|
|
133
|
+
function inferCategory(ruleId) {
|
|
134
|
+
if (ruleId.startsWith('S')) return 'security';
|
|
135
|
+
if (ruleId.startsWith('T')) return 'typescript';
|
|
136
|
+
if (ruleId.startsWith('R')) return 'react';
|
|
137
|
+
|
|
138
|
+
// Infer from common patterns
|
|
139
|
+
if (ruleId.includes('naming') || ruleId.includes('name')) return 'naming';
|
|
140
|
+
if (ruleId.includes('error') || ruleId.includes('exception')) return 'error-handling';
|
|
141
|
+
if (ruleId.includes('log')) return 'logging';
|
|
142
|
+
if (ruleId.includes('complexity')) return 'complexity';
|
|
143
|
+
|
|
144
|
+
return 'general';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function inferStrategy(ruleId) {
|
|
148
|
+
// Rules that typically need AST analysis
|
|
149
|
+
const astRules = ['C010', 'C012', 'C015', 'C017'];
|
|
150
|
+
if (astRules.includes(ruleId)) return 'ast';
|
|
151
|
+
|
|
152
|
+
// Most rules can start with regex
|
|
153
|
+
return 'regex';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Run migration
|
|
157
|
+
migrateRuleData().catch(console.error);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Quick validation that unified rule registry system is working
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { getInstance } = require('./core/unified-rule-registry');
|
|
8
|
+
|
|
9
|
+
async function validateUnifiedSystem() {
|
|
10
|
+
console.log('š Validating unified rule registry system...\n');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const registry = getInstance();
|
|
14
|
+
await registry.initialize();
|
|
15
|
+
|
|
16
|
+
console.log(`ā
Registry loaded: ${registry.rules.size} rules`);
|
|
17
|
+
|
|
18
|
+
// Test specific rules
|
|
19
|
+
const testRules = ['C006', 'C047', 'C002'];
|
|
20
|
+
console.log('\nš Testing specific rules:');
|
|
21
|
+
|
|
22
|
+
for (const ruleId of testRules) {
|
|
23
|
+
const rule = registry.rules.get(ruleId);
|
|
24
|
+
if (rule) {
|
|
25
|
+
console.log(` ā
${ruleId}: ${rule.title}`);
|
|
26
|
+
if (rule.engineMappings?.eslint) {
|
|
27
|
+
console.log(` ESLint: ${JSON.stringify(rule.engineMappings.eslint)}`);
|
|
28
|
+
}
|
|
29
|
+
if (rule.engineMappings?.heuristic) {
|
|
30
|
+
console.log(` Heuristic: ${rule.engineMappings.heuristic.implementation}`);
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
console.log(` ā ${ruleId}: NOT FOUND`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('\nš Unified rule registry system is working correctly!');
|
|
38
|
+
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('ā Validation failed:', error.message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (require.main === module) {
|
|
45
|
+
validateUnifiedSystem();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = { validateUnifiedSystem };
|
package/.sunlint.json
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@sun/sunlint/recommended",
|
|
3
|
-
"rules": {
|
|
4
|
-
"C019": "warn",
|
|
5
|
-
"C006": "warn",
|
|
6
|
-
"C029": "error",
|
|
7
|
-
"C031": "warn",
|
|
8
|
-
"S001": "warn",
|
|
9
|
-
"S002": "warn",
|
|
10
|
-
"S007": "warn",
|
|
11
|
-
"S013": "warn",
|
|
12
|
-
"T019": "error",
|
|
13
|
-
"T020": "warn",
|
|
14
|
-
"T021": "error"
|
|
15
|
-
},
|
|
16
|
-
"include": ["**/*.js", "**/*.ts", "**/*.jsx", "**/*.tsx"],
|
|
17
|
-
"exclude": [
|
|
18
|
-
"node_modules/**",
|
|
19
|
-
"coverage/**",
|
|
20
|
-
"**/*.min.*",
|
|
21
|
-
".git/**",
|
|
22
|
-
"dist/**",
|
|
23
|
-
"build/**"
|
|
24
|
-
],
|
|
25
|
-
"engine": "eslint",
|
|
26
|
-
"languages": ["typescript", "javascript"],
|
|
27
|
-
"output": {
|
|
28
|
-
"format": "summary",
|
|
29
|
-
"console": true
|
|
30
|
-
},
|
|
31
|
-
"fileTargeting": {
|
|
32
|
-
"followSymlinks": false,
|
|
33
|
-
"maxDepth": 10
|
|
34
|
-
}
|
|
35
|
-
}
|
package/config/README.md
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# SunLint Configuration Structure
|
|
2
|
-
|
|
3
|
-
This folder contains all configuration files for SunLint, organized for clarity and maintainability.
|
|
4
|
-
|
|
5
|
-
## š Structure Overview
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
config/
|
|
9
|
-
āāā schemas/ # JSON schemas for validation
|
|
10
|
-
ā āāā sunlint-schema.json # Main SunLint config schema
|
|
11
|
-
āāā engines/ # Analysis engine configurations
|
|
12
|
-
ā āāā engines.json # Available engines (ESLint, TypeScript, etc.)
|
|
13
|
-
ā āāā eslint-rule-mapping.json # ESLint rule mappings
|
|
14
|
-
āāā presets/ # Pre-defined rule configurations
|
|
15
|
-
ā āāā beginner.json # Beginner-friendly preset
|
|
16
|
-
ā āāā ci.json # CI/CD optimized preset
|
|
17
|
-
ā āāā recommended.json # Recommended preset
|
|
18
|
-
ā āāā strict.json # Strict coding standards
|
|
19
|
-
āāā integrations/ # Integration-specific configs
|
|
20
|
-
ā āāā eslint/
|
|
21
|
-
ā āāā base.config.js # Base ESLint configuration
|
|
22
|
-
ā āāā typescript.config.js # TypeScript ESLint config
|
|
23
|
-
ā āāā simple.config.js # Simplified ESLint config
|
|
24
|
-
āāā rules/ # Rule definitions and registry
|
|
25
|
-
ā āāā rules-registry.json # Master rule registry
|
|
26
|
-
āāā defaults/ # Default configurations
|
|
27
|
-
ā āāā default.json # Default SunLint settings
|
|
28
|
-
ā āāā ai-rules-context.json # AI analysis context
|
|
29
|
-
āāā testing/ # Test configurations and samples
|
|
30
|
-
āāā test-s005-working.ts # Test file for S005 rule
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## šÆ Key Improvements
|
|
34
|
-
|
|
35
|
-
### ā
Eliminated Duplicates
|
|
36
|
-
- **Before**: ESLint configs in both `config/typescript/` and `integrations/eslint/`
|
|
37
|
-
- **After**: All ESLint configs consolidated in `config/integrations/eslint/`
|
|
38
|
-
|
|
39
|
-
### ā
Logical Organization
|
|
40
|
-
- **Schemas**: All JSON schemas in one place
|
|
41
|
-
- **Engines**: Engine-specific configurations separated
|
|
42
|
-
- **Presets**: User-facing preset configurations grouped
|
|
43
|
-
- **Integrations**: Third-party integration configs organized by tool
|
|
44
|
-
|
|
45
|
-
### ā
Reduced Complexity
|
|
46
|
-
- **Before**: 10+ files scattered in root config/
|
|
47
|
-
- **After**: Organized into 6 logical categories
|
|
48
|
-
|
|
49
|
-
## š Usage
|
|
50
|
-
|
|
51
|
-
### For ESLint Integration
|
|
52
|
-
```bash
|
|
53
|
-
# Use the consolidated TypeScript ESLint config
|
|
54
|
-
npx eslint --config config/integrations/eslint/typescript.config.js src/
|
|
55
|
-
|
|
56
|
-
# Use the base ESLint config
|
|
57
|
-
npx eslint --config config/integrations/eslint/base.config.js src/
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### For Rule Presets
|
|
61
|
-
```json
|
|
62
|
-
{
|
|
63
|
-
"extends": "config/presets/recommended.json"
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### For Schema Validation
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"$schema": "config/schemas/sunlint-schema.json"
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## š§ Migration Notes
|
|
75
|
-
|
|
76
|
-
- **Old `config/typescript/`**: ā Removed (duplicated functionality)
|
|
77
|
-
- **ESLint configs**: ā
Moved to `config/integrations/eslint/`
|
|
78
|
-
- **Default configs**: ā
Moved to `config/defaults/`
|
|
79
|
-
- **Engine configs**: ā
Moved to `config/engines/`
|
|
80
|
-
|
|
81
|
-
## š Next Steps
|
|
82
|
-
|
|
83
|
-
1. Update documentation references to new paths
|
|
84
|
-
2. Update CI/CD scripts to use new config locations
|
|
85
|
-
3. Consider adding more integration-specific configs as needed
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
*Last updated: July 21, 2025 | SunLint Config Refactor*
|