@sun-asterisk/sunlint 1.2.2 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +107 -1
  2. package/CONTRIBUTING.md +1654 -66
  3. package/README.md +19 -6
  4. package/config/ci-cd.json +54 -0
  5. package/config/development.json +56 -0
  6. package/config/engines/engines-enhanced.json +86 -0
  7. package/config/engines/semantic-config.json +114 -0
  8. package/config/eslint-rule-mapping.json +50 -38
  9. package/config/large-project.json +143 -0
  10. package/config/presets/all.json +0 -1
  11. package/config/release.json +70 -0
  12. package/config/rule-analysis-strategies.js +23 -4
  13. package/config/rules/S027-categories.json +122 -0
  14. package/config/rules/enhanced-rules-registry.json +2564 -0
  15. package/config/rules/rules-registry-generated.json +785 -837
  16. package/config/rules/rules-registry.json +13 -1
  17. package/core/adapters/sunlint-rule-adapter.js +25 -30
  18. package/core/analysis-orchestrator.js +42 -2
  19. package/core/categories.js +52 -0
  20. package/core/category-constants.js +39 -0
  21. package/core/cli-action-handler.js +53 -32
  22. package/core/cli-program.js +11 -3
  23. package/core/config-manager.js +111 -0
  24. package/core/config-merger.js +88 -0
  25. package/core/constants/categories.js +168 -0
  26. package/core/constants/defaults.js +165 -0
  27. package/core/constants/engines.js +185 -0
  28. package/core/constants/index.js +30 -0
  29. package/core/constants/rules.js +215 -0
  30. package/core/enhanced-rules-registry.js +3 -3
  31. package/core/file-targeting-service.js +128 -7
  32. package/core/interfaces/rule-plugin.interface.js +207 -0
  33. package/core/plugin-manager.js +448 -0
  34. package/core/rule-selection-service.js +42 -15
  35. package/core/semantic-engine.js +658 -0
  36. package/core/semantic-rule-base.js +433 -0
  37. package/core/unified-rule-registry.js +484 -0
  38. package/docs/COMMAND-EXAMPLES.md +134 -0
  39. package/docs/CONSTANTS-ARCHITECTURE.md +288 -0
  40. package/docs/LARGE-PROJECT-GUIDE.md +324 -0
  41. package/engines/core/base-engine.js +249 -0
  42. package/engines/engine-factory.js +275 -0
  43. package/engines/eslint-engine.js +171 -19
  44. package/engines/heuristic-engine.js +569 -78
  45. package/integrations/eslint/plugin/index.js +26 -28
  46. package/origin-rules/common-en.md +8 -8
  47. package/package.json +10 -6
  48. package/rules/common/C003_no_vague_abbreviations/analyzer.js +1 -1
  49. package/rules/common/C017_constructor_logic/analyzer.js +254 -17
  50. package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
  51. package/rules/common/C029_catch_block_logging/analyzer.js +17 -5
  52. package/rules/common/C033_separate_service_repository/README.md +78 -0
  53. package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
  54. package/rules/common/C033_separate_service_repository/config.json +50 -0
  55. package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
  56. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
  57. package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
  58. package/rules/common/C035_error_logging_context/analyzer.js +230 -0
  59. package/rules/common/C035_error_logging_context/config.json +54 -0
  60. package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
  61. package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
  62. package/rules/common/C040_centralized_validation/analyzer.js +165 -0
  63. package/rules/common/C040_centralized_validation/config.json +46 -0
  64. package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
  65. package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
  66. package/rules/common/C047_no_duplicate_retry_logic/c047-semantic-rule.js +278 -0
  67. package/rules/common/C047_no_duplicate_retry_logic/symbol-analyzer-enhanced.js +968 -0
  68. package/rules/common/C047_no_duplicate_retry_logic/symbol-config.json +71 -0
  69. package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
  70. package/rules/common/C076_explicit_function_types/README.md +30 -0
  71. package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
  72. package/rules/common/C076_explicit_function_types/config.json +15 -0
  73. package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
  74. package/rules/index.js +8 -0
  75. package/rules/parser/rule-parser.js +13 -2
  76. package/rules/security/S005_no_origin_auth/README.md +226 -0
  77. package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
  78. package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
  79. package/rules/security/S005_no_origin_auth/config.json +85 -0
  80. package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
  81. package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
  82. package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
  83. package/rules/security/S007_no_plaintext_otp/README.md +198 -0
  84. package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
  85. package/rules/security/S007_no_plaintext_otp/config.json +79 -0
  86. package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
  87. package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
  88. package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
  89. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
  90. package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
  91. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
  92. package/scripts/category-manager.js +150 -0
  93. package/scripts/generate-rules-registry.js +88 -0
  94. package/scripts/migrate-rule-registry.js +157 -0
  95. package/scripts/prepare-release.sh +1 -1
  96. package/scripts/validate-system.js +48 -0
  97. package/.sunlint.json +0 -35
  98. package/config/README.md +0 -88
  99. package/config/engines/eslint-rule-mapping.json +0 -74
  100. package/config/schemas/sunlint-schema.json +0 -0
  101. package/config/testing/test-s005-working.ts +0 -22
  102. package/core/multi-rule-runner.js +0 -0
  103. package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
  104. package/docs/FUTURE_PACKAGES.md +0 -83
  105. package/docs/HEURISTIC_VS_AI.md +0 -113
  106. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
  107. package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
  108. package/docs/RELEASE_GUIDE.md +0 -230
  109. package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
  110. package/engines/tree-sitter-parser.js +0 -0
  111. package/engines/universal-ast-engine.js +0 -0
  112. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
  113. package/rules/common/C029_catch_block_logging/analyzer-backup.js +0 -426
  114. package/rules/common/C029_catch_block_logging/analyzer-fixed.js +0 -130
  115. package/rules/common/C029_catch_block_logging/analyzer-multi-tech.js +0 -487
  116. package/rules/common/C029_catch_block_logging/analyzer-simple.js +0 -110
  117. package/rules/common/C029_catch_block_logging/ast-analyzer-backup.js +0 -441
  118. package/rules/common/C029_catch_block_logging/ast-analyzer-new.js +0 -127
  119. package/rules/common/C029_catch_block_logging/ast-analyzer.js +0 -133
  120. package/rules/common/C029_catch_block_logging/cfg-analyzer.js +0 -408
  121. package/rules/common/C029_catch_block_logging/dataflow-analyzer.js +0 -454
  122. package/rules/common/C029_catch_block_logging/multi-language-ast-engine.js +0 -700
  123. package/rules/common/C029_catch_block_logging/pattern-learning-analyzer.js +0 -568
  124. package/rules/common/C029_catch_block_logging/semantic-analyzer.js +0 -459
