semantic-complexity 0.0.1-44fdea25
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/LICENSE +21 -0
- package/dist/ast/index.d.ts +2 -0
- package/dist/ast/index.d.ts.map +1 -0
- package/dist/ast/index.js +2 -0
- package/dist/ast/index.js.map +1 -0
- package/dist/ast/parser.d.ts +27 -0
- package/dist/ast/parser.d.ts.map +1 -0
- package/dist/ast/parser.js +273 -0
- package/dist/ast/parser.js.map +1 -0
- package/dist/compare.d.ts +31 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +354 -0
- package/dist/compare.js.map +1 -0
- package/dist/context/index.d.ts +41 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +253 -0
- package/dist/context/index.js.map +1 -0
- package/dist/graph/call.d.ts +63 -0
- package/dist/graph/call.d.ts.map +1 -0
- package/dist/graph/call.js +240 -0
- package/dist/graph/call.js.map +1 -0
- package/dist/graph/dependency.d.ts +52 -0
- package/dist/graph/dependency.d.ts.map +1 -0
- package/dist/graph/dependency.js +296 -0
- package/dist/graph/dependency.js.map +1 -0
- package/dist/graph/index.d.ts +3 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +3 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/cognitive.d.ts +42 -0
- package/dist/metrics/cognitive.d.ts.map +1 -0
- package/dist/metrics/cognitive.js +204 -0
- package/dist/metrics/cognitive.js.map +1 -0
- package/dist/metrics/cyclomatic.d.ts +31 -0
- package/dist/metrics/cyclomatic.d.ts.map +1 -0
- package/dist/metrics/cyclomatic.js +121 -0
- package/dist/metrics/cyclomatic.js.map +1 -0
- package/dist/metrics/dimensional.d.ts +32 -0
- package/dist/metrics/dimensional.d.ts.map +1 -0
- package/dist/metrics/dimensional.js +560 -0
- package/dist/metrics/dimensional.js.map +1 -0
- package/dist/metrics/index.d.ts +26 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +120 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/types.d.ts +341 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { ComplexityResult, ComplexityDetail, FunctionInfo } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* McCabe 순환복잡도 계산
|
|
5
|
+
*
|
|
6
|
+
* V(G) = E - N + 2P
|
|
7
|
+
* 단순화: 분기점 개수 + 1
|
|
8
|
+
*
|
|
9
|
+
* 분기점:
|
|
10
|
+
* - if, else if
|
|
11
|
+
* - case (switch)
|
|
12
|
+
* - for, for-in, for-of
|
|
13
|
+
* - while, do-while
|
|
14
|
+
* - catch
|
|
15
|
+
* - 삼항 연산자 (?:)
|
|
16
|
+
* - 논리 AND (&&), OR (||)
|
|
17
|
+
* - nullish coalescing (??)
|
|
18
|
+
*/
|
|
19
|
+
export declare function calculateCyclomaticComplexity(node: ts.Node, sourceFile: ts.SourceFile): {
|
|
20
|
+
complexity: number;
|
|
21
|
+
details: ComplexityDetail[];
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 함수 노드에서 순환복잡도 계산
|
|
25
|
+
*/
|
|
26
|
+
export declare function analyzeFunctionCyclomatic(functionNode: ts.Node, sourceFile: ts.SourceFile, functionInfo: FunctionInfo): ComplexityResult;
|
|
27
|
+
/**
|
|
28
|
+
* 소스 파일의 모든 함수에 대한 순환복잡도 계산
|
|
29
|
+
*/
|
|
30
|
+
export declare function analyzeFileCyclomatic(sourceFile: ts.SourceFile): ComplexityResult[];
|
|
31
|
+
//# sourceMappingURL=cyclomatic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cyclomatic.d.ts","sourceRoot":"","sources":["../../src/metrics/cyclomatic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAEhB,YAAY,EACb,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAqFrD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,EAAE,CAAC,IAAI,EACrB,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,YAAY,EAAE,YAAY,GACzB,gBAAgB,CAYlB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,gBAAgB,EAAE,CAwBpB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { getSourceLocation, extractFunctionInfo } from '../ast/parser.js';
|
|
3
|
+
/**
|
|
4
|
+
* McCabe 순환복잡도 계산
|
|
5
|
+
*
|
|
6
|
+
* V(G) = E - N + 2P
|
|
7
|
+
* 단순화: 분기점 개수 + 1
|
|
8
|
+
*
|
|
9
|
+
* 분기점:
|
|
10
|
+
* - if, else if
|
|
11
|
+
* - case (switch)
|
|
12
|
+
* - for, for-in, for-of
|
|
13
|
+
* - while, do-while
|
|
14
|
+
* - catch
|
|
15
|
+
* - 삼항 연산자 (?:)
|
|
16
|
+
* - 논리 AND (&&), OR (||)
|
|
17
|
+
* - nullish coalescing (??)
|
|
18
|
+
*/
|
|
19
|
+
export function calculateCyclomaticComplexity(node, sourceFile) {
|
|
20
|
+
let complexity = 1; // 기본 경로
|
|
21
|
+
const details = [];
|
|
22
|
+
function addDetail(node, type, description) {
|
|
23
|
+
details.push({
|
|
24
|
+
type,
|
|
25
|
+
location: getSourceLocation(node, sourceFile),
|
|
26
|
+
increment: 1,
|
|
27
|
+
nestingLevel: 0, // 순환복잡도에서는 중첩 레벨 무시
|
|
28
|
+
description,
|
|
29
|
+
});
|
|
30
|
+
complexity++;
|
|
31
|
+
}
|
|
32
|
+
function visit(node) {
|
|
33
|
+
switch (node.kind) {
|
|
34
|
+
case ts.SyntaxKind.IfStatement:
|
|
35
|
+
addDetail(node, 'if', 'if 조건문');
|
|
36
|
+
break;
|
|
37
|
+
case ts.SyntaxKind.CaseClause:
|
|
38
|
+
addDetail(node, 'case', 'switch case');
|
|
39
|
+
break;
|
|
40
|
+
case ts.SyntaxKind.DefaultClause:
|
|
41
|
+
// default는 복잡도에 포함하지 않음 (경로가 아닌 fallback)
|
|
42
|
+
break;
|
|
43
|
+
case ts.SyntaxKind.ForStatement:
|
|
44
|
+
addDetail(node, 'for', 'for 반복문');
|
|
45
|
+
break;
|
|
46
|
+
case ts.SyntaxKind.ForInStatement:
|
|
47
|
+
addDetail(node, 'for-in', 'for-in 반복문');
|
|
48
|
+
break;
|
|
49
|
+
case ts.SyntaxKind.ForOfStatement:
|
|
50
|
+
addDetail(node, 'for-of', 'for-of 반복문');
|
|
51
|
+
break;
|
|
52
|
+
case ts.SyntaxKind.WhileStatement:
|
|
53
|
+
addDetail(node, 'while', 'while 반복문');
|
|
54
|
+
break;
|
|
55
|
+
case ts.SyntaxKind.DoStatement:
|
|
56
|
+
addDetail(node, 'do-while', 'do-while 반복문');
|
|
57
|
+
break;
|
|
58
|
+
case ts.SyntaxKind.CatchClause:
|
|
59
|
+
addDetail(node, 'catch', 'catch 예외 처리');
|
|
60
|
+
break;
|
|
61
|
+
case ts.SyntaxKind.ConditionalExpression:
|
|
62
|
+
addDetail(node, 'conditional', '삼항 연산자');
|
|
63
|
+
break;
|
|
64
|
+
case ts.SyntaxKind.BinaryExpression: {
|
|
65
|
+
const binary = node;
|
|
66
|
+
if (binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
67
|
+
addDetail(node, 'logical-and', '논리 AND (&&)');
|
|
68
|
+
}
|
|
69
|
+
else if (binary.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
70
|
+
addDetail(node, 'logical-or', '논리 OR (||)');
|
|
71
|
+
}
|
|
72
|
+
else if (binary.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
73
|
+
addDetail(node, 'nullish-coalescing', 'Nullish coalescing (??)');
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
default:
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
ts.forEachChild(node, visit);
|
|
81
|
+
}
|
|
82
|
+
visit(node);
|
|
83
|
+
return { complexity, details };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 함수 노드에서 순환복잡도 계산
|
|
87
|
+
*/
|
|
88
|
+
export function analyzeFunctionCyclomatic(functionNode, sourceFile, functionInfo) {
|
|
89
|
+
const { complexity, details } = calculateCyclomaticComplexity(functionNode, sourceFile);
|
|
90
|
+
return {
|
|
91
|
+
function: functionInfo,
|
|
92
|
+
cyclomatic: complexity,
|
|
93
|
+
cognitive: 0, // cognitive.ts에서 별도 계산
|
|
94
|
+
details,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 소스 파일의 모든 함수에 대한 순환복잡도 계산
|
|
99
|
+
*/
|
|
100
|
+
export function analyzeFileCyclomatic(sourceFile) {
|
|
101
|
+
const results = [];
|
|
102
|
+
function visit(node, className) {
|
|
103
|
+
// 클래스 처리
|
|
104
|
+
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
|
|
105
|
+
const name = node.name?.getText(sourceFile) ?? '<anonymous>';
|
|
106
|
+
node.members.forEach((member) => visit(member, name));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// 함수 노드 확인
|
|
110
|
+
const functionInfo = extractFunctionInfo(node, sourceFile, className);
|
|
111
|
+
if (functionInfo) {
|
|
112
|
+
const result = analyzeFunctionCyclomatic(node, sourceFile, functionInfo);
|
|
113
|
+
results.push(result);
|
|
114
|
+
}
|
|
115
|
+
// 자식 노드 순회
|
|
116
|
+
ts.forEachChild(node, (child) => visit(child, className));
|
|
117
|
+
}
|
|
118
|
+
visit(sourceFile);
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=cyclomatic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cyclomatic.js","sourceRoot":"","sources":["../../src/metrics/cyclomatic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 차원 기반 복잡도 분석 (Dimensional Complexity)
|
|
3
|
+
*
|
|
4
|
+
* 1D: 제어 흐름 (순환복잡도 기반) - cyclomatic.ts
|
|
5
|
+
* 2D: 중첩 (인지복잡도 기반) - cognitive.ts
|
|
6
|
+
* 3D: 상태 복잡도 - 이 파일
|
|
7
|
+
* 4D: 비동기 복잡도 - 이 파일
|
|
8
|
+
* 5D: 숨은 결합 복잡도 - 이 파일
|
|
9
|
+
*/
|
|
10
|
+
import * as ts from 'typescript';
|
|
11
|
+
import type { StateComplexity, AsyncComplexity, CouplingComplexity, DimensionalComplexity, DimensionalWeights } from '../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* 상태 복잡도 분석
|
|
14
|
+
*/
|
|
15
|
+
export declare function analyzeStateComplexity(node: ts.Node, sourceFile: ts.SourceFile): StateComplexity;
|
|
16
|
+
/**
|
|
17
|
+
* 비동기 복잡도 분석
|
|
18
|
+
*/
|
|
19
|
+
export declare function analyzeAsyncComplexity(node: ts.Node, sourceFile: ts.SourceFile): AsyncComplexity;
|
|
20
|
+
/**
|
|
21
|
+
* 숨은 결합 복잡도 분석
|
|
22
|
+
*/
|
|
23
|
+
export declare function analyzeCouplingComplexity(node: ts.Node, sourceFile: ts.SourceFile, scopeVariables?: Set<string>): CouplingComplexity;
|
|
24
|
+
/**
|
|
25
|
+
* 기본 가중치
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_WEIGHTS: DimensionalWeights;
|
|
28
|
+
/**
|
|
29
|
+
* 차원 기반 복잡도 전체 분석
|
|
30
|
+
*/
|
|
31
|
+
export declare function analyzeDimensionalComplexity(node: ts.Node, sourceFile: ts.SourceFile, cyclomatic: number, nestingPenalty: number, weights?: DimensionalWeights): DimensionalComplexity;
|
|
32
|
+
//# sourceMappingURL=dimensional.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dimensional.d.ts","sourceRoot":"","sources":["../../src/metrics/dimensional.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,KAAK,EAEV,eAAe,EACf,eAAe,EACf,kBAAkB,EAElB,qBAAqB,EACrB,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AAwBrB;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,eAAe,CA+FjB;AAuBD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,GACxB,eAAe,CAmHjB;AA0CD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,cAAc,GAAE,GAAG,CAAC,MAAM,CAAa,GACtC,kBAAkB,CAoKpB;AAgCD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,kBAM7B,CAAC;AA2CF;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,UAAU,EAAE,EAAE,CAAC,UAAU,EACzB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,kBAAoC,GAC5C,qBAAqB,CAqEvB"}
|