@sun-asterisk/sunlint 1.3.2 → 1.3.4
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 +73 -0
- package/README.md +5 -3
- package/config/rules/enhanced-rules-registry.json +144 -33
- package/core/analysis-orchestrator.js +173 -42
- package/core/auto-performance-manager.js +243 -0
- package/core/cli-action-handler.js +24 -2
- package/core/cli-program.js +19 -5
- package/core/constants/defaults.js +56 -0
- package/core/performance-optimizer.js +271 -0
- package/docs/FILE_LIMITS_COMPLETION_REPORT.md +151 -0
- package/docs/FILE_LIMITS_EXPLANATION.md +190 -0
- package/docs/PERFORMANCE.md +311 -0
- package/docs/PERFORMANCE_MIGRATION_GUIDE.md +368 -0
- package/docs/PERFORMANCE_OPTIMIZATION_PLAN.md +255 -0
- package/docs/QUICK_FILE_LIMITS.md +64 -0
- package/docs/SIMPLIFIED_USAGE_GUIDE.md +208 -0
- package/engines/engine-factory.js +7 -0
- package/engines/heuristic-engine.js +182 -5
- package/package.json +2 -1
- package/rules/common/C048_no_bypass_architectural_layers/analyzer.js +180 -0
- package/rules/common/C048_no_bypass_architectural_layers/config.json +50 -0
- package/rules/common/C048_no_bypass_architectural_layers/symbol-based-analyzer.js +235 -0
- package/rules/common/C052_parsing_or_data_transformation/analyzer.js +180 -0
- package/rules/common/C052_parsing_or_data_transformation/config.json +50 -0
- package/rules/common/C052_parsing_or_data_transformation/symbol-based-analyzer.js +132 -0
- package/rules/index.js +2 -0
- package/rules/security/S017_use_parameterized_queries/README.md +128 -0
- package/rules/security/S017_use_parameterized_queries/analyzer.js +286 -0
- package/rules/security/S017_use_parameterized_queries/config.json +109 -0
- package/rules/security/S017_use_parameterized_queries/regex-based-analyzer.js +541 -0
- package/rules/security/S017_use_parameterized_queries/symbol-based-analyzer.js +777 -0
- package/rules/security/S031_secure_session_cookies/README.md +127 -0
- package/rules/security/S031_secure_session_cookies/analyzer.js +245 -0
- package/rules/security/S031_secure_session_cookies/config.json +86 -0
- package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +196 -0
- package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +1084 -0
- package/rules/security/S032_httponly_session_cookies/FRAMEWORK_SUPPORT.md +209 -0
- package/rules/security/S032_httponly_session_cookies/README.md +184 -0
- package/rules/security/S032_httponly_session_cookies/analyzer.js +282 -0
- package/rules/security/S032_httponly_session_cookies/config.json +96 -0
- package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +715 -0
- package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +1348 -0
- package/rules/security/S033_samesite_session_cookies/README.md +227 -0
- package/rules/security/S033_samesite_session_cookies/analyzer.js +242 -0
- package/rules/security/S033_samesite_session_cookies/config.json +87 -0
- package/rules/security/S033_samesite_session_cookies/regex-based-analyzer.js +703 -0
- package/rules/security/S033_samesite_session_cookies/symbol-based-analyzer.js +732 -0
- package/rules/security/S034_host_prefix_session_cookies/README.md +204 -0
- package/rules/security/S034_host_prefix_session_cookies/analyzer.js +290 -0
- package/rules/security/S034_host_prefix_session_cookies/config.json +62 -0
- package/rules/security/S034_host_prefix_session_cookies/regex-based-analyzer.js +478 -0
- package/rules/security/S034_host_prefix_session_cookies/symbol-based-analyzer.js +277 -0
- package/rules/security/S035_path_session_cookies/README.md +257 -0
- package/rules/security/S035_path_session_cookies/analyzer.js +316 -0
- package/rules/security/S035_path_session_cookies/config.json +99 -0
- package/rules/security/S035_path_session_cookies/regex-based-analyzer.js +724 -0
- package/rules/security/S035_path_session_cookies/symbol-based-analyzer.js +373 -0
- package/scripts/batch-processing-demo.js +334 -0
- package/scripts/performance-test.js +541 -0
- package/scripts/quick-performance-test.js +108 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## � **v1.3.4 - Engine Auto Hotfix (September 5, 2025)**
|
|
6
|
+
|
|
7
|
+
**Release Date**: September 5, 2025
|
|
8
|
+
**Type**: Critical Hotfix
|
|
9
|
+
|
|
10
|
+
### 🚨 **Critical Bug Fix**
|
|
11
|
+
- **FIXED**: Engine "auto" validation and selection logic
|
|
12
|
+
- **Issue**: `--engine=auto` causing "Invalid engine: auto" error in v1.3.3
|
|
13
|
+
- **Root Cause**: Missing auto engine support in validation and orchestrator
|
|
14
|
+
- **Solution**: Comprehensive auto engine implementation
|
|
15
|
+
- Added "auto" case to engine factory with heuristic fallback
|
|
16
|
+
- Updated CLI validation to include "auto" in valid engines
|
|
17
|
+
- Enhanced orchestrator to resolve "auto" to actual engines (heuristic + eslint)
|
|
18
|
+
- Fixed CLI action handler auto-detection logic
|
|
19
|
+
|
|
20
|
+
### 🧪 **Validation Results**
|
|
21
|
+
- **✅ Auto engine**: Works correctly (auto-selects heuristic + eslint)
|
|
22
|
+
- **✅ Heuristic engine**: Unchanged, working properly
|
|
23
|
+
- **✅ ESLint engine**: Unchanged, working properly
|
|
24
|
+
- **✅ CLI help**: Shows all engines including auto option
|
|
25
|
+
|
|
26
|
+
### 📦 **Upgrade Notes**
|
|
27
|
+
- **Zero breaking changes** - seamless upgrade from v1.3.3
|
|
28
|
+
- **Default `--engine=auto`** now works as intended
|
|
29
|
+
- **All existing commands** continue to work unchanged
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## �🚀 **v1.3.3 - Performance & File Limits Optimization (September 4, 2025)**
|
|
34
|
+
|
|
35
|
+
**Release Date**: September 4, 2025
|
|
36
|
+
**Type**: Performance Enhancement & User Experience
|
|
37
|
+
|
|
38
|
+
### ⚡ **Performance Engineering**
|
|
39
|
+
- **ENHANCED**: Heuristic Engine v4.0 with integrated performance optimizations
|
|
40
|
+
- **Smart file limits**: Auto-detection prevents memory issues
|
|
41
|
+
- **Batch processing**: Optimized rule execution for large projects
|
|
42
|
+
- **Memory management**: Symbol table limits for TypeScript projects
|
|
43
|
+
- **Timeout protection**: Graceful handling of long-running analysis
|
|
44
|
+
|
|
45
|
+
### 🎛️ **CLI Enhancement & Clarity**
|
|
46
|
+
- **CLARIFIED**: File limit options with comprehensive documentation
|
|
47
|
+
- **`--max-files`**: Controls total analysis workload (performance)
|
|
48
|
+
- **`--max-semantic-files`**: Controls TypeScript symbol table memory
|
|
49
|
+
- **Auto-detection**: Smart defaults for 90% of use cases
|
|
50
|
+
- **Manual tuning**: Fine control for enterprise projects
|
|
51
|
+
|
|
52
|
+
### � **Bug Fixes**
|
|
53
|
+
- **FIXED**: Engine "auto" validation and selection logic
|
|
54
|
+
- **Engine Factory**: Added "auto" case with fallback to heuristic engine
|
|
55
|
+
- **CLI Validation**: Added "auto" to valid engines list
|
|
56
|
+
- **Orchestrator**: Auto-resolve "auto" to actual engines (heuristic + eslint)
|
|
57
|
+
- **Engine Selection**: Auto-detection works correctly for rule preferences
|
|
58
|
+
|
|
59
|
+
### �📚 **Documentation Expansion**
|
|
60
|
+
- **NEW**: [FILE_LIMITS_EXPLANATION.md](./docs/FILE_LIMITS_EXPLANATION.md) - Comprehensive guide (5.7KB)
|
|
61
|
+
- **NEW**: [QUICK_FILE_LIMITS.md](./docs/QUICK_FILE_LIMITS.md) - Quick reference (1.8KB)
|
|
62
|
+
- **ENHANCED**: CLI help with clear usage examples
|
|
63
|
+
- **INTEGRATED**: Performance docs in README.md
|
|
64
|
+
|
|
65
|
+
### 🧠 **Architecture Improvements**
|
|
66
|
+
- **INTEGRATED**: Performance logic into heuristic engine (no separate files)
|
|
67
|
+
- **ENHANCED**: Auto-performance-manager for intelligent limit calculation
|
|
68
|
+
- **OPTIMIZED**: Memory usage patterns for large codebases
|
|
69
|
+
- **TESTED**: GitHub Actions compatibility with resource constraints
|
|
70
|
+
|
|
71
|
+
### 🎯 **User Experience**
|
|
72
|
+
- **90/10 Rule**: Auto-detection works for most cases, manual tuning available
|
|
73
|
+
- **Progressive disclosure**: Quick ref → detailed guide → implementation details
|
|
74
|
+
- **CI/CD Ready**: Optimized for memory-constrained environments
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
5
78
|
## 🏆 **v1.3.2 - Precision Engineering & Rule Maturity (August 21, 2025)**
|
|
6
79
|
|
|
7
80
|
**Release Date**: August 21, 2025
|
package/README.md
CHANGED
|
@@ -9,12 +9,13 @@ Sun Lint is a universal coding standards checker providing comprehensive code qu
|
|
|
9
9
|
### **✨ Key Features**
|
|
10
10
|
- ✅ **256+ Coding Rules**: Quality (161), Security (70), Performance (25)
|
|
11
11
|
- ✅ **Unified Architecture**: Same adapter pattern for CLI and VSCode extension
|
|
12
|
-
- ✅ **Multi-Engine Support**: Heuristic (244 rules) + ESLint (17 rules) + AI (256 rules)
|
|
12
|
+
- ✅ **Multi-Engine Support**: Heuristic v4.0 (244 rules) + ESLint (17 rules) + AI (256 rules)
|
|
13
|
+
- ✅ **Performance Optimized**: Auto file limits, memory management, GitHub Actions ready
|
|
13
14
|
- ✅ **Built-in AST Analysis**: JavaScript/TypeScript parsing out of the box
|
|
14
15
|
- ✅ **Git Integration**: `--changed-files`, `--staged-files`, `--pr-mode`
|
|
15
|
-
- ✅ **TypeScript Support**: Native TypeScript 5.8+ analysis
|
|
16
|
+
- ✅ **TypeScript Support**: Native TypeScript 5.8+ analysis with smart memory limits
|
|
16
17
|
- ✅ **Zero Config**: Works immediately after `npm install`
|
|
17
|
-
- ✅ **CI/CD Ready**: Baseline comparison, fail-on-new-violations
|
|
18
|
+
- ✅ **CI/CD Ready**: Baseline comparison, fail-on-new-violations, timeout protection
|
|
18
19
|
- ✅ **Advanced File Targeting**: Include/exclude patterns, language filtering
|
|
19
20
|
|
|
20
21
|
### **🏗️ Architecture**
|
|
@@ -376,6 +377,7 @@ sunlint --validate-config .sunlint.json
|
|
|
376
377
|
## 📚 **Documentation**
|
|
377
378
|
|
|
378
379
|
- **[Configuration Guide](./docs/CONFIGURATION.md)** - Complete config options with examples
|
|
380
|
+
- **[Performance & File Limits](./docs/FILE_LIMITS_EXPLANATION.md)** - Understanding `--max-files` vs `--max-semantic-files`
|
|
379
381
|
- [ESLint Integration Guide](./docs/ESLINT_INTEGRATION.md)
|
|
380
382
|
- [CI/CD Guide](./docs/CI-CD-GUIDE.md)
|
|
381
383
|
- [Architecture](./docs/ARCHITECTURE.md)
|
|
@@ -27,14 +27,8 @@
|
|
|
27
27
|
"status": "stable",
|
|
28
28
|
"tags": ["logging", "error-handling", "severity"],
|
|
29
29
|
"engineMappings": {
|
|
30
|
-
"eslint": [
|
|
31
|
-
|
|
32
|
-
"no-alert",
|
|
33
|
-
"no-debugger"
|
|
34
|
-
],
|
|
35
|
-
"heuristic": [
|
|
36
|
-
"rules/common/C019_log_level_usage/analyzer.js"
|
|
37
|
-
]
|
|
30
|
+
"eslint": ["no-console", "no-alert", "no-debugger"],
|
|
31
|
+
"heuristic": ["rules/common/C019_log_level_usage/analyzer.js"]
|
|
38
32
|
}
|
|
39
33
|
},
|
|
40
34
|
"C006": {
|
|
@@ -635,8 +629,8 @@
|
|
|
635
629
|
"category": "security",
|
|
636
630
|
"severity": "error",
|
|
637
631
|
"languages": ["typescript", "javascript"],
|
|
638
|
-
"analyzer": "
|
|
639
|
-
"
|
|
632
|
+
"analyzer": "./rules/security/S017_use_parameterized_queries/analyzer.js",
|
|
633
|
+
"config": "./rules/security/S017_use_parameterized_queries/config.json",
|
|
640
634
|
"version": "1.0.0",
|
|
641
635
|
"status": "stable",
|
|
642
636
|
"tags": ["security", "sql-injection", "database"]
|
|
@@ -769,41 +763,122 @@
|
|
|
769
763
|
"status": "stable",
|
|
770
764
|
"tags": ["security", "directory-browsing", "information-disclosure"]
|
|
771
765
|
},
|
|
766
|
+
"S031": {
|
|
767
|
+
"name": "Set Secure flag for Session Cookies",
|
|
768
|
+
"description": "Set Secure flag for Session Cookies to protect via HTTPS. This ensures cookies are only transmitted over secure connections, preventing interception.",
|
|
769
|
+
"category": "security",
|
|
770
|
+
"severity": "error",
|
|
771
|
+
"languages": ["typescript", "javascript"],
|
|
772
|
+
"analyzer": "./rules/security/S031_secure_session_cookies/analyzer.js",
|
|
773
|
+
"config": "./rules/security/S031_secure_session_cookies/config.json",
|
|
774
|
+
"version": "1.0.0",
|
|
775
|
+
"status": "stable",
|
|
776
|
+
"tags": ["security", "cookies", "session", "https", "secure"],
|
|
777
|
+
"strategy": {
|
|
778
|
+
"preferred": "ast",
|
|
779
|
+
"fallbacks": ["ast", "regex"],
|
|
780
|
+
"accuracy": {
|
|
781
|
+
"ast": 95,
|
|
782
|
+
"regex": 85
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
"engineMappings": {
|
|
786
|
+
"heuristic": ["rules/security/S031_secure_session_cookies/analyzer.js"]
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
"S032": {
|
|
790
|
+
"name": "Set HttpOnly attribute for Session Cookies",
|
|
791
|
+
"description": "Set HttpOnly attribute for Session Cookies to prevent JavaScript access. This protects against XSS attacks by preventing client-side script access to sensitive cookies.",
|
|
792
|
+
"category": "security",
|
|
793
|
+
"severity": "error",
|
|
794
|
+
"languages": ["typescript", "javascript"],
|
|
795
|
+
"analyzer": "./rules/security/S032_httponly_session_cookies/analyzer.js",
|
|
796
|
+
"config": "./rules/security/S032_httponly_session_cookies/config.json",
|
|
797
|
+
"version": "1.0.0",
|
|
798
|
+
"status": "stable",
|
|
799
|
+
"tags": ["security", "cookies", "session", "httponly", "xss"],
|
|
800
|
+
"strategy": {
|
|
801
|
+
"preferred": "ast",
|
|
802
|
+
"fallbacks": ["ast", "regex"],
|
|
803
|
+
"accuracy": {
|
|
804
|
+
"ast": 95,
|
|
805
|
+
"regex": 85
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
"engineMappings": {
|
|
809
|
+
"heuristic": [
|
|
810
|
+
"rules/security/S032_httponly_session_cookies/analyzer.js"
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
},
|
|
772
814
|
"S033": {
|
|
773
|
-
"name": "
|
|
774
|
-
"description": "
|
|
815
|
+
"name": "Set SameSite attribute for Session Cookies",
|
|
816
|
+
"description": "Set SameSite attribute for Session Cookies to reduce CSRF risk. This prevents the browser from sending cookies along with cross-site requests, mitigating CSRF attacks.",
|
|
775
817
|
"category": "security",
|
|
776
818
|
"severity": "error",
|
|
777
819
|
"languages": ["typescript", "javascript"],
|
|
778
|
-
"analyzer": "
|
|
779
|
-
"
|
|
820
|
+
"analyzer": "./rules/security/S033_samesite_session_cookies/analyzer.js",
|
|
821
|
+
"config": "./rules/security/S033_samesite_session_cookies/config.json",
|
|
780
822
|
"version": "1.0.0",
|
|
781
823
|
"status": "stable",
|
|
782
|
-
"tags": ["security", "cookies", "samesite"]
|
|
824
|
+
"tags": ["security", "cookies", "session", "samesite", "csrf"],
|
|
825
|
+
"strategy": {
|
|
826
|
+
"preferred": "ast",
|
|
827
|
+
"fallbacks": ["ast", "regex"],
|
|
828
|
+
"accuracy": {
|
|
829
|
+
"ast": 95,
|
|
830
|
+
"regex": 85
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
"engineMappings": {
|
|
834
|
+
"heuristic": [
|
|
835
|
+
"rules/security/S033_samesite_session_cookies/analyzer.js"
|
|
836
|
+
]
|
|
837
|
+
}
|
|
783
838
|
},
|
|
784
839
|
"S034": {
|
|
785
|
-
"name": "
|
|
786
|
-
"description": "
|
|
840
|
+
"name": "Use __Host- prefix for Session Cookies",
|
|
841
|
+
"description": "Use __Host- prefix for Session Cookies to prevent subdomain sharing. The __Host- prefix ensures cookies are only sent to the exact domain that set them, preventing subdomain cookie sharing attacks.",
|
|
787
842
|
"category": "security",
|
|
788
|
-
"severity": "
|
|
843
|
+
"severity": "warning",
|
|
789
844
|
"languages": ["typescript", "javascript"],
|
|
790
|
-
"analyzer": "
|
|
791
|
-
"
|
|
845
|
+
"analyzer": "./rules/security/S034_host_prefix_session_cookies/analyzer.js",
|
|
846
|
+
"config": "./rules/security/S034_host_prefix_session_cookies/config.json",
|
|
792
847
|
"version": "1.0.0",
|
|
793
848
|
"status": "stable",
|
|
794
|
-
"tags": ["security", "cookies", "host-prefix"]
|
|
849
|
+
"tags": ["security", "cookies", "session", "host-prefix", "subdomain"],
|
|
850
|
+
"strategy": {
|
|
851
|
+
"preferred": "ast",
|
|
852
|
+
"fallbacks": ["ast", "regex"],
|
|
853
|
+
"accuracy": {
|
|
854
|
+
"ast": 95,
|
|
855
|
+
"regex": 85
|
|
856
|
+
}
|
|
857
|
+
},
|
|
858
|
+
"engineMappings": {
|
|
859
|
+
"heuristic": [
|
|
860
|
+
"rules/security/S034_host_prefix_session_cookies/analyzer.js"
|
|
861
|
+
]
|
|
862
|
+
}
|
|
795
863
|
},
|
|
796
864
|
"S035": {
|
|
797
|
-
"name": "
|
|
798
|
-
"description": "
|
|
865
|
+
"name": "Set Path attribute for Session Cookies",
|
|
866
|
+
"description": "Set Path attribute for Session Cookies to limit access scope",
|
|
799
867
|
"category": "security",
|
|
800
|
-
"severity": "
|
|
868
|
+
"severity": "warning",
|
|
801
869
|
"languages": ["typescript", "javascript"],
|
|
802
|
-
"analyzer": "
|
|
803
|
-
"eslintRule": "custom/typescript_s035",
|
|
870
|
+
"analyzer": "heuristic",
|
|
804
871
|
"version": "1.0.0",
|
|
805
872
|
"status": "stable",
|
|
806
|
-
"tags": ["security", "cookies", "path"]
|
|
873
|
+
"tags": ["security", "cookies", "path"],
|
|
874
|
+
"strategy": {
|
|
875
|
+
"defaultEngine": "heuristic",
|
|
876
|
+
"engineMappings": {
|
|
877
|
+
"heuristic": ["rules/security/S035_path_session_cookies/analyzer.js"]
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
"configPath": "rules/security/S035_path_session_cookies/config.json",
|
|
881
|
+
"analyzerPath": ["rules/security/S035_path_session_cookies/analyzer.js"]
|
|
807
882
|
},
|
|
808
883
|
"S036": {
|
|
809
884
|
"name": "No Unsafe File Include",
|
|
@@ -1196,6 +1271,36 @@
|
|
|
1196
1271
|
"accuracy": {}
|
|
1197
1272
|
}
|
|
1198
1273
|
},
|
|
1274
|
+
"C048": {
|
|
1275
|
+
"name": "Do not bypass architectural layers (controller/service/repository)",
|
|
1276
|
+
"description": "Maintain a clear layered architecture, ensuring logic and data flow are well-structured and maintainable.",
|
|
1277
|
+
"category": "naming",
|
|
1278
|
+
"severity": "warning",
|
|
1279
|
+
"languages": ["typescript", "javascript", "dart", "kotlin"],
|
|
1280
|
+
"analyzer": "./rules/common/C048_no_bypass_architectural_layers/analyzer.js",
|
|
1281
|
+
"config": "./rules/common/C048_no_bypass_architectural_layers/config.json",
|
|
1282
|
+
"version": "1.0.0",
|
|
1283
|
+
"status": "stable",
|
|
1284
|
+
"tags": ["naming", "domain", "readability"],
|
|
1285
|
+
"engineMappings": {
|
|
1286
|
+
"eslint": ["@typescript-eslint/naming-convention", "camelcase"]
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
"C052": {
|
|
1290
|
+
"name": "Parsing or data transformation logic must be separated from controllers",
|
|
1291
|
+
"description": "Enforce separation of concerns — controllers should only handle requests and delegate processing, improving testability, maintainability, and reuse.",
|
|
1292
|
+
"category": "naming",
|
|
1293
|
+
"severity": "warning",
|
|
1294
|
+
"languages": ["typescript", "javascript", "dart", "kotlin"],
|
|
1295
|
+
"analyzer": "./rules/common/C052_parsing_or_data_transformation/analyzer.js",
|
|
1296
|
+
"config": "./rules/common/C052_parsing_or_data_transformation/config.json",
|
|
1297
|
+
"version": "1.0.0",
|
|
1298
|
+
"status": "stable",
|
|
1299
|
+
"tags": ["naming", "domain", "readability"],
|
|
1300
|
+
"engineMappings": {
|
|
1301
|
+
"eslint": ["@typescript-eslint/naming-convention", "camelcase"]
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1199
1304
|
"C072": {
|
|
1200
1305
|
"id": "C072",
|
|
1201
1306
|
"name": "Single Test Behavior",
|
|
@@ -1612,6 +1717,7 @@
|
|
|
1612
1717
|
"C017",
|
|
1613
1718
|
"C018",
|
|
1614
1719
|
"C023",
|
|
1720
|
+
"C024",
|
|
1615
1721
|
"C029",
|
|
1616
1722
|
"C030",
|
|
1617
1723
|
"C035",
|
|
@@ -1619,6 +1725,8 @@
|
|
|
1619
1725
|
"C042",
|
|
1620
1726
|
"C043",
|
|
1621
1727
|
"C047",
|
|
1728
|
+
"C048",
|
|
1729
|
+
"C052",
|
|
1622
1730
|
"C072",
|
|
1623
1731
|
"C075",
|
|
1624
1732
|
"T002",
|
|
@@ -1668,6 +1776,8 @@
|
|
|
1668
1776
|
"S027",
|
|
1669
1777
|
"S029",
|
|
1670
1778
|
"S030",
|
|
1779
|
+
"S031",
|
|
1780
|
+
"S032",
|
|
1671
1781
|
"S033",
|
|
1672
1782
|
"S034",
|
|
1673
1783
|
"S035",
|
|
@@ -1777,12 +1887,12 @@
|
|
|
1777
1887
|
}
|
|
1778
1888
|
},
|
|
1779
1889
|
"metadata": {
|
|
1780
|
-
"version": "1.1.
|
|
1781
|
-
"lastUpdated": "2025-08-
|
|
1782
|
-
"totalRules":
|
|
1890
|
+
"version": "1.1.7",
|
|
1891
|
+
"lastUpdated": "2025-08-25",
|
|
1892
|
+
"totalRules": 97,
|
|
1783
1893
|
"qualityRules": 33,
|
|
1784
|
-
"securityRules":
|
|
1785
|
-
"stableRules":
|
|
1894
|
+
"securityRules": 49,
|
|
1895
|
+
"stableRules": 45,
|
|
1786
1896
|
"experimentalRules": 1,
|
|
1787
1897
|
"supportedLanguages": 4,
|
|
1788
1898
|
"features": [
|
|
@@ -1791,7 +1901,8 @@
|
|
|
1791
1901
|
"Dynamic rule configuration",
|
|
1792
1902
|
"ESLint 9.x integration",
|
|
1793
1903
|
"React rules integration",
|
|
1794
|
-
"Memory leak fixes"
|
|
1904
|
+
"Memory leak fixes",
|
|
1905
|
+
"S032 HttpOnly session cookies"
|
|
1795
1906
|
],
|
|
1796
1907
|
"consolidatedFrom": "/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint/config/rules/rules-registry.json"
|
|
1797
1908
|
}
|
|
@@ -10,6 +10,7 @@ const path = require('path');
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const AnalysisEngineInterface = require('./interfaces/analysis-engine.interface');
|
|
12
12
|
const SunlintRuleAdapter = require('./adapters/sunlint-rule-adapter');
|
|
13
|
+
const PerformanceOptimizer = require('./performance-optimizer');
|
|
13
14
|
|
|
14
15
|
class AnalysisOrchestrator {
|
|
15
16
|
constructor() {
|
|
@@ -18,6 +19,7 @@ class AnalysisOrchestrator {
|
|
|
18
19
|
this.defaultTimeout = 30000; // 30 seconds default timeout
|
|
19
20
|
this.ruleAdapter = SunlintRuleAdapter.getInstance();
|
|
20
21
|
this.enginesConfigPath = path.join(__dirname, '..', 'config', 'engines', 'engines.json');
|
|
22
|
+
this.performanceOptimizer = new PerformanceOptimizer();
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -171,14 +173,35 @@ class AnalysisOrchestrator {
|
|
|
171
173
|
throw new Error('No analysis engines registered');
|
|
172
174
|
}
|
|
173
175
|
|
|
176
|
+
// Initialize performance optimizer
|
|
177
|
+
await this.performanceOptimizer.initialize(config);
|
|
178
|
+
|
|
179
|
+
// Apply performance optimizations to files and rules
|
|
180
|
+
const { optimizedFiles, optimizedRules, performanceMetrics } =
|
|
181
|
+
await this.performanceOptimizer.optimizeAnalysis(
|
|
182
|
+
options.files || [options.input],
|
|
183
|
+
rulesToRun,
|
|
184
|
+
config
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (!options.quiet) {
|
|
188
|
+
console.log(chalk.cyan(`🔍 Analyzing ${optimizedRules.length} rules on ${optimizedFiles.length} files...`));
|
|
189
|
+
if (performanceMetrics.filteredFiles > 0) {
|
|
190
|
+
console.log(chalk.gray(` 📦 Filtered ${performanceMetrics.filteredFiles} files for performance`));
|
|
191
|
+
}
|
|
192
|
+
if (performanceMetrics.ruleBatches > 1) {
|
|
193
|
+
console.log(chalk.gray(` 🔄 Using ${performanceMetrics.ruleBatches} rule batches`));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
174
197
|
// Group rules by their preferred engines
|
|
175
|
-
const engineGroups = this.groupRulesByEngine(
|
|
198
|
+
const engineGroups = this.groupRulesByEngine(optimizedRules, config);
|
|
176
199
|
|
|
177
200
|
if (!options.quiet) {
|
|
178
|
-
console.log(chalk.cyan(
|
|
201
|
+
console.log(chalk.cyan(`🚀 Running analysis across ${engineGroups.size} engines...`));
|
|
179
202
|
}
|
|
180
203
|
|
|
181
|
-
// Run analysis on each engine
|
|
204
|
+
// Run analysis on each engine with batching
|
|
182
205
|
const results = [];
|
|
183
206
|
for (const [engineName, rules] of engineGroups) {
|
|
184
207
|
const engine = this.engines.get(engineName);
|
|
@@ -187,35 +210,64 @@ class AnalysisOrchestrator {
|
|
|
187
210
|
continue;
|
|
188
211
|
}
|
|
189
212
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
engine,
|
|
197
|
-
options.files || [options.input],
|
|
198
|
-
rules,
|
|
199
|
-
options
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
results.push({
|
|
203
|
-
engine: engineName,
|
|
204
|
-
rules: rules.map(r => r.id),
|
|
205
|
-
...engineResult
|
|
206
|
-
});
|
|
213
|
+
// Process rules in batches for performance
|
|
214
|
+
const ruleBatches = this.performanceOptimizer.createRuleBatches(rules, config);
|
|
215
|
+
|
|
216
|
+
for (let i = 0; i < ruleBatches.length; i++) {
|
|
217
|
+
const batch = ruleBatches[i];
|
|
218
|
+
const batchNumber = i + 1;
|
|
207
219
|
|
|
208
|
-
if (!options.quiet) {
|
|
209
|
-
|
|
210
|
-
|
|
220
|
+
if (!options.quiet && ruleBatches.length > 1) {
|
|
221
|
+
console.log(chalk.blue(`⚙️ ${engineName} - Batch ${batchNumber}/${ruleBatches.length}: ${batch.length} rules`));
|
|
222
|
+
} else if (!options.quiet) {
|
|
223
|
+
console.log(chalk.blue(`⚙️ Running ${batch.length} rules on ${engineName} engine...`));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const engineResult = await this.runEngineWithOptimizations(
|
|
228
|
+
engine,
|
|
229
|
+
optimizedFiles,
|
|
230
|
+
batch,
|
|
231
|
+
options,
|
|
232
|
+
{ batchNumber, totalBatches: ruleBatches.length }
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
results.push({
|
|
236
|
+
engine: engineName,
|
|
237
|
+
batch: batchNumber,
|
|
238
|
+
rules: batch.map(r => r.id),
|
|
239
|
+
...engineResult
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (!options.quiet) {
|
|
243
|
+
const violationCount = this.countViolations(engineResult);
|
|
244
|
+
console.log(chalk.blue(`✅ ${engineName} batch ${batchNumber}: ${violationCount} violations found`));
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
// Enhanced error recovery with batch context
|
|
248
|
+
const errorInfo = this.performanceOptimizer.handleAnalysisError(error, {
|
|
249
|
+
engine: engineName,
|
|
250
|
+
batch: batchNumber,
|
|
251
|
+
rules: batch.map(r => r.id),
|
|
252
|
+
files: optimizedFiles.length
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
console.error(chalk.red(`❌ Engine ${engineName} batch ${batchNumber} failed:`), errorInfo.message);
|
|
256
|
+
|
|
257
|
+
if (errorInfo.shouldRetry && !options.noRetry) {
|
|
258
|
+
console.log(chalk.yellow(`🔄 Retrying with reduced batch size...`));
|
|
259
|
+
// Split batch and retry - implement recursive retry logic here
|
|
260
|
+
}
|
|
261
|
+
// Continue with other batches instead of failing completely
|
|
211
262
|
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
console.error(chalk.red(`❌ Engine ${engineName} failed:`), error.message);
|
|
214
|
-
// Continue with other engines instead of failing completely
|
|
215
263
|
}
|
|
216
264
|
}
|
|
217
265
|
|
|
218
|
-
|
|
266
|
+
// Merge results and add performance metrics
|
|
267
|
+
const mergedResults = this.mergeEngineResults(results, options);
|
|
268
|
+
mergedResults.performance = performanceMetrics;
|
|
269
|
+
|
|
270
|
+
return mergedResults;
|
|
219
271
|
|
|
220
272
|
} catch (error) {
|
|
221
273
|
console.error(chalk.red('❌ Analysis orchestration failed:'), error.message);
|
|
@@ -293,6 +345,12 @@ class AnalysisOrchestrator {
|
|
|
293
345
|
getEnginePreference(rule, config) {
|
|
294
346
|
// If user specified a specific engine via --engine option, use only that engine
|
|
295
347
|
if (config.requestedEngine) {
|
|
348
|
+
// Handle "auto" engine selection
|
|
349
|
+
if (config.requestedEngine === 'auto') {
|
|
350
|
+
// Auto-select best engines: default to heuristic, add eslint for JS/TS
|
|
351
|
+
return ['heuristic', 'eslint'];
|
|
352
|
+
}
|
|
353
|
+
|
|
296
354
|
return [config.requestedEngine];
|
|
297
355
|
}
|
|
298
356
|
|
|
@@ -393,23 +451,68 @@ class AnalysisOrchestrator {
|
|
|
393
451
|
}
|
|
394
452
|
|
|
395
453
|
/**
|
|
396
|
-
* Run engine analysis with timeout protection
|
|
454
|
+
* Run engine analysis with timeout protection and performance optimizations
|
|
397
455
|
* Following Rule C006: Verb-noun naming
|
|
398
456
|
* @param {AnalysisEngineInterface} engine - Engine to run
|
|
399
457
|
* @param {string[]} files - Files to analyze
|
|
400
458
|
* @param {Object[]} rules - Rules to apply
|
|
401
459
|
* @param {Object} options - Analysis options
|
|
460
|
+
* @param {Object} batchInfo - Batch context information
|
|
402
461
|
* @returns {Promise<Object>} Engine results
|
|
403
462
|
*/
|
|
404
|
-
async
|
|
405
|
-
|
|
463
|
+
async runEngineWithOptimizations(engine, files, rules, options, batchInfo = {}) {
|
|
464
|
+
// Dynamic timeout based on file count and rules
|
|
465
|
+
const adaptiveTimeout = this.performanceOptimizer.calculateAdaptiveTimeout(
|
|
466
|
+
files.length,
|
|
467
|
+
rules.length,
|
|
468
|
+
options.timeout || this.defaultTimeout
|
|
469
|
+
);
|
|
406
470
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
471
|
+
const enhancedOptions = {
|
|
472
|
+
...options,
|
|
473
|
+
timeout: adaptiveTimeout,
|
|
474
|
+
batchInfo
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
try {
|
|
478
|
+
return await Promise.race([
|
|
479
|
+
engine.analyze(files, rules, enhancedOptions),
|
|
480
|
+
new Promise((_, reject) =>
|
|
481
|
+
setTimeout(() => reject(new Error(
|
|
482
|
+
`Engine ${engine.name} batch ${batchInfo.batchNumber || 1} timed out after ${adaptiveTimeout}ms`
|
|
483
|
+
)), adaptiveTimeout)
|
|
484
|
+
)
|
|
485
|
+
]);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
// Enhanced error context for debugging
|
|
488
|
+
const errorContext = {
|
|
489
|
+
engine: engine.name,
|
|
490
|
+
filesCount: files.length,
|
|
491
|
+
rulesCount: rules.length,
|
|
492
|
+
timeout: adaptiveTimeout,
|
|
493
|
+
batch: batchInfo
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
// Wrap error with context
|
|
497
|
+
const enhancedError = new Error(`${error.message} (Context: ${JSON.stringify(errorContext)})`);
|
|
498
|
+
enhancedError.originalError = error;
|
|
499
|
+
enhancedError.context = errorContext;
|
|
500
|
+
|
|
501
|
+
throw enhancedError;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Run engine analysis with timeout protection (legacy method for backward compatibility)
|
|
507
|
+
* Following Rule C006: Verb-noun naming
|
|
508
|
+
* @param {AnalysisEngineInterface} engine - Engine to run
|
|
509
|
+
* @param {string[]} files - Files to analyze
|
|
510
|
+
* @param {Object[]} rules - Rules to apply
|
|
511
|
+
* @param {Object} options - Analysis options
|
|
512
|
+
* @returns {Promise<Object>} Engine results
|
|
513
|
+
*/
|
|
514
|
+
async runEngineWithTimeout(engine, files, rules, options) {
|
|
515
|
+
return this.runEngineWithOptimizations(engine, files, rules, options);
|
|
413
516
|
}
|
|
414
517
|
|
|
415
518
|
/**
|
|
@@ -425,6 +528,7 @@ class AnalysisOrchestrator {
|
|
|
425
528
|
results: [],
|
|
426
529
|
summary: {
|
|
427
530
|
totalEngines: engineResults.length,
|
|
531
|
+
totalBatches: engineResults.length,
|
|
428
532
|
totalViolations: 0,
|
|
429
533
|
totalFiles: 0,
|
|
430
534
|
engines: {}
|
|
@@ -436,8 +540,13 @@ class AnalysisOrchestrator {
|
|
|
436
540
|
}
|
|
437
541
|
};
|
|
438
542
|
|
|
543
|
+
// Track unique engines for summary
|
|
544
|
+
const uniqueEngines = new Set();
|
|
545
|
+
|
|
439
546
|
// Combine results from all engines
|
|
440
547
|
for (const engineResult of engineResults) {
|
|
548
|
+
uniqueEngines.add(engineResult.engine);
|
|
549
|
+
|
|
441
550
|
// Add engine-specific results
|
|
442
551
|
if (engineResult.results) {
|
|
443
552
|
mergedResults.results.push(...engineResult.results);
|
|
@@ -445,16 +554,30 @@ class AnalysisOrchestrator {
|
|
|
445
554
|
|
|
446
555
|
// Track engine statistics
|
|
447
556
|
const violationCount = this.countViolations(engineResult);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
557
|
+
const engineName = engineResult.engine;
|
|
558
|
+
|
|
559
|
+
if (!mergedResults.summary.engines[engineName]) {
|
|
560
|
+
mergedResults.summary.engines[engineName] = {
|
|
561
|
+
rules: [],
|
|
562
|
+
violations: 0,
|
|
563
|
+
files: 0,
|
|
564
|
+
batches: 0
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Accumulate engine statistics across batches
|
|
569
|
+
mergedResults.summary.engines[engineName].rules.push(...(engineResult.rules || []));
|
|
570
|
+
mergedResults.summary.engines[engineName].violations += violationCount;
|
|
571
|
+
mergedResults.summary.engines[engineName].files += engineResult.filesAnalyzed || 0;
|
|
572
|
+
mergedResults.summary.engines[engineName].batches += 1;
|
|
453
573
|
|
|
454
574
|
mergedResults.summary.totalViolations += violationCount;
|
|
455
575
|
mergedResults.summary.totalFiles += engineResult.filesAnalyzed || 0;
|
|
456
576
|
}
|
|
457
577
|
|
|
578
|
+
// Update unique engine count
|
|
579
|
+
mergedResults.summary.totalEngines = uniqueEngines.size;
|
|
580
|
+
|
|
458
581
|
return mergedResults;
|
|
459
582
|
}
|
|
460
583
|
|
|
@@ -517,7 +640,7 @@ class AnalysisOrchestrator {
|
|
|
517
640
|
}
|
|
518
641
|
|
|
519
642
|
/**
|
|
520
|
-
* Cleanup all engines
|
|
643
|
+
* Cleanup all engines and performance optimizer
|
|
521
644
|
* Following Rule C006: Verb-noun naming
|
|
522
645
|
* @returns {Promise<void>}
|
|
523
646
|
*/
|
|
@@ -529,6 +652,14 @@ class AnalysisOrchestrator {
|
|
|
529
652
|
console.warn(chalk.yellow(`⚠️ Failed to cleanup engine ${engine.id}:`), error.message);
|
|
530
653
|
}
|
|
531
654
|
}
|
|
655
|
+
|
|
656
|
+
// Cleanup performance optimizer
|
|
657
|
+
try {
|
|
658
|
+
await this.performanceOptimizer.cleanup();
|
|
659
|
+
} catch (error) {
|
|
660
|
+
console.warn(chalk.yellow(`⚠️ Failed to cleanup performance optimizer:`), error.message);
|
|
661
|
+
}
|
|
662
|
+
|
|
532
663
|
this.initialized = false;
|
|
533
664
|
console.log(chalk.blue('🧹 Engine cleanup completed'));
|
|
534
665
|
}
|