@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.
Files changed (109) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/CONTRIBUTING.md +533 -70
  3. package/README.md +16 -2
  4. package/config/engines/engines-enhanced.json +86 -0
  5. package/config/engines/semantic-config.json +114 -0
  6. package/config/eslint-rule-mapping.json +50 -38
  7. package/config/rule-analysis-strategies.js +18 -2
  8. package/config/rules/enhanced-rules-registry.json +2503 -0
  9. package/config/rules/rules-registry-generated.json +785 -837
  10. package/core/adapters/sunlint-rule-adapter.js +25 -30
  11. package/core/analysis-orchestrator.js +42 -2
  12. package/core/categories.js +52 -0
  13. package/core/category-constants.js +39 -0
  14. package/core/cli-action-handler.js +32 -5
  15. package/core/config-manager.js +111 -0
  16. package/core/config-merger.js +61 -0
  17. package/core/constants/categories.js +168 -0
  18. package/core/constants/defaults.js +165 -0
  19. package/core/constants/engines.js +185 -0
  20. package/core/constants/index.js +30 -0
  21. package/core/constants/rules.js +215 -0
  22. package/core/file-targeting-service.js +128 -7
  23. package/core/interfaces/rule-plugin.interface.js +207 -0
  24. package/core/plugin-manager.js +448 -0
  25. package/core/rule-selection-service.js +42 -15
  26. package/core/semantic-engine.js +560 -0
  27. package/core/semantic-rule-base.js +433 -0
  28. package/core/unified-rule-registry.js +484 -0
  29. package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
  30. package/engines/core/base-engine.js +249 -0
  31. package/engines/engine-factory.js +275 -0
  32. package/engines/eslint-engine.js +180 -30
  33. package/engines/heuristic-engine.js +513 -56
  34. package/integrations/eslint/plugin/index.js +27 -27
  35. package/package.json +11 -6
  36. package/rules/README.md +252 -0
  37. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  38. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  39. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  40. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  41. package/rules/common/C006_function_naming/analyzer.js +504 -0
  42. package/rules/common/C006_function_naming/config.json +86 -0
  43. package/rules/common/C006_function_naming/smart-analyzer.js +503 -0
  44. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  45. package/rules/common/C012_command_query_separation/analyzer.js +481 -0
  46. package/rules/common/C012_command_query_separation/ast-analyzer.js +495 -0
  47. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  48. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  49. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  50. package/rules/common/C019_log_level_usage/analyzer.js +362 -0
  51. package/rules/common/C019_log_level_usage/config.json +121 -0
  52. package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +755 -0
  53. package/rules/common/C029_catch_block_logging/analyzer.js +141 -0
  54. package/rules/common/C029_catch_block_logging/config.json +59 -0
  55. package/rules/common/C031_validation_separation/analyzer.js +186 -0
  56. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  57. package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +296 -0
  58. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  59. package/rules/common/C043_no_console_or_print/analyzer.js +431 -0
  60. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +590 -0
  61. package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
  62. package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
  63. package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
  64. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  65. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  66. package/rules/docs/C002_no_duplicate_code.md +57 -0
  67. package/rules/docs/C031_validation_separation.md +72 -0
  68. package/rules/index.js +162 -0
  69. package/rules/migration/converter.js +385 -0
  70. package/rules/migration/mapping.json +164 -0
  71. package/rules/parser/constants.js +31 -0
  72. package/rules/parser/file-config.js +80 -0
  73. package/rules/parser/rule-parser-simple.js +305 -0
  74. package/rules/parser/rule-parser.js +527 -0
  75. package/rules/security/S015_insecure_tls_certificate/analyzer.js +150 -0
  76. package/rules/security/S015_insecure_tls_certificate/ast-analyzer.js +237 -0
  77. package/rules/security/S023_no_json_injection/analyzer.js +278 -0
  78. package/rules/security/S023_no_json_injection/ast-analyzer.js +359 -0
  79. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  80. package/rules/security/S026_json_schema_validation/config.json +27 -0
  81. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +436 -0
  82. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  83. package/rules/security/S029_csrf_protection/analyzer.js +330 -0
  84. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  85. package/rules/utils/ast-utils.js +191 -0
  86. package/rules/utils/base-analyzer.js +98 -0
  87. package/rules/utils/pattern-matchers.js +239 -0
  88. package/rules/utils/rule-helpers.js +264 -0
  89. package/rules/utils/severity-constants.js +93 -0
  90. package/scripts/category-manager.js +150 -0
  91. package/scripts/generate-rules-registry.js +88 -0
  92. package/scripts/generate_insights.js +188 -0
  93. package/scripts/migrate-rule-registry.js +157 -0
  94. package/scripts/validate-system.js +48 -0
  95. package/.sunlint.json +0 -35
  96. package/config/README.md +0 -88
  97. package/config/engines/eslint-rule-mapping.json +0 -74
  98. package/config/testing/test-s005-working.ts +0 -22
  99. package/engines/tree-sitter-parser.js +0 -0
  100. package/engines/universal-ast-engine.js +0 -0
  101. package/scripts/merge-reports.js +0 -424
  102. package/scripts/test-scripts/README.md +0 -22
  103. package/scripts/test-scripts/test-c041-comparison.js +0 -114
  104. package/scripts/test-scripts/test-c041-eslint.js +0 -67
  105. package/scripts/test-scripts/test-eslint-rules.js +0 -146
  106. package/scripts/test-scripts/test-real-world.js +0 -44
  107. package/scripts/test-scripts/test-rules-on-real-projects.js +0 -86
  108. /package/{config/schemas/sunlint-schema.json → rules/universal/C010/generic.js} +0 -0
  109. /package/{core/multi-rule-runner.js → rules/universal/C010/tree-sitter-analyzer.js} +0 -0
