Skip to content

Commit 653ab60

Browse files
committed
feat: cyclomatic complexity computation
1 parent bbbccb4 commit 653ab60

4 files changed

Lines changed: 71 additions & 1 deletion

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { CodeTokens } from '../tokenizer/CodeTokens';
2+
3+
/**
4+
* The cyclomatic complexity number reflect the number of decisions in an algorithm.
5+
*/
6+
export class CyclomaticComplexity {
7+
/**
8+
* The cyclomatic complexity of a function is calculated according to the following rules:
9+
* -1 is the base complexity of a function
10+
* +1 for each 'if', 'for', 'case', '&&' or '||'
11+
* @param tokenizedCode
12+
* @return cyclomaticComplexity
13+
*/
14+
public compute(tokenizedCode: CodeTokens[]): number {
15+
let cyclomaticComplexity = -1;
16+
17+
tokenizedCode.forEach((token) => {
18+
switch (token) {
19+
case CodeTokens.FOR:
20+
cyclomaticComplexity += 1;
21+
break;
22+
case CodeTokens.WHILE:
23+
cyclomaticComplexity += 1;
24+
break;
25+
case CodeTokens.IF:
26+
cyclomaticComplexity += 1;
27+
break;
28+
case CodeTokens.CASE:
29+
cyclomaticComplexity += 1;
30+
break;
31+
case CodeTokens.AND:
32+
cyclomaticComplexity += 1;
33+
break;
34+
case CodeTokens.OR:
35+
cyclomaticComplexity += 1;
36+
break;
37+
default:
38+
break;
39+
}
40+
});
41+
42+
return cyclomaticComplexity;
43+
}
44+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {MigrationInterface, QueryRunner} from "typeorm";
2+
3+
export class AddCyclomaticComplexity1627142886075 implements MigrationInterface {
4+
name = 'AddCyclomaticComplexity1627142886075'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`ALTER TABLE "submissions" ADD "cyclomaticComplexity" integer NOT NULL DEFAULT '0'`);
8+
}
9+
10+
public async down(queryRunner: QueryRunner): Promise<void> {
11+
await queryRunner.query(`ALTER TABLE "submissions" DROP COLUMN "cyclomaticComplexity"`);
12+
}
13+
14+
}

‎src/submissions/submission.entity.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ export class Submission extends BaseEntity {
9696
@Column({ nullable: true })
9797
qualityScore: number;
9898

99+
@jsonMember
100+
@Column({ default: 0 })
101+
cyclomaticComplexity: number;
102+
99103
@ManyToOne(() => User, (user) => user.submissions, {
100104
nullable: false,
101105
eager: true,

‎src/submissions/submissions.service.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { InsertSubmissionDTO } from './dto/insert-submission-dto';
1919
import { JobStatusDTO } from './dto/job-status.dto';
2020
import { Submission } from './submission.entity';
2121
import { CodeTokenizer } from '../code-quality/tokenizer/CodeTokenizer';
22+
import { CyclomaticComplexity } from '../code-quality/complexity/CyclomaticComplexity';
2223

2324
@Injectable()
2425
export class SubmissionsService {
@@ -34,6 +35,8 @@ export class SubmissionsService {
3435

3536
private codeTokenizer = new CodeTokenizer();
3637

38+
private cyclomaticComplexity = new CyclomaticComplexity();
39+
3740
async create(
3841
insertSubmissionDTO: InsertSubmissionDTO,
3942
lintScore: number,
@@ -60,7 +63,12 @@ export class SubmissionsService {
6063
insertSubmissionDTO.language,
6164
);
6265
// submission.self = submission;
63-
this.codeTokenizer.tokenize(submission.code, submission.language);
66+
const tokenizedCode = this.codeTokenizer.tokenize(
67+
submission.code,
68+
submission.language,
69+
);
70+
submission.cyclomaticComplexity =
71+
this.cyclomaticComplexity.compute(tokenizedCode);
6472

6573
return submission.save();
6674
}

0 commit comments

Comments
 (0)