@sun-asterisk/sunlint 1.3.0 → 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 +68 -1
- package/CONTRIBUTING.md +1179 -54
- package/README.md +3 -4
- package/config/ci-cd.json +54 -0
- package/config/development.json +56 -0
- 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 +136 -75
- package/config/rules/rules-registry-generated.json +2 -2
- package/config/rules/rules-registry.json +13 -1
- package/core/cli-action-handler.js +24 -30
- package/core/cli-program.js +11 -3
- package/core/config-merger.js +29 -2
- package/core/enhanced-rules-registry.js +3 -3
- package/core/semantic-engine.js +117 -19
- package/core/unified-rule-registry.js +1 -1
- package/docs/COMMAND-EXAMPLES.md +134 -0
- package/docs/LARGE-PROJECT-GUIDE.md +324 -0
- package/engines/heuristic-engine.js +71 -13
- package/integrations/eslint/plugin/index.js +0 -2
- package/origin-rules/common-en.md +8 -8
- package/package.json +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/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/{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 +1 -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/prepare-release.sh +1 -1
- 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/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
package/core/semantic-engine.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const fs = require('fs').promises;
|
|
11
|
+
const { Project, SyntaxKind } = require('ts-morph');
|
|
11
12
|
|
|
12
13
|
class SemanticEngine {
|
|
13
14
|
constructor(options = {}) {
|
|
@@ -49,8 +50,9 @@ class SemanticEngine {
|
|
|
49
50
|
/**
|
|
50
51
|
* Initialize ts-morph project with optimized memory configuration
|
|
51
52
|
* Designed for large projects (3000+ files, 800-1000 lines each)
|
|
53
|
+
* OPTIMIZED: Accept targetFiles parameter to avoid loading unnecessary files
|
|
52
54
|
*/
|
|
53
|
-
async initialize(projectPath) {
|
|
55
|
+
async initialize(projectPath, targetFiles = null) {
|
|
54
56
|
try {
|
|
55
57
|
// Load ts-morph conditionally
|
|
56
58
|
const { Project } = await import('ts-morph');
|
|
@@ -59,8 +61,8 @@ class SemanticEngine {
|
|
|
59
61
|
const tsConfigPath = await this.findTsConfig(projectPath);
|
|
60
62
|
|
|
61
63
|
// Initialize project with memory-optimized settings
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
// When using targetFiles, skip tsconfig to avoid auto-discovery
|
|
65
|
+
const projectOptions = {
|
|
64
66
|
compilerOptions: {
|
|
65
67
|
...this.options.compilerOptions,
|
|
66
68
|
// Memory optimization flags
|
|
@@ -78,22 +80,118 @@ class SemanticEngine {
|
|
|
78
80
|
// Performance settings for large codebases
|
|
79
81
|
resolutionHost: undefined, // Disable resolution host
|
|
80
82
|
libFolderPath: undefined, // Don't load TypeScript libs
|
|
81
|
-
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Only use tsconfig when auto-discovering files (no targetFiles)
|
|
86
|
+
if (!targetFiles && tsConfigPath) {
|
|
87
|
+
projectOptions.tsConfigFilePath = tsConfigPath;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.project = new Project(projectOptions);
|
|
91
|
+
|
|
92
|
+
// Use provided targetFiles if available, otherwise discover
|
|
93
|
+
const sourceFiles = targetFiles || await this.discoverTargetFiles(projectPath);
|
|
94
|
+
|
|
95
|
+
// Filter to TypeScript/JavaScript files only for semantic analysis
|
|
96
|
+
const semanticFiles = sourceFiles.filter(filePath =>
|
|
97
|
+
/\.(ts|tsx|js|jsx)$/i.test(filePath)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (targetFiles) {
|
|
101
|
+
console.log(`🎯 Targeted files received: ${targetFiles.length} total, ${semanticFiles.length} TS/JS files`);
|
|
102
|
+
if (semanticFiles.length < 10) {
|
|
103
|
+
console.log(` Files: ${semanticFiles.map(f => path.basename(f)).join(', ')}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
82
106
|
|
|
83
|
-
//
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
// Adaptive loading strategy based on project size and user preference
|
|
108
|
+
const userMaxFiles = this.options.maxSemanticFiles;
|
|
109
|
+
let maxFiles;
|
|
110
|
+
|
|
111
|
+
if (userMaxFiles === -1) {
|
|
112
|
+
// Unlimited: Load all files
|
|
113
|
+
maxFiles = semanticFiles.length;
|
|
114
|
+
console.log(`🔧 Semantic Engine config: UNLIMITED analysis (all ${semanticFiles.length} files)`);
|
|
115
|
+
} else if (userMaxFiles === 0) {
|
|
116
|
+
// Disable semantic analysis
|
|
117
|
+
maxFiles = 0;
|
|
118
|
+
console.log(`🔧 Semantic Engine config: DISABLED semantic analysis (heuristic only)`);
|
|
119
|
+
} else if (userMaxFiles > 0) {
|
|
120
|
+
// User-specified limit
|
|
121
|
+
maxFiles = Math.min(userMaxFiles, semanticFiles.length);
|
|
122
|
+
console.log(`🔧 Semantic Engine config: USER limit ${maxFiles} files (requested: ${userMaxFiles})`);
|
|
89
123
|
} else {
|
|
90
|
-
|
|
124
|
+
// Auto-detect based on project size
|
|
125
|
+
maxFiles = semanticFiles.length > 1000 ? 1000 : semanticFiles.length;
|
|
126
|
+
console.log(`🔧 Semantic Engine config: AUTO limit ${maxFiles} files (project has ${semanticFiles.length} files)`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (this.options.verbose) {
|
|
130
|
+
console.log(`🔧 Semantic Engine detailed config:`);
|
|
131
|
+
console.log(` 📊 maxSemanticFiles option: ${this.options.maxSemanticFiles}`);
|
|
132
|
+
console.log(` 📈 Total semantic files: ${semanticFiles.length}`);
|
|
133
|
+
console.log(` 🎯 Files to load: ${maxFiles}`);
|
|
134
|
+
console.log(` 📉 Coverage: ${maxFiles > 0 ? Math.round(maxFiles/semanticFiles.length*100) : 0}%`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Skip semantic analysis if disabled
|
|
138
|
+
if (maxFiles === 0) {
|
|
139
|
+
console.log(`⚠️ Semantic analysis DISABLED - using heuristic rules only`);
|
|
140
|
+
console.log(`💡 To enable semantic analysis, use --max-semantic-files=1000 (or higher)`);
|
|
141
|
+
this.initialized = true;
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (semanticFiles.length > maxFiles && maxFiles !== semanticFiles.length) {
|
|
146
|
+
console.warn(`⚠️ Large semantic project detected (${semanticFiles.length} files)`);
|
|
147
|
+
console.warn(`⚠️ Loading ${maxFiles} files for memory optimization (${Math.round(maxFiles/semanticFiles.length*100)}% coverage)`);
|
|
148
|
+
if (userMaxFiles !== -1) {
|
|
149
|
+
console.warn(`⚠️ Use --max-semantic-files=-1 to analyze ALL files (unlimited)`);
|
|
150
|
+
console.warn(`⚠️ Use --max-semantic-files=${semanticFiles.length} to analyze exactly this project`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const filesToLoad = semanticFiles.slice(0, maxFiles);
|
|
154
|
+
|
|
155
|
+
// Load files one by one to handle any parse errors gracefully
|
|
156
|
+
let successCount = 0;
|
|
157
|
+
let errorCount = 0;
|
|
158
|
+
|
|
159
|
+
for (const filePath of filesToLoad) {
|
|
160
|
+
try {
|
|
161
|
+
if (require('fs').existsSync(filePath)) {
|
|
162
|
+
this.project.addSourceFileAtPath(filePath);
|
|
163
|
+
successCount++;
|
|
164
|
+
} else {
|
|
165
|
+
errorCount++;
|
|
166
|
+
}
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (this.options.verbose) {
|
|
169
|
+
console.warn(`❌ Failed to load: ${path.basename(filePath)} - ${error.message}`);
|
|
170
|
+
}
|
|
171
|
+
errorCount++;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log(`📊 Semantic analysis: ${successCount} files loaded, ${errorCount} skipped`);
|
|
176
|
+
|
|
177
|
+
} else {
|
|
178
|
+
console.log(`📊 Loading all ${semanticFiles.length} files for complete semantic analysis`);
|
|
179
|
+
// For projects within limits, load all files
|
|
180
|
+
this.project.addSourceFilesAtPaths(semanticFiles);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Debug what ts-morph actually loaded
|
|
184
|
+
const actualFiles = this.project.getSourceFiles();
|
|
185
|
+
console.log(`📊 ts-morph loaded: ${actualFiles.length} files (expected: ${semanticFiles.length})`);
|
|
186
|
+
if (actualFiles.length > semanticFiles.length * 2) {
|
|
187
|
+
console.warn(`⚠️ ts-morph auto-discovered additional files (dependency resolution)`);
|
|
91
188
|
}
|
|
92
189
|
|
|
93
190
|
console.log(`🔧 Semantic Engine initialized (Memory Optimized):`);
|
|
94
191
|
console.log(` 📁 Project: ${projectPath}`);
|
|
95
192
|
console.log(` 📋 TS Config: ${tsConfigPath || 'default (minimal)'}`);
|
|
96
193
|
console.log(` 📄 Files loaded: ${this.project.getSourceFiles().length}`);
|
|
194
|
+
console.log(` 🎯 Targeting mode: ${targetFiles ? 'Filtered files' : 'Auto-discovery'}`);
|
|
97
195
|
console.log(` 💾 Memory mode: Optimized for large projects`);
|
|
98
196
|
|
|
99
197
|
this.initialized = true;
|
|
@@ -199,7 +297,7 @@ class SemanticEngine {
|
|
|
199
297
|
const namedImports = importDecl.getNamedImports().map(namedImport => ({
|
|
200
298
|
name: namedImport.getName(),
|
|
201
299
|
alias: namedImport.getAliasNode()?.getText(),
|
|
202
|
-
line: namedImport.
|
|
300
|
+
line: sourceFile.getLineAndColumnAtPos(namedImport.getStart()).line
|
|
203
301
|
}));
|
|
204
302
|
|
|
205
303
|
// Default import
|
|
@@ -209,7 +307,7 @@ class SemanticEngine {
|
|
|
209
307
|
module: moduleSpecifier,
|
|
210
308
|
defaultImport: defaultImport?.getText(),
|
|
211
309
|
namedImports,
|
|
212
|
-
line: importDecl.
|
|
310
|
+
line: sourceFile.getLineAndColumnAtPos(importDecl.getStart()).line,
|
|
213
311
|
isTypeOnly: importDecl.isTypeOnly(),
|
|
214
312
|
resolvedPath: this.resolveModule(moduleSpecifier, sourceFile)
|
|
215
313
|
});
|
|
@@ -224,7 +322,7 @@ class SemanticEngine {
|
|
|
224
322
|
extractFunctionCalls(sourceFile) {
|
|
225
323
|
const calls = [];
|
|
226
324
|
|
|
227
|
-
sourceFile.getDescendantsOfKind(
|
|
325
|
+
sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(callExpr => {
|
|
228
326
|
const expression = callExpr.getExpression();
|
|
229
327
|
|
|
230
328
|
calls.push({
|
|
@@ -232,10 +330,10 @@ class SemanticEngine {
|
|
|
232
330
|
arguments: callExpr.getArguments().map(arg => ({
|
|
233
331
|
text: arg.getText(),
|
|
234
332
|
type: this.getExpressionType(arg),
|
|
235
|
-
line: arg.
|
|
333
|
+
line: sourceFile.getLineAndColumnAtPos(arg.getStart()).line
|
|
236
334
|
})),
|
|
237
|
-
line: callExpr.
|
|
238
|
-
column: callExpr.
|
|
335
|
+
line: sourceFile.getLineAndColumnAtPos(callExpr.getStart()).line,
|
|
336
|
+
column: sourceFile.getLineAndColumnAtPos(callExpr.getStart()).column,
|
|
239
337
|
|
|
240
338
|
// Detailed analysis for retry patterns
|
|
241
339
|
isRetryPattern: this.isRetryPattern(callExpr),
|
|
@@ -253,7 +351,7 @@ class SemanticEngine {
|
|
|
253
351
|
extractHooks(sourceFile) {
|
|
254
352
|
const hooks = [];
|
|
255
353
|
|
|
256
|
-
sourceFile.getDescendantsOfKind(
|
|
354
|
+
sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(callExpr => {
|
|
257
355
|
const expression = callExpr.getExpression();
|
|
258
356
|
const functionName = expression.getText();
|
|
259
357
|
|
|
@@ -262,7 +360,7 @@ class SemanticEngine {
|
|
|
262
360
|
hooks.push({
|
|
263
361
|
hookName: functionName,
|
|
264
362
|
arguments: callExpr.getArguments().map(arg => arg.getText()),
|
|
265
|
-
line: callExpr.
|
|
363
|
+
line: sourceFile.getLineAndColumnAtPos(callExpr.getStart()).line,
|
|
266
364
|
|
|
267
365
|
// Special analysis for useQuery, useMutation, etc.
|
|
268
366
|
isQueryHook: this.isQueryHook(functionName),
|
package/docs/COMMAND-EXAMPLES.md
CHANGED
|
@@ -113,6 +113,22 @@ node cli.js --all --input=. --timeout=60000 --format=summary --no-ai
|
|
|
113
113
|
# Disable caching
|
|
114
114
|
node cli.js --all --input=. --no-cache --format=summary --no-ai
|
|
115
115
|
|
|
116
|
+
# **Control semantic analysis for large projects**
|
|
117
|
+
# Default limit: 1000 files for performance balance
|
|
118
|
+
node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
119
|
+
|
|
120
|
+
# For small projects: Analyze all files
|
|
121
|
+
node cli.js --all --input=. --max-semantic-files=0 --format=summary
|
|
122
|
+
|
|
123
|
+
# For large projects: Conservative analysis
|
|
124
|
+
node cli.js --all --input=. --max-semantic-files=500 --format=summary
|
|
125
|
+
|
|
126
|
+
# For massive projects: Minimal semantic analysis
|
|
127
|
+
node cli.js --all --input=. --max-semantic-files=100 --format=summary
|
|
128
|
+
|
|
129
|
+
# Unlimited semantic analysis (use with caution!)
|
|
130
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=summary
|
|
131
|
+
|
|
116
132
|
# Verbose logging
|
|
117
133
|
node cli.js --all --input=. --verbose --format=summary --no-ai
|
|
118
134
|
|
|
@@ -203,6 +219,124 @@ node cli.js --all --changed-files --diff-base=origin/main --format=github --no-a
|
|
|
203
219
|
node cli.js --all --changed-files --ai --format=detailed
|
|
204
220
|
```
|
|
205
221
|
|
|
222
|
+
## 🏗️ **Large Project Strategies**
|
|
223
|
+
|
|
224
|
+
> **⚡ Performance Note**: SunLint uses semantic analysis for advanced rules (like C047). For projects with 1000+ files, you can control semantic analysis scope to balance accuracy vs performance.
|
|
225
|
+
|
|
226
|
+
### **Strategy 1: Incremental Analysis** 📈
|
|
227
|
+
```bash
|
|
228
|
+
# Start with changed files only (fastest)
|
|
229
|
+
node cli.js --all --changed-files --format=summary --no-ai
|
|
230
|
+
|
|
231
|
+
# Focus on specific directories
|
|
232
|
+
node cli.js --all --input=src/critical --max-semantic-files=2000 --format=summary
|
|
233
|
+
|
|
234
|
+
# Target important file patterns only
|
|
235
|
+
node cli.js --all --include="src/**/*.ts" --exclude="**/*.test.*,**/*.d.ts" --input=.
|
|
236
|
+
|
|
237
|
+
# Use directory-based analysis
|
|
238
|
+
node cli.js --all --input=src/auth --format=summary # Most critical module first
|
|
239
|
+
node cli.js --all --input=src/api --format=summary # Then API layer
|
|
240
|
+
node cli.js --all --input=src/utils --format=summary # Finally utilities
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### **Strategy 2: Semantic Analysis Tuning** 🔧
|
|
244
|
+
```bash
|
|
245
|
+
# Conservative: 500 files for faster analysis
|
|
246
|
+
node cli.js --all --input=. --max-semantic-files=500 --format=summary
|
|
247
|
+
|
|
248
|
+
# Balanced: 1000 files (default) for medium projects
|
|
249
|
+
node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
250
|
+
|
|
251
|
+
# Comprehensive: 2000+ files for complete analysis
|
|
252
|
+
node cli.js --all --input=. --max-semantic-files=2000 --format=summary
|
|
253
|
+
|
|
254
|
+
# Unlimited: All files (use for final validation)
|
|
255
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=summary
|
|
256
|
+
|
|
257
|
+
# Disable semantic analysis completely (heuristic only)
|
|
258
|
+
node cli.js --all --input=. --max-semantic-files=0 --format=summary
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### **Strategy 3: Rule-Based Prioritization** 🎯
|
|
262
|
+
```bash
|
|
263
|
+
# Phase 1: Critical security issues (fast heuristic rules)
|
|
264
|
+
node cli.js --security --input=. --max-semantic-files=0 --format=summary
|
|
265
|
+
|
|
266
|
+
# Phase 2: Code quality basics
|
|
267
|
+
node cli.js --rules=C006,C019,C029 --input=. --max-semantic-files=500 --format=summary
|
|
268
|
+
|
|
269
|
+
# Phase 3: Advanced semantic rules (targeted)
|
|
270
|
+
node cli.js --rules=C047 --input=src --max-semantic-files=1000 --format=summary
|
|
271
|
+
|
|
272
|
+
# Phase 4: Full comprehensive scan
|
|
273
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=detailed
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### **Strategy 4: CI/CD Optimization** ⚡
|
|
277
|
+
```bash
|
|
278
|
+
# PR checks: Fast semantic analysis
|
|
279
|
+
node cli.js --all --changed-files --max-semantic-files=300 --format=github --no-ai
|
|
280
|
+
|
|
281
|
+
# Nightly builds: Medium semantic analysis
|
|
282
|
+
node cli.js --all --input=. --max-semantic-files=1000 --format=json --output=nightly.json
|
|
283
|
+
|
|
284
|
+
# Weekly reports: Full semantic analysis
|
|
285
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=detailed --output=weekly.json
|
|
286
|
+
|
|
287
|
+
# Release validation: Comprehensive with baselines
|
|
288
|
+
node cli.js --all --input=. --max-semantic-files=2000 --baseline=last-release.json
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### **Strategy 5: Memory & Performance Monitoring** 📊
|
|
292
|
+
```bash
|
|
293
|
+
# Monitor file loading (debug mode)
|
|
294
|
+
node cli.js --all --input=. --max-semantic-files=1000 --verbose --debug
|
|
295
|
+
|
|
296
|
+
# Track performance with different limits
|
|
297
|
+
time node cli.js --all --input=. --max-semantic-files=500 --format=summary
|
|
298
|
+
time node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
299
|
+
time node cli.js --all --input=. --max-semantic-files=2000 --format=summary
|
|
300
|
+
|
|
301
|
+
# Memory-conscious analysis for CI
|
|
302
|
+
node cli.js --all --input=. --max-semantic-files=300 --max-concurrent=2 --format=summary
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### **📋 Recommended Limits by Project Size**
|
|
306
|
+
|
|
307
|
+
| Project Size | Files Count | Recommended Limit | Use Case |
|
|
308
|
+
|-------------|-------------|-------------------|----------|
|
|
309
|
+
| Small | < 100 files | `--max-semantic-files=0` (all) | Complete analysis |
|
|
310
|
+
| Medium | 100-500 files | `--max-semantic-files=500` | Balanced |
|
|
311
|
+
| Large | 500-2000 files | `--max-semantic-files=1000` | Default recommended |
|
|
312
|
+
| Enterprise | 2000-5000 files | `--max-semantic-files=1500` | Conservative |
|
|
313
|
+
| Massive | 5000+ files | `--max-semantic-files=500` | Targeted analysis |
|
|
314
|
+
|
|
315
|
+
> **💡 Pro Tips for Large Projects:**
|
|
316
|
+
> 1. Use `--changed-files` for daily development
|
|
317
|
+
> 2. Use `--max-semantic-files=500` for CI/CD pipelines
|
|
318
|
+
> 3. Use `--max-semantic-files=-1` for release validation
|
|
319
|
+
> 4. Combine with `--include` patterns to focus on critical code
|
|
320
|
+
> 5. Monitor analysis time and adjust limits accordingly
|
|
321
|
+
|
|
322
|
+
### **Example 1: Monorepo with 5000+ Files**
|
|
323
|
+
```bash
|
|
324
|
+
# Daily development: Changed files only
|
|
325
|
+
node cli.js --all --changed-files --max-semantic-files=300 --format=summary
|
|
326
|
+
|
|
327
|
+
# Module-specific analysis
|
|
328
|
+
node cli.js --all --input=packages/core --max-semantic-files=1000 --format=summary
|
|
329
|
+
node cli.js --all --input=packages/api --max-semantic-files=1000 --format=summary
|
|
330
|
+
|
|
331
|
+
# CI pipeline: Conservative semantic analysis
|
|
332
|
+
node cli.js --all --changed-files --max-semantic-files=500 --format=github
|
|
333
|
+
|
|
334
|
+
# Release validation: Full analysis by modules
|
|
335
|
+
for dir in packages/*/; do
|
|
336
|
+
node cli.js --all --input="$dir" --max-semantic-files=2000 --format=json --output="${dir//\//-}-report.json"
|
|
337
|
+
done
|
|
338
|
+
```
|
|
339
|
+
|
|
206
340
|
### **Example 2: Legacy Code Improvement**
|
|
207
341
|
```bash
|
|
208
342
|
# Step 1: Baseline assessment
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# 🏗️ Large Project Analysis Guide
|
|
2
|
+
|
|
3
|
+
> **For projects with 1000+ files**: Complete strategies to optimize SunLint performance while maintaining comprehensive analysis coverage.
|
|
4
|
+
|
|
5
|
+
## 📊 Overview
|
|
6
|
+
|
|
7
|
+
SunLint uses **semantic analysis** for advanced rules like `C047` (retry pattern detection). For large projects, you can control the scope of semantic analysis to balance accuracy vs performance.
|
|
8
|
+
|
|
9
|
+
### 🎯 Key Benefits
|
|
10
|
+
|
|
11
|
+
- **Configurable file limits**: Control memory usage and analysis time
|
|
12
|
+
- **Smart defaults**: Automatic optimization for different project sizes
|
|
13
|
+
- **Multiple strategies**: Choose the best approach for your workflow
|
|
14
|
+
- **Full coverage options**: Ensure no violations are missed
|
|
15
|
+
|
|
16
|
+
## ⚙️ Configuration Options
|
|
17
|
+
|
|
18
|
+
### CLI Option: `--max-semantic-files`
|
|
19
|
+
|
|
20
|
+
Controls how many files are loaded for semantic analysis:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Default behavior (auto-detect)
|
|
24
|
+
node cli.js --all --input=.
|
|
25
|
+
|
|
26
|
+
# Conservative analysis (500 files)
|
|
27
|
+
node cli.js --all --input=. --max-semantic-files=500
|
|
28
|
+
|
|
29
|
+
# Balanced analysis (1000 files - default)
|
|
30
|
+
node cli.js --all --input=. --max-semantic-files=1000
|
|
31
|
+
|
|
32
|
+
# Comprehensive analysis (2000 files)
|
|
33
|
+
node cli.js --all --input=. --max-semantic-files=2000
|
|
34
|
+
|
|
35
|
+
# Unlimited analysis (all files)
|
|
36
|
+
node cli.js --all --input=. --max-semantic-files=-1
|
|
37
|
+
|
|
38
|
+
# Disable semantic analysis (heuristic only)
|
|
39
|
+
node cli.js --all --input=. --max-semantic-files=0
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 📋 Recommended Limits by Project Size
|
|
43
|
+
|
|
44
|
+
| Project Size | Files Count | Recommended Limit | Memory Usage | Analysis Time |
|
|
45
|
+
|-------------|-------------|-------------------|--------------|---------------|
|
|
46
|
+
| **Small** | < 100 files | `0` (all files) | Low | Fast |
|
|
47
|
+
| **Medium** | 100-500 files | `500` | Medium | Medium |
|
|
48
|
+
| **Large** | 500-2000 files | `1000` ⭐ | Medium-High | Medium |
|
|
49
|
+
| **Enterprise** | 2000-5000 files | `1500` | High | Slow |
|
|
50
|
+
| **Massive** | 5000+ files | `500-1000` | Controlled | Reasonable |
|
|
51
|
+
|
|
52
|
+
⭐ **Default recommended setting**
|
|
53
|
+
|
|
54
|
+
## 🚀 Analysis Strategies
|
|
55
|
+
|
|
56
|
+
### Strategy 1: Incremental Development
|
|
57
|
+
|
|
58
|
+
Perfect for daily development work:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Focus on changed files only (fastest)
|
|
62
|
+
node cli.js --all --changed-files --max-semantic-files=300 --format=summary
|
|
63
|
+
|
|
64
|
+
# Target specific modules
|
|
65
|
+
node cli.js --all --input=src/auth --max-semantic-files=1000 --format=summary
|
|
66
|
+
node cli.js --all --input=src/api --max-semantic-files=1000 --format=summary
|
|
67
|
+
|
|
68
|
+
# Use file patterns to focus on critical code
|
|
69
|
+
node cli.js --all --include="src/**/*.ts" --exclude="**/*.test.*" --max-semantic-files=1500
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Strategy 2: CI/CD Pipeline Optimization
|
|
73
|
+
|
|
74
|
+
Optimize for different CI stages:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# PR checks: Fast semantic analysis
|
|
78
|
+
node cli.js --all --changed-files --max-semantic-files=300 --format=github --no-ai
|
|
79
|
+
|
|
80
|
+
# Nightly builds: Medium coverage
|
|
81
|
+
node cli.js --all --input=. --max-semantic-files=1000 --format=json --output=nightly.json
|
|
82
|
+
|
|
83
|
+
# Weekly reports: Comprehensive analysis
|
|
84
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=detailed --output=weekly.json
|
|
85
|
+
|
|
86
|
+
# Release validation: Full coverage with baseline
|
|
87
|
+
node cli.js --all --input=. --max-semantic-files=2000 --baseline=last-release.json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Strategy 3: Rule-Based Prioritization
|
|
91
|
+
|
|
92
|
+
Different limits for different rule types:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Phase 1: Critical security (fast heuristic rules)
|
|
96
|
+
node cli.js --security --input=. --max-semantic-files=0 --format=summary
|
|
97
|
+
|
|
98
|
+
# Phase 2: Code quality basics
|
|
99
|
+
node cli.js --rules=C006,C019,C029 --input=. --max-semantic-files=500 --format=summary
|
|
100
|
+
|
|
101
|
+
# Phase 3: Advanced semantic rules (targeted)
|
|
102
|
+
node cli.js --rules=C047 --input=src --max-semantic-files=1000 --format=summary
|
|
103
|
+
|
|
104
|
+
# Phase 4: Full comprehensive scan
|
|
105
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=detailed
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Strategy 4: Monorepo Management
|
|
109
|
+
|
|
110
|
+
For large monorepos with multiple packages:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Analyze each package separately
|
|
114
|
+
for package in packages/*/; do
|
|
115
|
+
node cli.js --all --input="$package" --max-semantic-files=1000 \
|
|
116
|
+
--format=json --output="${package//\//-}-report.json"
|
|
117
|
+
done
|
|
118
|
+
|
|
119
|
+
# Focus on core packages first
|
|
120
|
+
node cli.js --all --input=packages/core --max-semantic-files=2000 --format=summary
|
|
121
|
+
node cli.js --all --input=packages/api --max-semantic-files=1500 --format=summary
|
|
122
|
+
node cli.js --all --input=packages/ui --max-semantic-files=1000 --format=summary
|
|
123
|
+
|
|
124
|
+
# Changed files across the entire monorepo
|
|
125
|
+
node cli.js --all --changed-files --max-semantic-files=500 --format=summary
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 📈 Performance Monitoring
|
|
129
|
+
|
|
130
|
+
### Memory & Time Tracking
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Monitor performance with different limits
|
|
134
|
+
time node cli.js --all --input=. --max-semantic-files=500 --format=summary
|
|
135
|
+
time node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
136
|
+
time node cli.js --all --input=. --max-semantic-files=2000 --format=summary
|
|
137
|
+
|
|
138
|
+
# Memory-conscious analysis for CI
|
|
139
|
+
node cli.js --all --input=. --max-semantic-files=300 --max-concurrent=2 --format=summary
|
|
140
|
+
|
|
141
|
+
# Debug file loading behavior
|
|
142
|
+
node cli.js --all --input=. --max-semantic-files=1000 --verbose --debug
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Coverage Analysis
|
|
146
|
+
|
|
147
|
+
Check what percentage of your project is being analyzed:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Show file loading statistics
|
|
151
|
+
node cli.js --all --input=. --max-semantic-files=1000 --verbose --format=summary
|
|
152
|
+
|
|
153
|
+
# Compare different limits
|
|
154
|
+
node cli.js --all --input=. --max-semantic-files=500 --verbose --dry-run
|
|
155
|
+
node cli.js --all --input=. --max-semantic-files=1000 --verbose --dry-run
|
|
156
|
+
node cli.js --all --input=. --max-semantic-files=-1 --verbose --dry-run
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 🎛️ Configuration Files
|
|
160
|
+
|
|
161
|
+
### sunlint.config.json
|
|
162
|
+
|
|
163
|
+
Create a configuration file for consistent settings:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"performance": {
|
|
168
|
+
"maxSemanticFiles": 1000,
|
|
169
|
+
"maxConcurrentRules": 5,
|
|
170
|
+
"timeoutMs": 30000
|
|
171
|
+
},
|
|
172
|
+
"input": ["src", "lib"],
|
|
173
|
+
"exclude": [
|
|
174
|
+
"**/*.test.*",
|
|
175
|
+
"**/*.d.ts",
|
|
176
|
+
"**/generated/**"
|
|
177
|
+
],
|
|
178
|
+
"output": {
|
|
179
|
+
"format": "summary"
|
|
180
|
+
},
|
|
181
|
+
"engines": {
|
|
182
|
+
"semantic": {
|
|
183
|
+
"enabled": true,
|
|
184
|
+
"fileLimit": 1000
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Environment-Specific Configs
|
|
191
|
+
|
|
192
|
+
Different configs for different environments:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Development (fast feedback)
|
|
196
|
+
cp config/sunlint.dev.json sunlint.config.json
|
|
197
|
+
node cli.js --all --input=.
|
|
198
|
+
|
|
199
|
+
# CI (balanced coverage)
|
|
200
|
+
cp config/sunlint.ci.json sunlint.config.json
|
|
201
|
+
node cli.js --all --changed-files
|
|
202
|
+
|
|
203
|
+
# Release (comprehensive)
|
|
204
|
+
cp config/sunlint.release.json sunlint.config.json
|
|
205
|
+
node cli.js --all --input=.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 💡 Best Practices
|
|
209
|
+
|
|
210
|
+
### 1. Start Conservative, Scale Up
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Begin with conservative limits
|
|
214
|
+
node cli.js --all --input=. --max-semantic-files=500 --format=summary
|
|
215
|
+
|
|
216
|
+
# Gradually increase if performance allows
|
|
217
|
+
node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
218
|
+
node cli.js --all --input=. --max-semantic-files=1500 --format=summary
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 2. Use Different Limits for Different Contexts
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Daily development: Focus on changed files
|
|
225
|
+
alias sunlint-dev="node cli.js --all --changed-files --max-semantic-files=300"
|
|
226
|
+
|
|
227
|
+
# Code review: Medium coverage
|
|
228
|
+
alias sunlint-review="node cli.js --all --changed-files --max-semantic-files=500"
|
|
229
|
+
|
|
230
|
+
# Release preparation: Full coverage
|
|
231
|
+
alias sunlint-release="node cli.js --all --input=. --max-semantic-files=-1"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 3. Monitor and Adjust
|
|
235
|
+
|
|
236
|
+
Track your analysis performance over time:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Create performance baseline
|
|
240
|
+
echo "Project size: $(find . -name '*.ts' -o -name '*.js' | wc -l) files"
|
|
241
|
+
time node cli.js --all --input=. --max-semantic-files=1000 --format=summary
|
|
242
|
+
|
|
243
|
+
# Adjust based on CI constraints
|
|
244
|
+
if [[ $CI_MEMORY_LIMIT -lt 4096 ]]; then
|
|
245
|
+
SEMANTIC_LIMIT=500
|
|
246
|
+
else
|
|
247
|
+
SEMANTIC_LIMIT=1000
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
node cli.js --all --input=. --max-semantic-files=$SEMANTIC_LIMIT --format=summary
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 4. Combine with File Targeting
|
|
254
|
+
|
|
255
|
+
Use semantic limits together with file patterns:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Focus semantic analysis on source files only
|
|
259
|
+
node cli.js --all --include="src/**/*.ts" --exclude="**/*.test.*" --max-semantic-files=1500
|
|
260
|
+
|
|
261
|
+
# Analyze tests separately with lower limits
|
|
262
|
+
node cli.js --all --include="**/*.test.*" --max-semantic-files=500
|
|
263
|
+
|
|
264
|
+
# Target critical modules with higher limits
|
|
265
|
+
node cli.js --all --input=src/security --max-semantic-files=2000
|
|
266
|
+
node cli.js --all --input=src/api --max-semantic-files=1500
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 🔍 Troubleshooting
|
|
270
|
+
|
|
271
|
+
### Memory Issues
|
|
272
|
+
|
|
273
|
+
If you encounter out-of-memory errors:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Reduce semantic file limit
|
|
277
|
+
node cli.js --all --input=. --max-semantic-files=500
|
|
278
|
+
|
|
279
|
+
# Disable semantic analysis completely
|
|
280
|
+
node cli.js --all --input=. --max-semantic-files=0
|
|
281
|
+
|
|
282
|
+
# Reduce concurrent rules
|
|
283
|
+
node cli.js --all --input=. --max-semantic-files=1000 --max-concurrent=2
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Slow Analysis
|
|
287
|
+
|
|
288
|
+
If analysis takes too long:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Use incremental analysis
|
|
292
|
+
node cli.js --all --changed-files --max-semantic-files=300
|
|
293
|
+
|
|
294
|
+
# Focus on specific directories
|
|
295
|
+
node cli.js --all --input=src/critical --max-semantic-files=1000
|
|
296
|
+
|
|
297
|
+
# Use timeout limits
|
|
298
|
+
node cli.js --all --input=. --max-semantic-files=1000 --timeout=60000
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Missed Violations
|
|
302
|
+
|
|
303
|
+
If you suspect violations are being missed:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Run comprehensive analysis periodically
|
|
307
|
+
node cli.js --all --input=. --max-semantic-files=-1 --format=detailed
|
|
308
|
+
|
|
309
|
+
# Compare different limits
|
|
310
|
+
node cli.js --all --input=. --max-semantic-files=1000 --output=report-1k.json
|
|
311
|
+
node cli.js --all --input=. --max-semantic-files=-1 --output=report-full.json
|
|
312
|
+
diff report-1k.json report-full.json
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## 📚 Related Documentation
|
|
316
|
+
|
|
317
|
+
- [Command Examples](./COMMAND-EXAMPLES.md) - Complete CLI usage examples
|
|
318
|
+
- [Configuration Guide](./CONFIGURATION.md) - Detailed configuration options
|
|
319
|
+
- [CI/CD Guide](./CI-CD-GUIDE.md) - Integration with CI/CD pipelines
|
|
320
|
+
- [Architecture](./ARCHITECTURE.md) - Technical implementation details
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
**💡 Pro Tip**: For projects with 2000+ files, consider breaking analysis into modules and running them in parallel, rather than analyzing everything at once.
|