@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
@@ -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;