@sun-asterisk/sunlint 1.0.5

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 (192) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/LICENSE +21 -0
  3. package/README.md +490 -0
  4. package/cli-legacy.js +355 -0
  5. package/cli.js +35 -0
  6. package/config/default.json +22 -0
  7. package/config/presets/beginner.json +36 -0
  8. package/config/presets/ci.json +46 -0
  9. package/config/presets/recommended.json +24 -0
  10. package/config/presets/strict.json +32 -0
  11. package/config/rules-registry.json +681 -0
  12. package/config/sunlint-schema.json +166 -0
  13. package/config/typescript/custom-rules-new.js +0 -0
  14. package/config/typescript/custom-rules.js +9 -0
  15. package/config/typescript/eslint.config.js +110 -0
  16. package/config/typescript/package-lock.json +1585 -0
  17. package/config/typescript/package.json +13 -0
  18. package/config/typescript/security-rules/index.js +90 -0
  19. package/config/typescript/security-rules/s005-no-origin-auth.js +95 -0
  20. package/config/typescript/security-rules/s006-activation-recovery-secret-not-plaintext.js +69 -0
  21. package/config/typescript/security-rules/s008-crypto-agility.js +62 -0
  22. package/config/typescript/security-rules/s009-no-insecure-crypto.js +103 -0
  23. package/config/typescript/security-rules/s010-no-insecure-random-in-sensitive-context.js +123 -0
  24. package/config/typescript/security-rules/s011-no-insecure-uuid.js +66 -0
  25. package/config/typescript/security-rules/s012-hardcode-secret.js +71 -0
  26. package/config/typescript/security-rules/s014-insecure-tls-version.js +50 -0
  27. package/config/typescript/security-rules/s015-insecure-tls-certificate.js +43 -0
  28. package/config/typescript/security-rules/s016-sensitive-query-parameter.js +59 -0
  29. package/config/typescript/security-rules/s017-no-sql-injection.js +193 -0
  30. package/config/typescript/security-rules/s018-positive-input-validation.js +56 -0
  31. package/config/typescript/security-rules/s019-no-raw-user-input-in-email.js +113 -0
  32. package/config/typescript/security-rules/s020-no-eval-dynamic-execution.js +89 -0
  33. package/config/typescript/security-rules/s022-output-encoding.js +78 -0
  34. package/config/typescript/security-rules/s023-no-json-injection.js +300 -0
  35. package/config/typescript/security-rules/s025-server-side-input-validation.js +217 -0
  36. package/config/typescript/security-rules/s026-json-schema-validation.js +68 -0
  37. package/config/typescript/security-rules/s027-no-hardcoded-secrets.js +80 -0
  38. package/config/typescript/security-rules/s029-require-csrf-protection.js +79 -0
  39. package/config/typescript/security-rules/s030-no-directory-browsing.js +78 -0
  40. package/config/typescript/security-rules/s033-require-samesite-cookie.js +80 -0
  41. package/config/typescript/security-rules/s034-require-host-cookie-prefix.js +77 -0
  42. package/config/typescript/security-rules/s035-cookie-specific-path.js +74 -0
  43. package/config/typescript/security-rules/s036-no-unsafe-file-include.js +68 -0
  44. package/config/typescript/security-rules/s037-require-anti-cache-headers.js +70 -0
  45. package/config/typescript/security-rules/s038-no-version-disclosure.js +74 -0
  46. package/config/typescript/security-rules/s039-no-session-token-in-url.js +63 -0
  47. package/config/typescript/security-rules/s041-require-session-invalidate-on-logout.js +211 -0
  48. package/config/typescript/security-rules/s042-require-periodic-reauthentication.js +294 -0
  49. package/config/typescript/security-rules/s043-terminate-sessions-on-password-change.js +254 -0
  50. package/config/typescript/security-rules/s044-require-full-session-for-sensitive-operations.js +292 -0
  51. package/config/typescript/security-rules/s045-anti-automation-controls.js +46 -0
  52. package/config/typescript/security-rules/s046-secure-notification-on-auth-change.js +44 -0
  53. package/config/typescript/security-rules/s048-password-credential-recovery.js +54 -0
  54. package/config/typescript/security-rules/s050-session-token-weak-hash.js +94 -0
  55. package/config/typescript/security-rules/s052-secure-random-authentication-code.js +66 -0
  56. package/config/typescript/security-rules/s054-verification-default-account.js +109 -0
  57. package/config/typescript/security-rules/s057-utc-logging.js +54 -0
  58. package/config/typescript/security-rules/s058-no-ssrf.js +73 -0
  59. package/config/typescript/test-s005-working.ts +22 -0
  60. package/config/typescript/tsconfig.json +29 -0
  61. package/core/ai-analyzer.js +169 -0
  62. package/core/analysis-orchestrator.js +705 -0
  63. package/core/cli-action-handler.js +230 -0
  64. package/core/cli-program.js +106 -0
  65. package/core/config-manager.js +396 -0
  66. package/core/config-merger.js +136 -0
  67. package/core/config-override-processor.js +74 -0
  68. package/core/config-preset-resolver.js +65 -0
  69. package/core/config-source-loader.js +152 -0
  70. package/core/config-validator.js +126 -0
  71. package/core/dependency-manager.js +105 -0
  72. package/core/eslint-engine-service.js +312 -0
  73. package/core/eslint-instance-manager.js +104 -0
  74. package/core/eslint-integration-service.js +363 -0
  75. package/core/git-utils.js +170 -0
  76. package/core/multi-rule-runner.js +239 -0
  77. package/core/output-service.js +250 -0
  78. package/core/report-generator.js +320 -0
  79. package/core/rule-mapping-service.js +309 -0
  80. package/core/rule-selection-service.js +121 -0
  81. package/core/sunlint-engine-service.js +23 -0
  82. package/core/typescript-analyzer.js +262 -0
  83. package/core/typescript-engine.js +313 -0
  84. package/docs/AI.md +163 -0
  85. package/docs/ARCHITECTURE.md +78 -0
  86. package/docs/CI-CD-GUIDE.md +315 -0
  87. package/docs/COMMAND-EXAMPLES.md +256 -0
  88. package/docs/DEBUG.md +86 -0
  89. package/docs/DISTRIBUTION.md +153 -0
  90. package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
  91. package/docs/ESLINT_INTEGRATION.md +238 -0
  92. package/docs/FOLDER_STRUCTURE.md +59 -0
  93. package/docs/HEURISTIC_VS_AI.md +113 -0
  94. package/docs/README.md +32 -0
  95. package/docs/RELEASE_GUIDE.md +230 -0
  96. package/docs/RULE-RESPONSIBILITY-MATRIX.md +204 -0
  97. package/eslint-integration/.eslintrc.js +98 -0
  98. package/eslint-integration/cli.js +35 -0
  99. package/eslint-integration/eslint-plugin-custom/c002-no-duplicate-code.js +204 -0
  100. package/eslint-integration/eslint-plugin-custom/c003-no-vague-abbreviations.js +246 -0
  101. package/eslint-integration/eslint-plugin-custom/c006-function-name-verb-noun.js +207 -0
  102. package/eslint-integration/eslint-plugin-custom/c010-limit-block-nesting.js +90 -0
  103. package/eslint-integration/eslint-plugin-custom/c013-no-dead-code.js +43 -0
  104. package/eslint-integration/eslint-plugin-custom/c014-abstract-dependency-preferred.js +38 -0
  105. package/eslint-integration/eslint-plugin-custom/c017-limit-constructor-logic.js +39 -0
  106. package/eslint-integration/eslint-plugin-custom/c018-no-generic-throw.js +335 -0
  107. package/eslint-integration/eslint-plugin-custom/c023-no-duplicate-variable-name-in-scope.js +142 -0
  108. package/eslint-integration/eslint-plugin-custom/c027-limit-function-nesting.js +50 -0
  109. package/eslint-integration/eslint-plugin-custom/c029-catch-block-logging.js +80 -0
  110. package/eslint-integration/eslint-plugin-custom/c030-use-custom-error-classes.js +294 -0
  111. package/eslint-integration/eslint-plugin-custom/c034-no-implicit-return.js +34 -0
  112. package/eslint-integration/eslint-plugin-custom/c035-no-empty-catch.js +32 -0
  113. package/eslint-integration/eslint-plugin-custom/c041-no-config-inline.js +64 -0
  114. package/eslint-integration/eslint-plugin-custom/c042-boolean-name-prefix.js +406 -0
  115. package/eslint-integration/eslint-plugin-custom/c043-no-console-or-print.js +300 -0
  116. package/eslint-integration/eslint-plugin-custom/c047-no-duplicate-retry-logic.js +239 -0
  117. package/eslint-integration/eslint-plugin-custom/c048-no-var-declaration.js +31 -0
  118. package/eslint-integration/eslint-plugin-custom/c076-one-assert-per-test.js +184 -0
  119. package/eslint-integration/eslint-plugin-custom/index.js +155 -0
  120. package/eslint-integration/eslint-plugin-custom/package.json +13 -0
  121. package/eslint-integration/eslint-plugin-custom/package.json.bak +9 -0
  122. package/eslint-integration/eslint-plugin-custom/s003-no-unvalidated-redirect.js +86 -0
  123. package/eslint-integration/eslint-plugin-custom/s005-no-origin-auth.js +95 -0
  124. package/eslint-integration/eslint-plugin-custom/s006-activation-recovery-secret-not-plaintext.js +69 -0
  125. package/eslint-integration/eslint-plugin-custom/s008-crypto-agility.js +62 -0
  126. package/eslint-integration/eslint-plugin-custom/s009-no-insecure-crypto.js +103 -0
  127. package/eslint-integration/eslint-plugin-custom/s010-no-insecure-random-in-sensitive-context.js +123 -0
  128. package/eslint-integration/eslint-plugin-custom/s011-no-insecure-uuid.js +66 -0
  129. package/eslint-integration/eslint-plugin-custom/s012-hardcode-secret.js +71 -0
  130. package/eslint-integration/eslint-plugin-custom/s014-insecure-tls-version.js +50 -0
  131. package/eslint-integration/eslint-plugin-custom/s015-insecure-tls-certificate.js +43 -0
  132. package/eslint-integration/eslint-plugin-custom/s016-sensitive-query-parameter.js +59 -0
  133. package/eslint-integration/eslint-plugin-custom/s017-no-sql-injection.js +193 -0
  134. package/eslint-integration/eslint-plugin-custom/s018-positive-input-validation.js +56 -0
  135. package/eslint-integration/eslint-plugin-custom/s019-no-raw-user-input-in-email.js +113 -0
  136. package/eslint-integration/eslint-plugin-custom/s020-no-eval-dynamic-execution.js +89 -0
  137. package/eslint-integration/eslint-plugin-custom/s022-output-encoding.js +78 -0
  138. package/eslint-integration/eslint-plugin-custom/s023-no-json-injection.js +300 -0
  139. package/eslint-integration/eslint-plugin-custom/s025-server-side-input-validation.js +217 -0
  140. package/eslint-integration/eslint-plugin-custom/s026-json-schema-validation.js +68 -0
  141. package/eslint-integration/eslint-plugin-custom/s027-no-hardcoded-secrets.js +80 -0
  142. package/eslint-integration/eslint-plugin-custom/s029-require-csrf-protection.js +79 -0
  143. package/eslint-integration/eslint-plugin-custom/s030-no-directory-browsing.js +78 -0
  144. package/eslint-integration/eslint-plugin-custom/s033-require-samesite-cookie.js +80 -0
  145. package/eslint-integration/eslint-plugin-custom/s034-require-host-cookie-prefix.js +77 -0
  146. package/eslint-integration/eslint-plugin-custom/s035-cookie-specific-path.js +74 -0
  147. package/eslint-integration/eslint-plugin-custom/s036-no-unsafe-file-include.js +68 -0
  148. package/eslint-integration/eslint-plugin-custom/s037-require-anti-cache-headers.js +70 -0
  149. package/eslint-integration/eslint-plugin-custom/s038-no-version-disclosure.js +74 -0
  150. package/eslint-integration/eslint-plugin-custom/s039-no-session-token-in-url.js +63 -0
  151. package/eslint-integration/eslint-plugin-custom/s041-require-session-invalidate-on-logout.js +211 -0
  152. package/eslint-integration/eslint-plugin-custom/s042-require-periodic-reauthentication.js +294 -0
  153. package/eslint-integration/eslint-plugin-custom/s043-terminate-sessions-on-password-change.js +254 -0
  154. package/eslint-integration/eslint-plugin-custom/s044-require-full-session-for-sensitive-operations.js +292 -0
  155. package/eslint-integration/eslint-plugin-custom/s045-anti-automation-controls.js +46 -0
  156. package/eslint-integration/eslint-plugin-custom/s046-secure-notification-on-auth-change.js +44 -0
  157. package/eslint-integration/eslint-plugin-custom/s047-secure-random-passwords.js +108 -0
  158. package/eslint-integration/eslint-plugin-custom/s048-password-credential-recovery.js +54 -0
  159. package/eslint-integration/eslint-plugin-custom/s050-session-token-weak-hash.js +94 -0
  160. package/eslint-integration/eslint-plugin-custom/s052-secure-random-authentication-code.js +66 -0
  161. package/eslint-integration/eslint-plugin-custom/s054-verification-default-account.js +109 -0
  162. package/eslint-integration/eslint-plugin-custom/s055-verification-rest-check-the-incoming-content-type.js +143 -0
  163. package/eslint-integration/eslint-plugin-custom/s057-utc-logging.js +54 -0
  164. package/eslint-integration/eslint-plugin-custom/s058-no-ssrf.js +73 -0
  165. package/eslint-integration/eslint-plugin-custom/t002-interface-prefix-i.js +42 -0
  166. package/eslint-integration/eslint-plugin-custom/t003-ts-ignore-reason.js +48 -0
  167. package/eslint-integration/eslint-plugin-custom/t004-interface-public-only.js +160 -0
  168. package/eslint-integration/eslint-plugin-custom/t007-no-fn-in-constructor.js +52 -0
  169. package/eslint-integration/eslint-plugin-custom/t011-no-real-time-dependency.js +175 -0
  170. package/eslint-integration/eslint-plugin-custom/t019-no-empty-type.js +95 -0
  171. package/eslint-integration/eslint-plugin-custom/t025-no-nested-union-tuple.js +48 -0
  172. package/eslint-integration/eslint-plugin-custom/t026-limit-nested-generics.js +377 -0
  173. package/eslint-integration/eslint.config.js +125 -0
  174. package/eslint-integration/eslint.config.simple.js +24 -0
  175. package/eslint-integration/node_modules/eslint-plugin-custom/package.json +0 -0
  176. package/eslint-integration/package.json +23 -0
  177. package/eslint-integration/sample.ts +53 -0
  178. package/eslint-integration/test-s003.js +5 -0
  179. package/eslint-integration/tsconfig.json +27 -0
  180. package/examples/.github/workflows/code-quality.yml +111 -0
  181. package/examples/.sunlint.json +42 -0
  182. package/examples/README.md +47 -0
  183. package/examples/package.json +33 -0
  184. package/package.json +100 -0
  185. package/rules/C006_function_naming/analyzer.js +338 -0
  186. package/rules/C006_function_naming/config.json +86 -0
  187. package/rules/C019_log_level_usage/analyzer.js +359 -0
  188. package/rules/C019_log_level_usage/config.json +121 -0
  189. package/rules/C029_catch_block_logging/analyzer.js +339 -0
  190. package/rules/C029_catch_block_logging/config.json +59 -0
  191. package/rules/C031_validation_separation/README.md +72 -0
  192. package/rules/C031_validation_separation/analyzer.js +186 -0
