@sun-asterisk/sunlint 1.3.7 โ†’ 1.3.8

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 (38) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/config/defaults/default.json +2 -1
  3. package/config/rule-analysis-strategies.js +20 -0
  4. package/config/rules/enhanced-rules-registry.json +190 -35
  5. package/core/file-targeting-service.js +83 -7
  6. package/package.json +1 -1
  7. package/rules/common/C065_one_behavior_per_test/analyzer.js +851 -0
  8. package/rules/common/C065_one_behavior_per_test/config.json +95 -0
  9. package/rules/security/S037_cache_headers/README.md +128 -0
  10. package/rules/security/S037_cache_headers/analyzer.js +263 -0
  11. package/rules/security/S037_cache_headers/config.json +50 -0
  12. package/rules/security/S037_cache_headers/regex-based-analyzer.js +463 -0
  13. package/rules/security/S037_cache_headers/symbol-based-analyzer.js +546 -0
  14. package/rules/security/S038_no_version_headers/README.md +234 -0
  15. package/rules/security/S038_no_version_headers/analyzer.js +262 -0
  16. package/rules/security/S038_no_version_headers/config.json +49 -0
  17. package/rules/security/S038_no_version_headers/regex-based-analyzer.js +339 -0
  18. package/rules/security/S038_no_version_headers/symbol-based-analyzer.js +375 -0
  19. package/rules/security/S039_no_session_tokens_in_url/README.md +198 -0
  20. package/rules/security/S039_no_session_tokens_in_url/analyzer.js +262 -0
  21. package/rules/security/S039_no_session_tokens_in_url/config.json +92 -0
  22. package/rules/security/S039_no_session_tokens_in_url/regex-based-analyzer.js +337 -0
  23. package/rules/security/S039_no_session_tokens_in_url/symbol-based-analyzer.js +436 -0
  24. package/rules/security/S049_short_validity_tokens/analyzer.js +175 -0
  25. package/rules/security/S049_short_validity_tokens/config.json +124 -0
  26. package/rules/security/S049_short_validity_tokens/regex-based-analyzer.js +295 -0
  27. package/rules/security/S049_short_validity_tokens/symbol-based-analyzer.js +389 -0
  28. package/rules/security/S051_password_length_policy/analyzer.js +410 -0
  29. package/rules/security/S051_password_length_policy/config.json +83 -0
  30. package/rules/security/S052_weak_otp_entropy/analyzer.js +403 -0
  31. package/rules/security/S052_weak_otp_entropy/config.json +57 -0
  32. package/rules/security/S054_no_default_accounts/README.md +129 -0
  33. package/rules/security/S054_no_default_accounts/analyzer.js +792 -0
  34. package/rules/security/S054_no_default_accounts/config.json +101 -0
  35. package/rules/security/S056_log_injection_protection/analyzer.js +242 -0
  36. package/rules/security/S056_log_injection_protection/config.json +148 -0
  37. package/rules/security/S056_log_injection_protection/regex-based-analyzer.js +120 -0
  38. package/rules/security/S056_log_injection_protection/symbol-based-analyzer.js +287 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## ๐Ÿงช **v1.3.8 - C065 Rule Enhancement & Advanced Context Analysis (October 1, 2025)**
