@nahisaho/musubix-core 1.0.0

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 (214) hide show
  1. package/bin/musubix.js +18 -0
  2. package/dist/__tests__/index.test.d.ts +2 -0
  3. package/dist/__tests__/index.test.d.ts.map +1 -0
  4. package/dist/__tests__/index.test.js +27 -0
  5. package/dist/__tests__/index.test.js.map +1 -0
  6. package/dist/auth/auth-manager.d.ts +320 -0
  7. package/dist/auth/auth-manager.d.ts.map +1 -0
  8. package/dist/auth/auth-manager.js +580 -0
  9. package/dist/auth/auth-manager.js.map +1 -0
  10. package/dist/cli/base.d.ts +58 -0
  11. package/dist/cli/base.d.ts.map +1 -0
  12. package/dist/cli/base.js +93 -0
  13. package/dist/cli/base.js.map +1 -0
  14. package/dist/cli/commands/help.d.ts +17 -0
  15. package/dist/cli/commands/help.d.ts.map +1 -0
  16. package/dist/cli/commands/help.js +228 -0
  17. package/dist/cli/commands/help.js.map +1 -0
  18. package/dist/cli/commands/index.d.ts +14 -0
  19. package/dist/cli/commands/index.d.ts.map +1 -0
  20. package/dist/cli/commands/index.js +25 -0
  21. package/dist/cli/commands/index.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +38 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +258 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/index.d.ts +9 -0
  27. package/dist/cli/index.d.ts.map +1 -0
  28. package/dist/cli/index.js +9 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/codegen/coding-standards.d.ts +250 -0
  31. package/dist/codegen/coding-standards.d.ts.map +1 -0
  32. package/dist/codegen/coding-standards.js +976 -0
  33. package/dist/codegen/coding-standards.js.map +1 -0
  34. package/dist/codegen/coverage-reporter.d.ts +264 -0
  35. package/dist/codegen/coverage-reporter.d.ts.map +1 -0
  36. package/dist/codegen/coverage-reporter.js +697 -0
  37. package/dist/codegen/coverage-reporter.js.map +1 -0
  38. package/dist/codegen/dependency-analyzer.d.ts +271 -0
  39. package/dist/codegen/dependency-analyzer.d.ts.map +1 -0
  40. package/dist/codegen/dependency-analyzer.js +661 -0
  41. package/dist/codegen/dependency-analyzer.js.map +1 -0
  42. package/dist/codegen/generator.d.ts +275 -0
  43. package/dist/codegen/generator.d.ts.map +1 -0
  44. package/dist/codegen/generator.js +781 -0
  45. package/dist/codegen/generator.js.map +1 -0
  46. package/dist/codegen/index.d.ts +18 -0
  47. package/dist/codegen/index.d.ts.map +1 -0
  48. package/dist/codegen/index.js +27 -0
  49. package/dist/codegen/index.js.map +1 -0
  50. package/dist/codegen/integration-test-generator.d.ts +312 -0
  51. package/dist/codegen/integration-test-generator.d.ts.map +1 -0
  52. package/dist/codegen/integration-test-generator.js +765 -0
  53. package/dist/codegen/integration-test-generator.js.map +1 -0
  54. package/dist/codegen/pattern-conformance.d.ts +309 -0
  55. package/dist/codegen/pattern-conformance.d.ts.map +1 -0
  56. package/dist/codegen/pattern-conformance.js +590 -0
  57. package/dist/codegen/pattern-conformance.js.map +1 -0
  58. package/dist/codegen/quality-metrics.d.ts +235 -0
  59. package/dist/codegen/quality-metrics.d.ts.map +1 -0
  60. package/dist/codegen/quality-metrics.js +439 -0
  61. package/dist/codegen/quality-metrics.js.map +1 -0
  62. package/dist/codegen/security-scanner.d.ts +179 -0
  63. package/dist/codegen/security-scanner.d.ts.map +1 -0
  64. package/dist/codegen/security-scanner.js +495 -0
  65. package/dist/codegen/security-scanner.js.map +1 -0
  66. package/dist/codegen/static-analyzer.d.ts +188 -0
  67. package/dist/codegen/static-analyzer.d.ts.map +1 -0
  68. package/dist/codegen/static-analyzer.js +490 -0
  69. package/dist/codegen/static-analyzer.js.map +1 -0
  70. package/dist/codegen/unit-test-generator.d.ts +289 -0
  71. package/dist/codegen/unit-test-generator.d.ts.map +1 -0
  72. package/dist/codegen/unit-test-generator.js +634 -0
  73. package/dist/codegen/unit-test-generator.js.map +1 -0
  74. package/dist/design/adr-generator.d.ts +227 -0
  75. package/dist/design/adr-generator.d.ts.map +1 -0
  76. package/dist/design/adr-generator.js +423 -0
  77. package/dist/design/adr-generator.js.map +1 -0
  78. package/dist/design/c4-generator.d.ts +267 -0
  79. package/dist/design/c4-generator.d.ts.map +1 -0
  80. package/dist/design/c4-generator.js +453 -0
  81. package/dist/design/c4-generator.js.map +1 -0
  82. package/dist/design/framework-optimizer.d.ts +190 -0
  83. package/dist/design/framework-optimizer.d.ts.map +1 -0
  84. package/dist/design/framework-optimizer.js +589 -0
  85. package/dist/design/framework-optimizer.js.map +1 -0
  86. package/dist/design/index.d.ts +12 -0
  87. package/dist/design/index.d.ts.map +1 -0
  88. package/dist/design/index.js +13 -0
  89. package/dist/design/index.js.map +1 -0
  90. package/dist/design/pattern-detector.d.ts +270 -0
  91. package/dist/design/pattern-detector.d.ts.map +1 -0
  92. package/dist/design/pattern-detector.js +621 -0
  93. package/dist/design/pattern-detector.js.map +1 -0
  94. package/dist/design/solid-validator.d.ts +188 -0
  95. package/dist/design/solid-validator.d.ts.map +1 -0
  96. package/dist/design/solid-validator.js +579 -0
  97. package/dist/design/solid-validator.js.map +1 -0
  98. package/dist/error/data-persistence.d.ts +311 -0
  99. package/dist/error/data-persistence.d.ts.map +1 -0
  100. package/dist/error/data-persistence.js +586 -0
  101. package/dist/error/data-persistence.js.map +1 -0
  102. package/dist/error/graceful-degradation.d.ts +309 -0
  103. package/dist/error/graceful-degradation.d.ts.map +1 -0
  104. package/dist/error/graceful-degradation.js +510 -0
  105. package/dist/error/graceful-degradation.js.map +1 -0
  106. package/dist/error/index.d.ts +11 -0
  107. package/dist/error/index.d.ts.map +1 -0
  108. package/dist/error/index.js +19 -0
  109. package/dist/error/index.js.map +1 -0
  110. package/dist/explanation/explanation-generator.d.ts +228 -0
  111. package/dist/explanation/explanation-generator.d.ts.map +1 -0
  112. package/dist/explanation/explanation-generator.js +662 -0
  113. package/dist/explanation/explanation-generator.js.map +1 -0
  114. package/dist/explanation/index.d.ts +11 -0
  115. package/dist/explanation/index.d.ts.map +1 -0
  116. package/dist/explanation/index.js +19 -0
  117. package/dist/explanation/index.js.map +1 -0
  118. package/dist/explanation/reasoning-chain.d.ts +314 -0
  119. package/dist/explanation/reasoning-chain.d.ts.map +1 -0
  120. package/dist/explanation/reasoning-chain.js +414 -0
  121. package/dist/explanation/reasoning-chain.js.map +1 -0
  122. package/dist/explanation/visual-explanation.d.ts +315 -0
  123. package/dist/explanation/visual-explanation.d.ts.map +1 -0
  124. package/dist/explanation/visual-explanation.js +667 -0
  125. package/dist/explanation/visual-explanation.js.map +1 -0
  126. package/dist/index.d.ts +33 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +47 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/requirements/decomposer.d.ts +235 -0
  131. package/dist/requirements/decomposer.d.ts.map +1 -0
  132. package/dist/requirements/decomposer.js +587 -0
  133. package/dist/requirements/decomposer.js.map +1 -0
  134. package/dist/requirements/related-finder.d.ts +261 -0
  135. package/dist/requirements/related-finder.d.ts.map +1 -0
  136. package/dist/requirements/related-finder.js +629 -0
  137. package/dist/requirements/related-finder.js.map +1 -0
  138. package/dist/traceability/impact.d.ts +196 -0
  139. package/dist/traceability/impact.d.ts.map +1 -0
  140. package/dist/traceability/impact.js +438 -0
  141. package/dist/traceability/impact.js.map +1 -0
  142. package/dist/traceability/index.d.ts +9 -0
  143. package/dist/traceability/index.d.ts.map +1 -0
  144. package/dist/traceability/index.js +10 -0
  145. package/dist/traceability/index.js.map +1 -0
  146. package/dist/traceability/manager.d.ts +266 -0
  147. package/dist/traceability/manager.d.ts.map +1 -0
  148. package/dist/traceability/manager.js +412 -0
  149. package/dist/traceability/manager.js.map +1 -0
  150. package/dist/types/common.d.ts +294 -0
  151. package/dist/types/common.d.ts.map +1 -0
  152. package/dist/types/common.js +15 -0
  153. package/dist/types/common.js.map +1 -0
  154. package/dist/types/ears.d.ts +158 -0
  155. package/dist/types/ears.d.ts.map +1 -0
  156. package/dist/types/ears.js +33 -0
  157. package/dist/types/ears.js.map +1 -0
  158. package/dist/types/errors.d.ts +176 -0
  159. package/dist/types/errors.d.ts.map +1 -0
  160. package/dist/types/errors.js +55 -0
  161. package/dist/types/errors.js.map +1 -0
  162. package/dist/types/index.d.ts +10 -0
  163. package/dist/types/index.d.ts.map +1 -0
  164. package/dist/types/index.js +10 -0
  165. package/dist/types/index.js.map +1 -0
  166. package/dist/utils/data-protector.d.ts +122 -0
  167. package/dist/utils/data-protector.d.ts.map +1 -0
  168. package/dist/utils/data-protector.js +275 -0
  169. package/dist/utils/data-protector.js.map +1 -0
  170. package/dist/utils/error-handler.d.ts +101 -0
  171. package/dist/utils/error-handler.d.ts.map +1 -0
  172. package/dist/utils/error-handler.js +324 -0
  173. package/dist/utils/error-handler.js.map +1 -0
  174. package/dist/utils/i18n-manager.d.ts +259 -0
  175. package/dist/utils/i18n-manager.d.ts.map +1 -0
  176. package/dist/utils/i18n-manager.js +554 -0
  177. package/dist/utils/i18n-manager.js.map +1 -0
  178. package/dist/utils/index.d.ts +10 -0
  179. package/dist/utils/index.d.ts.map +1 -0
  180. package/dist/utils/index.js +10 -0
  181. package/dist/utils/index.js.map +1 -0
  182. package/dist/utils/logger.d.ts +120 -0
  183. package/dist/utils/logger.d.ts.map +1 -0
  184. package/dist/utils/logger.js +237 -0
  185. package/dist/utils/logger.js.map +1 -0
  186. package/dist/utils/performance-profiler.d.ts +251 -0
  187. package/dist/utils/performance-profiler.d.ts.map +1 -0
  188. package/dist/utils/performance-profiler.js +458 -0
  189. package/dist/utils/performance-profiler.js.map +1 -0
  190. package/dist/utils/scalability-optimizer.d.ts +294 -0
  191. package/dist/utils/scalability-optimizer.d.ts.map +1 -0
  192. package/dist/utils/scalability-optimizer.js +606 -0
  193. package/dist/utils/scalability-optimizer.js.map +1 -0
  194. package/dist/utils/structured-logger.d.ts +294 -0
  195. package/dist/utils/structured-logger.d.ts.map +1 -0
  196. package/dist/utils/structured-logger.js +630 -0
  197. package/dist/utils/structured-logger.js.map +1 -0
  198. package/dist/utils/version-compatibility.d.ts +217 -0
  199. package/dist/utils/version-compatibility.d.ts.map +1 -0
  200. package/dist/utils/version-compatibility.js +443 -0
  201. package/dist/utils/version-compatibility.js.map +1 -0
  202. package/dist/validators/ears-validator.d.ts +182 -0
  203. package/dist/validators/ears-validator.d.ts.map +1 -0
  204. package/dist/validators/ears-validator.js +357 -0
  205. package/dist/validators/ears-validator.js.map +1 -0
  206. package/dist/validators/index.d.ts +8 -0
  207. package/dist/validators/index.d.ts.map +1 -0
  208. package/dist/validators/index.js +9 -0
  209. package/dist/validators/index.js.map +1 -0
  210. package/dist/version.d.ts +8 -0
  211. package/dist/version.d.ts.map +1 -0
  212. package/dist/version.js +8 -0
  213. package/dist/version.js.map +1 -0
  214. package/package.json +100 -0
