@sun-asterisk/sunlint 1.0.7 → 1.1.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.
Files changed (219) hide show
  1. package/.sunlint.json +35 -0
  2. package/CHANGELOG.md +30 -3
  3. package/CONTRIBUTING.md +235 -0
  4. package/PROJECT_STRUCTURE.md +60 -0
  5. package/README.md +146 -58
  6. package/cli.js +1 -0
  7. package/config/README.md +88 -0
  8. package/config/defaults/ai-rules-context.json +231 -0
  9. package/config/engines/engines.json +49 -0
  10. package/config/engines/eslint-rule-mapping.json +74 -0
  11. package/config/eslint-rule-mapping.json +126 -0
  12. package/config/integrations/eslint/base.config.js +125 -0
  13. package/config/integrations/eslint/simple.config.js +24 -0
  14. package/config/presets/strict.json +0 -1
  15. package/config/rule-analysis-strategies.js +74 -0
  16. package/config/{rules-registry.json → rules/rules-registry.json} +30 -7
  17. package/core/analysis-orchestrator.js +383 -591
  18. package/core/ast-modules/README.md +103 -0
  19. package/core/ast-modules/base-parser.js +90 -0
  20. package/core/ast-modules/index.js +97 -0
  21. package/core/ast-modules/package.json +37 -0
  22. package/core/ast-modules/parsers/eslint-js-parser.js +153 -0
  23. package/core/ast-modules/parsers/eslint-ts-parser.js +98 -0
  24. package/core/ast-modules/parsers/javascript-parser.js +187 -0
  25. package/core/ast-modules/parsers/typescript-parser.js +187 -0
  26. package/core/cli-action-handler.js +271 -255
  27. package/core/cli-program.js +18 -4
  28. package/core/config-manager.js +9 -3
  29. package/core/config-merger.js +40 -1
  30. package/core/config-validator.js +2 -2
  31. package/core/dependency-checker.js +125 -0
  32. package/core/enhanced-rules-registry.js +331 -0
  33. package/core/file-targeting-service.js +92 -23
  34. package/core/interfaces/analysis-engine.interface.js +100 -0
  35. package/core/multi-rule-runner.js +0 -221
  36. package/core/output-service.js +1 -1
  37. package/core/rule-mapping-service.js +1 -1
  38. package/core/rule-selection-service.js +10 -2
  39. package/core/smart-installer.js +164 -0
  40. package/docs/AI.md +163 -0
  41. package/docs/ARCHITECTURE.md +78 -0
  42. package/docs/CI-CD-GUIDE.md +315 -0
  43. package/docs/COMMAND-EXAMPLES.md +256 -0
  44. package/docs/CONFIGURATION.md +414 -0
  45. package/docs/DEBUG.md +86 -0
  46. package/docs/DEPENDENCIES.md +90 -0
  47. package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
  48. package/docs/DISTRIBUTION.md +153 -0
  49. package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
  50. package/docs/ESLINT_INTEGRATION.md +238 -0
  51. package/docs/FOLDER_STRUCTURE.md +59 -0
  52. package/docs/FUTURE_PACKAGES.md +83 -0
  53. package/docs/HEURISTIC_VS_AI.md +113 -0
  54. package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +112 -0
  55. package/docs/PRODUCTION_SIZE_IMPACT.md +183 -0
  56. package/docs/README.md +32 -0
  57. package/docs/RELEASE_GUIDE.md +230 -0
  58. package/engines/eslint-engine.js +610 -0
  59. package/engines/heuristic-engine.js +864 -0
  60. package/engines/openai-engine.js +374 -0
  61. package/engines/tree-sitter-parser.js +0 -0
  62. package/engines/universal-ast-engine.js +0 -0
  63. package/integrations/eslint/README.md +99 -0
  64. package/integrations/eslint/configs/.eslintrc.js +98 -0
  65. package/integrations/eslint/configs/eslint.config.js +133 -0
  66. package/integrations/eslint/configs/eslint.config.simple.js +24 -0
  67. package/integrations/eslint/package.json +23 -0
  68. package/integrations/eslint/plugin/index.js +164 -0
  69. package/integrations/eslint/plugin/package.json +13 -0
  70. package/integrations/eslint/plugin/rules/common/c002-no-duplicate-code.js +204 -0
  71. package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +246 -0
  72. package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +216 -0
  73. package/integrations/eslint/plugin/rules/common/c010-limit-block-nesting.js +90 -0
  74. package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
  75. package/integrations/eslint/plugin/rules/common/c014-abstract-dependency-preferred.js +38 -0
  76. package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
  77. package/integrations/eslint/plugin/rules/common/c018-no-generic-throw.js +335 -0
  78. package/integrations/eslint/plugin/rules/common/c023-no-duplicate-variable-name-in-scope.js +142 -0
  79. package/integrations/eslint/plugin/rules/common/c029-catch-block-logging.js +115 -0
  80. package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +294 -0
  81. package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
  82. package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
  83. package/integrations/eslint/plugin/rules/common/c042-boolean-name-prefix.js +406 -0
  84. package/integrations/eslint/plugin/rules/common/c043-no-console-or-print.js +300 -0
  85. package/integrations/eslint/plugin/rules/common/c047-no-duplicate-retry-logic.js +239 -0
  86. package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
  87. package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
  88. package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
  89. package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
  90. package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
  91. package/integrations/eslint/plugin/rules/security/s003-no-unvalidated-redirect.js +86 -0
  92. package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
  93. package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
  94. package/integrations/eslint/plugin/rules/security/s047-secure-random-passwords.js +108 -0
  95. package/integrations/eslint/plugin/rules/security/s055-verification-rest-check-the-incoming-content-type.js +143 -0
  96. package/integrations/eslint/plugin/rules/typescript/t002-interface-prefix-i.js +42 -0
  97. package/integrations/eslint/plugin/rules/typescript/t003-ts-ignore-reason.js +48 -0
  98. package/integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js +95 -0
  99. package/integrations/eslint/plugin/rules/typescript/t007-no-fn-in-constructor.js +52 -0
  100. package/integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js +48 -0
  101. package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
  102. package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
  103. package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
  104. package/integrations/eslint/tsconfig.json +27 -0
  105. package/package.json +61 -21
  106. package/rules/README.md +252 -0
  107. package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
  108. package/rules/common/C002_no_duplicate_code/config.json +23 -0
  109. package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
  110. package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
  111. package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
  112. package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
  113. package/rules/common/C013_no_dead_code/analyzer.js +206 -0
  114. package/rules/common/C014_dependency_injection/analyzer.js +338 -0
  115. package/rules/common/C017_constructor_logic/analyzer.js +314 -0
  116. package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
  117. package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
  118. package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
  119. package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
  120. package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
  121. package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
  122. package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
  123. package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
  124. package/rules/docs/C002_no_duplicate_code.md +57 -0
  125. package/rules/index.js +149 -0
  126. package/rules/migration/converter.js +385 -0
  127. package/rules/migration/mapping.json +164 -0
  128. package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
  129. package/rules/security/S026_json_schema_validation/config.json +27 -0
  130. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
  131. package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
  132. package/rules/security/S029_csrf_protection/analyzer.js +264 -0
  133. package/rules/tests/C002_no_duplicate_code.test.js +50 -0
  134. package/rules/universal/C010/generic.js +0 -0
  135. package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
  136. package/rules/utils/ast-utils.js +191 -0
  137. package/rules/utils/base-analyzer.js +98 -0
  138. package/rules/utils/pattern-matchers.js +239 -0
  139. package/rules/utils/rule-helpers.js +264 -0
  140. package/rules/utils/severity-constants.js +93 -0
  141. package/scripts/build-release.sh +117 -0
  142. package/scripts/ci-report.js +179 -0
  143. package/scripts/install.sh +196 -0
  144. package/scripts/manual-release.sh +338 -0
  145. package/scripts/merge-reports.js +424 -0
  146. package/scripts/pre-release-test.sh +175 -0
  147. package/scripts/prepare-release.sh +202 -0
  148. package/scripts/setup-github-registry.sh +42 -0
  149. package/scripts/test-scripts/README.md +22 -0
  150. package/scripts/test-scripts/test-c041-comparison.js +114 -0
  151. package/scripts/test-scripts/test-c041-eslint.js +67 -0
  152. package/scripts/test-scripts/test-eslint-rules.js +146 -0
  153. package/scripts/test-scripts/test-real-world.js +44 -0
  154. package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
  155. package/scripts/trigger-release.sh +285 -0
  156. package/scripts/validate-rule-structure.js +148 -0
  157. package/scripts/verify-install.sh +82 -0
  158. package/config/sunlint-schema.json +0 -159
  159. package/config/typescript/custom-rules.js +0 -9
  160. package/config/typescript/package-lock.json +0 -1585
  161. package/config/typescript/package.json +0 -13
  162. package/config/typescript/security-rules/index.js +0 -90
  163. package/config/typescript/tsconfig.json +0 -29
  164. package/core/ai-analyzer.js +0 -169
  165. package/core/eslint-engine-service.js +0 -312
  166. package/core/eslint-instance-manager.js +0 -104
  167. package/core/eslint-integration-service.js +0 -363
  168. package/core/sunlint-engine-service.js +0 -23
  169. package/core/typescript-analyzer.js +0 -262
  170. package/core/typescript-engine.js +0 -313
  171. /package/config/{default.json → defaults/default.json} +0 -0
  172. /package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +0 -0
  173. /package/config/{typescript/custom-rules-new.js → schemas/sunlint-schema.json} +0 -0
  174. /package/config/{typescript → testing}/test-s005-working.ts +0 -0
  175. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
  176. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
  177. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
  178. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
  179. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
  180. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
  181. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
  182. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
  183. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
  184. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
  185. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
  186. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
  187. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
  188. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
  189. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
  190. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
  191. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
  192. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
  193. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
  194. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
  195. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
  196. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
  197. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
  198. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
  199. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
  200. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
  201. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
  202. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
  203. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
  204. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
  205. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
  206. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
  207. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
  208. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
  209. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
  210. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
  211. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
  212. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
  213. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
  214. /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
  215. /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
  216. /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
  217. /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
  218. /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
  219. /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * JavaScript AST Parser
