@sun-asterisk/sunlint 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/config/rule-analysis-strategies.js +18 -2
  2. package/engines/eslint-engine.js +9 -11
  3. package/engines/heuristic-engine.js +55 -31
  4. package/package.json +2 -1
  5. package/rules/README.md +252 -0
  6. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  7. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  8. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  9. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  10. package/rules/common/C006_function_naming/analyzer.js +504 -0
  11. package/rules/common/C006_function_naming/config.json +86 -0
  12. package/rules/common/C006_function_naming/smart-analyzer.js +503 -0
  13. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  14. package/rules/common/C012_command_query_separation/analyzer.js +481 -0
  15. package/rules/common/C012_command_query_separation/ast-analyzer.js +495 -0
  16. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  17. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  18. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  19. package/rules/common/C019_log_level_usage/analyzer.js +362 -0
  20. package/rules/common/C019_log_level_usage/config.json +121 -0
  21. package/rules/common/C029_catch_block_logging/analyzer-backup.js +426 -0
  22. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +130 -0
  23. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +487 -0
  24. package/rules/common/C029_catch_block_logging/analyzer-simple.js +110 -0
  25. package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +755 -0
  26. package/rules/common/C029_catch_block_logging/analyzer.js +129 -0
  27. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +441 -0
  28. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +127 -0
  29. package/rules/common/C029_catch_block_logging/ast-analyzer.js +133 -0
  30. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +408 -0
  31. package/rules/common/C029_catch_block_logging/config.json +59 -0
  32. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +454 -0
  33. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +700 -0
  34. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +568 -0
  35. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +459 -0
  36. package/rules/common/C031_validation_separation/analyzer.js +186 -0
  37. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  38. package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +296 -0
  39. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  40. package/rules/common/C043_no_console_or_print/analyzer.js +431 -0
  41. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +590 -0
  42. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  43. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  44. package/rules/docs/C002_no_duplicate_code.md +57 -0
  45. package/rules/docs/C031_validation_separation.md +72 -0
  46. package/rules/index.js +155 -0
  47. package/rules/migration/converter.js +385 -0
  48. package/rules/migration/mapping.json +164 -0
  49. package/rules/parser/constants.js +31 -0
  50. package/rules/parser/file-config.js +80 -0
  51. package/rules/parser/rule-parser-simple.js +305 -0
  52. package/rules/parser/rule-parser.js +527 -0
  53. package/rules/security/S015_insecure_tls_certificate/analyzer.js +150 -0
  54. package/rules/security/S015_insecure_tls_certificate/ast-analyzer.js +237 -0
  55. package/rules/security/S023_no_json_injection/analyzer.js +278 -0
  56. package/rules/security/S023_no_json_injection/ast-analyzer.js +359 -0
  57. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  58. package/rules/security/S026_json_schema_validation/config.json +27 -0
  59. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +436 -0
  60. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  61. package/rules/security/S029_csrf_protection/analyzer.js +330 -0
  62. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  63. package/rules/universal/C010/generic.js +0 -0
  64. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  65. package/rules/utils/ast-utils.js +191 -0
  66. package/rules/utils/base-analyzer.js +98 -0
  67. package/rules/utils/pattern-matchers.js +239 -0
  68. package/rules/utils/rule-helpers.js +264 -0
  69. package/rules/utils/severity-constants.js +93 -0
  70. package/scripts/generate_insights.js +188 -0
  71. package/scripts/merge-reports.js +0 -424
  72. package/scripts/test-scripts/README.md +0 -22
  73. package/scripts/test-scripts/test-c041-comparison.js +0 -114
  74. package/scripts/test-scripts/test-c041-eslint.js +0 -67
  75. package/scripts/test-scripts/test-eslint-rules.js +0 -146
  76. package/scripts/test-scripts/test-real-world.js +0 -44
  77. package/scripts/test-scripts/test-rules-on-real-projects.js +0 -86
