@sun-asterisk/sunlint 1.2.2 → 1.3.1

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 (124) hide show
  1. package/CHANGELOG.md +107 -1
  2. package/CONTRIBUTING.md +1654 -66
  3. package/README.md +19 -6
  4. package/config/ci-cd.json +54 -0
  5. package/config/development.json +56 -0
  6. package/config/engines/engines-enhanced.json +86 -0
  7. package/config/engines/semantic-config.json +114 -0
  8. package/config/eslint-rule-mapping.json +50 -38
  9. package/config/large-project.json +143 -0
  10. package/config/presets/all.json +0 -1
  11. package/config/release.json +70 -0
  12. package/config/rule-analysis-strategies.js +23 -4
  13. package/config/rules/S027-categories.json +122 -0
  14. package/config/rules/enhanced-rules-registry.json +2564 -0
  15. package/config/rules/rules-registry-generated.json +785 -837
  16. package/config/rules/rules-registry.json +13 -1
  17. package/core/adapters/sunlint-rule-adapter.js +25 -30
  18. package/core/analysis-orchestrator.js +42 -2
  19. package/core/categories.js +52 -0
  20. package/core/category-constants.js +39 -0
  21. package/core/cli-action-handler.js +53 -32
  22. package/core/cli-program.js +11 -3
  23. package/core/config-manager.js +111 -0
  24. package/core/config-merger.js +88 -0
  25. package/core/constants/categories.js +168 -0
  26. package/core/constants/defaults.js +165 -0
  27. package/core/constants/engines.js +185 -0
  28. package/core/constants/index.js +30 -0
  29. package/core/constants/rules.js +215 -0
  30. package/core/enhanced-rules-registry.js +3 -3
  31. package/core/file-targeting-service.js +128 -7
  32. package/core/interfaces/rule-plugin.interface.js +207 -0
  33. package/core/plugin-manager.js +448 -0
  34. package/core/rule-selection-service.js +42 -15
  35. package/core/semantic-engine.js +658 -0
  36. package/core/semantic-rule-base.js +433 -0
  37. package/core/unified-rule-registry.js +484 -0
  38. package/docs/COMMAND-EXAMPLES.md +134 -0
  39. package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
  40. package/docs/LARGE-PROJECT-GUIDE.md +324 -0
  41. package/engines/core/base-engine.js +249 -0
  42. package/engines/engine-factory.js +275 -0
  43. package/engines/eslint-engine.js +171 -19
  44. package/engines/heuristic-engine.js +569 -78
  45. package/integrations/eslint/plugin/index.js +26 -28
  46. package/origin-rules/common-en.md +8 -8
  47. package/package.json +10 -6
  48. package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
  49. package/rules/common/C017_constructor_logic/analyzer.js +254 -17
  50. package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
  51. package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
  52. package/rules/common/C033_separate_service_repository/README.md +78 -0
  53. package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
  54. package/rules/common/C033_separate_service_repository/config.json +50 -0
  55. package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
  56. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
  57. package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
  58. package/rules/common/C035_error_logging_context/analyzer.js +230 -0
  59. package/rules/common/C035_error_logging_context/config.json +54 -0
  60. package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
  61. package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
  62. package/rules/common/C040_centralized_validation/analyzer.js +165 -0
  63. package/rules/common/C040_centralized_validation/config.json +46 -0
  64. package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
  65. package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
  66. package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
  67. package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
  68. package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
  69. package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
  70. package/rules/common/C076_explicit_function_types/README.md +30 -0
  71. package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
  72. package/rules/common/C076_explicit_function_types/config.json +15 -0
  73. package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
  74. package/rules/index.js +8 -0
  75. package/rules/parser/rule-parser.js +13 -2
  76. package/rules/security/S005_no_origin_auth/README.md +226 -0
  77. package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
  78. package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
  79. package/rules/security/S005_no_origin_auth/config.json +85 -0
  80. package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
  81. package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
  82. package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
  83. package/rules/security/S007_no_plaintext_otp/README.md +198 -0
  84. package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
  85. package/rules/security/S007_no_plaintext_otp/config.json +79 -0
  86. package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
  87. package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
  88. package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
  89. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
  90. package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
  91. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
  92. package/scripts/category-manager.js +150 -0
  93. package/scripts/generate-rules-registry.js +88 -0
  94. package/scripts/migrate-rule-registry.js +157 -0
  95. package/scripts/prepare-release.sh +1 -1
  96. package/scripts/validate-system.js +48 -0
  97. package/.sunlint.json +0 -35
  98. package/config/README.md +0 -88
  99. package/config/engines/eslint-rule-mapping.json +0 -74
  100. package/config/schemas/sunlint-schema.json +0 -0
  101. package/config/testing/test-s005-working.ts +0 -22
  102. package/core/multi-rule-runner.js +0 -0
  103. package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
  104. package/docs/FUTURE_PACKAGES.md +0 -83
  105. package/docs/HEURISTIC_VS_AI.md +0 -113
  106. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
  107. package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
  108. package/docs/RELEASE_GUIDE.md +0 -230
  109. package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
  110. package/engines/tree-sitter-parser.js +0 -0
  111. package/engines/universal-ast-engine.js +0 -0
  112. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
  113. package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
  114. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
  115. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
  116. package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
  117. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
  118. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
  119. package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
  120. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
  121. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
  122. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
  123. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
  124. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