6
+
7
+ **Release Date**: October 1, 2025
8
+ **Type**: Major Enhancement
9
+ **Branch**: `feature.sunlint.heuristic_rule_c065`
10
+
11
+ ### โœจ **Major Features**
12
+ - **ENHANCED**: C065 "One Behavior per Test" Rule with Advanced Context Analysis
13
+ - **New**: UI Workflow Detection for legitimate testing patterns
14
+ - **New**: UI Interaction Loop Detection (fireEvent iterations)
15
+ - **New**: Smart Control Flow Analysis with UI pattern exclusions
16
+ - **New**: Assertion context grouping for accurate behavior detection
17
+ - **ENHANCED**: File Targeting System with Smart Test Detection
18
+ - **Performance**: 98% file reduction (6873 โ†’ 112 files) with `--include-tests`
19
+ - **Accuracy**: Intelligent project targeting and language filter override
20
+ - **ENHANCED**: Debug Output Management
21
+ - **Clean**: Production-ready output with conditional debug logging
22
+ - **Detailed**: Comprehensive debug info available with `--verbose` flag
23
+
24
+ ### ๐Ÿ› **Critical Bug Fixes**
25
+ - **FIXED**: C065 Rule Registry and Configuration
26
+ - **Issue**: Rule loading from incorrect `rules/quality/` path
27
+ - **Solution**: Updated to correct `rules/common/` path with proper categorization
28
+ - **FIXED**: False Positive Control Flow Detection
29
+ - **Issue**: UI testing loops incorrectly flagged as violations
30
+ - **Solution**: Pattern recognition for legitimate UI element iteration
31
+ - **FIXED**: Test File Language Filtering
32
+ - **Issue**: Test files excluded by language patterns
33
+ - **Solution**: Override exclusions for `--include-tests` flag
34
+
35
+ ### ๐ŸŽฏ **Rule Accuracy Validation**
36
+ - **UI Loops**: `for (const checkbox of listCheckbox) { fireEvent.click(checkbox); }` โœ… No false positive
37
+ - **Button Iteration**: `for (const button of buttons) { fireEvent.click(button); }` โœ… No false positive
38
+ - **Business Logic**: Complex control flow with if/else statements โŒ Properly flagged
39
+ - **Multiple Behaviors**: Tests with multiple mock setups โŒ Properly flagged
40
+
41
+ ---
42
+
5
43
  ## ๏ฟฝ **v1.3.7 - File Count Reporting & Performance Fixes (September 11, 2025)**
6
44
 
7
45
  **Release Date**: September 11, 2025
@@ -3,7 +3,8 @@
3
3
  "C006": true,
4
4
  "C019": true,
5
5
  "C032": true,
6
- "C045": true
6
+ "C045": true,
7
+ "S054": true
7
8
  },
8
9
  "categories": ["quality", "security"],
9
10
  "integration": {
@@ -41,6 +41,26 @@ module.exports = {
41
41
  reason: 'JSON injection detection requires AST context analysis',
42
42
  methods: ['ast', 'regex'],
43
43
  accuracy: { ast: 95, regex: 60 }
44
+ },
45
+ 'S054': {
46
+ reason: 'Default account detection in code, SQL, and config files',
47
+ methods: ['regex', 'ast'],
48
+ accuracy: { regex: 85, ast: 90 }
49
+ },
50
+ 'S052': {
51
+ reason: 'OTP entropy analysis requires hybrid approach for RNG detection and context awareness',
52
+ methods: ['regex', 'ast'],
53
+ accuracy: { regex: 80, ast: 90 }
54
+ },
55
+ 'S051': {
56
+ reason: 'Password length policy requires multi-signal context detection and cross-file validation',
57
+ methods: ['regex', 'ast'],
58
+ accuracy: { regex: 85, ast: 92 }
59
+ },
60
+ 'C065': {
61
+ reason: 'Test behavior analysis requires hybrid heuristic + AST context for multiple assertions and control flow detection',
62
+ methods: ['regex', 'ast'],
63
+ accuracy: { regex: 85, ast: 92 }
44
64
  }
45
65
  },
46
66
 
@@ -736,7 +736,13 @@
736
736
  "config": "./rules/security/S025_server_side_validation/config.json",
737
737
  "version": "1.0.0",
738
738
  "status": "stable",
739
- "tags": ["security", "validation", "server-side", "owasp", "input-validation"],
739
+ "tags": [
740
+ "security",
741
+ "validation",
742
+ "server-side",
743
+ "owasp",
744
+ "input-validation"
745
+ ],
740
746
  "strategy": {
741
747
  "preferred": "ast",
742
748
  "fallbacks": ["ast", "regex"],
@@ -927,40 +933,71 @@
927
933
  "tags": ["security", "file-inclusion", "path-traversal"]
928
934
  },