@@ -0,0 +1,487 @@
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();
@@ -0,0 +1,110 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ class C029Analyzer {
5
+ constructor() {
6
+ this.ruleId = 'C029';
7
+ this.ruleName = 'Enhanced Catch Block Error Logging';
8
+ this.description = 'Smart 3-stage pipeline: Regex → AST → Data Flow analysis';
9
+
10
+ // Load smart pipeline analyzer
11
+ this.smartPipeline = null;
12
+
13
+ try {
14
+ this.smartPipeline = require('./analyzer-smart-pipeline.js');
15
+ console.log('🎯 C029: Smart Pipeline loaded (Regex → AST → Data Flow)');
16
+ } catch (error) {
17
+ console.warn('⚠️ C029: Smart Pipeline failed, falling back to basic analysis:', error.message);
18
+ }
19
+ }
20
+
21
+ async analyze(files, language, options = {}) {
22
+ // Use smart pipeline for optimal performance and accuracy
23
+ if (this.smartPipeline) {
24
+ console.log('🎯 C029: Using Smart Pipeline (Regex → AST → Data Flow)...');
25
+ return await this.smartPipeline.analyze(files, language, options);
26
+ } else {
27
+ console.log('🔍 C029: Using basic regex analysis (fallback)...');
28
+ return await this.analyzeWithRegex(files, language, options);
29
+ }
30
+ }
31
+
32
+ async analyzeWithRegex(files, language, options = {}) {
33
+ const violations = [];
34
+
35
+ for (const filePath of files) {
36
+ if (options.verbose) {
37
+ console.log(`Analyzing ${path.basename(filePath)}...`);
38
+ }
39
+
40
+ try {
41
+ const content = fs.readFileSync(filePath, 'utf8');
42
+ const lines = content.split('\n');
43
+
44
+ for (let i = 0; i < lines.length; i++) {
45
+ const line = lines[i];
46
+
47
+ // Basic catch block detection
48
+ if (/catch\s*\([^)]*\)\s*\{/.test(line)) {
49
+ const catchBlock = this.extractBasicCatchBlock(lines, i);
50
+
51
+ if (this.isBasicViolation(catchBlock, filePath)) {
52
+ violations.push({
53
+ ruleId: this.ruleId,
54
+ file: filePath,
55
+ line: i + 1,
56
+ column: 1,
57
+ message: 'Catch block should log error information',
58
+ severity: 'error',
59
+ code: line.trim(),
60
+ suggestion: 'Add console.error() or appropriate logging'
61
+ });
62
+ }
63
+ }
64
+ }
65
+ } catch (error) {
66
+ console.warn(`Error analyzing ${filePath}:`, error.message);
67
+ }
68
+ }
69
+
70
+ return violations;
71
+ }
72
+
73
+ extractBasicCatchBlock(lines, startIndex) {
74
+ let braceCount = 0;
75
+ let content = '';
76
+
77
+ for (let i = startIndex; i < lines.length; i++) {
78
+ const line = lines[i];
79
+ content += line + '\n';
80
+
81
+ braceCount += (line.match(/\{/g) || []).length;
82
+ braceCount -= (line.match(/\}/g) || []).length;
83
+
84
+ if (braceCount === 0 && i > startIndex) {
85
+ break;
86
+ }
87
+ }
88
+
89
+ return content.trim();
90
+ }
91
+
92
+ isBasicViolation(catchContent, filePath) {
93
+ // Skip test files
94
+ if (/(__tests__|\.test\.|\.spec\.|\/test\/|\/tests\/)/.test(filePath)) {
95
+ return false;
96
+ }
97
+
98
+ // Empty catch block
99
+ if (!catchContent || catchContent.replace(/[{}\s]/g, '').length === 0) {
100
+ return true;
101
+ }
102
+
103
+ // No logging patterns
104
+ const hasLogging = /console\.(log|error|warn|debug)|logger?\.(error|warn|info|debug)/.test(catchContent);
105
+
106
+ return !hasLogging;
107
+ }
108
+ }
109
+
110
+ module.exports = new C029Analyzer();