@@ -1,130 +0,0 @@
1
- /**
2
- * C029 Analyzer - Smart Pipeline Integration
3
- *
4
- * This analyzer forwards to the Smart Pipeline for superior accuracy and performance
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- class C029Analyzer {
11
- constructor() {
12
- this.ruleId = 'C029';
13
- this.ruleName = 'Enhanced Catch Block Error Logging';
14
- this.description = 'Mọi catch block phải log nguyên nhân lỗi đầy đủ và bảo toàn context (Smart Pipeline 3-stage analysis)';
15
-
16
- // Load Smart Pipeline as primary analyzer
17
- this.smartPipeline = null;
18
-
19
- try {
20
- const SmartPipelineClass = require('./analyzer-smart-pipeline.js');
21
- this.smartPipeline = new SmartPipelineClass();
22
- console.log('🎯 C029: Smart Pipeline loaded (3-stage: Regex → AST → Data Flow)');
23
- } catch (error) {
24
- console.warn('⚠️ C029: Smart Pipeline failed, using fallback:', error.message);
25
- this.smartPipeline = null;
26
- }
27
- }
28
-
29
- async analyze(files, language, options = {}) {
30
- // Use Smart Pipeline as primary choice
31
- if (this.smartPipeline) {
32
- console.log('🎯 C029: Using Smart Pipeline (3-stage analysis)...');
33
- return await this.smartPipeline.analyze(files, language, options);
34
- } else {
35
- console.log('🔍 C029: Using fallback regex analysis...');
36
- return await this.analyzeWithRegex(files, language, options);
37
- }
38
- }
39
-
40
- async analyzeWithRegex(files, language, options = {}) {
41
- const violations = [];
42
-
43
- for (const filePath of files) {
44
- if (options.verbose) {
45
- console.log(`🔍 C029 Regex: Processing ${path.basename(filePath)}...`);
46
- }
47
-
48
- try {
49
- const content = fs.readFileSync(filePath, 'utf8');
50
- const fileViolations = await this.analyzeFile(filePath, content, language);
51
- violations.push(...fileViolations);
52
- } catch (error) {
53
- console.warn(`⚠️ C029: Error processing ${filePath}:`, error.message);
54
- }
55
- }
56
-
57
- return violations;
58
- }
59
-
60
- async analyzeFile(filePath, content, language) {
61
- const violations = [];
62
- const lines = content.split('\n');
63
-
64
- for (let i = 0; i < lines.length; i++) {
65
- const line = lines[i];
66
-
67
- // Simple catch block detection
68
- if (line.includes('catch') && line.includes('(')) {
69
- const catchBlock = this.extractCatchBlock(lines, i);
70
-
71
- if (this.isCatchBlockEmpty(catchBlock.content)) {
72
- violations.push({
73
- file: filePath,
74
- line: i + 1,
75
- column: line.indexOf('catch') + 1,
76
- message: 'Empty catch block detected',
77
- severity: 'error',
78
- ruleId: this.ruleId,
79
- type: 'empty_catch'
80
- });
81
- }
82
- }
83
- }
84
-
85
- return violations;
86
- }
87
-
88
- extractCatchBlock(lines, startIndex) {
89
- const content = [];
90
- let braceCount = 0;
91
- let inBlock = false;
92
-
93
- for (let i = startIndex; i < lines.length; i++) {
94
- const line = lines[i];
95
- content.push(line);
96
-
97
- for (const char of line) {
98
- if (char === '{') {
99
- braceCount++;
100
- inBlock = true;
101
- } else if (char === '}') {
102
- braceCount--;
103
- if (braceCount === 0 && inBlock) {
104
- return { content, endIndex: i };
105
- }
106
- }
107
- }
108
- }
109
-
110
- return { content, endIndex: startIndex };
111
- }
112
-
113
- isCatchBlockEmpty(content) {
114
- const blockContent = content.join('\n');
115
-
116
- // Remove comments and whitespace
117
- const cleanContent = blockContent
118
- .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
119
- .replace(/\/\/.*$/gm, '') // Remove single-line comments
120
- .replace(/\s+/g, ' ') // Normalize whitespace
121
- .trim();
122
-
123
- // Check if only contains catch declaration and braces
124
- const hasOnlyStructure = /^catch\s*\([^)]*\)\s*\{\s*\}$/.test(cleanContent);
125
-
126
- return hasOnlyStructure;
127
- }
128
- }
129
-
130
- module.exports = C029Analyzer;
@@ -1,487 +0,0 @@
1
- /**
2
- * C029 Catch Block Logging Analyzer
3
- *
4
- * Enhanced multi-technology analyzer combining:
5
- * - Regex pattern matching (basic detection)
6
- * - AST-based analysis (structural understanding)
7
- * - Data flow analysis (variable tracking)
8
- * - Control flow analysis (execution path understanding)
9
- * - Semantic analysis (intent understanding)
10
- * - Pattern learning (adaptive rules)
11
- * - Multi-language support (cross-language compatibility)
12
- *
13
- * Technology Showcase: Demonstrates SunLint's advanced analysis capabilities
14
- */
15
-
16
- const fs = require('fs');
17
- const path = require('path');
18
-
19
- class C029CatchBlockAnalyzer {
20
- constructor() {
21
- this.ruleId = 'C029';
22
- this.ruleName = 'Advanced Catch Block Logging';
23
- this.description = 'Multi-technology analysis for catch block error handling';
24
-
25
- // Load analyzers with graceful fallback
26
- this.analyzers = this.loadAnalyzers();
27
-
28
- // Technology orchestration configuration
29
- this.analysisConfig = {
30
- enableRegex: true,
31
- enableAST: true,
32
- enableDataflow: true,
33
- enableControlflow: true,
34
- enableSemantic: true,
35
- enablePatternLearning: true,
36
- enableMultiLanguage: true,
37
- confidenceThreshold: 0.5,
38
- combinationStrategy: 'weighted_voting' // Options: 'union', 'intersection', 'weighted_voting'
39
- };
40
-
41
- // Technology weights for voting
42
- this.technologyWeights = {
43
- regex: 0.15,
44
- ast: 0.25,
45
- dataflow: 0.20,
46
- controlflow: 0.15,
47
- semantic: 0.15,
48
- patternLearning: 0.10
49
- };
50
-
51
- // Performance tracking
52
- this.performanceMetrics = {
53
- technologyExecutionTimes: new Map(),
54
- accuracyComparisons: new Map(),
55
- combinationEffectiveness: new Map()
56
- };
57
- }
58
-
59
- /**
60
- * Load all available analyzers with graceful fallback
61
- */
62
- loadAnalyzers() {
63
- const analyzers = {};
64
-
65
- const analyzerConfigs = [
66
- { name: 'ast', path: './ast-analyzer.js', description: 'AST-based analysis' },
67
- { name: 'dataflow', path: './dataflow-analyzer.js', description: 'Data flow analysis' },
68
- { name: 'cfg', path: './cfg-analyzer.js', description: 'Control flow analysis' },
69
- { name: 'semantic', path: './semantic-analyzer.js', description: 'Semantic analysis' },
70
- { name: 'patternLearning', path: './pattern-learning-analyzer.js', description: 'Pattern learning' },
71
- { name: 'multiLanguage', path: './multi-language-ast-engine.js', description: 'Multi-language support' }
72
- ];
73
-
74
- for (const config of analyzerConfigs) {
75
- try {
76
- analyzers[config.name] = require(config.path);
77
- console.log(`✅ C029: ${config.description} loaded`);
78
- } catch (error) {
79
- console.warn(`⚠️ C029: ${config.description} not available:`, error.message);
80
- analyzers[config.name] = null;
81
- }
82
- }
83
-
84
- return analyzers;
85
- }
86
-
87
- async analyze(files, language, options = {}) {
88
- console.log(`🔬 C029 Multi-Technology Analysis: Processing ${files.length} files with advanced techniques...`);
89
-
90
- const startTime = Date.now();
91
- const allResults = new Map(); // technology -> violations
92
- const executionTimes = new Map();
93
-
94
- // Run all available technologies in parallel
95
- const analysisPromises = [];
96
-
97
- // 1. Regex Analysis (always available)
98
- if (this.analysisConfig.enableRegex) {
99
- analysisPromises.push(
100
- this.runTechnologyAnalysis('regex', () => this.analyzeWithRegex(files, language, options))
101
- );
102
- }
103
-
104
- // 2. AST Analysis
105
- if (this.analysisConfig.enableAST && this.analyzers.ast) {
106
- analysisPromises.push(
107
- this.runTechnologyAnalysis('ast', () => this.analyzers.ast.analyze(files, language, options))
108
- );
109
- }
110
-
111
- // 3. Data Flow Analysis
112
- if (this.analysisConfig.enableDataflow && this.analyzers.dataflow) {
113
- analysisPromises.push(
114
- this.runTechnologyAnalysis('dataflow', () => this.analyzers.dataflow.analyze(files, language, options))
115
- );
116
- }
117
-
118
- // 4. Control Flow Analysis
119
- if (this.analysisConfig.enableControlflow && this.analyzers.cfg) {
120
- analysisPromises.push(
121
- this.runTechnologyAnalysis('controlflow', () => this.analyzers.cfg.analyze(files, language, options))
122
- );
123
- }
124
-
125
- // 5. Semantic Analysis
126
- if (this.analysisConfig.enableSemantic && this.analyzers.semantic) {
127
- analysisPromises.push(
128
- this.runTechnologyAnalysis('semantic', () => this.analyzers.semantic.analyze(files, language, options))
129
- );
130
- }
131
-
132
- // 6. Pattern Learning Analysis
133
- if (this.analysisConfig.enablePatternLearning && this.analyzers.patternLearning) {
134
- analysisPromises.push(
135
- this.runTechnologyAnalysis('patternLearning', () => this.analyzers.patternLearning.analyze(files, language, options))
136
- );
137
- }
138
-
139
- // 7. Multi-Language Analysis
140
- if (this.analysisConfig.enableMultiLanguage && this.analyzers.multiLanguage) {
141
- analysisPromises.push(
142
- this.runTechnologyAnalysis('multiLanguage', () => this.analyzers.multiLanguage.analyze(files, language, options))
143
- );
144
- }
145
-
146
- // Wait for all analyses to complete
147
- const results = await Promise.allSettled(analysisPromises);
148
-
149
- // Process results
150
- for (const result of results) {
151
- if (result.status === 'fulfilled') {
152
- const { technology, violations, executionTime } = result.value;
153
- allResults.set(technology, violations);
154
- executionTimes.set(technology, executionTime);
155
- console.log(`✅ ${technology}: ${violations.length} issues found (${executionTime}ms)`);
156
- } else {
157
- console.error(`❌ Analysis failed:`, result.reason);
158
- }
159
- }
160
-
161
- // Combine results using configured strategy
162
- const finalViolations = this.combineResults(allResults, executionTimes);
163
-
164
- const totalTime = Date.now() - startTime;
165
- console.log(`🎯 C029 Final Results: ${finalViolations.length} issues identified (${totalTime}ms total)`);
166
-
167
- // Update performance metrics
168
- this.updatePerformanceMetrics(allResults, executionTimes, totalTime);
169
-
170
- return finalViolations;
171
- }
172
-
173
- /**
174
- * Run a technology analysis with timing and error handling
175
- */
176
- async runTechnologyAnalysis(technology, analysisFunction) {
177
- const startTime = Date.now();
178
-
179
- try {
180
- const violations = await analysisFunction();
181
- const executionTime = Date.now() - startTime;
182
-
183
- return {
184
- technology,
185
- violations: violations || [],
186
- executionTime,
187
- success: true
188
- };
189
- } catch (error) {
190
- const executionTime = Date.now() - startTime;
191
- console.error(`❌ ${technology} analysis failed:`, error.message);
192
-
193
- return {
194
- technology,
195
- violations: [],
196
- executionTime,
197
- success: false,
198
- error: error.message
199
- };
200
- }
201
- }
202
-
203
- /**
204
- * Combine results from multiple technologies
205
- */
206
- combineResults(allResults, executionTimes) {
207
- switch (this.analysisConfig.combinationStrategy) {
208
- case 'union':
209
- return this.combineUnion(allResults);
210
-
211
- case 'intersection':
212
- return this.combineIntersection(allResults);
213
-
214
- case 'weighted_voting':
215
- default:
216
- return this.combineWeightedVoting(allResults);
217
- }
218
- }
219
-
220
- /**
221
- * Union strategy: Include all violations from all technologies
222
- */
223
- combineUnion(allResults) {
224
- const allViolations = [];
225
- const seenViolations = new Set();
226
-
227
- for (const [technology, violations] of allResults) {
228
- for (const violation of violations) {
229
- const key = `${violation.file}:${violation.line}:${violation.type}`;
230
-
231
- if (!seenViolations.has(key)) {
232
- seenViolations.add(key);
233
- allViolations.push({
234
- ...violation,
235
- detectedBy: [technology],
236
- combinationStrategy: 'union'
237
- });
238
- } else {
239
- // Find existing violation and add technology
240
- const existing = allViolations.find(v =>
241
- v.file === violation.file &&
242
- v.line === violation.line &&
243
- v.type === violation.type
244
- );
245
- if (existing) {
246
- existing.detectedBy.push(technology);
247
- }
248
- }
249
- }
250
- }
251
-
252
- return allViolations;
253
- }
254
-
255
- /**
256
- * Intersection strategy: Only include violations found by multiple technologies
257
- */
258
- combineIntersection(allResults) {
259
- const violationCounts = new Map();
260
- const violationData = new Map();
261
-
262
- // Count how many technologies detected each violation
263
- for (const [technology, violations] of allResults) {
264
- for (const violation of violations) {
265
- const key = `${violation.file}:${violation.line}:${violation.type}`;
266
-
267
- violationCounts.set(key, (violationCounts.get(key) || 0) + 1);
268
-
269
- if (!violationData.has(key)) {
270
- violationData.set(key, {
271
- ...violation,
272
- detectedBy: [technology],
273
- combinationStrategy: 'intersection'
274
- });
275
- } else {
276
- violationData.get(key).detectedBy.push(technology);
277
- }
278
- }
279
- }
280
-
281
- // Only return violations detected by at least 2 technologies
282
- const minDetections = Math.max(2, Math.floor(allResults.size / 2));
283
- return Array.from(violationData.values())
284
- .filter(violation => violationCounts.get(`${violation.file}:${violation.line}:${violation.type}`) >= minDetections);
285
- }
286
-
287
- /**
288
- * Weighted voting strategy: Use confidence scores and technology weights
289
- */
290
- combineWeightedVoting(allResults) {
291
- const violationScores = new Map();
292
- const violationData = new Map();
293
-
294
- // Calculate weighted scores for each violation
295
- for (const [technology, violations] of allResults) {
296
- const weight = this.technologyWeights[technology] || 0.1;
297
-
298
- for (const violation of violations) {
299
- const key = `${violation.file}:${violation.line}:${violation.type}`;
300
- const score = (violation.confidence || 0.7) * weight;
301
-
302
- violationScores.set(key, (violationScores.get(key) || 0) + score);
303
-
304
- if (!violationData.has(key)) {
305
- violationData.set(key, {
306
- ...violation,
307
- detectedBy: [technology],
308
- weightedScore: score,
309
- combinationStrategy: 'weighted_voting'
310
- });
311
- } else {
312
- const existing = violationData.get(key);
313
- existing.detectedBy.push(technology);
314
- existing.weightedScore = violationScores.get(key);
315
-
316
- // Use highest confidence message
317
- if ((violation.confidence || 0.7) > (existing.confidence || 0.7)) {
318
- existing.message = violation.message;
319
- existing.suggestion = violation.suggestion;
320
- }
321
- }
322
- }
323
- }
324
-
325
- // Return violations above confidence threshold
326
- return Array.from(violationData.values())
327
- .filter(violation => violation.weightedScore >= this.analysisConfig.confidenceThreshold)
328
- .sort((a, b) => b.weightedScore - a.weightedScore);
329
- }
330
-
331
- /**
332
- * Regex-based analysis (fallback)
333
- */
334
- async analyzeWithRegex(files, language, options = {}) {
335
- const violations = [];
336
- console.log(`📄 C029 Regex: Analyzing ${files.length} files with pattern matching...`);
337
-
338
- for (const filePath of files) {
339
- try {
340
- const content = fs.readFileSync(filePath, 'utf8');
341
- const regexViolations = this.findCatchBlocksRegex(content, filePath);
342
- violations.push(...regexViolations);
343
- } catch (error) {
344
- console.warn(`C029 Regex skipping ${filePath}: ${error.message}`);
345
- }
346
- }
347
-
348
- return violations;
349
- }
350
-
351
- /**
352
- * Find catch blocks using regex patterns
353
- */
354
- findCatchBlocksRegex(content, filePath) {
355
- const violations = [];
356
- const lines = content.split('\n');
357
-
358
- for (let i = 0; i < lines.length; i++) {
359
- const line = lines[i];
360
-
361
- // Basic catch block detection
362
- if (/catch\s*\([^)]*\)\s*\{/.test(line)) {
363
- const catchBlock = this.extractCatchBlock(lines, i);
364
-
365
- if (this.isCatchBlockViolation(catchBlock, filePath)) {
366
- violations.push({
367
- ruleId: this.ruleId,
368
- file: filePath,
369
- line: i + 1,
370
- column: 1,
371
- message: 'Empty or inadequate error handling in catch block',
372
- severity: 'error',
373
- code: catchBlock.code,
374
- type: 'regex_catch_violation',
375
- confidence: 0.6,
376
- suggestion: 'Add error logging or appropriate error handling',
377
- detectedBy: ['regex']
378
- });
379
- }
380
- }
381
- }
382
-
383
- return violations;
384
- }
385
-
386
- /**
387
- * Extract catch block content
388
- */
389
- extractCatchBlock(lines, startIndex) {
390
- let braceCount = 0;
391
- let content = '';
392
- let endIndex = startIndex;
393
-
394
- for (let i = startIndex; i < lines.length; i++) {
395
- const line = lines[i];
396
- content += line + '\n';
397
-
398
- braceCount += (line.match(/\{/g) || []).length;
399
- braceCount -= (line.match(/\}/g) || []).length;
400
-
401
- if (braceCount === 0 && i > startIndex) {
402
- endIndex = i;
403
- break;
404
- }
405
- }
406
-
407
- return {
408
- code: content.trim(),
409
- startLine: startIndex + 1,
410
- endLine: endIndex + 1,
411
- content: content.trim()
412
- };
413
- }
414
-
415
- /**
416
- * Check if catch block is a violation
417
- */
418
- isCatchBlockViolation(catchBlock, filePath) {
419
- const content = catchBlock.content;
420
-
421
- // Empty catch block
422
- if (!content || content.replace(/[{}\s]/g, '').length === 0) {
423
- return true;
424
- }
425
-
426
- // Check for logging patterns
427
- const hasLogging = /console\.(log|error|warn|debug)|logger?\.(error|warn|info|debug)|print/.test(content);
428
-
429
- // Skip test files (less strict)
430
- const isTestFile = /(__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/.test(filePath);
431
-
432
- return !hasLogging && !isTestFile;
433
- }
434
-
435
- /**
436
- * Update performance metrics for analysis
437
- */
438
- updatePerformanceMetrics(allResults, executionTimes, totalTime) {
439
- // Track execution times
440
- for (const [technology, time] of executionTimes) {
441
- if (!this.performanceMetrics.technologyExecutionTimes.has(technology)) {
442
- this.performanceMetrics.technologyExecutionTimes.set(technology, []);
443
- }
444
- this.performanceMetrics.technologyExecutionTimes.get(technology).push(time);
445
- }
446
-
447
- // Track accuracy comparisons (simplified)
448
- const technologiesUsed = Array.from(allResults.keys());
449
- for (let i = 0; i < technologiesUsed.length; i++) {
450
- for (let j = i + 1; j < technologiesUsed.length; j++) {
451
- const tech1 = technologiesUsed[i];
452
- const tech2 = technologiesUsed[j];
453
- const pair = `${tech1}-${tech2}`;
454
-
455
- const violations1 = allResults.get(tech1).length;
456
- const violations2 = allResults.get(tech2).length;
457
- const agreement = Math.abs(violations1 - violations2) / Math.max(violations1, violations2, 1);
458
-
459
- if (!this.performanceMetrics.accuracyComparisons.has(pair)) {
460
- this.performanceMetrics.accuracyComparisons.set(pair, []);
461
- }
462
- this.performanceMetrics.accuracyComparisons.get(pair).push(agreement);
463
- }
464
- }
465
- }
466
-
467
- /**
468
- * Get performance insights
469
- */
470
- getPerformanceInsights() {
471
- const insights = {
472
- averageExecutionTimes: new Map(),
473
- technologiesUsed: Array.from(this.performanceMetrics.technologyExecutionTimes.keys()),
474
- totalAnalysesRun: 0
475
- };
476
-
477
- for (const [technology, times] of this.performanceMetrics.technologyExecutionTimes) {
478
- const avg = times.reduce((sum, time) => sum + time, 0) / times.length;
479
- insights.averageExecutionTimes.set(technology, avg);
480
- insights.totalAnalysesRun += times.length;
481
- }
482
-
483
- return insights;
484
- }
485
- }
486
-
487
- module.exports = new C029CatchBlockAnalyzer();