929
935
  "S037": {
930
- "name": "Require Anti Cache Headers",
931
- "description": "Require anti-cache headers for sensitive content",
936
+ "name": "Configure comprehensive cache headers to prevent sensitive data leakage",
937
+ "description": "Configure comprehensive cache headers (Cache-Control: no-store, no-cache, must-revalidate, Pragma: no-cache, Expires: 0) for sensitive responses to avoid caching sensitive data in browsers or intermediaries.",
932
938
  "category": "security",
933
939
  "severity": "warning",
934
940
  "languages": ["typescript", "javascript"],
935
- "analyzer": "eslint",
936
- "eslintRule": "custom/typescript_s037",
941
+ "analyzer": "./rules/security/S037_cache_headers/analyzer.js",
942
+ "config": "./rules/security/S037_cache_headers/config.json",
937
943
  "version": "1.0.0",
938
- "status": "stable",
939
- "tags": ["security", "caching", "headers"]
944
+ "status": "experimental",
945
+ "tags": ["security", "caching", "headers", "privacy"],
946
+ "strategy": {
947
+ "preferred": "ast",
948
+ "fallbacks": ["ast", "regex"],
949
+ "accuracy": { "ast": 90, "regex": 75 }
950
+ },
951
+ "engineMappings": {
952
+ "heuristic": ["rules/security/S037_cache_headers/analyzer.js"]
953
+ }
940
954
  },
941
955
  "S038": {
942
- "name": "No Version Disclosure",
943
- "description": "Prevent version information disclosure",
956
+ "name": "Do not expose version information in response headers",
957
+ "description": "Prevent exposure of server version information through response headers (Server, X-Powered-By, X-AspNet-Version, etc.) to reduce information disclosure and potential attack vectors.",
944
958
  "category": "security",
945
959
  "severity": "warning",
946
960
  "languages": ["typescript", "javascript"],
947
- "analyzer": "eslint",
948
- "eslintRule": "custom/typescript_s038",
961
+ "analyzer": "./rules/security/S038_no_version_headers/analyzer.js",
962
+ "config": "./rules/security/S038_no_version_headers/config.json",
949
963
  "version": "1.0.0",
950
- "status": "stable",
951
- "tags": ["security", "information-disclosure", "version"]
964
+ "status": "experimental",
965
+ "tags": ["security", "information-disclosure", "version", "headers"],
966
+ "strategy": {
967
+ "preferred": "ast",
968
+ "fallbacks": ["ast", "regex"],
969
+ "accuracy": { "ast": 90, "regex": 75 }
970
+ },
971
+ "engineMappings": {
972
+ "heuristic": ["rules/security/S038_no_version_headers/analyzer.js"]
973
+ }
952
974
  },
953
975
  "S039": {
954
- "name": "No Session Token in URL",
955
- "description": "Prevent session tokens in URL parameters",
976
+ "name": "Do not pass Session Tokens via URL parameters",
977
+ "description": "Detects when session tokens, authentication tokens, JWT tokens, or other sensitive authentication data are passed as URL parameters instead of secure headers or request body. URL parameters are logged in web server logs, browser history, and can be exposed in referrer headers.",
956
978
  "category": "security",
957
- "severity": "error",
979
+ "severity": "warning",
958
980
  "languages": ["typescript", "javascript"],
959
- "analyzer": "eslint",
960
- "eslintRule": "custom/typescript_s039",
981
+ "analyzer": "./rules/security/S039_no_session_tokens_in_url/analyzer.js",
982
+ "config": "./rules/security/S039_no_session_tokens_in_url/config.json",
961
983
  "version": "1.0.0",
962
- "status": "stable",
963
- "tags": ["security", "session", "url"]
984
+ "status": "experimental",
985
+ "tags": [
986
+ "security",
987
+ "session-tokens",
988
+ "url-parameters",
989
+ "authentication"
990
+ ],
991
+ "strategy": {
992
+ "preferred": "ast",
993
+ "fallbacks": ["ast", "regex"],
994
+ "accuracy": { "ast": 85, "regex": 70 }
995
+ },
996
+ "engineMappings": {
997
+ "heuristic": [
998
+ "rules/security/S039_no_session_tokens_in_url/analyzer.js"
999
+ ]
1000
+ }
964
1001
  },
965
1002
  "S041": {
966
1003
  "name": "Require Session Invalidate on Logout",
@@ -1058,6 +1095,36 @@
1058
1095
  "status": "stable",
1059
1096
  "tags": ["security", "password", "recovery"]
1060
1097
  },