@@ -22,7 +22,6 @@ const c043 = require("./rules/common/c043-no-console-or-print.js");
22
22
  const c047 = require("./rules/common/c047-no-duplicate-retry-logic.js");
23
23
  const c072 = require("./rules/common/c072-one-assert-per-test.js");
24
24
  const c075 = require("./rules/common/c075-explicit-function-return-types.js");
25
- const c076 = require("./rules/common/c076-single-behavior-per-test.js");
26
25
 
27
26
  // 📘 TypeScript Rules (T-series)
28
27
  const t002 = require("./rules/typescript/t002-interface-prefix-i.js");
@@ -85,33 +84,32 @@ const s058 = require("./rules/security/s058-no-ssrf.js");
85
84
 
86
85
  module.exports = {
87
86
  rules: {
88
- "c002": c002,
89
- "c003": c003,
90
- "c006": c006,
91
- "c010": c010,
92
- "c013": c013,
93
- "c014": c014,
94
- "c017": c017,
95
- "c018": c018,
96
- "c030": c030,
97
- "c035": c035,
98
- "c023": c023,
99
- "c029": c029,
100
- "c041": c041,
101
- "c042": c042,
102
- "c043": c043,
103
- "c047": c047,
104
- "c072": c072,
105
- "c075": c075,
106
- "c076": c076,
107
- "t002": t002,
108
- "t003": t003,
109
- "t004": t004,
110
- "t007": t007,
111
- "t010": t010,
112
- "t019": t019,
113
- "t020": t020,
114
- "t021": t021,
87
+ "c002-no-duplicate-code": c002,
88
+ "c003-no-vague-abbreviations": c003,
89
+ "c006-function-name-verb-noun": c006,
90
+ "c010-limit-block-nesting": c010,
91
+ "c013-no-dead-code": c013,
92
+ "c014-abstract-dependency-preferred": c014,
93
+ "c017-limit-constructor-logic": c017,
94
+ "c018-no-generic-throw": c018,
95
+ "c030-use-custom-error-classes": c030,
96
+ "c035-no-empty-catch": c035,
97
+ "c023-no-duplicate-variable-name-in-scope": c023,
98
+ "c029-catch-block-logging": c029,
99
+ "c041-no-config-inline": c041,
100
+ "c042-boolean-name-prefix": c042,
101
+ "c043-no-console-or-print": c043,
102
+ "c047-no-duplicate-retry-logic": c047,
103
+ "c072-one-assert-per-test": c072,
104
+ "c075-explicit-function-return-types": c075,
105
+ "t002-interface-prefix-i": t002,
106
+ "t003-ts-ignore-reason": t003,
107
+ "t004-no-empty-type": t004,
108
+ "t007-no-fn-in-constructor": t007,
109
+ "t010-no-nested-union-tuple": t010,
110
+ "t019-no-this-assign": t019,
111
+ "t020-no-default-multi-export": t020,
112
+ "t021-limit-nested-generics": t021,
115
113
  // Security rules
116
114
  "typescript_s001": s001,
117
115
  "typescript_s002": s002,
@@ -675,7 +675,7 @@
675
675
 
676
676
  - **Objective**: Protect sensitive application data, avoid security risks, and comply with security standards. Exposing sensitive information can lead to serious security and privacy issues.
677
677
 
678
- - **Details**
678
+ - **Details**:
679
679
  - Use environment variables or separate config files to store secrets
680
680
  - Add secret files to `.gitignore` to prevent committing them
681
681
  - Use secret management tools such as Vault or AWS Secrets Manager
@@ -692,7 +692,7 @@
692
692
 
693
693
  - **Objective**: Ensure clarity and readability by making boolean variables self-explanatory. This naming convention improves code maintainability and documentation.
694
694
 
695
- - **Details**
695
+ - **Details**:
696
696
  - Use `is` for state attributes (e.g., `isActive`, `isEnabled`)
697
697
  - Use `has` for ownership (e.g., `hasPermission`, `hasChildren`)
698
698
  - Use `should` for decision flags (e.g., `shouldUpdate`, `shouldRetry`)
@@ -709,7 +709,7 @@
709
709
 
710
710
  - **Objective**: Ensure logging is done in a controlled and effective manner in production. Using `print` or `console.log` can lead to performance issues, security risks, and log management difficulties.
711
711
 
712
- - **Details**
712
+ - **Details**:
713
713
  - Use a dedicated logging framework instead of `print` or `console.log`
714
714
  - Set appropriate log levels for each environment (debug, info, warn, error)
715
715
  - Ensure logs contain useful metadata like timestamp, level, and context
@@ -726,7 +726,7 @@
726
726
 
727
727
  - **Objective**: Leverage well-tested, optimized, and community-maintained libraries to reduce bugs and improve development efficiency.
728
728
 
729
- - **Details**
729
+ - **Details**:
730
730
  - Prefer using standard language libraries
731
731
  - Use trusted and popular community libraries
732
732
  - Evaluate library compatibility and performance
@@ -743,7 +743,7 @@
743
743
 
744
744
  - **Objective**: Ensure APIs return appropriate HTTP status codes so clients can handle errors effectively. HTTP 500 should be reserved for unexpected system errors.
745
745
 
746
- - **Details**
746
+ - **Details**:
747
747
  - Use specific HTTP status codes based on error type:
748
748
  - 400 for validation errors
749
749
  - 401 for authentication failures
@@ -763,7 +763,7 @@
763
763
 
764
764
  - **Objective**: Keep code readable, maintainable, and efficient by avoiding the use of overly complex regular expressions in business-critical logic.
765
765
 
766
- - **Details**
766
+ - **Details**:
767
767
  - Move complex regex into constants or helper functions
768
768
  - Prefer string manipulation libraries over complex regex
769
769
  - Break down complex regex into simpler processing steps
@@ -781,7 +781,7 @@
781
781
 
782
782
  - **Objective**: Centralize retry logic to improve consistency, maintainability, and observability of error handling and retry mechanisms.
783
783
 
784
- - **Details**
784
+ - **Details**:
785
785
  - Create a dedicated utility class or service for retry logic
786
786
  - Centralize retry policy configuration (retry count, delay, backoff)
787
787
  - Use decorator pattern or AOP to apply retry logic
@@ -799,7 +799,7 @@
799
799
 
800
800
  - **Objective**: Maintain a clear layered architecture, ensuring logic and data flow are well-structured and maintainable.
801
801
 
802
- - **Details**
802
+ - **Details**:
803
803
  - Controllers should only call Services, not Repositories directly
804
804
  - Services should only call Repositories, not Controllers
805
805
  - Repositories should only handle data access, not call Services
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
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": {
@@ -40,17 +40,18 @@
40
40
  "demo:file-targeting": "./demo-file-targeting.sh",
41
41
  "lint": "node cli.js --config=.sunlint.json --input=.",
42
42
  "lint:eslint-integration": "node cli.js --all --eslint-integration --input=.",
43
- "build": "npm run copy-rules && echo 'Build completed with rules copy'",
43
+ "build": "npm run copy-rules && npm run generate-registry && echo 'Build completed with rules copy and registry generation'",
44
44
  "copy-rules": "node scripts/copy-rules.js",
45
+ "generate-registry": "node scripts/generate-rules-registry.js",
45
46
  "clean": "rm -rf coverage/ *.log reports/ *.tgz",
46
47
  "postpack": "echo '📦 Package created successfully! Size: ' && ls -lh *.tgz | awk '{print $5}'",
47
48
  "start": "node cli.js --help",
48
49
  "version": "node cli.js --version",
49
- "pack": "npm run copy-rules && npm pack",
50
+ "pack": "npm run copy-rules && npm run generate-registry && npm pack",
50
51
  "publish:github": "npm publish --registry=https://npm.pkg.github.com",
51
52
  "publish:npmjs": "npm publish --registry=https://registry.npmjs.org",
52
53
  "publish:test": "npm publish --dry-run --registry=https://registry.npmjs.org",
53
- "prepublishOnly": "npm run clean && npm run copy-rules"
54
+ "prepublishOnly": "npm run clean && npm run copy-rules && npm run generate-registry"
54
55
  },
55
56
  "keywords": [
56
57
  "linting",
@@ -99,7 +100,8 @@
99
100
  "espree": "^10.3.0",
100
101
  "minimatch": "^10.0.3",
101
102
  "node-fetch": "^3.3.2",
102
- "table": "^6.8.2"
103
+ "table": "^6.8.2",
104
+ "ts-morph": "^26.0.0"
103
105
  },
104
106
  "peerDependencies": {
105
107
  "typescript": ">=4.0.0"
@@ -126,8 +128,10 @@
126
128
  },
127
129
  "devDependencies": {
128
130
  "@types/node": "^22.10.1",
131
+ "eslint-plugin-import": "^2.32.0",
129
132
  "glob": "^11.0.3",
130
- "jest": "^29.7.0"
133
+ "jest": "^29.7.0",
134
+ "typescript": "^5.8.3"
131
135
  },
132
136
  "bugs": {
133
137
  "url": "https://github.com/sun-asterisk/engineer-excellence/issues"
@@ -295,7 +295,7 @@ class C003NoVagueAbbreviations {
295
295
  const violation = this.checkVariableName(variableName, content, lineNumber, match.index);
296
296
  if (violation) {
297
297
  violations.push({
298
- rule: 'C003',
298
+ ruleId: 'C003',
299
299
  severity: 'warning',
300
300
  message: violation.message,
301
301
  line: lineNumber,
@@ -51,6 +51,13 @@ class C017Analyzer {
51
51
  if (this.isConstructorStart(trimmedLine)) {
52
52
  const constructorInfo = this.extractConstructorInfo(lines, index);
53
53
 
54
+ // Debug logging to understand boundary detection
55
+ if (config?.verbose) {
56
+ console.log(`[DEBUG] Constructor found at line ${lineNumber}`);
57
+ console.log(`[DEBUG] Constructor body lines: ${constructorInfo.body.length}`);
58
+ console.log(`[DEBUG] Constructor content:`, constructorInfo.body.map((l, i) => `${lineNumber + i}: ${l}`));
59
+ }
60
+
54
61
  const complexLogic = this.findComplexLogic(constructorInfo.body);
55
62
 
56
63
  complexLogic.forEach(logic => {
@@ -81,34 +88,94 @@ class C017Analyzer {
81
88
  const constructorLines = [];
82
89
  let braceDepth = 0;
83
90
  let foundConstructorBrace = false;
91
+ let inConstructor = false;
92
+ let parenthesesDepth = 0;
93
+ let inCallback = false;
84
94
 
85
95
  for (let i = startIndex; i < lines.length; i++) {
86
96
  const line = lines[i];
87
- constructorLines.push(line);
97
+ const trimmedLine = line.trim();
88
98
 
89
99
  // Check if this is the constructor line with opening brace
90
- if (this.isConstructorStart(line.trim())) {
91
- // Count braces in the constructor line itself
100
+ if (this.isConstructorStart(trimmedLine)) {
101
+ inConstructor = true;
102
+ constructorLines.push(line);
103
+
104
+ // Special case: empty constructor () {}
105
+ if (trimmedLine.includes(') {}')) {
106
+ foundConstructorBrace = true;
107
+ braceDepth = 0; // Already closed
108
+ break; // Stop immediately for empty constructor
109
+ }
110
+
111
+ // Count braces and parentheses in the constructor line itself
92
112
  for (const char of line) {
93
113
  if (char === '{') {
94
114
  foundConstructorBrace = true;
95
115
  braceDepth = 1; // Start counting from 1 for the constructor block
116
+ } else if (char === '(') {
117
+ parenthesesDepth++;
118
+ } else if (char === ')') {
119
+ parenthesesDepth--;
96
120
  }
97
121
  }
98
- } else if (foundConstructorBrace) {
99
- // Count braces in subsequent lines
122
+ } else if (inConstructor && foundConstructorBrace) {
123
+ constructorLines.push(line);
124
+
125
+ // Track callback functions and nested structures
100
126
  for (const char of line) {
101
- if (char === '{') {
127
+ if (char === '(') {
128
+ parenthesesDepth++;
129
+ // Detect callback patterns: .use(, .then(, .catch(, etc.
130
+ if (line.includes('.use(') || line.includes('.then(') ||
131
+ line.includes('.catch(') || line.includes('.finally(') ||
132
+ line.includes('=>')) {
133
+ inCallback = true;
134
+ }
135
+ } else if (char === ')') {
136
+ parenthesesDepth--;
137
+ if (parenthesesDepth <= 0) {
138
+ inCallback = false;
139
+ }
140
+ } else if (char === '{') {
102
141
  braceDepth++;
103
142
  } else if (char === '}') {
104
143
  braceDepth--;
105
144
  }
106
145
  }
107
146
 
108
- // If we've closed all braces, we're done
109
- if (braceDepth === 0) {
147
+ // If we've closed all braces and not in callback, we're done
148
+ if (braceDepth === 0 && !inCallback) {
110
149
  break;
111
150
  }
151
+ } else if (inConstructor) {
152
+ // Haven't found the opening brace yet, keep looking
153
+ constructorLines.push(line);
154
+
155
+ // Check for empty constructor pattern: ) {}
156
+ if (trimmedLine.includes(') {}')) {
157
+ foundConstructorBrace = true;
158
+ braceDepth = 0; // Already closed
159
+ break; // Stop immediately
160
+ }
161
+
162
+ for (const char of line) {
163
+ if (char === '{') {
164
+ foundConstructorBrace = true;
165
+ braceDepth = 1;
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ for (const char of line) {
173
+ if (char === '{') {
174
+ foundConstructorBrace = true;
175
+ braceDepth = 1;
176
+ break;
177
+ }
178
+ }
112
179
  }
113
180
  }
114
181
 
@@ -120,6 +187,14 @@ class C017Analyzer {
120
187
 
121
188
  findComplexLogic(constructorBody) {
122
189
  const complexLogic = [];
190
+ let inCallbackFunction = false;
191
+ let callbackDepth = 0;
192
+
193
+ // Check if this is an empty constructor first
194
+ // TEMPORARILY DISABLED for debugging
195
+ // if (this.isEmptyConstructor(constructorBody)) {
196
+ // return complexLogic; // Return empty array - no violations for empty constructors
197
+ // }
123
198
 
124
199
  constructorBody.forEach((line, index) => {
125
200
  const trimmedLine = line.trim();
@@ -135,7 +210,27 @@ class C017Analyzer {
135
210
  return;
136
211
  }
137
212
 
138
- // Analyze line for complex logic patterns
213
+ // Track callback functions to avoid flagging their content
214
+ if (this.isCallbackStart(trimmedLine)) {
215
+ inCallbackFunction = true;
216
+ callbackDepth = 1;
217
+ return;
218
+ }
219
+
220
+ if (inCallbackFunction) {
221
+ // Count braces to track callback boundaries
222
+ const openBraces = (trimmedLine.match(/\{/g) || []).length;
223
+ const closeBraces = (trimmedLine.match(/\}/g) || []).length;
224
+ callbackDepth += openBraces - closeBraces;
225
+
226
+ if (callbackDepth <= 0) {
227
+ inCallbackFunction = false;
228
+ callbackDepth = 0;
229
+ }
230
+ return; // Skip analysis inside callbacks
231
+ }
232
+
233
+ // Analyze line for complex logic patterns only if not in callback
139
234
  const logicType = this.analyzeLineComplexity(trimmedLine);
140
235
 
141
236
  if (logicType) {
@@ -153,6 +248,55 @@ class C017Analyzer {
153
248
  return complexLogic;
154
249
  }
155
250
 
251
+ isEmptyConstructor(constructorBody) {
252
+ // Check if constructor body contains only dependency injection parameters and closing brace
253
+ const meaningfulLines = constructorBody.filter(line => {
254
+ const trimmed = line.trim();
255
+
256
+ // Skip empty lines, comments, and constructor declaration
257
+ if (!trimmed ||
258
+ trimmed.startsWith('//') ||
259
+ trimmed.startsWith('/*') ||
260
+ trimmed.startsWith('*') ||
261
+ this.isConstructorStart(trimmed) ||
262
+ trimmed === '{' ||
263
+ trimmed === '}' ||
264
+ trimmed === ') {}') {
265
+ return false;
266
+ }
267
+
268
+ // Skip constructor parameter declarations (NestJS style)
269
+ if (trimmed.startsWith('@') || // Decorators like @InjectRepository
270
+ trimmed.match(/^\s*(private|public|protected)\s+readonly\s+\w+/) || // DI parameters
271
+ trimmed.match(/^\s*(private|public|protected)\s+\w+/) || // Other parameters
272
+ trimmed.endsWith(',') || // Parameter continuation
273
+ trimmed.endsWith(') {')) { // Constructor parameter closing
274
+ return false;
275
+ }
276
+
277
+ // This is a meaningful line (logic, assignments, calls, etc.)
278
+ return true;
279
+ });
280
+
281
+ return meaningfulLines.length === 0;
282
+ }
283
+
284
+ isCallbackStart(line) {
285
+ // Patterns that indicate callback function starts
286
+ const callbackPatterns = [
287
+ /\.(use|then|catch|finally|map|filter|forEach|reduce)\s*\(/,
288
+ /=>\s*\{/,
289
+ /function\s*\(/,
290
+ /\(\s*\w+\s*\)\s*=>/,
291
+ /interceptors\.(request|response)\.use\(/,
292
+ /\.addEventListener\(/,
293
+ /setTimeout\(/,
294
+ /setInterval\(/
295
+ ];
296
+
297
+ return callbackPatterns.some(pattern => pattern.test(line));
298
+ }
299
+
156
300
  analyzeLineComplexity(line) {
157
301
  // Simple property assignments are OK
158
302
  if (this.isSimpleAssignment(line)) {
@@ -179,6 +323,16 @@ class C017Analyzer {
179
323
  return null;
180
324
  }
181
325
 
326
+ // Configuration setup is OK
327
+ if (this.isConfigurationSetup(line)) {
328
+ return null;
329
+ }
330
+
331
+ // Interceptor setup is OK (axios, etc.)
332
+ if (this.isInterceptorSetup(line)) {
333
+ return null;
334
+ }
335
+
182
336
  // Detect complex logic patterns
183
337
  const complexPatterns = [
184
338
  {
@@ -209,7 +363,7 @@ class C017Analyzer {
209
363
  pattern: /\w+\s*\(\s*[^)]*\)\s*[;{]/,
210
364
  type: 'method_call',
211
365
  description: 'complex method calls',
212
- confidence: 0.6 // Lower confidence, only flag complex calls
366
+ confidence: 0.4 // Reduced confidence to minimize false positives
213
367
  },
214
368
  {
215
369
  pattern: /new\s+\w+\s*\([^)]*\)\s*\./,
@@ -238,16 +392,75 @@ class C017Analyzer {
238
392
  }
239
393
 
240
394
  isSimpleAssignment(line) {
241
- // Patterns for simple assignments
395
+ // Patterns for simple assignments - expanded to catch more legitimate patterns
242
396
  const simplePatterns = [
243
397
  /^this\.\w+\s*=\s*[^;]+;?$/, // this.property = value;
244
398
  /^this\.\w+\s*=\s*\w+;?$/, // this.property = parameter;
245
399
  /^this\.\w+\s*=\s*(null|undefined|true|false|\d+|'[^']*'|"[^"]*");?$/, // this.property = literal;
400
+ /^this\.\w+\s*=\s*this\.\w+\s*\.\s*get\s*\(/, // this.property = this.configService.get(
401
+ /^this\.\w+\s*=\s*new\s+\w+\s*\(/, // this.property = new SomeClass(
402
+ /^this\.\w+\s*=\s*\w+\s*\.\s*\w+\s*\(/, // this.property = service.method(
403
+ // Enhanced patterns for configuration initialization
404
+ /^this\.\w+\s*=\s*new\s+\w+Client\s*\(/, // this.s3 = new S3Client(
405
+ /^this\.\w+\s*=\s*new\s+\w+\s*\(\s*\{/, // this.prop = new Class({ config })
406
+ /^this\.\w+\s*=\s*\w+\s*\.\s*create\s*\(/, // this.prop = Factory.create(
407
+ /^this\.\w+\s*=\s*\w+\s*\.\s*getInstance\s*\(/, // this.prop = Service.getInstance(
246
408
  ];
247
409
 
248
410
  return simplePatterns.some(pattern => pattern.test(line));
249
411
  }
250
412
 
413
+ isConfigurationSetup(line) {
414
+ // Check if this is configuration/options object setup
415
+ const configPatterns = [
416
+ /^\s*\w+:\s*/, // Property definition in object literal
417
+ /level:\s*/, // Log level setting
418
+ /timestamp:\s*/, // Timestamp configuration
419
+ /formatters:\s*/, // Formatter configuration
420
+ /mixin:\s*/, // Mixin configuration
421
+ /transport:\s*/, // Transport configuration
422
+ /options:\s*/, // Options configuration
423
+ /target:\s*/, // Target configuration
424
+ /baseURL:\s*/, // Axios baseURL
425
+ /timeout:\s*/, // Axios timeout
426
+ /region:\s*/, // AWS region configuration
427
+ /credentials:\s*/, // AWS credentials
428
+ /endpoint:\s*/, // API endpoint
429
+ /apiVersion:\s*/, // API version
430
+ /maxRetries:\s*/, // Retry configuration
431
+ /headers:\s*/, // HTTP headers
432
+ /defaultHeaders:\s*/, // Default headers
433
+ /interceptors:\s*/, // Request/response interceptors
434
+ /transformRequest:\s*/, // Request transformation
435
+ /transformResponse:\s*/, // Response transformation
436
+ /validateStatus:\s*/, // Status validation
437
+ /responseType:\s*/, // Response type
438
+ /maxContentLength:\s*/, // Content length limit
439
+ /ssl:\s*/, // SSL configuration
440
+ /auth:\s*/, // Authentication
441
+ /withCredentials:\s*/, // CORS credentials
442
+ /maxRedirects:\s*/, // Max redirects
443
+ ];
444
+
445
+ return configPatterns.some(pattern => pattern.test(line));
446
+ }
447
+
448
+ isInterceptorSetup(line) {
449
+ // Check if this is axios interceptor setup (should be allowed in constructor)
450
+ const interceptorPatterns = [
451
+ /interceptors\.(request|response)\.use/,
452
+ /\.use\s*\(/,
453
+ /\.then\s*\(/,
454
+ /\.catch\s*\(/,
455
+ /\.finally\s*\(/,
456
+ /=>\s*\{?/,
457
+ /=>\s*[^{]/, // Arrow function without braces
458
+ /function\s*\(/
459
+ ];
460
+
461
+ return interceptorPatterns.some(pattern => pattern.test(line));
462
+ }
463
+
251
464
  isSuperCall(line) {
252
465
  return line.includes('super(') || line.startsWith('super.');
253
466
  }
@@ -279,7 +492,7 @@ class C017Analyzer {
279
492
  }
280
493
 
281
494
  isAllowedMethodCall(line) {
282
- // Method calls that are typically OK in constructors
495
+ // Method calls that are typically OK in constructors - expanded list
283
496
  const allowedMethods = [
284
497
  'makeObservable',
285
498
  'makeAutoObservable',
@@ -289,22 +502,46 @@ class C017Analyzer {
289
502
  'Object.assign',
290
503
  'Object.defineProperty',
291
504
  'console.log',
292
- 'console.warn'
505
+ 'console.warn',
506
+ // Common initialization patterns
507
+ 'createLogger',
508
+ 'initializeLogger',
509
+ 'setupConfiguration',
510
+ 'initializeService',
511
+ 'configure',
512
+ 'init',
513
+ 'setup',
514
+ // Common service/config patterns
515
+ 'get',
516
+ 'getService',
517
+ 'getInstance',
518
+ // Dependency injection patterns
519
+ 'inject',
520
+ 'resolve',
521
+ // Axios/HTTP setup patterns
522
+ 'interceptors',
523
+ 'use',
524
+ 'defaults',
525
+ 'timeout',
526
+ 'baseURL',
527
+ 'headers'
293
528
  ];
294
529
 
530
+ const lowerLine = line.toLowerCase();
295
531
  return allowedMethods.some(method =>
296
- line.includes(method)
532
+ lowerLine.includes(method.toLowerCase())
297
533
  );
298
534
  }
299
535
 
300
536
  hasComplexExpression(line) {
301
537
  // Check for complex expressions (multiple operators, complex calculations)
538
+ // Made more restrictive to reduce false positives
302
539
  const complexityIndicators = [
303
540
  /[+\-*/]\s*[+\-*/]/, // Multiple arithmetic operators
304
541
  /\?\s*.*\s*:/, // Ternary operators
305
- /&&|\|\|/, // Logical operators
306
- /\[[^\]]*\]/, // Array access
307
- /\.[^.]*\./ // Chained property access
542
+ /&&.*&&|\|\|.*\|\|/, // Multiple logical operators (more restrictive)
543
+ /\[[^\]]*\].*\[[^\]]*\]/, // Multiple array accesses
544
+ /\.[^.]*\.[^.]*\./ // Triple+ chained property access (more restrictive)
308
545
  ];
309
546
 
310
547
  return complexityIndicators.some(pattern => pattern.test(line));