@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.
- package/bin/musubix.js +18 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +27 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/auth/auth-manager.d.ts +320 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +580 -0
- package/dist/auth/auth-manager.js.map +1 -0
- package/dist/cli/base.d.ts +58 -0
- package/dist/cli/base.d.ts.map +1 -0
- package/dist/cli/base.js +93 -0
- package/dist/cli/base.js.map +1 -0
- package/dist/cli/commands/help.d.ts +17 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +228 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/index.d.ts +14 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +25 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +38 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +258 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/codegen/coding-standards.d.ts +250 -0
- package/dist/codegen/coding-standards.d.ts.map +1 -0
- package/dist/codegen/coding-standards.js +976 -0
- package/dist/codegen/coding-standards.js.map +1 -0
- package/dist/codegen/coverage-reporter.d.ts +264 -0
- package/dist/codegen/coverage-reporter.d.ts.map +1 -0
- package/dist/codegen/coverage-reporter.js +697 -0
- package/dist/codegen/coverage-reporter.js.map +1 -0
- package/dist/codegen/dependency-analyzer.d.ts +271 -0
- package/dist/codegen/dependency-analyzer.d.ts.map +1 -0
- package/dist/codegen/dependency-analyzer.js +661 -0
- package/dist/codegen/dependency-analyzer.js.map +1 -0
- package/dist/codegen/generator.d.ts +275 -0
- package/dist/codegen/generator.d.ts.map +1 -0
- package/dist/codegen/generator.js +781 -0
- package/dist/codegen/generator.js.map +1 -0
- package/dist/codegen/index.d.ts +18 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +27 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/integration-test-generator.d.ts +312 -0
- package/dist/codegen/integration-test-generator.d.ts.map +1 -0
- package/dist/codegen/integration-test-generator.js +765 -0
- package/dist/codegen/integration-test-generator.js.map +1 -0
- package/dist/codegen/pattern-conformance.d.ts +309 -0
- package/dist/codegen/pattern-conformance.d.ts.map +1 -0
- package/dist/codegen/pattern-conformance.js +590 -0
- package/dist/codegen/pattern-conformance.js.map +1 -0
- package/dist/codegen/quality-metrics.d.ts +235 -0
- package/dist/codegen/quality-metrics.d.ts.map +1 -0
- package/dist/codegen/quality-metrics.js +439 -0
- package/dist/codegen/quality-metrics.js.map +1 -0
- package/dist/codegen/security-scanner.d.ts +179 -0
- package/dist/codegen/security-scanner.d.ts.map +1 -0
- package/dist/codegen/security-scanner.js +495 -0
- package/dist/codegen/security-scanner.js.map +1 -0
- package/dist/codegen/static-analyzer.d.ts +188 -0
- package/dist/codegen/static-analyzer.d.ts.map +1 -0
- package/dist/codegen/static-analyzer.js +490 -0
- package/dist/codegen/static-analyzer.js.map +1 -0
- package/dist/codegen/unit-test-generator.d.ts +289 -0
- package/dist/codegen/unit-test-generator.d.ts.map +1 -0
- package/dist/codegen/unit-test-generator.js +634 -0
- package/dist/codegen/unit-test-generator.js.map +1 -0
- package/dist/design/adr-generator.d.ts +227 -0
- package/dist/design/adr-generator.d.ts.map +1 -0
- package/dist/design/adr-generator.js +423 -0
- package/dist/design/adr-generator.js.map +1 -0
- package/dist/design/c4-generator.d.ts +267 -0
- package/dist/design/c4-generator.d.ts.map +1 -0
- package/dist/design/c4-generator.js +453 -0
- package/dist/design/c4-generator.js.map +1 -0
- package/dist/design/framework-optimizer.d.ts +190 -0
- package/dist/design/framework-optimizer.d.ts.map +1 -0
- package/dist/design/framework-optimizer.js +589 -0
- package/dist/design/framework-optimizer.js.map +1 -0
- package/dist/design/index.d.ts +12 -0
- package/dist/design/index.d.ts.map +1 -0
- package/dist/design/index.js +13 -0
- package/dist/design/index.js.map +1 -0
- package/dist/design/pattern-detector.d.ts +270 -0
- package/dist/design/pattern-detector.d.ts.map +1 -0
- package/dist/design/pattern-detector.js +621 -0
- package/dist/design/pattern-detector.js.map +1 -0
- package/dist/design/solid-validator.d.ts +188 -0
- package/dist/design/solid-validator.d.ts.map +1 -0
- package/dist/design/solid-validator.js +579 -0
- package/dist/design/solid-validator.js.map +1 -0
- package/dist/error/data-persistence.d.ts +311 -0
- package/dist/error/data-persistence.d.ts.map +1 -0
- package/dist/error/data-persistence.js +586 -0
- package/dist/error/data-persistence.js.map +1 -0
- package/dist/error/graceful-degradation.d.ts +309 -0
- package/dist/error/graceful-degradation.d.ts.map +1 -0
- package/dist/error/graceful-degradation.js +510 -0
- package/dist/error/graceful-degradation.js.map +1 -0
- package/dist/error/index.d.ts +11 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +19 -0
- package/dist/error/index.js.map +1 -0
- package/dist/explanation/explanation-generator.d.ts +228 -0
- package/dist/explanation/explanation-generator.d.ts.map +1 -0
- package/dist/explanation/explanation-generator.js +662 -0
- package/dist/explanation/explanation-generator.js.map +1 -0
- package/dist/explanation/index.d.ts +11 -0
- package/dist/explanation/index.d.ts.map +1 -0
- package/dist/explanation/index.js +19 -0
- package/dist/explanation/index.js.map +1 -0
- package/dist/explanation/reasoning-chain.d.ts +314 -0
- package/dist/explanation/reasoning-chain.d.ts.map +1 -0
- package/dist/explanation/reasoning-chain.js +414 -0
- package/dist/explanation/reasoning-chain.js.map +1 -0
- package/dist/explanation/visual-explanation.d.ts +315 -0
- package/dist/explanation/visual-explanation.d.ts.map +1 -0
- package/dist/explanation/visual-explanation.js +667 -0
- package/dist/explanation/visual-explanation.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/requirements/decomposer.d.ts +235 -0
- package/dist/requirements/decomposer.d.ts.map +1 -0
- package/dist/requirements/decomposer.js +587 -0
- package/dist/requirements/decomposer.js.map +1 -0
- package/dist/requirements/related-finder.d.ts +261 -0
- package/dist/requirements/related-finder.d.ts.map +1 -0
- package/dist/requirements/related-finder.js +629 -0
- package/dist/requirements/related-finder.js.map +1 -0
- package/dist/traceability/impact.d.ts +196 -0
- package/dist/traceability/impact.d.ts.map +1 -0
- package/dist/traceability/impact.js +438 -0
- package/dist/traceability/impact.js.map +1 -0
- package/dist/traceability/index.d.ts +9 -0
- package/dist/traceability/index.d.ts.map +1 -0
- package/dist/traceability/index.js +10 -0
- package/dist/traceability/index.js.map +1 -0
- package/dist/traceability/manager.d.ts +266 -0
- package/dist/traceability/manager.d.ts.map +1 -0
- package/dist/traceability/manager.js +412 -0
- package/dist/traceability/manager.js.map +1 -0
- package/dist/types/common.d.ts +294 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +15 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/ears.d.ts +158 -0
- package/dist/types/ears.d.ts.map +1 -0
- package/dist/types/ears.js +33 -0
- package/dist/types/ears.js.map +1 -0
- package/dist/types/errors.d.ts +176 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +55 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/data-protector.d.ts +122 -0
- package/dist/utils/data-protector.d.ts.map +1 -0
- package/dist/utils/data-protector.js +275 -0
- package/dist/utils/data-protector.js.map +1 -0
- package/dist/utils/error-handler.d.ts +101 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +324 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/i18n-manager.d.ts +259 -0
- package/dist/utils/i18n-manager.d.ts.map +1 -0
- package/dist/utils/i18n-manager.js +554 -0
- package/dist/utils/i18n-manager.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +120 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +237 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/performance-profiler.d.ts +251 -0
- package/dist/utils/performance-profiler.d.ts.map +1 -0
- package/dist/utils/performance-profiler.js +458 -0
- package/dist/utils/performance-profiler.js.map +1 -0
- package/dist/utils/scalability-optimizer.d.ts +294 -0
- package/dist/utils/scalability-optimizer.d.ts.map +1 -0
- package/dist/utils/scalability-optimizer.js +606 -0
- package/dist/utils/scalability-optimizer.js.map +1 -0
- package/dist/utils/structured-logger.d.ts +294 -0
- package/dist/utils/structured-logger.d.ts.map +1 -0
- package/dist/utils/structured-logger.js +630 -0
- package/dist/utils/structured-logger.js.map +1 -0
- package/dist/utils/version-compatibility.d.ts +217 -0
- package/dist/utils/version-compatibility.d.ts.map +1 -0
- package/dist/utils/version-compatibility.js +443 -0
- package/dist/utils/version-compatibility.js.map +1 -0
- package/dist/validators/ears-validator.d.ts +182 -0
- package/dist/validators/ears-validator.d.ts.map +1 -0
- package/dist/validators/ears-validator.js +357 -0
- package/dist/validators/ears-validator.js.map +1 -0
- package/dist/validators/index.d.ts +8 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +9 -0
- package/dist/validators/index.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +100 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Metrics Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates code quality metrics
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module codegen/quality-metrics
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-QUA-001 - Quality Metrics
|
|
10
|
+
* @see Article VI - Quality Standards
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Quality metric type
|
|
14
|
+
*/
|
|
15
|
+
export type MetricType = 'loc' | 'sloc' | 'comments' | 'blank' | 'complexity' | 'maintainability' | 'duplication' | 'coupling' | 'cohesion' | 'test-coverage';
|
|
16
|
+
/**
|
|
17
|
+
* Metric value
|
|
18
|
+
*/
|
|
19
|
+
export interface MetricValue {
|
|
20
|
+
/** Metric type */
|
|
21
|
+
type: MetricType;
|
|
22
|
+
/** Numeric value */
|
|
23
|
+
value: number;
|
|
24
|
+
/** Unit */
|
|
25
|
+
unit?: string;
|
|
26
|
+
/** Thresholds */
|
|
27
|
+
thresholds?: MetricThresholds;
|
|
28
|
+
/** Status */
|
|
29
|
+
status: 'good' | 'warning' | 'critical';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Metric thresholds
|
|
33
|
+
*/
|
|
34
|
+
export interface MetricThresholds {
|
|
35
|
+
/** Good threshold */
|
|
36
|
+
good: number;
|
|
37
|
+
/** Warning threshold */
|
|
38
|
+
warning: number;
|
|
39
|
+
/** Critical threshold */
|
|
40
|
+
critical: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* File metrics
|
|
44
|
+
*/
|
|
45
|
+
export interface FileMetrics {
|
|
46
|
+
/** File path */
|
|
47
|
+
file: string;
|
|
48
|
+
/** Language */
|
|
49
|
+
language: string;
|
|
50
|
+
/** Metrics */
|
|
51
|
+
metrics: MetricValue[];
|
|
52
|
+
/** Functions/methods */
|
|
53
|
+
functions: FunctionMetrics[];
|
|
54
|
+
/** Classes */
|
|
55
|
+
classes: ClassMetrics[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Function metrics
|
|
59
|
+
*/
|
|
60
|
+
export interface FunctionMetrics {
|
|
61
|
+
/** Function name */
|
|
62
|
+
name: string;
|
|
63
|
+
/** Line number */
|
|
64
|
+
line: number;
|
|
65
|
+
/** Lines of code */
|
|
66
|
+
loc: number;
|
|
67
|
+
/** Cyclomatic complexity */
|
|
68
|
+
complexity: number;
|
|
69
|
+
/** Parameters count */
|
|
70
|
+
parameters: number;
|
|
71
|
+
/** Nesting depth */
|
|
72
|
+
nestingDepth: number;
|
|
73
|
+
/** Cognitive complexity */
|
|
74
|
+
cognitiveComplexity: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Class metrics
|
|
78
|
+
*/
|
|
79
|
+
export interface ClassMetrics {
|
|
80
|
+
/** Class name */
|
|
81
|
+
name: string;
|
|
82
|
+
/** Line number */
|
|
83
|
+
line: number;
|
|
84
|
+
/** Methods count */
|
|
85
|
+
methodCount: number;
|
|
86
|
+
/** Properties count */
|
|
87
|
+
propertyCount: number;
|
|
88
|
+
/** Lines of code */
|
|
89
|
+
loc: number;
|
|
90
|
+
/** Weighted methods per class */
|
|
91
|
+
wmc: number;
|
|
92
|
+
/** Lack of cohesion */
|
|
93
|
+
lcom: number;
|
|
94
|
+
/** Depth of inheritance */
|
|
95
|
+
dit: number;
|
|
96
|
+
/** Number of children */
|
|
97
|
+
noc: number;
|
|
98
|
+
/** Coupling between objects */
|
|
99
|
+
cbo: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Project metrics summary
|
|
103
|
+
*/
|
|
104
|
+
export interface ProjectMetrics {
|
|
105
|
+
/** Total files */
|
|
106
|
+
totalFiles: number;
|
|
107
|
+
/** Total lines */
|
|
108
|
+
totalLines: number;
|
|
109
|
+
/** Average complexity */
|
|
110
|
+
averageComplexity: number;
|
|
111
|
+
/** Average maintainability */
|
|
112
|
+
averageMaintainability: number;
|
|
113
|
+
/** Duplication percentage */
|
|
114
|
+
duplicationPercentage: number;
|
|
115
|
+
/** Overall quality score */
|
|
116
|
+
qualityScore: number;
|
|
117
|
+
/** File metrics */
|
|
118
|
+
files: FileMetrics[];
|
|
119
|
+
/** Trends */
|
|
120
|
+
trends?: MetricTrends;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Metric trends
|
|
124
|
+
*/
|
|
125
|
+
export interface MetricTrends {
|
|
126
|
+
/** Period */
|
|
127
|
+
period: string;
|
|
128
|
+
/** Changes */
|
|
129
|
+
changes: Array<{
|
|
130
|
+
metric: MetricType;
|
|
131
|
+
previous: number;
|
|
132
|
+
current: number;
|
|
133
|
+
change: number;
|
|
134
|
+
direction: 'improved' | 'degraded' | 'stable';
|
|
135
|
+
}>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Quality metrics calculator configuration
|
|
139
|
+
*/
|
|
140
|
+
export interface QualityMetricsConfig {
|
|
141
|
+
/** Include test files */
|
|
142
|
+
includeTests: boolean;
|
|
143
|
+
/** Calculate duplication */
|
|
144
|
+
calculateDuplication: boolean;
|
|
145
|
+
/** Duplication threshold (min lines) */
|
|
146
|
+
duplicationThreshold: number;
|
|
147
|
+
/** Complexity thresholds */
|
|
148
|
+
complexityThresholds: MetricThresholds;
|
|
149
|
+
/** Maintainability thresholds */
|
|
150
|
+
maintainabilityThresholds: MetricThresholds;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Default configuration
|
|
154
|
+
*/
|
|
155
|
+
export declare const DEFAULT_METRICS_CONFIG: QualityMetricsConfig;
|
|
156
|
+
/**
|
|
157
|
+
* Quality Metrics Calculator
|
|
158
|
+
*/
|
|
159
|
+
export declare class QualityMetricsCalculator {
|
|
160
|
+
private config;
|
|
161
|
+
constructor(config?: Partial<QualityMetricsConfig>);
|
|
162
|
+
/**
|
|
163
|
+
* Calculate metrics for code
|
|
164
|
+
*/
|
|
165
|
+
calculate(code: string, file: string, language?: string): FileMetrics;
|
|
166
|
+
/**
|
|
167
|
+
* Calculate metrics for multiple files
|
|
168
|
+
*/
|
|
169
|
+
calculateProject(files: Array<{
|
|
170
|
+
path: string;
|
|
171
|
+
content: string;
|
|
172
|
+
language?: string;
|
|
173
|
+
}>): ProjectMetrics;
|
|
174
|
+
/**
|
|
175
|
+
* Count source lines (non-blank, non-comment)
|
|
176
|
+
*/
|
|
177
|
+
private countSourceLines;
|
|
178
|
+
/**
|
|
179
|
+
* Count comment lines
|
|
180
|
+
*/
|
|
181
|
+
private countCommentLines;
|
|
182
|
+
/**
|
|
183
|
+
* Count blank lines
|
|
184
|
+
*/
|
|
185
|
+
private countBlankLines;
|
|
186
|
+
/**
|
|
187
|
+
* Calculate cyclomatic complexity
|
|
188
|
+
*/
|
|
189
|
+
private calculateCyclomaticComplexity;
|
|
190
|
+
/**
|
|
191
|
+
* Calculate Halstead volume
|
|
192
|
+
*/
|
|
193
|
+
private calculateHalsteadVolume;
|
|
194
|
+
/**
|
|
195
|
+
* Calculate maintainability index
|
|
196
|
+
*/
|
|
197
|
+
private calculateMaintainabilityIndex;
|
|
198
|
+
/**
|
|
199
|
+
* Calculate code duplication percentage
|
|
200
|
+
*/
|
|
201
|
+
private calculateDuplication;
|
|
202
|
+
/**
|
|
203
|
+
* Extract function metrics
|
|
204
|
+
*/
|
|
205
|
+
private extractFunctionMetrics;
|
|
206
|
+
/**
|
|
207
|
+
* Count function parameters
|
|
208
|
+
*/
|
|
209
|
+
private countParameters;
|
|
210
|
+
/**
|
|
211
|
+
* Calculate nesting depth
|
|
212
|
+
*/
|
|
213
|
+
private calculateNestingDepth;
|
|
214
|
+
/**
|
|
215
|
+
* Calculate cognitive complexity
|
|
216
|
+
*/
|
|
217
|
+
private calculateCognitiveComplexity;
|
|
218
|
+
/**
|
|
219
|
+
* Extract class metrics
|
|
220
|
+
*/
|
|
221
|
+
private extractClassMetrics;
|
|
222
|
+
/**
|
|
223
|
+
* Create metric value with status
|
|
224
|
+
*/
|
|
225
|
+
private createMetric;
|
|
226
|
+
/**
|
|
227
|
+
* Calculate overall quality score
|
|
228
|
+
*/
|
|
229
|
+
private calculateQualityScore;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Create quality metrics calculator instance
|
|
233
|
+
*/
|
|
234
|
+
export declare function createQualityMetricsCalculator(config?: Partial<QualityMetricsConfig>): QualityMetricsCalculator;
|
|
235
|
+
//# sourceMappingURL=quality-metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-metrics.d.ts","sourceRoot":"","sources":["../../src/codegen/quality-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Metrics Calculator
|
|
3
|
+
*
|
|
4
|
+
* Calculates code quality metrics
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
* @module codegen/quality-metrics
|
|
8
|
+
*
|
|
9
|
+
* @see REQ-QUA-001 - Quality Metrics
|
|
10
|
+
* @see Article VI - Quality Standards
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Default configuration
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_METRICS_CONFIG = {
|
|
16
|
+
includeTests: false,
|
|
17
|
+
calculateDuplication: true,
|
|
18
|
+
duplicationThreshold: 6,
|
|
19
|
+
complexityThresholds: {
|
|
20
|
+
good: 10,
|
|
21
|
+
warning: 20,
|
|
22
|
+
critical: 30,
|
|
23
|
+
},
|
|
24
|
+
maintainabilityThresholds: {
|
|
25
|
+
good: 80,
|
|
26
|
+
warning: 60,
|
|
27
|
+
critical: 40,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Quality Metrics Calculator
|
|
32
|
+
*/
|
|
33
|
+
export class QualityMetricsCalculator {
|
|
34
|
+
config;
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.config = { ...DEFAULT_METRICS_CONFIG, ...config };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Calculate metrics for code
|
|
40
|
+
*/
|
|
41
|
+
calculate(code, file, language = 'typescript') {
|
|
42
|
+
const lines = code.split('\n');
|
|
43
|
+
// Basic line metrics
|
|
44
|
+
const loc = lines.length;
|
|
45
|
+
const sloc = this.countSourceLines(lines);
|
|
46
|
+
const comments = this.countCommentLines(lines, language);
|
|
47
|
+
const blank = this.countBlankLines(lines);
|
|
48
|
+
// Complexity metrics
|
|
49
|
+
const complexity = this.calculateCyclomaticComplexity(code);
|
|
50
|
+
const maintainability = this.calculateMaintainabilityIndex(loc, complexity, this.calculateHalsteadVolume(code));
|
|
51
|
+
// Function metrics
|
|
52
|
+
const functions = this.extractFunctionMetrics(code, language);
|
|
53
|
+
// Class metrics
|
|
54
|
+
const classes = this.extractClassMetrics(code, language);
|
|
55
|
+
return {
|
|
56
|
+
file,
|
|
57
|
+
language,
|
|
58
|
+
metrics: [
|
|
59
|
+
this.createMetric('loc', loc),
|
|
60
|
+
this.createMetric('sloc', sloc),
|
|
61
|
+
this.createMetric('comments', comments),
|
|
62
|
+
this.createMetric('blank', blank),
|
|
63
|
+
this.createMetric('complexity', complexity, this.config.complexityThresholds),
|
|
64
|
+
this.createMetric('maintainability', maintainability, this.config.maintainabilityThresholds),
|
|
65
|
+
],
|
|
66
|
+
functions,
|
|
67
|
+
classes,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Calculate metrics for multiple files
|
|
72
|
+
*/
|
|
73
|
+
calculateProject(files) {
|
|
74
|
+
const fileMetrics = files.map((f) => this.calculate(f.content, f.path, f.language));
|
|
75
|
+
const totalFiles = fileMetrics.length;
|
|
76
|
+
const totalLines = fileMetrics.reduce((sum, f) => sum + (f.metrics.find((m) => m.type === 'loc')?.value ?? 0), 0);
|
|
77
|
+
const complexities = fileMetrics.map((f) => f.metrics.find((m) => m.type === 'complexity')?.value ?? 0);
|
|
78
|
+
const averageComplexity = complexities.length > 0
|
|
79
|
+
? complexities.reduce((a, b) => a + b, 0) / complexities.length
|
|
80
|
+
: 0;
|
|
81
|
+
const maintainabilities = fileMetrics.map((f) => f.metrics.find((m) => m.type === 'maintainability')?.value ?? 0);
|
|
82
|
+
const averageMaintainability = maintainabilities.length > 0
|
|
83
|
+
? maintainabilities.reduce((a, b) => a + b, 0) / maintainabilities.length
|
|
84
|
+
: 0;
|
|
85
|
+
// Calculate duplication
|
|
86
|
+
let duplicationPercentage = 0;
|
|
87
|
+
if (this.config.calculateDuplication) {
|
|
88
|
+
const allCode = files.map((f) => f.content).join('\n');
|
|
89
|
+
duplicationPercentage = this.calculateDuplication(allCode);
|
|
90
|
+
}
|
|
91
|
+
// Overall quality score (0-100)
|
|
92
|
+
const qualityScore = this.calculateQualityScore(averageComplexity, averageMaintainability, duplicationPercentage);
|
|
93
|
+
return {
|
|
94
|
+
totalFiles,
|
|
95
|
+
totalLines,
|
|
96
|
+
averageComplexity,
|
|
97
|
+
averageMaintainability,
|
|
98
|
+
duplicationPercentage,
|
|
99
|
+
qualityScore,
|
|
100
|
+
files: fileMetrics,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Count source lines (non-blank, non-comment)
|
|
105
|
+
*/
|
|
106
|
+
countSourceLines(lines) {
|
|
107
|
+
return lines.filter((line) => {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
return trimmed.length > 0 &&
|
|
110
|
+
!trimmed.startsWith('//') &&
|
|
111
|
+
!trimmed.startsWith('/*') &&
|
|
112
|
+
!trimmed.startsWith('*') &&
|
|
113
|
+
!trimmed.startsWith('#');
|
|
114
|
+
}).length;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Count comment lines
|
|
118
|
+
*/
|
|
119
|
+
countCommentLines(lines, _language) {
|
|
120
|
+
let count = 0;
|
|
121
|
+
let inBlockComment = false;
|
|
122
|
+
for (const line of lines) {
|
|
123
|
+
const trimmed = line.trim();
|
|
124
|
+
if (inBlockComment) {
|
|
125
|
+
count++;
|
|
126
|
+
if (trimmed.includes('*/')) {
|
|
127
|
+
inBlockComment = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (trimmed.startsWith('/*')) {
|
|
131
|
+
count++;
|
|
132
|
+
if (!trimmed.includes('*/')) {
|
|
133
|
+
inBlockComment = true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (trimmed.startsWith('//') || trimmed.startsWith('#')) {
|
|
137
|
+
count++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return count;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Count blank lines
|
|
144
|
+
*/
|
|
145
|
+
countBlankLines(lines) {
|
|
146
|
+
return lines.filter((line) => line.trim().length === 0).length;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Calculate cyclomatic complexity
|
|
150
|
+
*/
|
|
151
|
+
calculateCyclomaticComplexity(code) {
|
|
152
|
+
let complexity = 1;
|
|
153
|
+
const patterns = [
|
|
154
|
+
/\bif\b/g,
|
|
155
|
+
/\belse\s+if\b/g,
|
|
156
|
+
/\bfor\b/g,
|
|
157
|
+
/\bwhile\b/g,
|
|
158
|
+
/\bdo\b/g,
|
|
159
|
+
/\bcase\b/g,
|
|
160
|
+
/\bcatch\b/g,
|
|
161
|
+
/\?\?/g,
|
|
162
|
+
/\?\./g,
|
|
163
|
+
/&&/g,
|
|
164
|
+
/\|\|/g,
|
|
165
|
+
/\?[^:]/g,
|
|
166
|
+
];
|
|
167
|
+
for (const pattern of patterns) {
|
|
168
|
+
const matches = code.match(pattern);
|
|
169
|
+
if (matches) {
|
|
170
|
+
complexity += matches.length;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return complexity;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Calculate Halstead volume
|
|
177
|
+
*/
|
|
178
|
+
calculateHalsteadVolume(code) {
|
|
179
|
+
// Simplified Halstead volume calculation
|
|
180
|
+
const operators = new Set();
|
|
181
|
+
const operands = new Set();
|
|
182
|
+
// Extract operators
|
|
183
|
+
const opMatches = code.match(/[+\-*/%=<>!&|^~?:]+|\b(function|return|if|else|for|while|class|const|let|var|new|this|typeof|instanceof)\b/g);
|
|
184
|
+
if (opMatches) {
|
|
185
|
+
opMatches.forEach((op) => operators.add(op));
|
|
186
|
+
}
|
|
187
|
+
// Extract operands (identifiers and literals)
|
|
188
|
+
const idMatches = code.match(/\b[a-zA-Z_]\w*\b/g);
|
|
189
|
+
if (idMatches) {
|
|
190
|
+
idMatches.forEach((id) => operands.add(id));
|
|
191
|
+
}
|
|
192
|
+
const n1 = operators.size;
|
|
193
|
+
const n2 = operands.size;
|
|
194
|
+
const N1 = opMatches?.length ?? 0;
|
|
195
|
+
const N2 = idMatches?.length ?? 0;
|
|
196
|
+
const N = N1 + N2;
|
|
197
|
+
const n = n1 + n2;
|
|
198
|
+
if (n === 0)
|
|
199
|
+
return 0;
|
|
200
|
+
return N * Math.log2(n);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Calculate maintainability index
|
|
204
|
+
*/
|
|
205
|
+
calculateMaintainabilityIndex(loc, complexity, halsteadVolume) {
|
|
206
|
+
// Original MI formula: 171 - 5.2 * ln(V) - 0.23 * CC - 16.2 * ln(LOC)
|
|
207
|
+
// Scaled to 0-100
|
|
208
|
+
if (loc === 0 || halsteadVolume === 0)
|
|
209
|
+
return 100;
|
|
210
|
+
const mi = 171
|
|
211
|
+
- 5.2 * Math.log(halsteadVolume + 1)
|
|
212
|
+
- 0.23 * complexity
|
|
213
|
+
- 16.2 * Math.log(loc);
|
|
214
|
+
// Scale to 0-100
|
|
215
|
+
return Math.max(0, Math.min(100, mi * 100 / 171));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Calculate code duplication percentage
|
|
219
|
+
*/
|
|
220
|
+
calculateDuplication(code) {
|
|
221
|
+
const lines = code.split('\n').filter((l) => l.trim().length > 0);
|
|
222
|
+
if (lines.length === 0)
|
|
223
|
+
return 0;
|
|
224
|
+
const threshold = this.config.duplicationThreshold;
|
|
225
|
+
const duplicatedLines = new Set();
|
|
226
|
+
// Simple duplication detection using n-gram comparison
|
|
227
|
+
for (let i = 0; i <= lines.length - threshold; i++) {
|
|
228
|
+
const chunk = lines.slice(i, i + threshold).join('\n');
|
|
229
|
+
for (let j = i + threshold; j <= lines.length - threshold; j++) {
|
|
230
|
+
const compareChunk = lines.slice(j, j + threshold).join('\n');
|
|
231
|
+
if (chunk === compareChunk) {
|
|
232
|
+
for (let k = 0; k < threshold; k++) {
|
|
233
|
+
duplicatedLines.add(i + k);
|
|
234
|
+
duplicatedLines.add(j + k);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return (duplicatedLines.size / lines.length) * 100;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Extract function metrics
|
|
243
|
+
*/
|
|
244
|
+
extractFunctionMetrics(code, _language) {
|
|
245
|
+
const functions = [];
|
|
246
|
+
const regex = /(?:function\s+(\w+)|(?:(\w+)\s*[=:]\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>)))/g;
|
|
247
|
+
let match;
|
|
248
|
+
while ((match = regex.exec(code)) !== null) {
|
|
249
|
+
const name = match[1] || match[2];
|
|
250
|
+
const line = code.substring(0, match.index).split('\n').length;
|
|
251
|
+
// Find function body
|
|
252
|
+
const startIndex = match.index;
|
|
253
|
+
let braceCount = 0;
|
|
254
|
+
let endIndex = startIndex;
|
|
255
|
+
let started = false;
|
|
256
|
+
for (let i = startIndex; i < code.length; i++) {
|
|
257
|
+
if (code[i] === '{') {
|
|
258
|
+
braceCount++;
|
|
259
|
+
started = true;
|
|
260
|
+
}
|
|
261
|
+
else if (code[i] === '}') {
|
|
262
|
+
braceCount--;
|
|
263
|
+
if (started && braceCount === 0) {
|
|
264
|
+
endIndex = i;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const funcBody = code.substring(startIndex, endIndex + 1);
|
|
270
|
+
const loc = funcBody.split('\n').length;
|
|
271
|
+
const complexity = this.calculateCyclomaticComplexity(funcBody);
|
|
272
|
+
const parameters = this.countParameters(funcBody);
|
|
273
|
+
const nestingDepth = this.calculateNestingDepth(funcBody);
|
|
274
|
+
const cognitiveComplexity = this.calculateCognitiveComplexity(funcBody);
|
|
275
|
+
functions.push({
|
|
276
|
+
name,
|
|
277
|
+
line,
|
|
278
|
+
loc,
|
|
279
|
+
complexity,
|
|
280
|
+
parameters,
|
|
281
|
+
nestingDepth,
|
|
282
|
+
cognitiveComplexity,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return functions;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Count function parameters
|
|
289
|
+
*/
|
|
290
|
+
countParameters(funcBody) {
|
|
291
|
+
const match = funcBody.match(/\(([^)]*)\)/);
|
|
292
|
+
if (!match || !match[1].trim())
|
|
293
|
+
return 0;
|
|
294
|
+
return match[1].split(',').filter((p) => p.trim()).length;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Calculate nesting depth
|
|
298
|
+
*/
|
|
299
|
+
calculateNestingDepth(code) {
|
|
300
|
+
let maxDepth = 0;
|
|
301
|
+
let currentDepth = 0;
|
|
302
|
+
for (const char of code) {
|
|
303
|
+
if (char === '{') {
|
|
304
|
+
currentDepth++;
|
|
305
|
+
maxDepth = Math.max(maxDepth, currentDepth);
|
|
306
|
+
}
|
|
307
|
+
else if (char === '}') {
|
|
308
|
+
currentDepth--;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return maxDepth;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Calculate cognitive complexity
|
|
315
|
+
*/
|
|
316
|
+
calculateCognitiveComplexity(code) {
|
|
317
|
+
let complexity = 0;
|
|
318
|
+
let nesting = 0;
|
|
319
|
+
const lines = code.split('\n');
|
|
320
|
+
for (const line of lines) {
|
|
321
|
+
const trimmed = line.trim();
|
|
322
|
+
// Control flow structures add to complexity based on nesting
|
|
323
|
+
if (/\b(if|else\s+if|for|while|do|switch|catch)\b/.test(trimmed)) {
|
|
324
|
+
complexity += 1 + nesting;
|
|
325
|
+
}
|
|
326
|
+
// Logical operators add 1
|
|
327
|
+
const logicalOps = trimmed.match(/&&|\|\|/g);
|
|
328
|
+
if (logicalOps) {
|
|
329
|
+
complexity += logicalOps.length;
|
|
330
|
+
}
|
|
331
|
+
// Track nesting
|
|
332
|
+
if (trimmed.includes('{'))
|
|
333
|
+
nesting++;
|
|
334
|
+
if (trimmed.includes('}'))
|
|
335
|
+
nesting = Math.max(0, nesting - 1);
|
|
336
|
+
}
|
|
337
|
+
return complexity;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Extract class metrics
|
|
341
|
+
*/
|
|
342
|
+
extractClassMetrics(code, _language) {
|
|
343
|
+
const classes = [];
|
|
344
|
+
const regex = /class\s+(\w+)/g;
|
|
345
|
+
let match;
|
|
346
|
+
while ((match = regex.exec(code)) !== null) {
|
|
347
|
+
const name = match[1];
|
|
348
|
+
const line = code.substring(0, match.index).split('\n').length;
|
|
349
|
+
// Find class body
|
|
350
|
+
const startIndex = code.indexOf('{', match.index);
|
|
351
|
+
let braceCount = 1;
|
|
352
|
+
let endIndex = startIndex + 1;
|
|
353
|
+
while (braceCount > 0 && endIndex < code.length) {
|
|
354
|
+
if (code[endIndex] === '{')
|
|
355
|
+
braceCount++;
|
|
356
|
+
else if (code[endIndex] === '}')
|
|
357
|
+
braceCount--;
|
|
358
|
+
endIndex++;
|
|
359
|
+
}
|
|
360
|
+
const classBody = code.substring(startIndex, endIndex);
|
|
361
|
+
const loc = classBody.split('\n').length;
|
|
362
|
+
// Count methods
|
|
363
|
+
const methodMatches = classBody.match(/(?:async\s+)?(?:static\s+)?(?:get\s+|set\s+)?(\w+)\s*\([^)]*\)\s*[:{]/g);
|
|
364
|
+
const methodCount = methodMatches?.length ?? 0;
|
|
365
|
+
// Count properties
|
|
366
|
+
const propMatches = classBody.match(/(?:private|public|protected|readonly)?\s*(\w+)\s*[?:]?\s*:\s*\w+/g);
|
|
367
|
+
const propertyCount = propMatches?.length ?? 0;
|
|
368
|
+
// WMC - sum of complexities of all methods
|
|
369
|
+
const wmc = this.calculateCyclomaticComplexity(classBody);
|
|
370
|
+
classes.push({
|
|
371
|
+
name,
|
|
372
|
+
line,
|
|
373
|
+
methodCount,
|
|
374
|
+
propertyCount,
|
|
375
|
+
loc,
|
|
376
|
+
wmc,
|
|
377
|
+
lcom: 0, // Simplified - would need full analysis
|
|
378
|
+
dit: 0, // Would need inheritance tree
|
|
379
|
+
noc: 0, // Would need full codebase
|
|
380
|
+
cbo: 0, // Would need dependency analysis
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
return classes;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Create metric value with status
|
|
387
|
+
*/
|
|
388
|
+
createMetric(type, value, thresholds) {
|
|
389
|
+
let status = 'good';
|
|
390
|
+
if (thresholds) {
|
|
391
|
+
// For metrics where lower is better (complexity)
|
|
392
|
+
if (type === 'complexity' || type === 'duplication' || type === 'coupling') {
|
|
393
|
+
if (value >= thresholds.critical)
|
|
394
|
+
status = 'critical';
|
|
395
|
+
else if (value >= thresholds.warning)
|
|
396
|
+
status = 'warning';
|
|
397
|
+
}
|
|
398
|
+
// For metrics where higher is better (maintainability, cohesion)
|
|
399
|
+
else {
|
|
400
|
+
if (value <= thresholds.critical)
|
|
401
|
+
status = 'critical';
|
|
402
|
+
else if (value <= thresholds.warning)
|
|
403
|
+
status = 'warning';
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
type,
|
|
408
|
+
value: Math.round(value * 100) / 100,
|
|
409
|
+
thresholds,
|
|
410
|
+
status,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Calculate overall quality score
|
|
415
|
+
*/
|
|
416
|
+
calculateQualityScore(avgComplexity, avgMaintainability, duplication) {
|
|
417
|
+
// Weight factors
|
|
418
|
+
const complexityWeight = 0.3;
|
|
419
|
+
const maintainabilityWeight = 0.5;
|
|
420
|
+
const duplicationWeight = 0.2;
|
|
421
|
+
// Normalize complexity (lower is better, target: 10)
|
|
422
|
+
const complexityScore = Math.max(0, 100 - (avgComplexity - 10) * 5);
|
|
423
|
+
// Maintainability is already 0-100
|
|
424
|
+
const maintainabilityScore = avgMaintainability;
|
|
425
|
+
// Normalize duplication (lower is better)
|
|
426
|
+
const duplicationScore = Math.max(0, 100 - duplication * 2);
|
|
427
|
+
const score = complexityScore * complexityWeight +
|
|
428
|
+
maintainabilityScore * maintainabilityWeight +
|
|
429
|
+
duplicationScore * duplicationWeight;
|
|
430
|
+
return Math.round(Math.max(0, Math.min(100, score)));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Create quality metrics calculator instance
|
|
435
|
+
*/
|
|
436
|
+
export function createQualityMetricsCalculator(config) {
|
|
437
|
+
return new QualityMetricsCalculator(config);
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=quality-metrics.js.map
|