1098
+ "S049": {
1099
+ "name": "Authentication tokens should have short validity periods",
1100
+ "description": "Authentication tokens (JWT, session tokens, etc.) should have appropriately short validity periods to minimize the risk of token compromise. Long-lived tokens increase the attack surface and potential impact of token theft.",
1101
+ "category": "security",
1102
+ "severity": "error",
1103
+ "languages": ["typescript", "javascript"],
1104
+ "analyzer": "./rules/security/S049_short_validity_tokens/analyzer.js",
1105
+ "config": "./rules/security/S049_short_validity_tokens/config.json",
1106
+ "version": "1.0.0",
1107
+ "status": "stable",
1108
+ "tags": [
1109
+ "security",
1110
+ "authentication",
1111
+ "tokens",
1112
+ "jwt",
1113
+ "session",
1114
+ "owasp"
1115
+ ],
1116
+ "strategy": {
1117
+ "preferred": "ast",
1118
+ "fallbacks": ["ast", "regex"],
1119
+ "accuracy": {
1120
+ "ast": 90,
1121
+ "regex": 75
1122
+ }
1123
+ },
1124
+ "engineMappings": {
1125
+ "heuristic": ["rules/security/S049_short_validity_tokens/analyzer.js"]
1126
+ }
1127
+ },
1061
1128
  "S050": {
1062
1129
  "name": "Session Token Weak Hash",
1063
1130
  "description": "Prevent weak hashing for session tokens",
@@ -1070,29 +1137,71 @@
1070
1137
  "status": "stable",
1071
1138
  "tags": ["security", "session", "hashing"]
1072
1139
  },
1140
+ "S051": {
1141
+ "name": "Password length policy enforcement (12-64 chars recommended, reject >128)",
1142
+ "description": "Enforce strong password length policies with multi-signal detection. Prevent weak validators, missing limits, and FE/BE mismatches.",
1143
+ "category": "security",
1144
+ "severity": "error",
1145
+ "languages": ["typescript", "javascript"],
1146
+ "analyzer": "./rules/security/S051_password_length_policy/analyzer.js",
1147
+ "config": "./rules/security/S051_password_length_policy/config.json",
1148
+ "eslintRule": "custom/typescript_s051",
1149
+ "version": "1.0.0",
1150
+ "status": "stable",
1151
+ "tags": ["security", "password", "validation", "length", "policy"],
1152
+ "engineMappings": {
1153
+ "eslint": ["custom/typescript_s051"],
1154
+ "heuristic": ["./rules/security/S051_password_length_policy/analyzer.js"]
1155
+ }
1156
+ },
1157
+ "C065": {
1158
+ "name": "One Behavior per Test (AAA Pattern)",
1159
+ "description": "Enforce single behavior testing - each test should verify exactly one action/behavior with clear Arrange-Act-Assert structure",
1160
+ "category": "common",
1161
+ "severity": "warning",
1162
+ "languages": ["typescript", "javascript", "java", "csharp", "swift", "kotlin", "python"],
1163
+ "analyzer": "./rules/common/C065_one_behavior_per_test/analyzer.js",
1164
+ "config": "./rules/common/C065_one_behavior_per_test/config.json",
1165
+ "version": "1.0.0",
1166
+ "status": "stable",
1167
+ "tags": ["testing", "aaa", "behavior", "maintainability", "clarity"],
1168
+ "engineMappings": {
1169
+ "heuristic": ["./rules/common/C065_one_behavior_per_test/analyzer.js"]
1170
+ }
1171
+ },
1073
1172
  "S052": {
1074
- "name": "Secure Random Authentication Code",
1075
- "description": "Require secure random number generation for authentication codes",
1173
+ "name": "OTP must have โ‰ฅ20-bit entropy (โ‰ฅ6 digits) and use CSPRNG",
1174
+ "description": "Prevent guessable OTP by enforcing CSPRNG and minimal entropy. Ban non-crypto RNG and too-short codes.",
1076
1175
  "category": "security",
1077
1176
  "severity": "error",
1078
1177
  "languages": ["typescript", "javascript"],
1079
- "analyzer": "eslint",
1178
+ "analyzer": "./rules/security/S052_weak_otp_entropy/analyzer.js",
1179
+ "config": "./rules/security/S052_weak_otp_entropy/config.json",
1080
1180
  "eslintRule": "custom/typescript_s052",
1081
1181
  "version": "1.0.0",
1082
1182
  "status": "stable",
1083
- "tags": ["security", "random", "authentication"]
1183
+ "tags": ["security", "otp", "entropy", "csprng"],
1184
+ "engines": {
1185
+ "eslint": ["custom/typescript_s052"],
1186
+ "heuristic": ["./rules/security/S052_weak_otp_entropy/analyzer.js"]
1187
+ }
1084
1188
  },