@@ -0,0 +1,313 @@
1
+ /**
2
+ * TypeScript Engine - Main coordinator for TypeScript analysis
3
+ * Rule C005: Single responsibility - orchestrates TypeScript analysis
4
+ * Rule C012: Command Query Separation - separate analysis and result processing
5
+ * Rule C014: Dependency Injection - inject required services
6
+ * Rule C015: Domain language - TypeScriptEngine
7
+ */
8
+
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+ const chalk = require('chalk');
12
+
13
+ // Rule C014: Dependency injection
14
+ const EslintInstanceManager = require('./eslint-instance-manager');
15
+ const DependencyManager = require('./dependency-manager');
16
+ const TypescriptAnalyzer = require('./typescript-analyzer');
17
+ const RuleMappingService = require('./rule-mapping-service');
18
+
19
+ class TypeScriptEngine {
20
+ constructor(eslintModulePath = null) {
21
+ // Rule C014: Dependency injection instead of direct instantiation
22
+ this.eslintInstanceManager = new EslintInstanceManager();
23
+ this.dependencyManager = new DependencyManager();
24
+ this.typescriptAnalyzer = new TypescriptAnalyzer(this.eslintInstanceManager);
25
+ this.ruleMappingService = new RuleMappingService();
26
+
27
+ this.eslintModulePath = eslintModulePath;
28
+ this.isInitialized = false;
29
+ }
30
+
31
+ /**
32
+ * Rule C006: initializeEngine - verb-noun naming
33
+ * Rule C032: No external API calls in constructor - initialization method
34
+ */
35
+ async initializeEngine() {
36
+ if (this.isInitialized) {
37
+ return;
38
+ }
39
+
40
+ // Check dependencies first
41
+ const dependenciesAvailable = await this.dependencyManager.checkDependenciesAvailable();
42
+ if (!dependenciesAvailable.allAvailable) {
43
+ console.log(chalk.yellow('⚠️ Missing TypeScript dependencies. Attempting to install...'));
44
+ const installed = await this.dependencyManager.installMissingDependencies();
45
+ if (!installed) {
46
+ throw new Error('Required TypeScript dependencies are not available');
47
+ }
48
+ }
49
+
50
+ // Initialize ESLint instance
51
+ await this.eslintInstanceManager.initializeEslintInstance(this.eslintModulePath);
52
+
53
+ this.isInitialized = true;
54
+ console.log(chalk.green('✅ TypeScript engine initialized successfully'));
55
+ }
56
+
57
+ /**
58
+ * Rule C006: runAnalysis - verb-noun naming
59
+ * Rule C005: Single responsibility - coordinates analysis
60
+ * Rule C012: Command method - performs analysis operation
61
+ */
62
+ async runAnalysis(filePaths, options = {}) {
63
+ if (!this.isInitialized) {
64
+ await this.initializeEngine();
65
+ }
66
+
67
+ // Validate input
68
+ if (!filePaths || filePaths.length === 0) {
69
+ throw new Error('No files provided for analysis');
70
+ }
71
+
72
+ const filePathsArray = Array.isArray(filePaths) ? filePaths : [filePaths];
73
+
74
+ if (options.verbose) {
75
+ console.log(chalk.blue(`🔄 Running TypeScript analysis on ${filePathsArray.length} files...`));
76
+ }
77
+
78
+ try {
79
+ const results = await this.typescriptAnalyzer.analyzeTypeScriptFiles(filePathsArray, options);
80
+
81
+ if (options.verbose) {
82
+ this.logAnalysisResults(results);
83
+ }
84
+
85
+ return results;
86
+ } catch (error) {
87
+ // Rule C035: Log full error information
88
+ console.error(chalk.red('❌ TypeScript analysis failed:'), {
89
+ message: error.message,
90
+ files: filePathsArray.length,
91
+ configPath: this.eslintInstanceManager.getConfigPath()
92
+ });
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Rule C006: configureRules - verb-noun naming
99
+ * Rule C005: Single responsibility - rule configuration
100
+ */
101
+ async configureRules(selectedRules = [], options = {}) {
102
+ if (!this.isInitialized) {
103
+ await this.initializeEngine();
104
+ }
105
+
106
+ try {
107
+ const configPath = this.eslintInstanceManager.getConfigPath();
108
+ const configFilePath = path.join(configPath, 'eslint.config.js');
109
+
110
+ if (options.verbose) {
111
+ console.log(chalk.blue(` Config path: ${configFilePath}`));
112
+ }
113
+
114
+ // Clear require cache to ensure fresh config
115
+ delete require.cache[require.resolve(configFilePath)];
116
+
117
+ // Read current config
118
+ const currentConfig = require(configFilePath);
119
+
120
+ // Convert SunLint rule IDs to ESLint rule names
121
+ const eslintRuleNames = selectedRules.map(sunlintRuleId => {
122
+ const eslintRule = this.ruleMappingService.sunlintToEslintMapping[sunlintRuleId];
123
+ return eslintRule || sunlintRuleId;
124
+ }).filter(rule => rule);
125
+
126
+ // Update rules based on selection
127
+ const updatedConfig = this.updateRulesConfiguration(currentConfig, eslintRuleNames, options);
128
+
129
+ if (options.verbose) {
130
+ console.log(chalk.blue(`🔧 Configured ${selectedRules.length} rules for analysis`));
131
+ console.log(chalk.gray(` SunLint rules: ${selectedRules.join(', ')}`));
132
+ console.log(chalk.gray(` ESLint rules: ${eslintRuleNames.join(', ')}`));
133
+ }
134
+
135
+ return updatedConfig;
136
+ } catch (error) {
137
+ console.error(chalk.red('❌ Failed to configure rules:'), error.message);
138
+ throw error;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Rule C006: updateRulesConfiguration - verb-noun naming
144
+ * Rule C005: Single responsibility - update config
145
+ * Rule C012: Pure function - no side effects
146
+ */
147
+ updateRulesConfiguration(currentConfig, selectedRules, options) {
148
+ if (!Array.isArray(currentConfig)) {
149
+ throw new Error('Expected flat config array format');
150
+ }
151
+
152
+ // Create new config with selected rules
153
+ const updatedConfig = currentConfig.map(config => {
154
+ if (config.rules) {
155
+ if (options.verbose) {
156
+ const ruleKeys = Object.keys(config.rules);
157
+ console.log(chalk.blue(` Config has ${ruleKeys.length} rules`));
158
+ const s003Rules = ruleKeys.filter(r => r.includes('s003'));
159
+ console.log(chalk.blue(` S003-related rules: ${s003Rules.join(', ') || 'none'}`));
160
+ }
161
+
162
+ // Keep all existing rules and enable selected ones
163
+ const updatedRules = { ...config.rules };
164
+
165
+ // Enable only selected rules
166
+ for (const ruleId of selectedRules) {
167
+ if (options.verbose) {
168
+ console.log(chalk.blue(` Checking rule: ${ruleId}`));
169
+ console.log(chalk.blue(` Available in config: ${ruleId in config.rules}`));
170
+ }
171
+
172
+ if (config.rules[ruleId] !== undefined) {
173
+ updatedRules[ruleId] = 'error'; // Enable the rule as error
174
+ if (options.verbose) {
175
+ console.log(chalk.gray(` Enabling rule: ${ruleId} as error`));
176
+ }
177
+ } else {
178
+ if (options.verbose) {
179
+ console.log(chalk.red(` Rule not found in config: ${ruleId}`));
180
+ }
181
+ }
182
+ }
183
+
184
+ return {
185
+ ...config,
186
+ rules: updatedRules
187
+ };
188
+ }
189
+ return config;
190
+ });
191
+
192
+ return updatedConfig;
193
+ }
194
+
195
+ /**
196
+ * Rule C006: logAnalysisResults - verb-noun naming
197
+ * Rule C005: Single responsibility - logging
198
+ */
199
+ logAnalysisResults(results) {
200
+ const { totalFiles, totalErrors, totalWarnings } = results;
201
+
202
+ console.log(chalk.blue('📊 TypeScript Analysis Results:'));
203
+ console.log(chalk.gray(` Files analyzed: ${totalFiles}`));
204
+ console.log(chalk.gray(` Errors found: ${totalErrors}`));
205
+ console.log(chalk.gray(` Warnings found: ${totalWarnings}`));
206
+
207
+ if (totalErrors === 0 && totalWarnings === 0) {
208
+ console.log(chalk.green(' ✅ All checks passed!'));
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Rule C006: getEngineStatus - verb-noun naming
214
+ * Rule C012: Query method - returns status without side effects
215
+ */
216
+ getEngineStatus() {
217
+ return {
218
+ initialized: this.isInitialized,
219
+ configPath: this.eslintInstanceManager.getConfigPath(),
220
+ eslintReady: this.eslintInstanceManager.checkInstanceReady()
221
+ };
222
+ }
223
+
224
+ /**
225
+ * Rule C006: checkDependencies - verb-noun naming
226
+ * Rule C014: Delegate to dependency manager
227
+ */
228
+ async checkDependencies() {
229
+ return this.dependencyManager.checkDependenciesAvailable();
230
+ }
231
+
232
+ /**
233
+ * Rule C006: installDependencies - verb-noun naming
234
+ * Rule C014: Delegate to dependency manager
235
+ */
236
+ async installDependencies() {
237
+ return this.dependencyManager.installMissingDependencies();
238
+ }
239
+
240
+ /**
241
+ * Rule C006: convertToSunLintFormat - verb-noun naming
242
+ * Rule C012: Pure function - converts ESLint results to SunLint format
243
+ */
244
+ convertToSunLintFormat(eslintResults, ruleMapping = {}, options = {}) {
245
+ const chalk = require('chalk');
246
+ // Handle both direct results and wrapped results
247
+ const resultsArray = eslintResults.results || [eslintResults];
248
+ const problems = [];
249
+ const convertedResults = [];
250
+
251
+ for (const result of resultsArray) {
252
+ // Skip if no messages
253
+ if (!result || !result.messages) continue;
254
+
255
+ const violations = [];
256
+
257
+ for (const message of result.messages) {
258
+ // Map ESLint rule ID to SunLint rule ID if mapping provided
259
+ const sunlintRuleId = ruleMapping[message.ruleId] || message.ruleId;
260
+
261
+ // Debug logging
262
+ if (options && options.verbose) {
263
+ console.log(chalk.gray(` ESLint message: ${message.ruleId} -> ${sunlintRuleId} (${message.message})`));
264
+ }
265
+
266
+ // Ensure we have a valid file path
267
+ const filePath = result.filePath || result.file || 'unknown';
268
+
269
+ const violation = {
270
+ ruleId: sunlintRuleId,
271
+ severity: message.severity === 2 ? 'error' : 'warning',
272
+ message: message.message,
273
+ file: filePath,
274
+ line: message.line,
275
+ column: message.column,
276
+ endLine: message.endLine,
277
+ endColumn: message.endColumn
278
+ };
279
+
280
+ violations.push(violation);
281
+ problems.push(violation);
282
+ }
283
+
284
+ if (violations.length > 0) {
285
+ convertedResults.push({
286
+ filePath: result.filePath || result.file || 'unknown',
287
+ violations: violations
288
+ });
289
+ }
290
+ }
291
+
292
+ return {
293
+ problems,
294
+ results: convertedResults,
295
+ errorCount: problems.filter(p => p.severity === 'error').length,
296
+ warningCount: problems.filter(p => p.severity === 'warning').length,
297
+ fileCount: eslintResults.totalFiles || resultsArray.length,
298
+ totalViolations: problems.length
299
+ };
300
+ }
301
+
302
+ // Legacy method names for backward compatibility
303
+ async initializeEslint() {
304
+ return this.initializeEngine();
305
+ }
306
+
307
+ // Rule C006: getEslintInstance - kept for backward compatibility
308
+ getEslintInstance() {
309
+ return this.eslintInstanceManager.getEslintInstance();
310
+ }
311
+ }
312
+
313
+ module.exports = TypeScriptEngine;
package/docs/AI.md ADDED
@@ -0,0 +1,163 @@
1
+ # 🤖 AI-Powered Analysis
2
+
3
+ Sunlint supports AI-powered code analysis alongside traditional pattern-based analysis for more intelligent and context-aware rule checking.
4
+
5
+ ## Overview
6
+
7
+ - **🎯 Smart Analysis**: Uses AI to understand code context and intent
8
+ - **🔄 Fallback Strategy**: Automatically falls back to pattern analysis if AI fails
9
+ - **⚡ Performance**: AI analysis runs per-file with caching support
10
+ - **🔧 Configurable**: Multiple AI providers and models supported
11
+
12
+ ## Configuration
13
+
14
+ ### In `.sunlint.json`:
15
+
16
+ ```json
17
+ {
18
+ "ai": {
19
+ "enabled": true,
20
+ "provider": "openai",
21
+ "model": "gpt-4o-mini",
22
+ "apiKey": "${OPENAI_API_KEY}",
23
+ "fallbackToPattern": true
24
+ }
25
+ }
26
+ ```
27
+
28
+ ### Environment Variables:
29
+
30
+ ```bash
31
+ export OPENAI_API_KEY="your-openai-api-key"
32
+ ```
33
+
34
+ ## Supported Providers
35
+
36
+ ### OpenAI
37
+ - **Models**: `gpt-4`, `gpt-4o-mini`, `gpt-3.5-turbo`
38
+ - **API Key**: Required via `OPENAI_API_KEY` environment variable
39
+ - **Cost**: Pay-per-use based on OpenAI pricing
40
+
41
+ ### GitHub Copilot (Planned)
42
+ - **Integration**: VS Code extension integration
43
+ - **Models**: GitHub Copilot models
44
+ - **Authentication**: VS Code Copilot session
45
+
46
+ ## AI-Enhanced Rules
47
+
48
+ ### C019 - Log Level Usage
49
+ ✅ **AI-Enabled**: Understands code context to determine appropriate log levels
50
+
51
+ **AI Analysis Features:**
52
+ - **Context Understanding**: Analyzes surrounding code to determine error criticality
53
+ - **Intent Recognition**: Understands whether errors are expected or exceptional
54
+ - **Semantic Analysis**: Goes beyond pattern matching to understand meaning
55
+
56
+ **Example:**
57
+ ```typescript
58
+ // AI understands this is a validation error, suggests warn level
59
+ if (!user.email) {
60
+ console.error('Missing email'); // AI: Should use console.warn()
61
+ }
62
+
63
+ // AI understands this is a critical system error, keeps error level
64
+ try {
65
+ await database.connect();
66
+ } catch (error) {
67
+ console.error('Database connection failed:', error); // AI: Appropriate error level
68
+ }
69
+ ```
70
+
71
+ ## Usage
72
+
73
+ ### CLI Commands
74
+
75
+ **Enable AI for specific rule:**
76
+ ```bash
77
+ sunlint --rule=C019 --input=src --ai
78
+ ```
79
+
80
+ **Enable AI for all rules:**
81
+ ```bash
82
+ sunlint --quality --input=src --ai
83
+ ```
84
+
85
+ **Debug AI analysis:**
86
+ ```bash
87
+ sunlint --rule=C019 --input=src --ai --verbose
88
+ ```
89
+
90
+ ### VS Code Integration
91
+
92
+ 1. **Debug Configuration**: Use "Debug Sunlint - AI Analysis"
93
+ 2. **Task**: Run "Sunlint: AI Analysis Test"
94
+ 3. **Set API Key**: Configure `OPENAI_API_KEY` in environment
95
+
96
+ ## Output Differences
97
+
98
+ ### Pattern Analysis Output:
99
+ ```
100
+ WARNING: Error log level used for non-critical issue - should use warn/info level
101
+ at src/user.ts:15:5 (C019)
102
+ ```
103
+
104
+ ### AI Analysis Output:
105
+ ```
106
+ WARNING: Email validation error should use console.warn() - this is user input validation, not a system error
107
+ at src/user.ts:15:5 (C019)
108
+ Suggestion: Change to console.warn('User email validation failed:', email)
109
+ ```
110
+
111
+ ## Performance Considerations
112
+
113
+ - **Caching**: AI responses are cached per file content hash
114
+ - **Concurrency**: AI calls are made concurrently with rate limiting
115
+ - **Timeout**: 30-second timeout per AI request
116
+ - **Cost**: Monitor API usage in OpenAI dashboard
117
+
118
+ ## Troubleshooting
119
+
120
+ ### Common Issues
121
+
122
+ **API Key Not Found:**
123
+ ```bash
124
+ ⚠️ AI API key not found, falling back to pattern analysis
125
+ ```
126
+ Solution: Set `OPENAI_API_KEY` environment variable
127
+
128
+ **API Rate Limit:**
129
+ ```bash
130
+ AI Analysis failed: OpenAI API error: 429 Too Many Requests
131
+ ```
132
+ Solution: Reduce `maxConcurrentRules` in config or wait
133
+
134
+ **Network Issues:**
135
+ ```bash
136
+ AI Analysis failed: OpenAI API error: Network timeout
137
+ ```
138
+ Solution: Check internet connection, increase `timeoutMs`
139
+
140
+ ### Debug AI Issues
141
+
142
+ 1. **Enable verbose mode**: `--verbose`
143
+ 2. **Check API key**: `echo $OPENAI_API_KEY`
144
+ 3. **Test connection**: Use debug configuration
145
+ 4. **Check API quota**: Visit OpenAI dashboard
146
+
147
+ ## Future Enhancements
148
+
149
+ - **🔄 GitHub Copilot Integration**: Direct integration with VS Code Copilot
150
+ - **📊 Custom Models**: Support for fine-tuned models
151
+ - **🎯 Rule-Specific Prompts**: Specialized prompts per rule type
152
+ - **💾 Smart Caching**: Semantic caching across similar code patterns
153
+ - **📈 Analytics**: AI vs Pattern analysis effectiveness metrics
154
+
155
+ ## Cost Estimation
156
+
157
+ **OpenAI API Costs** (approximate):
158
+ - **gpt-4o-mini**: ~$0.001 per 1K tokens
159
+ - **gpt-4**: ~$0.03 per 1K tokens
160
+ - **Average file**: ~500 tokens
161
+ - **1000 files with gpt-4o-mini**: ~$0.50
162
+
163
+ **Recommendation**: Start with `gpt-4o-mini` for cost-effectiveness.
@@ -0,0 +1,78 @@
1
+ # SunLint Modular Architecture
2
+
3
+ ## Phase 1: TypeScript Focus với Kiến trúc Modular
4
+
5
+ ### Cấu trúc mới:
6
+
7
+ ```
8
+ cli.js # CLI entry point (simplified)
9
+ core/
10
+ ├── cli-program.js # CLI options definition (Rule C005)
11
+ ├── cli-action-handler.js # Main execution flow (Rule C005)
12
+ ├── rule-selection-service.js # Rule selection logic (Rule C005)
13
+ ├── analysis-orchestrator.js # Analysis coordination (Rule C005)
14
+ ├── output-service.js # Output formatting (Rule C005)
15
+ ├── eslint-engine-service.js # ESLint integration (future)
16
+ └── sunlint-engine-service.js # Native SunLint engine
17
+ ```
18
+
19
+ ### Nguyên tắc thiết kế:
20
+
21
+ 1. **Rule C005**: Mỗi class/file chỉ làm một việc
22
+ 2. **Rule C014**: Dependency injection thay vì new trực tiếp
23
+ 3. **Rule C012**: Tách rõ Command và Query
24
+ 4. **Modular**: Dễ mở rộng cho Phase 2
25
+
26
+ ### Luồng hoạt động:
27
+
28
+ 1. `cli.js` → `CliActionHandler`
29
+ 2. `CliActionHandler` → Load config, validate input
30
+ 3. `RuleSelectionService` → Select rules based on options
31
+ 4. `AnalysisOrchestrator` → Run analysis (SunLint or ESLint)
32
+ 5. `OutputService` → Format and display results
33
+
34
+ ### Các tính năng hiện tại:
35
+
36
+ - ✅ Modular CLI với dependency injection
37
+ - ✅ Rule selection (single, multiple, all, category)
38
+ - ✅ Dry run mode
39
+ - ✅ TypeScript-specific options (chuẩn bị cho Phase 1)
40
+ - ✅ Graceful fallback khi không tìm thấy dependencies
41
+ - ✅ Clean error handling và logging
42
+
43
+ ### Phase 1 roadmap:
44
+
45
+ 1. **✅ Done**: Modular CLI architecture
46
+ 2. **✅ Done**: ESLint integration cho TypeScript
47
+ 3. **Next**: TypeScript custom rules thông qua ESLint
48
+ 4. **✅ Done**: Hybrid engine (ESLint + SunLint)
49
+
50
+ ### Phase 2 roadmap:
51
+
52
+ 1. Native SunLint engine cho tất cả ngôn ngữ
53
+ 2. Mở rộng Dart, Kotlin rules
54
+ 3. AI-powered analysis
55
+ 4. VS Code extension integration
56
+
57
+ ### Usage Examples:
58
+
59
+ ```bash
60
+ # Basic usage
61
+ sunlint --rule=C006 --input=src
62
+
63
+ # Category-based
64
+ sunlint --quality --input=src
65
+
66
+ # TypeScript-specific (Phase 1)
67
+ sunlint --typescript --input=src
68
+ sunlint --typescript-engine=eslint --input=src
69
+
70
+ # Dry run
71
+ sunlint --dry-run --all --input=src
72
+ ```
73
+
74
+ ### Dependencies:
75
+
76
+ - Minimal core dependencies
77
+ - ESLint integration sẽ được thêm trong Phase 1
78
+ - Graceful fallback khi dependencies không có sẵn