@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.
- package/CHANGELOG.md +107 -1
- package/CONTRIBUTING.md +1654 -66
- package/README.md +19 -6
- package/config/ci-cd.json +54 -0
- package/config/development.json +56 -0
- package/config/engines/engines-enhanced.json +86 -0
- package/config/engines/semantic-config.json +114 -0
- package/config/eslint-rule-mapping.json +50 -38
- package/config/large-project.json +143 -0
- package/config/presets/all.json +0 -1
- package/config/release.json +70 -0
- package/config/rule-analysis-strategies.js +23 -4
- package/config/rules/S027-categories.json +122 -0
- package/config/rules/enhanced-rules-registry.json +2564 -0
- package/config/rules/rules-registry-generated.json +785 -837
- package/config/rules/rules-registry.json +13 -1
- package/core/adapters/sunlint-rule-adapter.js +25 -30
- package/core/analysis-orchestrator.js +42 -2
- package/core/categories.js +52 -0
- package/core/category-constants.js +39 -0
- package/core/cli-action-handler.js +53 -32
- package/core/cli-program.js +11 -3
- package/core/config-manager.js +111 -0
- package/core/config-merger.js +88 -0
- package/core/constants/categories.js +168 -0
- package/core/constants/defaults.js +165 -0
- package/core/constants/engines.js +185 -0
- package/core/constants/index.js +30 -0
- package/core/constants/rules.js +215 -0
- package/core/enhanced-rules-registry.js +3 -3
- package/core/file-targeting-service.js +128 -7
- package/core/interfaces/rule-plugin.interface.js +207 -0
- package/core/plugin-manager.js +448 -0
- package/core/rule-selection-service.js +42 -15
- package/core/semantic-engine.js +658 -0
- package/core/semantic-rule-base.js +433 -0
- package/core/unified-rule-registry.js +484 -0
- package/docs/COMMAND-EXAMPLES.md +134 -0
- package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
- package/docs/LARGE-PROJECT-GUIDE.md +324 -0
- package/engines/core/base-engine.js +249 -0
- package/engines/engine-factory.js +275 -0
- package/engines/eslint-engine.js +171 -19
- package/engines/heuristic-engine.js +569 -78
- package/integrations/eslint/plugin/index.js +26 -28
- package/origin-rules/common-en.md +8 -8
- package/package.json +10 -6
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
- package/rules/common/C017_constructor_logic/analyzer.js +254 -17
- package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
- package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
- package/rules/common/C033_separate_service_repository/README.md +78 -0
- package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
- package/rules/common/C033_separate_service_repository/config.json +50 -0
- package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
- package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
- package/rules/common/C035_error_logging_context/analyzer.js +230 -0
- package/rules/common/C035_error_logging_context/config.json +54 -0
- package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
- package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
- package/rules/common/C040_centralized_validation/analyzer.js +165 -0
- package/rules/common/C040_centralized_validation/config.json +46 -0
- package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
- package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
- package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
- package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
- package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
- package/rules/common/C076_explicit_function_types/README.md +30 -0
- package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
- package/rules/common/C076_explicit_function_types/config.json +15 -0
- package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
- package/rules/index.js +8 -0
- package/rules/parser/rule-parser.js +13 -2
- package/rules/security/S005_no_origin_auth/README.md +226 -0
- package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
- package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
- package/rules/security/S005_no_origin_auth/config.json +85 -0
- package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
- package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
- package/rules/security/S007_no_plaintext_otp/README.md +198 -0
- package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
- package/rules/security/S007_no_plaintext_otp/config.json +79 -0
- package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
- package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
- package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
- package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
- package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
- package/scripts/category-manager.js +150 -0
- package/scripts/generate-rules-registry.js +88 -0
- package/scripts/migrate-rule-registry.js +157 -0
- package/scripts/prepare-release.sh +1 -1
- package/scripts/validate-system.js +48 -0
- package/.sunlint.json +0 -35
- package/config/README.md +0 -88
- package/config/engines/eslint-rule-mapping.json +0 -74
- package/config/schemas/sunlint-schema.json +0 -0
- package/config/testing/test-s005-working.ts +0 -22
- package/core/multi-rule-runner.js +0 -0
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
- package/docs/FUTURE_PACKAGES.md +0 -83
- package/docs/HEURISTIC_VS_AI.md +0 -113
- package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
- package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
- package/docs/RELEASE_GUIDE.md +0 -230
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -0
- package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
- package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
- package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
- package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
- package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
- package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
- package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
- package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
- package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
- package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
- package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
- package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
- package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* C047 Semantic Rule - Adapted for Shared Symbol Table
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const C047SymbolAnalyzerEnhanced = require('./symbol-analyzer-enhanced');
|
|
6
|
+
|
|
7
|
+
class C047SemanticRule extends C047SymbolAnalyzerEnhanced {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
super();
|
|
10
|
+
this.options = options;
|
|
11
|
+
this.verbose = options.verbose || false; // Store verbose setting
|
|
12
|
+
this.currentViolations = []; // Store violations for heuristic engine compatibility
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the semantic rule (required by heuristic engine)
|
|
17
|
+
*/
|
|
18
|
+
async initialize(semanticEngine = null) {
|
|
19
|
+
if (this.verbose) {
|
|
20
|
+
console.log(`[DEBUG] 🔧 Initializing C047 semantic rule...`);
|
|
21
|
+
}
|
|
22
|
+
// Store semantic engine reference if provided
|
|
23
|
+
if (semanticEngine) {
|
|
24
|
+
this.semanticEngine = semanticEngine;
|
|
25
|
+
}
|
|
26
|
+
// Load configuration from parent class
|
|
27
|
+
await this.loadConfiguration();
|
|
28
|
+
if (this.verbose) {
|
|
29
|
+
console.log(`[DEBUG] ✅ C047 semantic rule initialized`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Analyze single file (required by heuristic engine)
|
|
35
|
+
*/
|
|
36
|
+
async analyzeFile(filePath, options = {}) {
|
|
37
|
+
if (this.verbose) {
|
|
38
|
+
console.log(`[DEBUG] 🔍 C047: Analyzing file ${filePath}`);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
// Use parent analyze method for single file
|
|
42
|
+
const violations = await this.analyze([filePath], 'typescript', options);
|
|
43
|
+
this.currentViolations = violations || [];
|
|
44
|
+
if (this.verbose || options.verbose) {
|
|
45
|
+
console.log(`✅ C047: Found ${this.currentViolations.length} violations in ${filePath}`);
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (this.verbose || options.verbose) {
|
|
49
|
+
console.error(`❌ C047 analysis failed for ${filePath}:`, error.message);
|
|
50
|
+
}
|
|
51
|
+
this.currentViolations = [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get violations (required by heuristic engine)
|
|
57
|
+
*/
|
|
58
|
+
getViolations() {
|
|
59
|
+
return this.currentViolations;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Clear violations (required by heuristic engine)
|
|
64
|
+
*/
|
|
65
|
+
clearViolations() {
|
|
66
|
+
this.currentViolations = [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* New method: Analyze using shared Symbol Table
|
|
71
|
+
* This is more efficient than creating separate ts-morph projects
|
|
72
|
+
*/
|
|
73
|
+
async analyzeWithSymbolTable(symbolTable, options = {}) {
|
|
74
|
+
if (this.verbose) {
|
|
75
|
+
console.log(`[DEBUG] 🔍 C047 Semantic Rule: Using shared Symbol Table...`);
|
|
76
|
+
}
|
|
77
|
+
const startTime = Date.now();
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// Skip the project initialization since we use shared Symbol Table
|
|
81
|
+
if (this.verbose) {
|
|
82
|
+
console.log(`[DEBUG] 📋 Step 1: Using shared configuration...`);
|
|
83
|
+
}
|
|
84
|
+
await this.loadConfiguration();
|
|
85
|
+
|
|
86
|
+
// Use shared Symbol Table instead of creating new project
|
|
87
|
+
if (this.verbose) {
|
|
88
|
+
console.log(`[DEBUG] 🏗️ Step 2: Using shared Symbol Table...`);
|
|
89
|
+
}
|
|
90
|
+
this.project = symbolTable.project;
|
|
91
|
+
|
|
92
|
+
// Detect retry patterns using cached symbols
|
|
93
|
+
if (this.verbose) {
|
|
94
|
+
console.log(`[DEBUG] 🔍 Step 3: Detecting retry patterns with Symbol Table...`);
|
|
95
|
+
}
|
|
96
|
+
const allRetryPatterns = await this.detectRetryPatternsWithSymbolTable(symbolTable, options);
|
|
97
|
+
if (this.verbose) {
|
|
98
|
+
console.log(`[DEBUG] ✅ Pattern detection complete: ${allRetryPatterns.length} patterns`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Group by layers and flows
|
|
102
|
+
if (this.verbose) {
|
|
103
|
+
console.log(`[DEBUG] 📊 Step 4: Grouping patterns...`);
|
|
104
|
+
}
|
|
105
|
+
const layeredPatterns = this.groupByLayersAndFlows(allRetryPatterns);
|
|
106
|
+
if (this.verbose) {
|
|
107
|
+
console.log(`[DEBUG] ✅ Grouping complete`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Apply violation detection logic
|
|
111
|
+
if (this.verbose) {
|
|
112
|
+
console.log(`[DEBUG] ⚠️ Step 5: Detecting violations...`);
|
|
113
|
+
}
|
|
114
|
+
const violations = this.detectViolations(layeredPatterns);
|
|
115
|
+
if (this.verbose) {
|
|
116
|
+
console.log(`[DEBUG] ✅ Violation detection complete: ${violations.length} violations`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const duration = Date.now() - startTime;
|
|
120
|
+
if (this.verbose) {
|
|
121
|
+
console.log(`[DEBUG] 🎯 C047 Semantic analysis complete in ${duration}ms!`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (options.verbose) {
|
|
125
|
+
this.printAnalysisStats(allRetryPatterns, layeredPatterns, violations);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return violations;
|
|
129
|
+
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('❌ C047 Semantic rule failed:', error.message);
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Detect retry patterns using cached Symbol Table
|
|
138
|
+
*/
|
|
139
|
+
async detectRetryPatternsWithSymbolTable(symbolTable, options) {
|
|
140
|
+
if (this.verbose) {
|
|
141
|
+
console.log(`[DEBUG] 🔍 Detecting retry patterns with Symbol Table...`);
|
|
142
|
+
}
|
|
143
|
+
const allPatterns = [];
|
|
144
|
+
|
|
145
|
+
// Use cached source files from Symbol Table
|
|
146
|
+
const sourceFiles = symbolTable.sourceFiles;
|
|
147
|
+
if (this.verbose) {
|
|
148
|
+
console.log(`[DEBUG] 📄 Found ${sourceFiles.length} source files in Symbol Table`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (let i = 0; i < sourceFiles.length; i++) {
|
|
152
|
+
const sourceFile = sourceFiles[i];
|
|
153
|
+
const fileName = sourceFile.getBaseName();
|
|
154
|
+
|
|
155
|
+
if (this.verbose || options.verbose) {
|
|
156
|
+
console.log(`[DEBUG] 🔍 Analyzing ${i + 1}/${sourceFiles.length}: ${fileName}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// Check if symbols are already cached
|
|
161
|
+
const cachedSymbols = symbolTable.getSymbols(sourceFile.getFilePath());
|
|
162
|
+
let filePatterns;
|
|
163
|
+
|
|
164
|
+
if (cachedSymbols && this.options.useSymbolCache) {
|
|
165
|
+
// Use cached symbols for faster analysis
|
|
166
|
+
filePatterns = await this.analyzeWithCachedSymbols(sourceFile, cachedSymbols);
|
|
167
|
+
} else {
|
|
168
|
+
// Fallback to direct AST analysis
|
|
169
|
+
filePatterns = await this.analyzeSourceFile(sourceFile);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
allPatterns.push(...filePatterns);
|
|
173
|
+
|
|
174
|
+
if (this.verbose || options.verbose) {
|
|
175
|
+
console.log(`[DEBUG] ✅ Found ${filePatterns.length} patterns in ${fileName}`);
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (this.verbose) {
|
|
179
|
+
console.warn(`[DEBUG] ⚠️ Error analyzing ${fileName}: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (this.verbose) {
|
|
185
|
+
console.log(`[DEBUG] 🎯 Total patterns detected: ${allPatterns.length}`);
|
|
186
|
+
}
|
|
187
|
+
return allPatterns;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Analyze using pre-cached symbols (faster)
|
|
192
|
+
*/
|
|
193
|
+
async analyzeWithCachedSymbols(sourceFile, cachedSymbols) {
|
|
194
|
+
const patterns = [];
|
|
195
|
+
const filePath = sourceFile.getFilePath() || sourceFile.getBaseName();
|
|
196
|
+
|
|
197
|
+
if (this.verbose) {
|
|
198
|
+
console.log(`[DEBUG] 📁 Analyzing ${require('path').basename(filePath)} with cached symbols`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Process cached classes
|
|
202
|
+
for (const classSymbol of cachedSymbols.classes) {
|
|
203
|
+
if (this.verbose) {
|
|
204
|
+
console.log(`[DEBUG] 📦 Cached class: ${classSymbol.name}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (const methodName of classSymbol.methods) {
|
|
208
|
+
const fullFunctionName = `${classSymbol.name}.${methodName}`;
|
|
209
|
+
if (this.verbose) {
|
|
210
|
+
console.log(`[DEBUG] 🎯 Cached method: ${fullFunctionName}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Get the actual AST node for detailed analysis
|
|
214
|
+
const classNode = sourceFile.getClasses().find(c => c.getName() === classSymbol.name);
|
|
215
|
+
if (classNode) {
|
|
216
|
+
const methodNode = classNode.getMethods().find(m => m.getName() === methodName);
|
|
217
|
+
if (methodNode) {
|
|
218
|
+
const patterns_found = await this.analyzeFunction(methodNode, fullFunctionName, filePath);
|
|
219
|
+
patterns.push(...patterns_found);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Process cached functions
|
|
226
|
+
for (const functionSymbol of cachedSymbols.functions) {
|
|
227
|
+
if (this.verbose) {
|
|
228
|
+
console.log(`[DEBUG] 🔧 Cached function: ${functionSymbol.name}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const functionNode = sourceFile.getFunctions().find(f => f.getName() === functionSymbol.name);
|
|
232
|
+
if (functionNode) {
|
|
233
|
+
const patterns_found = await this.analyzeFunction(functionNode, functionSymbol.name, filePath);
|
|
234
|
+
patterns.push(...patterns_found);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Process cached variables (for React components)
|
|
239
|
+
for (const variableSymbol of cachedSymbols.variables) {
|
|
240
|
+
if (this.verbose) {
|
|
241
|
+
console.log(`[DEBUG] ⚡ Cached variable: ${variableSymbol.name}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const varDecl = sourceFile.getVariableDeclarations().find(v => v.getName() === variableSymbol.name);
|
|
245
|
+
if (varDecl) {
|
|
246
|
+
const initializer = varDecl.getInitializer();
|
|
247
|
+
if (initializer && (initializer.getKind() === require('ts-morph').SyntaxKind.ArrowFunction ||
|
|
248
|
+
initializer.getKind() === require('ts-morph').SyntaxKind.FunctionExpression)) {
|
|
249
|
+
|
|
250
|
+
// Check for useQuery calls with retry
|
|
251
|
+
const useQueryPatterns = this.detectUseQueryRetryPatterns(initializer, variableSymbol.name, filePath);
|
|
252
|
+
patterns.push(...useQueryPatterns);
|
|
253
|
+
|
|
254
|
+
// Also analyze for standard retry patterns
|
|
255
|
+
const patterns_found = await this.analyzeFunction(initializer, variableSymbol.name, filePath);
|
|
256
|
+
patterns.push(...patterns_found);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (this.verbose) {
|
|
262
|
+
console.log(`[DEBUG] 📊 Total patterns found with cached symbols: ${patterns.length}`);
|
|
263
|
+
}
|
|
264
|
+
return patterns;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Traditional analyze method (for backward compatibility)
|
|
269
|
+
*/
|
|
270
|
+
async analyze(files, language, options = {}) {
|
|
271
|
+
if (this.verbose) {
|
|
272
|
+
console.log(`[DEBUG] ⚠️ C047: Using traditional analysis (consider upgrading to Symbol Table)`);
|
|
273
|
+
}
|
|
274
|
+
return super.analyze(files, language, options);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = C047SemanticRule;
|