1085
1189
  "S054": {
1086
- "name": "Verification Default Account",
1087
- "description": "Verify and secure default accounts",
1190
+ "name": "Disallow Default/Built-in Accounts (admin/root/sa/...)",
1191
+ "description": "Prevent use of default or shared accounts. Enforce per-user identities, initial password change, and disabling well-known built-ins.",
1088
1192
  "category": "security",
1089
1193
  "severity": "error",
1090
- "languages": ["typescript", "javascript"],
1091
- "analyzer": "eslint",
1194
+ "languages": ["typescript", "javascript", "sql", "terraform", "yaml", "dockerfile", "all"],
1195
+ "analyzer": "./rules/security/S054_no_default_accounts/analyzer.js",
1196
+ "config": "./rules/security/S054_no_default_accounts/config.json",
1092
1197
  "eslintRule": "custom/typescript_s054",
1093
1198
  "version": "1.0.0",
1094
1199
  "status": "stable",
1095
- "tags": ["security", "accounts", "default"]
1200
+ "tags": ["security", "accounts", "default", "authentication", "authorization"],
1201
+ "engines": {
1202
+ "eslint": ["custom/typescript_s054"],
1203
+ "heuristic": ["./rules/security/S054_no_default_accounts/analyzer.js"]
1204
+ }
1096
1205
  },
1097
1206
  "S055": {
1098
1207
  "name": "REST Content-Type Verification",
@@ -1106,6 +1215,31 @@
1106
1215
  "status": "stable",
1107
1216
  "tags": ["security", "rest", "content-type"]
1108
1217
  },
1218
+ "S056": {
1219
+ "name": "Protect against Log Injection attacks",
1220
+ "description": "Protect against Log Injection attacks. Log injection occurs when user-controlled data is written to log files without proper sanitization, potentially allowing attackers to manipulate log entries, inject malicious content, or exploit log processing systems.",
1221
+ "category": "security",
1222
+ "severity": "error",
1223
+ "languages": ["typescript", "javascript"],
1224
+ "analyzer": "./rules/security/S056_log_injection_protection/analyzer.js",
1225
+ "config": "./rules/security/S056_log_injection_protection/config.json",
1226
+ "version": "1.0.0",
1227
+ "status": "stable",
1228
+ "tags": ["security", "logging", "injection", "owasp", "crlf"],
1229
+ "strategy": {
1230
+ "preferred": "ast",
1231
+ "fallbacks": ["ast", "regex"],
1232
+ "accuracy": {
1233
+ "ast": 95,
1234
+ "regex": 85
1235
+ }
1236
+ },
1237
+ "engineMappings": {
1238
+ "heuristic": [
1239
+ "rules/security/S056_log_injection_protection/analyzer.js"
1240
+ ]
1241
+ }
1242
+ },
1109
1243
  "S057": {
1110
1244
  "name": "Log with UTC Timestamps",
1111
1245
  "description": "Ensure all logs use synchronized UTC time with ISO 8601/RFC3339 format to avoid timezone discrepancies across systems",
@@ -1353,7 +1487,13 @@
1353
1487
  "config": "./rules/common/C067_no_hardcoded_config/config.json",
1354
1488
  "version": "1.0.0",
1355
1489
  "status": "stable",
1356
- "tags": ["configuration", "hardcode", "environment", "maintainability", "security"],
1490
+ "tags": [
1491
+ "configuration",
1492
+ "hardcode",
1493
+ "environment",
1494
+ "maintainability",
1495
+ "security"
1496
+ ],
1357
1497
  "strategy": {
1358
1498
  "preferred": "ast",
1359
1499
  "fallbacks": ["ast"],
@@ -1375,7 +1515,13 @@
1375
1515
  "config": "../rules/common/C070_no_real_time_tests/config.json",
1376
1516
  "version": "1.0.0",
1377
1517
  "status": "stable",
1378
- "tags": ["testing", "flaky-tests", "timing", "fake-timers", "reliability"],
1518
+ "tags": [
1519
+ "testing",
1520
+ "flaky-tests",
1521
+ "timing",
1522
+ "fake-timers",
1523
+ "reliability"
1524
+ ],
1379
1525
  "strategy": {
1380
1526
  "preferred": "ast",
1381
1527
  "fallbacks": ["regex"],
@@ -1385,7 +1531,9 @@
1385
1531
  }
1386
1532
  },
1387
1533
  "engineMappings": {
1388
- "heuristic": ["../rules/common/C070_no_real_time_tests/regex-analyzer.js"]
1534
+ "heuristic": [
1535
+ "../rules/common/C070_no_real_time_tests/regex-analyzer.js"
1536
+ ]
1389
1537
  }
1390
1538
  },