3
+ * Uses Tree-sitter for JavaScript parsing
4
+ * Rule C005: Single responsibility - JavaScript AST parsing only
5
+ */
6
+
7
+ const BaseASTParser = require('../base-parser');
8
+
9
+ class JavaScriptParser extends BaseASTParser {
10
+ constructor() {
11
+ super('javascript');
12
+ }
13
+
14
+ async initialize() {
15
+ try {
16
+ const Parser = require('tree-sitter');
17
+ const JavaScript = require('tree-sitter-javascript');
18
+
19
+ this.parser = new Parser();
20
+ this.parser.setLanguage(JavaScript);
21
+
22
+ return true;
23
+ } catch (error) {
24
+ console.warn('⚠️ Tree-sitter JavaScript parser not available:', error.message);
25
+ return false;
26
+ }
27
+ }
28
+
29
+ async parse(code, filePath) {
30
+ if (!this.parser) {
31
+ const initialized = await this.initialize();
32
+ if (!initialized) return null;
33
+ }
34
+
35
+ try {
36
+ const tree = this.parser.parse(code);
37
+ return tree.rootNode;
38
+ } catch (error) {
39
+ console.warn(`⚠️ JavaScript AST parsing failed for ${filePath}:`, error.message);
40
+ return null;
41
+ }
42
+ }
43
+
44
+ async analyzeRule(ruleId, code, filePath) {
45
+ const rootNode = await this.parse(code, filePath);
46
+ if (!rootNode) return null;
47
+
48
+ switch (ruleId) {
49
+ case 'C010':
50
+ return this.analyzeC010(rootNode, code, filePath);
51
+ case 'C012':
52
+ return this.analyzeC012(rootNode, code, filePath);
53
+ default:
54
+ return null;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Analyze C010: Limit block nesting depth
60
+ */
61
+ analyzeC010(rootNode, code, filePath) {
62
+ const violations = [];
63
+ const maxDepth = 4; // Default limit
64
+
65
+ const blockTypes = [
66
+ 'if_statement',
67
+ 'for_statement',
68
+ 'for_in_statement',
69
+ 'while_statement',
70
+ 'do_statement',
71
+ 'try_statement',
72
+ 'switch_statement',
73
+ 'with_statement'
74
+ ];
75
+
76
+ this.traverseAST(rootNode, (node) => {
77
+ if (blockTypes.includes(node.type)) {
78
+ const depth = this.calculateNestingDepth(node, blockTypes);
79
+ if (depth > maxDepth) {
80
+ violations.push({
81
+ ruleId: 'C010',
82
+ severity: 'warning',
83
+ message: `Block nesting depth (${depth}) exceeds maximum allowed (${maxDepth})`,
84
+ line: node.startPosition.row + 1,
85
+ column: node.startPosition.column + 1,
86
+ endLine: node.endPosition.row + 1,
87
+ endColumn: node.endPosition.column + 1,
88
+ source: this.getNodeText(node, code)
89
+ });
90
+ }
91
+ }
92
+ });
93
+
94
+ return violations;
95
+ }
96
+
97
+ /**
98
+ * Analyze C012: Limit function/method complexity
99
+ */
100
+ analyzeC012(rootNode, code, filePath) {
101
+ const violations = [];
102
+ const maxComplexity = 10; // Default limit
103
+
104
+ const functionTypes = [
105
+ 'function_declaration',
106
+ 'method_definition',
107
+ 'arrow_function',
108
+ 'function_expression'
109
+ ];
110
+
111
+ this.traverseAST(rootNode, (node) => {
112
+ if (functionTypes.includes(node.type)) {
113
+ const complexity = this.calculateCyclomaticComplexity(node);
114
+ if (complexity > maxComplexity) {
115
+ violations.push({
116
+ ruleId: 'C012',
117
+ severity: 'warning',
118
+ message: `Function complexity (${complexity}) exceeds maximum allowed (${maxComplexity})`,
119
+ line: node.startPosition.row + 1,
120
+ column: node.startPosition.column + 1,
121
+ endLine: node.endPosition.row + 1,
122
+ endColumn: node.endPosition.column + 1,
123
+ source: this.getNodeText(node, code)
124
+ });
125
+ }
126
+ }
127
+ });
128
+
129
+ return violations;
130
+ }
131
+
132
+ /**
133
+ * Calculate nesting depth from a given node
134
+ */
135
+ calculateNestingDepth(startNode, blockTypes) {
136
+ let depth = 0;
137
+ let current = startNode.parent;
138
+
139
+ while (current) {
140
+ if (blockTypes.includes(current.type)) {
141
+ depth++;
142
+ }
143
+ current = current.parent;
144
+ }
145
+
146
+ return depth + 1; // Include the current node
147
+ }
148
+
149
+ /**
150
+ * Calculate cyclomatic complexity
151
+ */
152
+ calculateCyclomaticComplexity(functionNode) {
153
+ let complexity = 1; // Base complexity
154
+
155
+ const complexityNodes = [
156
+ 'if_statement',
157
+ 'else_clause',
158
+ 'for_statement',
159
+ 'for_in_statement',
160
+ 'while_statement',
161
+ 'do_statement',
162
+ 'switch_case',
163
+ 'try_statement',
164
+ 'catch_clause',
165
+ 'conditional_expression'
166
+ ];
167
+
168
+ this.traverseAST(functionNode, (node) => {
169
+ if (complexityNodes.includes(node.type)) {
170
+ complexity++;
171
+ }
172
+ });
173
+
174
+ return complexity;
175
+ }
176
+
177
+ /**
178
+ * Get text content of a node
179
+ */
180
+ getNodeText(node, code) {
181
+ const startIndex = node.startIndex;
182
+ const endIndex = node.endIndex;
183
+ return code.slice(startIndex, endIndex);
184
+ }
185
+ }
186
+
187
+ module.exports = JavaScriptParser;
@@ -0,0 +1,187 @@
1
+ /**
2
+ * TypeScript AST Parser
3
+ * Uses Tree-sitter for TypeScript parsing
4
+ * Rule C005: Single responsibility - TypeScript AST parsing only
5
+ */
6
+
7
+ const BaseASTParser = require('../base-parser');
8
+
9
+ class TypeScriptParser extends BaseASTParser {
10
+ constructor() {
11
+ super('typescript');
12
+ }
13
+
14
+ async initialize() {
15
+ try {
16
+ const Parser = require('tree-sitter');
17
+ const TypeScript = require('tree-sitter-typescript').typescript;
18
+
19
+ this.parser = new Parser();
20
+ this.parser.setLanguage(TypeScript);
21
+
22
+ return true;
23
+ } catch (error) {
24
+ console.warn('⚠️ Tree-sitter TypeScript parser not available:', error.message);
25
+ return false;
26
+ }
27
+ }
28
+
29
+ async parse(code, filePath) {
30
+ if (!this.parser) {
31
+ const initialized = await this.initialize();
32
+ if (!initialized) return null;
33
+ }
34
+
35
+ try {
36
+ const tree = this.parser.parse(code);
37
+ return tree.rootNode;
38
+ } catch (error) {
39
+ console.warn(`⚠️ TypeScript AST parsing failed for ${filePath}:`, error.message);
40
+ return null;
41
+ }
42
+ }
43
+
44
+ async analyzeRule(ruleId, code, filePath) {
45
+ const rootNode = await this.parse(code, filePath);
46
+ if (!rootNode) return null;
47
+
48
+ switch (ruleId) {
49
+ case 'C010':
50
+ return this.analyzeC010(rootNode, code, filePath);
51
+ case 'C012':
52
+ return this.analyzeC012(rootNode, code, filePath);
53
+ default:
54
+ return null;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Analyze C010: Limit block nesting depth
60
+ */
61
+ analyzeC010(rootNode, code, filePath) {
62
+ const violations = [];
63
+ const maxDepth = 4; // Default limit
64
+
65
+ const blockTypes = [
66
+ 'if_statement',
67
+ 'for_statement',
68
+ 'for_in_statement',
69
+ 'while_statement',
70
+ 'do_statement',
71
+ 'try_statement',
72
+ 'switch_statement',
73
+ 'with_statement'
74
+ ];
75
+
76
+ this.traverseAST(rootNode, (node) => {
77
+ if (blockTypes.includes(node.type)) {
78
+ const depth = this.calculateNestingDepth(node, blockTypes);
79
+ if (depth > maxDepth) {
80
+ violations.push({
81
+ ruleId: 'C010',
82
+ severity: 'warning',
83
+ message: `Block nesting depth (${depth}) exceeds maximum allowed (${maxDepth})`,
84
+ line: node.startPosition.row + 1,
85
+ column: node.startPosition.column + 1,
86
+ endLine: node.endPosition.row + 1,
87
+ endColumn: node.endPosition.column + 1,
88
+ source: this.getNodeText(node, code)
89
+ });
90
+ }
91
+ }
92
+ });
93
+
94
+ return violations;
95
+ }
96
+
97
+ /**
98
+ * Analyze C012: Limit function/method complexity
99
+ */
100
+ analyzeC012(rootNode, code, filePath) {
101
+ const violations = [];
102
+ const maxComplexity = 10; // Default limit
103
+
104
+ const functionTypes = [
105
+ 'function_declaration',
106
+ 'method_definition',
107
+ 'arrow_function',
108
+ 'function_expression'
109
+ ];
110
+
111
+ this.traverseAST(rootNode, (node) => {
112
+ if (functionTypes.includes(node.type)) {
113
+ const complexity = this.calculateCyclomaticComplexity(node);
114
+ if (complexity > maxComplexity) {
115
+ violations.push({
116
+ ruleId: 'C012',
117
+ severity: 'warning',
118
+ message: `Function complexity (${complexity}) exceeds maximum allowed (${maxComplexity})`,
119
+ line: node.startPosition.row + 1,
120
+ column: node.startPosition.column + 1,
121
+ endLine: node.endPosition.row + 1,
122
+ endColumn: node.endPosition.column + 1,
123
+ source: this.getNodeText(node, code)
124
+ });
125
+ }
126
+ }
127
+ });
128
+
129
+ return violations;
130
+ }
131
+
132
+ /**
133
+ * Calculate nesting depth from a given node
134
+ */
135
+ calculateNestingDepth(startNode, blockTypes) {
136
+ let depth = 0;
137
+ let current = startNode.parent;
138
+
139
+ while (current) {
140
+ if (blockTypes.includes(current.type)) {
141
+ depth++;
142
+ }
143
+ current = current.parent;
144
+ }
145
+
146
+ return depth + 1; // Include the current node
147
+ }
148
+
149
+ /**
150
+ * Calculate cyclomatic complexity
151
+ */
152
+ calculateCyclomaticComplexity(functionNode) {
153
+ let complexity = 1; // Base complexity
154
+
155
+ const complexityNodes = [
156
+ 'if_statement',
157
+ 'else_clause',
158
+ 'for_statement',
159
+ 'for_in_statement',
160
+ 'while_statement',
161
+ 'do_statement',
162
+ 'switch_case',
163
+ 'try_statement',
164
+ 'catch_clause',
165
+ 'conditional_expression'
166
+ ];
167
+
168
+ this.traverseAST(functionNode, (node) => {
169
+ if (complexityNodes.includes(node.type)) {
170
+ complexity++;
171
+ }
172
+ });
173
+
174
+ return complexity;
175
+ }
176
+
177
+ /**
178
+ * Get text content of a node
179
+ */
180
+ getNodeText(node, code) {
181
+ const startIndex = node.startIndex;
182
+ const endIndex = node.endIndex;
183
+ return code.slice(startIndex, endIndex);
184
+ }
185
+ }
186
+
187
+ module.exports = TypeScriptParser;