@@ -0,0 +1,976 @@
1
+ /**
2
+ * Coding Standards Checker
3
+ *
4
+ * Checks and enforces coding standards
5
+ *
6
+ * @packageDocumentation
7
+ * @module codegen/coding-standards
8
+ *
9
+ * @see REQ-COD-005 - Coding Standards Enforcement
10
+ * @see Article III - Bidirectional Traceability
11
+ */
12
+ /**
13
+ * Default configuration
14
+ */
15
+ export const DEFAULT_STANDARDS_CONFIG = {
16
+ language: 'typescript',
17
+ enabledCategories: ['naming', 'formatting', 'structure', 'documentation', 'complexity'],
18
+ minSeverity: 'warning',
19
+ failOnWarning: false,
20
+ ignorePatterns: ['node_modules/**', 'dist/**', '*.min.*'],
21
+ customRules: [],
22
+ };
23
+ /**
24
+ * Built-in rules
25
+ */
26
+ export const BUILTIN_RULES = [
27
+ // Naming rules
28
+ {
29
+ id: 'naming/camel-case',
30
+ name: 'camelCase Variables',
31
+ description: 'Variables should use camelCase',
32
+ category: 'naming',
33
+ severity: 'warning',
34
+ enabled: true,
35
+ autoFixable: false,
36
+ },
37
+ {
38
+ id: 'naming/pascal-case-class',
39
+ name: 'PascalCase Classes',
40
+ description: 'Classes should use PascalCase',
41
+ category: 'naming',
42
+ severity: 'error',
43
+ enabled: true,
44
+ autoFixable: false,
45
+ },
46
+ {
47
+ id: 'naming/upper-case-constants',
48
+ name: 'UPPER_CASE Constants',
49
+ description: 'Constants should use UPPER_CASE',
50
+ category: 'naming',
51
+ severity: 'warning',
52
+ enabled: true,
53
+ autoFixable: false,
54
+ },
55
+ {
56
+ id: 'naming/prefix-interface',
57
+ name: 'Interface Prefix',
58
+ description: 'Interfaces should start with I prefix (optional)',
59
+ category: 'naming',
60
+ severity: 'info',
61
+ enabled: false,
62
+ autoFixable: false,
63
+ },
64
+ {
65
+ id: 'naming/meaningful-names',
66
+ name: 'Meaningful Names',
67
+ description: 'Names should be descriptive and meaningful',
68
+ category: 'naming',
69
+ severity: 'warning',
70
+ enabled: true,
71
+ autoFixable: false,
72
+ },
73
+ // Formatting rules
74
+ {
75
+ id: 'formatting/max-line-length',
76
+ name: 'Max Line Length',
77
+ description: 'Lines should not exceed max length',
78
+ category: 'formatting',
79
+ severity: 'warning',
80
+ enabled: true,
81
+ options: { maxLength: 100 },
82
+ autoFixable: false,
83
+ },
84
+ {
85
+ id: 'formatting/consistent-indentation',
86
+ name: 'Consistent Indentation',
87
+ description: 'Use consistent indentation',
88
+ category: 'formatting',
89
+ severity: 'error',
90
+ enabled: true,
91
+ options: { style: 'space', size: 2 },
92
+ autoFixable: true,
93
+ },
94
+ {
95
+ id: 'formatting/trailing-comma',
96
+ name: 'Trailing Comma',
97
+ description: 'Use trailing commas in multiline',
98
+ category: 'formatting',
99
+ severity: 'info',
100
+ enabled: true,
101
+ autoFixable: true,
102
+ },
103
+ {
104
+ id: 'formatting/semicolons',
105
+ name: 'Semicolons',
106
+ description: 'Use semicolons consistently',
107
+ category: 'formatting',
108
+ severity: 'warning',
109
+ enabled: true,
110
+ autoFixable: true,
111
+ },
112
+ // Structure rules
113
+ {
114
+ id: 'structure/max-file-lines',
115
+ name: 'Max File Lines',
116
+ description: 'Files should not exceed max lines',
117
+ category: 'structure',
118
+ severity: 'warning',
119
+ enabled: true,
120
+ options: { maxLines: 500 },
121
+ autoFixable: false,
122
+ },
123
+ {
124
+ id: 'structure/max-function-lines',
125
+ name: 'Max Function Lines',
126
+ description: 'Functions should not exceed max lines',
127
+ category: 'structure',
128
+ severity: 'warning',
129
+ enabled: true,
130
+ options: { maxLines: 50 },
131
+ autoFixable: false,
132
+ },
133
+ {
134
+ id: 'structure/max-parameters',
135
+ name: 'Max Parameters',
136
+ description: 'Functions should not have too many parameters',
137
+ category: 'structure',
138
+ severity: 'warning',
139
+ enabled: true,
140
+ options: { maxParams: 5 },
141
+ autoFixable: false,
142
+ },
143
+ {
144
+ id: 'structure/single-responsibility',
145
+ name: 'Single Responsibility',
146
+ description: 'Functions/classes should have single responsibility',
147
+ category: 'structure',
148
+ severity: 'info',
149
+ enabled: true,
150
+ autoFixable: false,
151
+ },
152
+ // Documentation rules
153
+ {
154
+ id: 'documentation/jsdoc-required',
155
+ name: 'JSDoc Required',
156
+ description: 'Public APIs should have JSDoc comments',
157
+ category: 'documentation',
158
+ severity: 'warning',
159
+ enabled: true,
160
+ autoFixable: false,
161
+ },
162
+ {
163
+ id: 'documentation/jsdoc-params',
164
+ name: 'JSDoc Parameters',
165
+ description: 'JSDoc should document all parameters',
166
+ category: 'documentation',
167
+ severity: 'warning',
168
+ enabled: true,
169
+ autoFixable: false,
170
+ },
171
+ {
172
+ id: 'documentation/jsdoc-returns',
173
+ name: 'JSDoc Returns',
174
+ description: 'JSDoc should document return value',
175
+ category: 'documentation',
176
+ severity: 'info',
177
+ enabled: true,
178
+ autoFixable: false,
179
+ },
180
+ // Complexity rules
181
+ {
182
+ id: 'complexity/cyclomatic',
183
+ name: 'Cyclomatic Complexity',
184
+ description: 'Cyclomatic complexity should not exceed threshold',
185
+ category: 'complexity',
186
+ severity: 'warning',
187
+ enabled: true,
188
+ options: { maxComplexity: 10 },
189
+ autoFixable: false,
190
+ },
191
+ {
192
+ id: 'complexity/max-nesting',
193
+ name: 'Max Nesting',
194
+ description: 'Nesting level should not exceed threshold',
195
+ category: 'complexity',
196
+ severity: 'warning',
197
+ enabled: true,
198
+ options: { maxNesting: 4 },
199
+ autoFixable: false,
200
+ },
201
+ {
202
+ id: 'complexity/cognitive',
203
+ name: 'Cognitive Complexity',
204
+ description: 'Cognitive complexity should not exceed threshold',
205
+ category: 'complexity',
206
+ severity: 'warning',
207
+ enabled: true,
208
+ options: { maxCognitive: 15 },
209
+ autoFixable: false,
210
+ },
211
+ // Security rules
212
+ {
213
+ id: 'security/no-eval',
214
+ name: 'No Eval',
215
+ description: 'Avoid using eval()',
216
+ category: 'security',
217
+ severity: 'error',
218
+ enabled: true,
219
+ autoFixable: false,
220
+ },
221
+ {
222
+ id: 'security/no-hardcoded-secrets',
223
+ name: 'No Hardcoded Secrets',
224
+ description: 'Avoid hardcoded secrets',
225
+ category: 'security',
226
+ severity: 'error',
227
+ enabled: true,
228
+ autoFixable: false,
229
+ },
230
+ ];
231
+ /**
232
+ * Naming patterns
233
+ */
234
+ const NAMING_PATTERNS = {
235
+ camelCase: /^[a-z][a-zA-Z0-9]*$/,
236
+ PascalCase: /^[A-Z][a-zA-Z0-9]*$/,
237
+ UPPER_CASE: /^[A-Z][A-Z0-9_]*$/,
238
+ kebabCase: /^[a-z][a-z0-9-]*$/,
239
+ snakeCase: /^[a-z][a-z0-9_]*$/,
240
+ };
241
+ /**
242
+ * Short name patterns (likely not meaningful)
243
+ */
244
+ const SHORT_NAME_EXCEPTIONS = new Set(['i', 'j', 'k', 'n', 'x', 'y', 'z', 'id', 'ok', 'fn', 'cb']);
245
+ /**
246
+ * Coding Standards Checker
247
+ */
248
+ export class CodingStandardsChecker {
249
+ config;
250
+ rules = new Map();
251
+ constructor(config) {
252
+ this.config = { ...DEFAULT_STANDARDS_CONFIG, ...config };
253
+ this.initializeRules();
254
+ }
255
+ /**
256
+ * Initialize rules
257
+ */
258
+ initializeRules() {
259
+ // Add built-in rules
260
+ for (const rule of BUILTIN_RULES) {
261
+ if (this.config.enabledCategories.includes(rule.category)) {
262
+ this.rules.set(rule.id, { ...rule });
263
+ }
264
+ }
265
+ // Add custom rules
266
+ for (const rule of this.config.customRules) {
267
+ this.rules.set(rule.id, rule);
268
+ }
269
+ }
270
+ /**
271
+ * Check file content
272
+ */
273
+ check(content, filePath) {
274
+ const startTime = Date.now();
275
+ const violations = [];
276
+ const lines = content.split('\n');
277
+ // Run each rule
278
+ for (const rule of this.rules.values()) {
279
+ if (!rule.enabled)
280
+ continue;
281
+ if (!this.shouldReport(rule.severity))
282
+ continue;
283
+ const ruleViolations = this.runRule(rule, content, lines, filePath);
284
+ violations.push(...ruleViolations);
285
+ }
286
+ // Sort violations by line number
287
+ violations.sort((a, b) => a.line - b.line);
288
+ // Count by severity
289
+ const errorCount = violations.filter((v) => v.severity === 'error').length;
290
+ const warningCount = violations.filter((v) => v.severity === 'warning').length;
291
+ const infoCount = violations.filter((v) => v.severity === 'info' || v.severity === 'hint').length;
292
+ // Determine pass/fail
293
+ const passed = errorCount === 0 && (!this.config.failOnWarning || warningCount === 0);
294
+ return {
295
+ file: filePath,
296
+ violations,
297
+ errorCount,
298
+ warningCount,
299
+ infoCount,
300
+ passed,
301
+ duration: Date.now() - startTime,
302
+ };
303
+ }
304
+ /**
305
+ * Check multiple files
306
+ */
307
+ checkFiles(files) {
308
+ const startTime = Date.now();
309
+ const results = [];
310
+ for (const file of files) {
311
+ // Check ignore patterns
312
+ if (this.shouldIgnore(file.path))
313
+ continue;
314
+ const result = this.check(file.content, file.path);
315
+ results.push(result);
316
+ }
317
+ // Aggregate results
318
+ const bySeverity = {
319
+ error: 0,
320
+ warning: 0,
321
+ info: 0,
322
+ hint: 0,
323
+ };
324
+ const byCategory = {
325
+ naming: 0,
326
+ formatting: 0,
327
+ structure: 0,
328
+ documentation: 0,
329
+ complexity: 0,
330
+ security: 0,
331
+ performance: 0,
332
+ testing: 0,
333
+ style: 0,
334
+ };
335
+ let totalViolations = 0;
336
+ for (const result of results) {
337
+ for (const violation of result.violations) {
338
+ totalViolations++;
339
+ bySeverity[violation.severity]++;
340
+ const rule = this.rules.get(violation.ruleId);
341
+ if (rule) {
342
+ byCategory[rule.category]++;
343
+ }
344
+ }
345
+ }
346
+ const filesPassed = results.filter((r) => r.passed).length;
347
+ const filesFailed = results.length - filesPassed;
348
+ return {
349
+ timestamp: new Date(),
350
+ filesChecked: results.length,
351
+ filesPassed,
352
+ filesFailed,
353
+ totalViolations,
354
+ bySeverity,
355
+ byCategory,
356
+ results,
357
+ duration: Date.now() - startTime,
358
+ passRate: results.length > 0 ? filesPassed / results.length : 1,
359
+ };
360
+ }
361
+ /**
362
+ * Run a specific rule
363
+ */
364
+ runRule(rule, content, lines, filePath) {
365
+ const violations = [];
366
+ switch (rule.id) {
367
+ case 'naming/camel-case':
368
+ violations.push(...this.checkCamelCase(rule, lines, filePath));
369
+ break;
370
+ case 'naming/pascal-case-class':
371
+ violations.push(...this.checkPascalCaseClass(rule, lines, filePath));
372
+ break;
373
+ case 'naming/upper-case-constants':
374
+ violations.push(...this.checkUpperCaseConstants(rule, lines, filePath));
375
+ break;
376
+ case 'naming/meaningful-names':
377
+ violations.push(...this.checkMeaningfulNames(rule, lines, filePath));
378
+ break;
379
+ case 'formatting/max-line-length':
380
+ violations.push(...this.checkMaxLineLength(rule, lines, filePath));
381
+ break;
382
+ case 'formatting/consistent-indentation':
383
+ violations.push(...this.checkIndentation(rule, lines, filePath));
384
+ break;
385
+ case 'structure/max-file-lines':
386
+ violations.push(...this.checkMaxFileLines(rule, lines, filePath));
387
+ break;
388
+ case 'structure/max-function-lines':
389
+ violations.push(...this.checkMaxFunctionLines(rule, lines, filePath));
390
+ break;
391
+ case 'structure/max-parameters':
392
+ violations.push(...this.checkMaxParameters(rule, lines, filePath));
393
+ break;
394
+ case 'documentation/jsdoc-required':
395
+ violations.push(...this.checkJSDocRequired(rule, lines, filePath));
396
+ break;
397
+ case 'complexity/cyclomatic':
398
+ violations.push(...this.checkCyclomaticComplexity(rule, content, filePath));
399
+ break;
400
+ case 'complexity/max-nesting':
401
+ violations.push(...this.checkMaxNesting(rule, lines, filePath));
402
+ break;
403
+ case 'security/no-eval':
404
+ violations.push(...this.checkNoEval(rule, lines, filePath));
405
+ break;
406
+ case 'security/no-hardcoded-secrets':
407
+ violations.push(...this.checkNoHardcodedSecrets(rule, lines, filePath));
408
+ break;
409
+ }
410
+ return violations;
411
+ }
412
+ /**
413
+ * Check camelCase naming
414
+ */
415
+ checkCamelCase(rule, lines, filePath) {
416
+ const violations = [];
417
+ const varPattern = /(?:let|const|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*[=:]/g;
418
+ for (let i = 0; i < lines.length; i++) {
419
+ const line = lines[i];
420
+ let match;
421
+ while ((match = varPattern.exec(line)) !== null) {
422
+ const name = match[1];
423
+ // Skip UPPER_CASE (constants) and PascalCase (classes/types)
424
+ if (NAMING_PATTERNS.UPPER_CASE.test(name) || NAMING_PATTERNS.PascalCase.test(name)) {
425
+ continue;
426
+ }
427
+ if (!NAMING_PATTERNS.camelCase.test(name) && !name.startsWith('_')) {
428
+ violations.push({
429
+ ruleId: rule.id,
430
+ ruleName: rule.name,
431
+ severity: rule.severity,
432
+ message: `Variable '${name}' should use camelCase`,
433
+ file: filePath,
434
+ line: i + 1,
435
+ column: match.index + 1,
436
+ autoFixable: false,
437
+ });
438
+ }
439
+ }
440
+ }
441
+ return violations;
442
+ }
443
+ /**
444
+ * Check PascalCase for classes
445
+ */
446
+ checkPascalCaseClass(rule, lines, filePath) {
447
+ const violations = [];
448
+ const classPattern = /class\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
449
+ for (let i = 0; i < lines.length; i++) {
450
+ const line = lines[i];
451
+ let match;
452
+ while ((match = classPattern.exec(line)) !== null) {
453
+ const name = match[1];
454
+ if (!NAMING_PATTERNS.PascalCase.test(name)) {
455
+ violations.push({
456
+ ruleId: rule.id,
457
+ ruleName: rule.name,
458
+ severity: rule.severity,
459
+ message: `Class '${name}' should use PascalCase`,
460
+ file: filePath,
461
+ line: i + 1,
462
+ column: match.index + 1,
463
+ autoFixable: false,
464
+ });
465
+ }
466
+ }
467
+ }
468
+ return violations;
469
+ }
470
+ /**
471
+ * Check UPPER_CASE for constants
472
+ */
473
+ checkUpperCaseConstants(rule, lines, filePath) {
474
+ const violations = [];
475
+ const constPattern = /const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/g;
476
+ for (let i = 0; i < lines.length; i++) {
477
+ const line = lines[i];
478
+ // Skip if inside a function/block (module-level constants only)
479
+ if (line.match(/^\s{2,}/))
480
+ continue;
481
+ let match;
482
+ while ((match = constPattern.exec(line)) !== null) {
483
+ const name = match[1];
484
+ // Check if it's a primitive constant (not object/array/function)
485
+ const valueStart = line.indexOf('=', match.index) + 1;
486
+ const valuePart = line.slice(valueStart).trim();
487
+ // Skip if it's an object, array, or function
488
+ if (valuePart.startsWith('{') || valuePart.startsWith('[') ||
489
+ valuePart.startsWith('function') || valuePart.includes('=>')) {
490
+ continue;
491
+ }
492
+ // Only flag if it looks like a constant (primitive value)
493
+ if (valuePart.match(/^['"`]|^\d|^true|^false|^null/)) {
494
+ if (!NAMING_PATTERNS.UPPER_CASE.test(name) && !NAMING_PATTERNS.PascalCase.test(name)) {
495
+ violations.push({
496
+ ruleId: rule.id,
497
+ ruleName: rule.name,
498
+ severity: rule.severity,
499
+ message: `Module-level constant '${name}' should use UPPER_CASE`,
500
+ file: filePath,
501
+ line: i + 1,
502
+ column: match.index + 1,
503
+ suggestion: name.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase(),
504
+ autoFixable: false,
505
+ });
506
+ }
507
+ }
508
+ }
509
+ }
510
+ return violations;
511
+ }
512
+ /**
513
+ * Check meaningful names
514
+ */
515
+ checkMeaningfulNames(rule, lines, filePath) {
516
+ const violations = [];
517
+ const namePattern = /(?:let|const|var|function)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
518
+ for (let i = 0; i < lines.length; i++) {
519
+ const line = lines[i];
520
+ let match;
521
+ while ((match = namePattern.exec(line)) !== null) {
522
+ const name = match[1];
523
+ // Skip if it's a known exception
524
+ if (SHORT_NAME_EXCEPTIONS.has(name.toLowerCase()))
525
+ continue;
526
+ // Flag very short names (1-2 chars)
527
+ if (name.length <= 2) {
528
+ violations.push({
529
+ ruleId: rule.id,
530
+ ruleName: rule.name,
531
+ severity: rule.severity,
532
+ message: `Name '${name}' is too short, use a more descriptive name`,
533
+ file: filePath,
534
+ line: i + 1,
535
+ column: match.index + 1,
536
+ autoFixable: false,
537
+ });
538
+ }
539
+ }
540
+ }
541
+ return violations;
542
+ }
543
+ /**
544
+ * Check max line length
545
+ */
546
+ checkMaxLineLength(rule, lines, filePath) {
547
+ const violations = [];
548
+ const maxLength = rule.options?.maxLength ?? 100;
549
+ for (let i = 0; i < lines.length; i++) {
550
+ const line = lines[i];
551
+ if (line.length > maxLength) {
552
+ violations.push({
553
+ ruleId: rule.id,
554
+ ruleName: rule.name,
555
+ severity: rule.severity,
556
+ message: `Line exceeds ${maxLength} characters (${line.length})`,
557
+ file: filePath,
558
+ line: i + 1,
559
+ column: maxLength + 1,
560
+ autoFixable: false,
561
+ });
562
+ }
563
+ }
564
+ return violations;
565
+ }
566
+ /**
567
+ * Check indentation
568
+ */
569
+ checkIndentation(rule, lines, filePath) {
570
+ const violations = [];
571
+ const size = rule.options?.size ?? 2;
572
+ for (let i = 0; i < lines.length; i++) {
573
+ const line = lines[i];
574
+ if (!line.trim())
575
+ continue; // Skip empty lines
576
+ const leadingSpaces = line.match(/^(\s*)/)?.[1] ?? '';
577
+ // Check for tabs
578
+ if (leadingSpaces.includes('\t')) {
579
+ violations.push({
580
+ ruleId: rule.id,
581
+ ruleName: rule.name,
582
+ severity: rule.severity,
583
+ message: 'Use spaces instead of tabs for indentation',
584
+ file: filePath,
585
+ line: i + 1,
586
+ column: 1,
587
+ autoFixable: true,
588
+ });
589
+ continue;
590
+ }
591
+ // Check indentation is multiple of size
592
+ if (leadingSpaces.length % size !== 0) {
593
+ violations.push({
594
+ ruleId: rule.id,
595
+ ruleName: rule.name,
596
+ severity: rule.severity,
597
+ message: `Indentation should be a multiple of ${size} spaces`,
598
+ file: filePath,
599
+ line: i + 1,
600
+ column: 1,
601
+ autoFixable: true,
602
+ });
603
+ }
604
+ }
605
+ return violations;
606
+ }
607
+ /**
608
+ * Check max file lines
609
+ */
610
+ checkMaxFileLines(rule, lines, filePath) {
611
+ const violations = [];
612
+ const maxLines = rule.options?.maxLines ?? 500;
613
+ if (lines.length > maxLines) {
614
+ violations.push({
615
+ ruleId: rule.id,
616
+ ruleName: rule.name,
617
+ severity: rule.severity,
618
+ message: `File has ${lines.length} lines, exceeds maximum of ${maxLines}`,
619
+ file: filePath,
620
+ line: 1,
621
+ column: 1,
622
+ suggestion: 'Consider splitting into multiple files',
623
+ autoFixable: false,
624
+ });
625
+ }
626
+ return violations;
627
+ }
628
+ /**
629
+ * Check max function lines
630
+ */
631
+ checkMaxFunctionLines(rule, lines, filePath) {
632
+ const violations = [];
633
+ const maxLines = rule.options?.maxLines ?? 50;
634
+ const funcPattern = /(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:function|\())/;
635
+ let funcStart = -1;
636
+ let funcName = '';
637
+ let braceCount = 0;
638
+ let inFunction = false;
639
+ for (let i = 0; i < lines.length; i++) {
640
+ const line = lines[i];
641
+ if (!inFunction) {
642
+ const match = line.match(funcPattern);
643
+ if (match) {
644
+ funcName = match[1] || match[2];
645
+ funcStart = i;
646
+ inFunction = true;
647
+ braceCount = 0;
648
+ }
649
+ }
650
+ if (inFunction) {
651
+ braceCount += (line.match(/{/g) || []).length;
652
+ braceCount -= (line.match(/}/g) || []).length;
653
+ if (braceCount === 0 && funcStart >= 0) {
654
+ const funcLines = i - funcStart + 1;
655
+ if (funcLines > maxLines) {
656
+ violations.push({
657
+ ruleId: rule.id,
658
+ ruleName: rule.name,
659
+ severity: rule.severity,
660
+ message: `Function '${funcName}' has ${funcLines} lines, exceeds maximum of ${maxLines}`,
661
+ file: filePath,
662
+ line: funcStart + 1,
663
+ column: 1,
664
+ suggestion: 'Consider breaking into smaller functions',
665
+ autoFixable: false,
666
+ });
667
+ }
668
+ inFunction = false;
669
+ funcStart = -1;
670
+ }
671
+ }
672
+ }
673
+ return violations;
674
+ }
675
+ /**
676
+ * Check max parameters
677
+ */
678
+ checkMaxParameters(rule, lines, filePath) {
679
+ const violations = [];
680
+ const maxParams = rule.options?.maxParams ?? 5;
681
+ const funcPattern = /(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?function)\s*\(([^)]*)\)/g;
682
+ for (let i = 0; i < lines.length; i++) {
683
+ const line = lines[i];
684
+ let match;
685
+ while ((match = funcPattern.exec(line)) !== null) {
686
+ const funcName = match[1] || match[2];
687
+ const params = match[3].split(',').filter((p) => p.trim());
688
+ if (params.length > maxParams) {
689
+ violations.push({
690
+ ruleId: rule.id,
691
+ ruleName: rule.name,
692
+ severity: rule.severity,
693
+ message: `Function '${funcName}' has ${params.length} parameters, exceeds maximum of ${maxParams}`,
694
+ file: filePath,
695
+ line: i + 1,
696
+ column: match.index + 1,
697
+ suggestion: 'Consider using an options object',
698
+ autoFixable: false,
699
+ });
700
+ }
701
+ }
702
+ }
703
+ return violations;
704
+ }
705
+ /**
706
+ * Check JSDoc required
707
+ */
708
+ checkJSDocRequired(rule, lines, filePath) {
709
+ const violations = [];
710
+ const exportPattern = /^export\s+(?:async\s+)?(?:function|class|const|interface|type)/;
711
+ for (let i = 0; i < lines.length; i++) {
712
+ const line = lines[i];
713
+ if (exportPattern.test(line.trim())) {
714
+ // Check if previous lines have JSDoc
715
+ let hasJSDoc = false;
716
+ for (let j = i - 1; j >= 0 && j >= i - 10; j--) {
717
+ const prevLine = lines[j].trim();
718
+ if (prevLine === '*/') {
719
+ hasJSDoc = true;
720
+ break;
721
+ }
722
+ if (prevLine && !prevLine.startsWith('*') && !prevLine.startsWith('//')) {
723
+ break;
724
+ }
725
+ }
726
+ if (!hasJSDoc) {
727
+ violations.push({
728
+ ruleId: rule.id,
729
+ ruleName: rule.name,
730
+ severity: rule.severity,
731
+ message: 'Exported member should have JSDoc documentation',
732
+ file: filePath,
733
+ line: i + 1,
734
+ column: 1,
735
+ autoFixable: false,
736
+ });
737
+ }
738
+ }
739
+ }
740
+ return violations;
741
+ }
742
+ /**
743
+ * Check cyclomatic complexity
744
+ */
745
+ checkCyclomaticComplexity(rule, content, filePath) {
746
+ const violations = [];
747
+ const maxComplexity = rule.options?.maxComplexity ?? 10;
748
+ // Count complexity indicators
749
+ const complexityPatterns = [
750
+ /\bif\b/g,
751
+ /\belse\s+if\b/g,
752
+ /\bfor\b/g,
753
+ /\bwhile\b/g,
754
+ /\bcase\b/g,
755
+ /\bcatch\b/g,
756
+ /\b\?\s*[^:]/g, // Ternary
757
+ /&&/g,
758
+ /\|\|/g,
759
+ ];
760
+ let complexity = 1; // Base complexity
761
+ for (const pattern of complexityPatterns) {
762
+ const matches = content.match(pattern);
763
+ if (matches) {
764
+ complexity += matches.length;
765
+ }
766
+ }
767
+ if (complexity > maxComplexity) {
768
+ violations.push({
769
+ ruleId: rule.id,
770
+ ruleName: rule.name,
771
+ severity: rule.severity,
772
+ message: `File cyclomatic complexity is ${complexity}, exceeds maximum of ${maxComplexity}`,
773
+ file: filePath,
774
+ line: 1,
775
+ column: 1,
776
+ suggestion: 'Consider refactoring to reduce complexity',
777
+ autoFixable: false,
778
+ });
779
+ }
780
+ return violations;
781
+ }
782
+ /**
783
+ * Check max nesting level
784
+ */
785
+ checkMaxNesting(rule, lines, filePath) {
786
+ const violations = [];
787
+ const maxNesting = rule.options?.maxNesting ?? 4;
788
+ let currentNesting = 0;
789
+ let maxFound = 0;
790
+ let maxFoundLine = 0;
791
+ for (let i = 0; i < lines.length; i++) {
792
+ const line = lines[i];
793
+ // Count braces
794
+ const opens = (line.match(/{/g) || []).length;
795
+ const closes = (line.match(/}/g) || []).length;
796
+ currentNesting += opens;
797
+ if (currentNesting > maxFound) {
798
+ maxFound = currentNesting;
799
+ maxFoundLine = i + 1;
800
+ }
801
+ currentNesting -= closes;
802
+ }
803
+ if (maxFound > maxNesting) {
804
+ violations.push({
805
+ ruleId: rule.id,
806
+ ruleName: rule.name,
807
+ severity: rule.severity,
808
+ message: `Nesting level is ${maxFound}, exceeds maximum of ${maxNesting}`,
809
+ file: filePath,
810
+ line: maxFoundLine,
811
+ column: 1,
812
+ suggestion: 'Consider extracting nested code to separate functions',
813
+ autoFixable: false,
814
+ });
815
+ }
816
+ return violations;
817
+ }
818
+ /**
819
+ * Check for eval usage
820
+ */
821
+ checkNoEval(rule, lines, filePath) {
822
+ const violations = [];
823
+ const evalPattern = /\beval\s*\(/g;
824
+ for (let i = 0; i < lines.length; i++) {
825
+ const line = lines[i];
826
+ let match;
827
+ while ((match = evalPattern.exec(line)) !== null) {
828
+ violations.push({
829
+ ruleId: rule.id,
830
+ ruleName: rule.name,
831
+ severity: rule.severity,
832
+ message: 'Avoid using eval() - it poses security risks',
833
+ file: filePath,
834
+ line: i + 1,
835
+ column: match.index + 1,
836
+ autoFixable: false,
837
+ });
838
+ }
839
+ }
840
+ return violations;
841
+ }
842
+ /**
843
+ * Check for hardcoded secrets
844
+ */
845
+ checkNoHardcodedSecrets(rule, lines, filePath) {
846
+ const violations = [];
847
+ const secretPatterns = [
848
+ /(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]+['"]/gi,
849
+ /(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]+['"]/gi,
850
+ /(?:secret|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
851
+ /(?:private[_-]?key)\s*[:=]\s*['"][^'"]+['"]/gi,
852
+ ];
853
+ for (let i = 0; i < lines.length; i++) {
854
+ const line = lines[i];
855
+ // Skip comments
856
+ if (line.trim().startsWith('//') || line.trim().startsWith('*'))
857
+ continue;
858
+ for (const pattern of secretPatterns) {
859
+ const match = line.match(pattern);
860
+ if (match) {
861
+ violations.push({
862
+ ruleId: rule.id,
863
+ ruleName: rule.name,
864
+ severity: rule.severity,
865
+ message: 'Potential hardcoded secret detected',
866
+ file: filePath,
867
+ line: i + 1,
868
+ column: line.indexOf(match[0]) + 1,
869
+ suggestion: 'Use environment variables or secure vault for secrets',
870
+ autoFixable: false,
871
+ });
872
+ break; // One violation per line
873
+ }
874
+ }
875
+ }
876
+ return violations;
877
+ }
878
+ /**
879
+ * Check if severity should be reported
880
+ */
881
+ shouldReport(severity) {
882
+ const levels = ['error', 'warning', 'info', 'hint'];
883
+ const minLevel = levels.indexOf(this.config.minSeverity);
884
+ const currentLevel = levels.indexOf(severity);
885
+ return currentLevel <= minLevel;
886
+ }
887
+ /**
888
+ * Check if file should be ignored
889
+ */
890
+ shouldIgnore(filePath) {
891
+ for (const pattern of this.config.ignorePatterns) {
892
+ const regex = new RegExp(pattern.replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*'));
893
+ if (regex.test(filePath)) {
894
+ return true;
895
+ }
896
+ }
897
+ return false;
898
+ }
899
+ /**
900
+ * Get enabled rules
901
+ */
902
+ getEnabledRules() {
903
+ return Array.from(this.rules.values()).filter((r) => r.enabled);
904
+ }
905
+ /**
906
+ * Enable/disable rule
907
+ */
908
+ setRuleEnabled(ruleId, enabled) {
909
+ const rule = this.rules.get(ruleId);
910
+ if (rule) {
911
+ rule.enabled = enabled;
912
+ }
913
+ }
914
+ /**
915
+ * Add custom rule
916
+ */
917
+ addRule(rule) {
918
+ this.rules.set(rule.id, rule);
919
+ }
920
+ /**
921
+ * Format report as string
922
+ */
923
+ formatReport(report) {
924
+ const lines = [];
925
+ lines.push('# Coding Standards Report');
926
+ lines.push('');
927
+ lines.push(`**Generated:** ${report.timestamp.toISOString()}`);
928
+ lines.push(`**Duration:** ${report.duration}ms`);
929
+ lines.push('');
930
+ // Summary
931
+ lines.push('## Summary');
932
+ lines.push('');
933
+ lines.push(`| Metric | Value |`);
934
+ lines.push(`|--------|-------|`);
935
+ lines.push(`| Files Checked | ${report.filesChecked} |`);
936
+ lines.push(`| Files Passed | ${report.filesPassed} |`);
937
+ lines.push(`| Files Failed | ${report.filesFailed} |`);
938
+ lines.push(`| Pass Rate | ${(report.passRate * 100).toFixed(1)}% |`);
939
+ lines.push(`| Total Violations | ${report.totalViolations} |`);
940
+ lines.push('');
941
+ // By severity
942
+ lines.push('### By Severity');
943
+ lines.push('');
944
+ lines.push(`- 🔴 Errors: ${report.bySeverity.error}`);
945
+ lines.push(`- 🟡 Warnings: ${report.bySeverity.warning}`);
946
+ lines.push(`- 🔵 Info: ${report.bySeverity.info}`);
947
+ lines.push('');
948
+ // Violations
949
+ if (report.totalViolations > 0) {
950
+ lines.push('## Violations');
951
+ lines.push('');
952
+ for (const result of report.results) {
953
+ if (result.violations.length === 0)
954
+ continue;
955
+ lines.push(`### ${result.file}`);
956
+ lines.push('');
957
+ for (const v of result.violations) {
958
+ const icon = v.severity === 'error' ? '🔴' : v.severity === 'warning' ? '🟡' : '🔵';
959
+ lines.push(`${icon} Line ${v.line}: ${v.message}`);
960
+ if (v.suggestion) {
961
+ lines.push(` 💡 ${v.suggestion}`);
962
+ }
963
+ }
964
+ lines.push('');
965
+ }
966
+ }
967
+ return lines.join('\n');
968
+ }
969
+ }
970
+ /**
971
+ * Create coding standards checker instance
972
+ */
973
+ export function createCodingStandardsChecker(config) {
974
+ return new CodingStandardsChecker(config);
975
+ }
976
+ //# sourceMappingURL=coding-standards.js.map