1391
1539
  "C072": {
@@ -1419,8 +1567,12 @@
1419
1567
  "status": "stable",
1420
1568
  "tags": ["configuration", "validation", "startup", "fail-fast"],
1421
1569
  "engineMappings": {
1422
- "heuristic": ["rules/common/C073_validate_required_config_on_startup/analyzer.js"],
1423
- "semantic": ["rules/common/C073_validate_required_config_on_startup/symbol-based-analyzer.js"]
1570
+ "heuristic": [
1571
+ "rules/common/C073_validate_required_config_on_startup/analyzer.js"
1572
+ ],
1573
+ "semantic": [
1574
+ "rules/common/C073_validate_required_config_on_startup/symbol-based-analyzer.js"
1575
+ ]
1424
1576
  },
1425
1577
  "strategy": {
1426
1578
  "preferred": "semantic",
@@ -1837,6 +1989,7 @@
1837
1989
  "C047",
1838
1990
  "C048",
1839
1991
  "C052",
1992
+ "C065",
1840
1993
  "C072",
1841
1994
  "C073",
1842
1995
  "C075",
@@ -1906,9 +2059,11 @@
1906
2059
  "S047",
1907
2060
  "S048",
1908
2061
  "S050",
2062
+ "S051",
1909
2063
  "S052",
1910
2064
  "S054",
1911
2065
  "S055",
2066
+ "S056",
1912
2067
  "S057",
1913
2068
  "S058"
1914
2069
  ],
@@ -2003,7 +2158,7 @@
2003
2158
  "lastUpdated": "2025-08-25",
2004
2159
  "totalRules": 98,
2005
2160
  "qualityRules": 33,
2006
- "securityRules": 50,
2161
+ "securityRules": 51,
2007
2162
  "stableRules": 45,
2008
2163
  "experimentalRules": 1,
2009
2164
  "supportedLanguages": 4,
@@ -16,7 +16,7 @@ class FileTargetingService {
16
16
 
17
17
  /**
18
18
  * Get target files based on enhanced configuration
19
- * ENHANCED: Uses metadata for intelligent file targeting
19
+ * ENHANCED: Uses metadata for intelligent file targeting with smart project-level optimization
20
20
  */
21
21
  async getTargetFiles(inputPaths, config, cliOptions = {}) {
22
22
  try {
@@ -32,11 +32,14 @@ class FileTargetingService {
32
32
 
33
33
  let allFiles = [];
34
34
 
35
+ // Smart project-level optimization
36
+ const optimizedPaths = this.optimizeProjectPaths(inputPaths, cliOptions);
37
+
35
38
  // Use enhanced targeting based on metadata
36
39
  if (metadata?.shouldBypassProjectDiscovery) {
37
- allFiles = await this.collectTargetedFiles(inputPaths, config, cliOptions);
40
+ allFiles = await this.collectTargetedFiles(optimizedPaths, config, cliOptions);
38
41
  } else {
39
- allFiles = await this.collectProjectFiles(inputPaths, config, cliOptions);
42
+ allFiles = await this.collectProjectFiles(optimizedPaths, config, cliOptions);
40
43
  }
41
44
 
42
45
  // Apply filtering logic
@@ -150,13 +153,69 @@ class FileTargetingService {
150
153
  return allFiles;
151
154
  }
152
155
 
156
+ /**
157
+ * Optimize project paths to focus on source and test directories
158
+ * Prevents unnecessary scanning of entire project when smart targeting is possible
159
+ */
160
+ optimizeProjectPaths(inputPaths, cliOptions = {}) {
161
+ const optimizedPaths = [];
162
+
163
+ for (const inputPath of inputPaths) {
164
+ // If targeting entire project directory, try to find source/test subdirectories
165
+ if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
166
+ const projectOptimization = this.findProjectSourceDirs(inputPath, cliOptions);
167
+ if (projectOptimization.length > 0) {
168
+ if (cliOptions.verbose) {
169
+ console.log(chalk.blue(`๐ŸŽฏ Smart targeting: Found ${projectOptimization.length} source directories in ${path.basename(inputPath)}`));
170
+ }
171
+ optimizedPaths.push(...projectOptimization);
172
+ } else {
173
+ optimizedPaths.push(inputPath);
174
+ }
175
+ } else {
176
+ optimizedPaths.push(inputPath);
177
+ }
178
+ }
179
+
180
+ return optimizedPaths;
181
+ }
182
+
183
+ /**
184
+ * Find source directories in project to avoid scanning entire project
185
+ */
186
+ findProjectSourceDirs(projectPath, cliOptions = {}) {
187
+ const sourceDirs = [];
188
+ const candidateDirs = ['src', 'lib', 'app', 'packages'];
189
+ const testDirs = ['test', 'tests', '__tests__', 'spec', 'specs'];
190
+
191
+ // Always include test directories if --include-tests flag is used
192
+ const dirsToCheck = cliOptions.includeTests ? [...candidateDirs, ...testDirs] : candidateDirs;
193
+
194
+ for (const dir of dirsToCheck) {
195
+ const dirPath = path.join(projectPath, dir);
196
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
197
+ sourceDirs.push(dirPath);
198
+ }
199
+ }
200
+
201
+ return sourceDirs;
202
+ }
203
+
153
204
  /**
154
205
  * Check if directory should be skipped
206
+ * Enhanced with more comprehensive ignore patterns
207
+ * Enhanced with more comprehensive ignore patterns
155
208
  */
156
209
  shouldSkipDirectory(dirName) {
157
210
  const skipDirs = [
158
211
  'node_modules', '.git', 'dist', 'build', 'coverage',
159
- '.next', '.nuxt', 'vendor', 'target', 'generated'
212
+ '.next', '.nuxt', 'vendor', 'target', 'generated',
213
+ '.vscode', '.id',
214
+ '.vscode', '.idea', '.husky', '.github', '.yarn',
215
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
216
+ 'cache', '.cache', 'logs', 'logea', '.husky', '.github', '.yarn',
217
+ 'out', 'public', 'static', 'assets', 'tmp', 'temp',
218
+ 'cache', '.cache', 'logs', 'log'
160
219
  ];
161
220
  return skipDirs.includes(dirName);
162
221
  }
@@ -278,10 +337,27 @@ class FileTargetingService {
278
337
  if (debug) console.log(`๐Ÿ” [DEBUG] After include patterns ${langConfig.include}: ${langFiles.length} files`);
279
338
  }
280
339
 
281
- // Apply language-specific exclude patterns
340
+ // Apply language-specific exclude patterns (but respect --include-tests for test files)
282
341
  if (langConfig.exclude && langConfig.exclude.length > 0) {
283
- langFiles = this.applyExcludePatterns(langFiles, langConfig.exclude, debug);
284
- if (debug) console.log(`๐Ÿ” [DEBUG] After exclude patterns ${langConfig.exclude}: ${langFiles.length} files`);
342
+ // Skip test-related exclude patterns if --include-tests is enabled
343
+ let effectiveExcludes = langConfig.exclude;
344
+ if (cliOptions.includeTests === true) {
345
+ // Remove test-related patterns completely
346
+ effectiveExcludes = langConfig.exclude.filter(pattern => {
347
+ const isTestPattern = pattern.includes('.test.') || pattern.includes('.spec.') ||
348
+ pattern.includes('/test/') || pattern.includes('/tests/') ||
349
+ pattern.includes('/__tests__/');
350
+ return !isTestPattern;
351
+ });
352
+ if (debug) console.log(`๐Ÿ” [DEBUG] --include-tests enabled, filtered excludes: ${effectiveExcludes}`);
353
+ }
354
+
355
+ if (effectiveExcludes.length > 0) {
356
+ langFiles = this.applyExcludePatterns(langFiles, effectiveExcludes, debug);
357
+ if (debug) console.log(`๐Ÿ” [DEBUG] After exclude patterns ${effectiveExcludes}: ${langFiles.length} files`);
358
+ } else {
359
+ if (debug) console.log(`๐Ÿ” [DEBUG] All exclude patterns filtered out by --include-tests`);
360
+ }
285
361
  }
286
362
 
287
363
  languageFiles.push(...langFiles);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "description": "โ˜€๏ธ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
5
5
  "main": "cli.js",
6
6
  "bin": {