@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,133 +0,0 @@
1
- /**
2
- * AST-based C029 Analyzer - Smart Pipeline Integration
3
- *
4
- * This analyzer forwards to the Smart Pipeline for superior accuracy and performance
5
- * Maintains compatibility with the heuristic engine's AST expectations
6
- */
7
-
8
- class C029ASTAnalyzer {
9
- constructor() {
10
- this.ruleId = 'C029';
11
- this.ruleName = 'AST-Enhanced Catch Block Error Logging (Smart Pipeline)';
12
- this.description = 'Catch blocks must log errors - using Smart Pipeline 3-stage analysis';
13
-
14
- // Load Smart Pipeline
15
- this.smartPipeline = null;
16
-
17
- try {
18
- this.smartPipeline = require('./analyzer-smart-pipeline.js');
19
- // Debug message will be shown by Smart Pipeline itself when verbose
20
- } catch (error) {
21
- console.warn('⚠️ C029 AST: Smart Pipeline failed:', error.message);
22
- this.smartPipeline = null;
23
- }
24
- }
25
-
26
- async analyze(files, language, options = {}) {
27
- // Use Smart Pipeline if available
28
- if (this.smartPipeline) {
29
- if (options.verbose) {
30
- console.log('🎯 C029 AST: Using Smart Pipeline (3-stage analysis)...');
31
- }
32
- return await this.smartPipeline.analyze(files, language, options);
33
- } else {
34
- if (options.verbose) {
35
- console.log('🔍 C029 AST: Using fallback analysis...');
36
- }
37
- return await this.fallbackAnalysis(files, language, options);
38
- }
39
- }
40
-
41
- async fallbackAnalysis(files, language, options = {}) {
42
- const violations = [];
43
- const fs = require('fs');
44
- const path = require('path');
45
-
46
- if (options.verbose) {
47
- console.log(`🔍 C029 AST: Processing ${files.length} files with fallback analysis...`);
48
- }
49
-
50
- for (const filePath of files) {
51
- try {
52
- const content = fs.readFileSync(filePath, 'utf8');
53
- const fileViolations = await this.analyzeFile(filePath, content, language);
54
- violations.push(...fileViolations);
55
- } catch (error) {
56
- console.warn(`⚠️ C029 AST: Error processing ${filePath}:`, error.message);
57
- }
58
- }
59
-
60
- return violations;
61
- }
62
-
63
- async analyzeFile(filePath, content, language) {
64
- const violations = [];
65
- const lines = content.split('\n');
66
-
67
- for (let i = 0; i < lines.length; i++) {
68
- const line = lines[i];
69
-
70
- // Simple catch block detection for fallback
71
- if (line.includes('catch') && line.includes('(')) {
72
- const catchBlock = this.extractCatchBlock(lines, i);
73
-
74
- if (this.isCatchBlockEmpty(catchBlock.content)) {
75
- violations.push({
76
- file: filePath,
77
- line: i + 1,
78
- column: line.indexOf('catch') + 1,
79
- message: 'Empty catch block detected (fallback analysis)',
80
- severity: 'error',
81
- ruleId: this.ruleId,
82
- type: 'empty_catch_fallback'
83
- });
84
- }
85
- }
86
- }
87
-
88
- return violations;
89
- }
90
-
91
- extractCatchBlock(lines, startIndex) {
92
- const content = [];
93
- let braceCount = 0;
94
- let inBlock = false;
95
-
96
- for (let i = startIndex; i < lines.length; i++) {
97
- const line = lines[i];
98
- content.push(line);
99
-
100
- for (const char of line) {
101
- if (char === '{') {
102
- braceCount++;
103
- inBlock = true;
104
- } else if (char === '}') {
105
- braceCount--;
106
- if (braceCount === 0 && inBlock) {
107
- return { content, endIndex: i };
108
- }
109
- }
110
- }
111
- }
112
-
113
- return { content, endIndex: startIndex };
114
- }
115
-
116
- isCatchBlockEmpty(content) {
117
- const blockContent = content.join('\n');
118
-
119
- // Remove comments and whitespace
120
- const cleanContent = blockContent
121
- .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
122
- .replace(/\/\/.*$/gm, '') // Remove single-line comments
123
- .replace(/\s+/g, ' ') // Normalize whitespace
124
- .trim();
125
-
126
- // Check if only contains catch declaration and braces
127
- const hasOnlyStructure = /^catch\s*\([^)]*\)\s*\{\s*\}$/.test(cleanContent);
128
-
129
- return hasOnlyStructure;
130
- }
131
- }
132
-
133
- module.exports = C029ASTAnalyzer;
@@ -1,408 +0,0 @@
1
- /**
2
- * C029 Control Flow Graph Analyzer
3
- *
4
- * Uses Control Flow Graph to understand execution paths and detect
5
- * unreachable error handling or dead error variables
6
- *
7
- * Technology Showcase: Advanced static analysis beyond traditional linters
8
- */
9
-
10
- class C029ControlFlowAnalyzer {
11
- constructor() {
12
- this.ruleId = 'C029';
13
- this.ruleName = 'Control Flow Graph Enhanced Catch Analysis';
14
- this.description = 'Uses CFG to detect unreachable error handling and dead variables';
15
- }
16
-
17
- async analyze(files, language, options = {}) {
18
- const violations = [];
19
- console.log(`📊 C029 CFG: Analyzing ${files.length} files with Control Flow Graph...`);
20
-
21
- for (const filePath of files) {
22
- try {
23
- const content = require('fs').readFileSync(filePath, 'utf8');
24
- const ast = await this.parseAST(content, language, filePath);
25
-
26
- if (ast) {
27
- // Build Control Flow Graph
28
- const cfg = this.buildControlFlowGraph(ast);
29
-
30
- // Analyze catch blocks within CFG context
31
- const cfgViolations = this.analyzeCatchBlocksInCFG(cfg, filePath, content);
32
- violations.push(...cfgViolations);
33
- }
34
-
35
- } catch (error) {
36
- console.warn(`C029 CFG skipping ${filePath}: ${error.message}`);
37
- }
38
- }
39
-
40
- return violations;
41
- }
42
-
43
- /**
44
- * Build Control Flow Graph from AST
45
- * Maps all possible execution paths through the code
46
- */
47
- buildControlFlowGraph(ast) {
48
- const cfg = {
49
- nodes: new Map(), // CFG nodes (basic blocks)
50
- edges: new Map(), // CFG edges (control flow)
51
- entryNode: null, // Program entry point
52
- exitNodes: new Set(), // Program exit points
53
- catchBlocks: new Map() // Catch block metadata
54
- };
55
-
56
- let nodeId = 0;
57
-
58
- // Traverse AST and build CFG
59
- const buildCFGVisitor = {
60
- // Handle function declarations/expressions
61
- visitFunction: (node) => {
62
- const functionCFG = this.buildFunctionCFG(node, nodeId);
63
- this.mergeCFG(cfg, functionCFG);
64
- nodeId += functionCFG.nodeCount;
65
- return true;
66
- },
67
-
68
- // Handle try-catch statements
69
- visitTryStatement: (node) => {
70
- const tryCatchCFG = this.buildTryCatchCFG(node, nodeId);
71
- this.mergeCFG(cfg, tryCatchCFG);
72
- nodeId += tryCatchCFG.nodeCount;
73
- return true;
74
- }
75
- };
76
-
77
- this.traverseAST(ast, buildCFGVisitor);
78
- return cfg;
79
- }
80
-
81
- /**
82
- * Build CFG for try-catch-finally blocks
83
- * Models exception flow and normal flow paths
84
- */
85
- buildTryCatchCFG(tryNode, startNodeId) {
86
- const cfg = {
87
- nodes: new Map(),
88
- edges: new Map(),
89
- nodeCount: 0,
90
- catchBlocks: new Map()
91
- };
92
-
93
- let currentNodeId = startNodeId;
94
-
95
- // Try block entry
96
- const tryEntry = this.createCFGNode(currentNodeId++, 'try_entry', tryNode.block);
97
- cfg.nodes.set(tryEntry.id, tryEntry);
98
-
99
- // Try block execution paths
100
- const tryExitNormal = this.createCFGNode(currentNodeId++, 'try_exit_normal');
101
- const tryExitException = this.createCFGNode(currentNodeId++, 'try_exit_exception');
102
-
103
- // Catch block(s)
104
- const catchNodes = [];
105
- if (tryNode.handler) {
106
- const catchEntry = this.createCFGNode(currentNodeId++, 'catch_entry', tryNode.handler);
107
- const catchExit = this.createCFGNode(currentNodeId++, 'catch_exit');
108
-
109
- catchNodes.push({ entry: catchEntry, exit: catchExit, handler: tryNode.handler });
110
- cfg.nodes.set(catchEntry.id, catchEntry);
111
- cfg.nodes.set(catchExit.id, catchExit);
112
-
113
- // Store catch block metadata for analysis
114
- cfg.catchBlocks.set(catchEntry.id, {
115
- handler: tryNode.handler,
116
- errorParam: tryNode.handler.param,
117
- body: tryNode.handler.body,
118
- reachableFromTry: true // Will be computed later
119
- });
120
- }
121
-
122
- // Finally block (if exists)
123
- let finallyEntry = null, finallyExit = null;
124
- if (tryNode.finalizer) {
125
- finallyEntry = this.createCFGNode(currentNodeId++, 'finally_entry', tryNode.finalizer);
126
- finallyExit = this.createCFGNode(currentNodeId++, 'finally_exit');
127
- cfg.nodes.set(finallyEntry.id, finallyEntry);
128
- cfg.nodes.set(finallyExit.id, finallyExit);
129
- }
130
-
131
- // Build control flow edges
132
- this.addCFGEdge(cfg, tryEntry.id, tryExitNormal.id, 'normal_flow');
133
- this.addCFGEdge(cfg, tryEntry.id, tryExitException.id, 'exception_flow');
134
-
135
- // Exception flow to catch blocks
136
- for (const catchNode of catchNodes) {
137
- this.addCFGEdge(cfg, tryExitException.id, catchNode.entry.id, 'catch_flow');
138
- this.addCFGEdge(cfg, catchNode.exit.id, finallyEntry?.id || 'exit', 'post_catch');
139
- }
140
-
141
- // Normal flow to finally or exit
142
- this.addCFGEdge(cfg, tryExitNormal.id, finallyEntry?.id || 'exit', 'normal_completion');
143
-
144
- cfg.nodeCount = currentNodeId - startNodeId;
145
- return cfg;
146
- }
147
-
148
- /**
149
- * Analyze catch blocks within CFG context
150
- * Detects unreachable error handling and control flow issues
151
- */
152
- analyzeCatchBlocksInCFG(cfg, filePath, content) {
153
- const violations = [];
154
- const isTestFile = this.isTestFile(filePath);
155
-
156
- for (const [nodeId, catchInfo] of cfg.catchBlocks) {
157
- const analysis = this.analyzeCatchBlockCFG(nodeId, catchInfo, cfg, isTestFile);
158
-
159
- if (analysis.isViolation) {
160
- violations.push({
161
- ruleId: this.ruleId,
162
- file: filePath,
163
- line: catchInfo.handler.loc ? catchInfo.handler.loc.start.line : 1,
164
- column: catchInfo.handler.loc ? catchInfo.handler.loc.start.column + 1 : 1,
165
- message: analysis.message,
166
- severity: analysis.severity,
167
- code: this.getCodeFromNode(catchInfo.handler, content),
168
- type: analysis.type,
169
- confidence: analysis.confidence,
170
- suggestion: analysis.suggestion,
171
- cfgAnalysis: analysis.cfgData
172
- });
173
- }
174
- }
175
-
176
- return violations;
177
- }
178
-
179
- /**
180
- * CFG-based analysis of single catch block
181
- */
182
- analyzeCatchBlockCFG(nodeId, catchInfo, cfg, isTestFile) {
183
- const errorParam = catchInfo.errorParam;
184
- const catchBody = catchInfo.body;
185
-
186
- // 1. Check if catch block is reachable
187
- const reachabilityAnalysis = this.analyzeCatchReachability(nodeId, cfg);
188
- if (!reachabilityAnalysis.isReachable) {
189
- return {
190
- isViolation: true,
191
- type: 'unreachable_catch',
192
- message: 'Catch block is unreachable - dead code',
193
- severity: 'warning',
194
- confidence: 0.9,
195
- suggestion: 'Remove unreachable catch block or fix control flow',
196
- cfgData: reachabilityAnalysis
197
- };
198
- }
199
-
200
- // 2. Check for control flow that bypasses error handling
201
- const flowAnalysis = this.analyzeErrorHandlingFlow(nodeId, catchInfo, cfg);
202
- if (flowAnalysis.hasBypassFlow) {
203
- return {
204
- isViolation: true,
205
- type: 'bypassed_error_handling',
206
- message: 'Control flow may bypass error handling',
207
- severity: 'warning',
208
- confidence: 0.8,
209
- suggestion: 'Ensure all exception paths are properly handled',
210
- cfgData: flowAnalysis
211
- };
212
- }
213
-
214
- // 3. Check for error variable usage in control flow
215
- if (errorParam) {
216
- const variableFlowAnalysis = this.analyzeErrorVariableFlow(errorParam, catchInfo, cfg);
217
-
218
- if (!variableFlowAnalysis.isUsed) {
219
- return {
220
- isViolation: true,
221
- type: 'unused_error_variable_cfg',
222
- message: `Error variable '${errorParam.name}' is unused in all control flow paths`,
223
- severity: 'error',
224
- confidence: 0.95,
225
- suggestion: 'Use error variable or rename to indicate intentional ignore',
226
- cfgData: variableFlowAnalysis
227
- };
228
- }
229
-
230
- if (variableFlowAnalysis.hasDeadCode) {
231
- return {
232
- isViolation: true,
233
- type: 'dead_error_code',
234
- message: 'Error handling code contains unreachable statements',
235
- severity: 'warning',
236
- confidence: 0.85,
237
- suggestion: 'Remove dead code or fix control flow logic',
238
- cfgData: variableFlowAnalysis
239
- };
240
- }
241
- }
242
-
243
- // 4. Apply context-specific rules
244
- if (isTestFile && this.hasTestAssertions(catchBody)) {
245
- return { isViolation: false, reason: 'test_assertions_cfg' };
246
- }
247
-
248
- return { isViolation: false, reason: 'properly_handled_cfg' };
249
- }
250
-
251
- /**
252
- * Analyze if catch block is reachable through any execution path
253
- */
254
- analyzeCatchReachability(catchNodeId, cfg) {
255
- const reachable = new Set();
256
- const visited = new Set();
257
-
258
- // DFS from entry points to find reachable nodes
259
- const dfs = (nodeId) => {
260
- if (visited.has(nodeId)) return;
261
- visited.add(nodeId);
262
- reachable.add(nodeId);
263
-
264
- const edges = cfg.edges.get(nodeId) || [];
265
- for (const edge of edges) {
266
- dfs(edge.to);
267
- }
268
- };
269
-
270
- // Start from all entry points
271
- if (cfg.entryNode) {
272
- dfs(cfg.entryNode);
273
- }
274
-
275
- return {
276
- isReachable: reachable.has(catchNodeId),
277
- reachablePaths: this.findPathsTo(catchNodeId, cfg),
278
- totalReachableNodes: reachable.size
279
- };
280
- }
281
-
282
- /**
283
- * Analyze error variable usage across control flow paths
284
- */
285
- analyzeErrorVariableFlow(errorParam, catchInfo, cfg) {
286
- const variableName = errorParam.name;
287
- const usageMap = new Map(); // nodeId -> usage info
288
-
289
- // Find all references to error variable in catch block
290
- const references = this.findVariableReferences(variableName, catchInfo.body);
291
-
292
- // Analyze usage in context of control flow
293
- let hasUsefulUsage = false;
294
- let hasDeadCode = false;
295
-
296
- for (const ref of references) {
297
- const usageType = this.categorizeErrorUsage(ref);
298
- if (['logging', 'rethrowing', 'error_handling'].includes(usageType)) {
299
- hasUsefulUsage = true;
300
- }
301
- }
302
-
303
- return {
304
- isUsed: references.length > 0,
305
- hasUsefulUsage,
306
- hasDeadCode,
307
- references: references.length,
308
- usageDistribution: this.getUsageDistribution(references)
309
- };
310
- }
311
-
312
- // Utility methods (simplified versions)
313
- createCFGNode(id, type, astNode = null) {
314
- return {
315
- id,
316
- type,
317
- astNode,
318
- predecessors: new Set(),
319
- successors: new Set()
320
- };
321
- }
322
-
323
- addCFGEdge(cfg, fromId, toId, type) {
324
- if (!cfg.edges.has(fromId)) {
325
- cfg.edges.set(fromId, []);
326
- }
327
- cfg.edges.get(fromId).push({ to: toId, type });
328
- }
329
-
330
- mergeCFG(targetCFG, sourceCFG) {
331
- // Merge nodes and edges from source to target
332
- for (const [id, node] of sourceCFG.nodes) {
333
- targetCFG.nodes.set(id, node);
334
- }
335
- for (const [id, edges] of sourceCFG.edges) {
336
- targetCFG.edges.set(id, edges);
337
- }
338
- for (const [id, catchInfo] of sourceCFG.catchBlocks) {
339
- targetCFG.catchBlocks.set(id, catchInfo);
340
- }
341
- }
342
-
343
- findPathsTo(targetNodeId, cfg) {
344
- // Simplified path finding implementation
345
- return [];
346
- }
347
-
348
- findVariableReferences(variableName, astNode) {
349
- // Reuse from previous implementation
350
- return [];
351
- }
352
-
353
- categorizeErrorUsage(referenceNode) {
354
- // Reuse from previous implementation
355
- return 'unknown';
356
- }
357
-
358
- getUsageDistribution(references) {
359
- return {
360
- logging: 0,
361
- rethrowing: 0,
362
- trivial: 0,
363
- other: references.length
364
- };
365
- }
366
-
367
- hasTestAssertions(astNode) {
368
- // Simplified test assertion check
369
- return false;
370
- }
371
-
372
- isTestFile(filePath) {
373
- const testPatterns = ['__tests__', '.test.', '.spec.', '/test/', '/tests/'];
374
- return testPatterns.some(pattern => filePath.includes(pattern));
375
- }
376
-
377
- getCodeFromNode(node, content) {
378
- // Simplified code extraction
379
- return node.toString ? node.toString() : 'catch block';
380
- }
381
-
382
- async parseAST(content, language, filePath) {
383
- // Reuse existing AST parsing logic
384
- return null;
385
- }
386
-
387
- traverseAST(node, visitor) {
388
- // Reuse existing AST traversal logic
389
- }
390
-
391
- analyzeErrorHandlingFlow(nodeId, catchInfo, cfg) {
392
- return {
393
- hasBypassFlow: false,
394
- flowPaths: []
395
- };
396
- }
397
-
398
- buildFunctionCFG(node, startNodeId) {
399
- return {
400
- nodes: new Map(),
401
- edges: new Map(),
402
- nodeCount: 1,
403
- catchBlocks: new Map()
404
- };
405
- }
406
- }
407
-
408
- module.exports = new C029ControlFlowAnalyzer();