@@ -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,188 @@
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.js');
6
+
7
+ class SunLintInsightGenerator {
8
+ constructor() {
9
+ this.parser = new SimpleRuleParser();
10
+ this.heuristicRulesPath = path.join(__dirname, '../rules/common');
11
+ }
12
+
13
+ // Get implemented rules
14
+ getImplementedRules() {
15
+ const implemented = new Set();
16
+ if (fs.existsSync(this.heuristicRulesPath)) {
17
+ const dirs = fs.readdirSync(this.heuristicRulesPath);
18
+ dirs.forEach(dir => {
19
+ const match = dir.match(/^([A-Z]\d+)_/);
20
+ if (match) {
21
+ implemented.add(match[1]);
22
+ }
23
+ });
24
+ }
25
+ return implemented;
26
+ }
27
+
28
+ // Assess priority based on rule content
29
+ assessPriority(rule) {
30
+ const text = `${rule.title} ${rule.description} ${rule.detail || ''}`.toLowerCase();
31
+ const principles = rule.principles || [];
32
+
33
+ if (principles.includes('SECURITY')) return 'High';
34
+ if (principles.includes('PERFORMANCE')) return 'High';
35
+ if (principles.includes('RELIABILITY')) return 'Medium-High';
36
+
37
+ const impactKeywords = {
38
+ high: ['security', 'memory', 'performance', 'crash', 'null pointer', 'xss', 'injection', 'vulnerability', 'race condition'],
39
+ medium: ['testability', 'maintainability', 'readability', 'coupling', 'cohesion', 'dependency'],
40
+ low: ['naming', 'style', 'convention', 'formatting', 'comment']
41
+ };
42
+
43
+ for (const keyword of impactKeywords.high) {
44
+ if (text.includes(keyword)) return 'High';
45
+ }
46
+ for (const keyword of impactKeywords.medium) {
47
+ if (text.includes(keyword)) return 'Medium';
48
+ }
49
+ for (const keyword of impactKeywords.low) {
50
+ if (text.includes(keyword)) return 'Low';
51
+ }
52
+
53
+ return 'Medium';
54
+ }
55
+
56
+ // Generate actionable insights
57
+ generateInsights() {
58
+ console.log('šŸ” Analyzing SunLint rules...');
59
+ const allRules = this.parser.parseAllRules();
60
+ const activatedRules = this.parser.filterRules(allRules, { status: 'activated' });
61
+ const implementedRules = this.getImplementedRules();
62
+
63
+ console.log('\nšŸ“Š === SUNLINT HEURISTIC ENGINE ANALYSIS ===\n');
64
+
65
+ // Overall statistics
66
+ const totalImplemented = activatedRules.filter(rule => implementedRules.has(rule.id)).length;
67
+ const implementationRate = ((totalImplemented / activatedRules.length) * 100).toFixed(1);
68
+
69
+ console.log(`šŸŽÆ **Current Implementation Status:**`);
70
+ console.log(` • Total Activated Rules: ${activatedRules.length}`);
71
+ console.log(` • Implemented in Heuristic: ${totalImplemented} (${implementationRate}%)`);
72
+ console.log(` • Remaining to Implement: ${activatedRules.length - totalImplemented}\n`);
73
+
74
+ // Priority analysis
75
+ const priorities = { 'High': 0, 'Medium-High': 0, 'Medium': 0, 'Low': 0 };
76
+ const notImplementedByPriority = { 'High': [], 'Medium-High': [], 'Medium': [], 'Low': [] };
77
+
78
+ activatedRules.forEach(rule => {
79
+ const priority = this.assessPriority(rule);
80
+ priorities[priority]++;
81
+
82
+ if (!implementedRules.has(rule.id)) {
83
+ notImplementedByPriority[priority].push(rule);
84
+ }
85
+ });
86
+
87
+ console.log(`šŸ”„ **Priority Breakdown:**`);
88
+ Object.entries(priorities).forEach(([priority, count]) => {
89
+ const missing = notImplementedByPriority[priority].length;
90
+ const implemented = count - missing;
91
+ const rate = count > 0 ? ((implemented / count) * 100).toFixed(1) : '0.0';
92
+ console.log(` • ${priority}: ${implemented}/${count} implemented (${rate}%) - ${missing} missing`);
93
+ });
94
+
95
+ // Category analysis
96
+ console.log(`\nšŸ“‚ **Implementation by Category:**`);
97
+ const categories = {
98
+ 'C': 'Common Code Quality',
99
+ 'T': 'TypeScript',
100
+ 'R': 'ReactJS',
101
+ 'S': 'Security',
102
+ 'J': 'Java',
103
+ 'K': 'Kotlin Mobile',
104
+ 'D': 'Dart/Flutter',
105
+ 'SW': 'Swift'
106
+ };
107
+
108
+ Object.entries(categories).forEach(([prefix, name]) => {
109
+ const categoryRules = activatedRules.filter(rule => rule.id.startsWith(prefix));
110
+ const categoryImplemented = categoryRules.filter(rule => implementedRules.has(rule.id)).length;
111
+ const rate = categoryRules.length > 0 ? ((categoryImplemented / categoryRules.length) * 100).toFixed(1) : '0.0';
112
+ console.log(` • ${name}: ${categoryImplemented}/${categoryRules.length} (${rate}%)`);
113
+ });
114
+
115
+ // Top missing high-priority rules
116
+ console.log(`\n🚨 **Top 10 Missing High-Priority Rules:**`);
117
+ notImplementedByPriority['High'].slice(0, 10).forEach((rule, i) => {
118
+ console.log(` ${i+1}. ${rule.id}: ${rule.title}`);
119
+ console.log(` → ${rule.description?.substring(0, 80)}...`);
120
+ });
121
+
122
+ // Quick wins (easy to implement)
123
+ console.log(`\n⚔ **Quick Wins (Low Complexity, High Impact):**`);
124
+ const quickWins = notImplementedByPriority['High'].filter(rule => {
125
+ const text = rule.title.toLowerCase();
126
+ return text.includes('console.log') || text.includes('print') ||
127
+ text.includes('hardcode') || text.includes('sensitive');
128
+ });
129
+
130
+ quickWins.slice(0, 5).forEach((rule, i) => {
131
+ console.log(` ${i+1}. ${rule.id}: ${rule.title} - Text/Regex patterns`);
132
+ });
133
+
134
+ // Performance impact rules
135
+ console.log(`\n⚔ **Performance-Critical Missing Rules:**`);
136
+ const perfRules = notImplementedByPriority['High'].filter(rule =>
137
+ rule.principles?.includes('PERFORMANCE') ||
138
+ rule.description?.toLowerCase().includes('performance')
139
+ );
140
+
141
+ perfRules.slice(0, 5).forEach((rule, i) => {
142
+ console.log(` ${i+1}. ${rule.id}: ${rule.title}`);
143
+ });
144
+
145
+ // Security rules
146
+ console.log(`\nšŸ”’ **Security-Critical Missing Rules:**`);
147
+ const securityRules = notImplementedByPriority['High'].filter(rule =>
148
+ rule.principles?.includes('SECURITY') ||
149
+ rule.description?.toLowerCase().includes('security')
150
+ );
151
+
152
+ securityRules.slice(0, 5).forEach((rule, i) => {
153
+ console.log(` ${i+1}. ${rule.id}: ${rule.title}`);
154
+ });
155
+
156
+ // Recommendations
157
+ console.log(`\nšŸ’” **Actionable Recommendations:**`);
158
+ console.log(` 1. Focus on High Priority rules first: ${notImplementedByPriority['High'].length} rules remaining`);
159
+ console.log(` 2. Implement Common (C) rules first - highest coverage impact`);
160
+ console.log(` 3. Start with Low complexity rules using text/regex patterns`);
161
+ console.log(` 4. Performance rules should be prioritized for production impact`);
162
+ console.log(` 5. Security rules are critical for safe code practices`);
163
+ console.log(` 6. Consider AST analysis for complex rules (Medium-High complexity)`);
164
+
165
+ console.log(`\nšŸ“ˆ **ROI Analysis:**`);
166
+ const commonMissing = notImplementedByPriority['High'].filter(rule => rule.id.startsWith('C')).length;
167
+ console.log(` • Common rules impact: All languages (${commonMissing} High-priority missing)`);
168
+ console.log(` • Language-specific rules: Limited scope but deep impact`);
169
+ console.log(` • Implementation effort: Low complexity rules = 1-2 days, High = 1-2 weeks`);
170
+
171
+ return {
172
+ total: activatedRules.length,
173
+ implemented: totalImplemented,
174
+ missing: activatedRules.length - totalImplemented,
175
+ highPriorityMissing: notImplementedByPriority['High'].length,
176
+ quickWins: quickWins.length,
177
+ recommendations: notImplementedByPriority
178
+ };
179
+ }
180
+ }
181
+
182
+ // Run analysis
183
+ if (require.main === module) {
184
+ const analyzer = new SunLintInsightGenerator();
185
+ analyzer.generateInsights();
186
+ }
187
+
188
+ module.exports = SunLintInsightGenerator;
@@ -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
- }