Skip to content

Commit

Permalink
feat: added CyclomaticComplexityCountableNode.
Browse files Browse the repository at this point in the history
  • Loading branch information
ytetsuro committed Aug 14, 2022
1 parent 285e14f commit 99de01f
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/Language/PHP/CyclomaticComplexityCountableNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as PHPParser from 'php-parser';
import { ComplexityCountableNode as ComplexityCountableNodeInterface } from '../../Analyzer/CodeMetricsCalculator/CyclomaticComplexity/Adapter/ComplexityCountableNode';
import { ASTNode } from './ASTNode';
import { ASTKind } from './ASTKind';
import { injectable } from 'inversify';

type BinNode = PHPParser.Node & { type: string };
type AssignNode = PHPParser.Node & { operator: string };

@injectable()
export class CyclomaticComplexityCountableNode implements ComplexityCountableNodeInterface {
private static readonly incrementSyntaxKinds = [
ASTKind.IF,
ASTKind.CATCH,
ASTKind.SWITCH,
ASTKind.FOR,
ASTKind.WHILE,
ASTKind.RETURN_IF,
ASTKind.MATCH_ARM,
ASTKind.NULL_SAFE_PROPERTY_LOOKUP,
];

private readonly node: ASTNode;

constructor(node: ASTNode) {
this.node = node;
}

isIncrement() {
if (CyclomaticComplexityCountableNode.incrementSyntaxKinds.includes(this.node.kind)) {
return true;
} else if (this.node.kind === ASTKind.LABEL) {
return true;
} else if (this.node.kind === ASTKind.ASSIGN && ['??='].includes((<AssignNode>this.node.node).operator)) {
return true;
} else if (
this.node.kind === ASTKind.BIN &&
['and', 'or', '&&', '||', 'xor', '??'].includes((<BinNode>this.node.node).type)
) {
return true;
}

return false;
}

getChildren() {
return this.node.getChildren().map((node) => new CyclomaticComplexityCountableNode(node));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Engine } from 'php-parser';
import { readFileSync } from 'fs';
import { ASTNode } from '../ASTNode';
import { CyclomaticComplexityCountableNode } from '../CyclomaticComplexityCountableNode';

describe('CyclomaticComplexityCountableNode', () => {
const engine = new Engine({
parser: {
extractDoc: true,
},
ast: {
withPositions: true,
withSource: true,
},
});
const node = engine.parseCode(
readFileSync(`${__dirname}/fixtures/example.php`).toString(),
`${__dirname}/fixtures/example.php`
);

const [_, ...members] = new ASTNode(node.children[0], node).getChildren();

const map = [...members].reduce(
(map, node) => map.set((<any>node.node).name.name, node.getChildren()[1]),
new Map<string, any>()
);

describe('.isIncrement()', () => {
it.each([
['if', map.get('if')!.getChildren()[0]],
['switch', map.get('switch')!.getChildren()[0]],
['for', map.get('for')!.getChildren()[0]],
['while', map.get('while')!.getChildren()[0]],
['catch', map.get('try')!.getChildren()[0].getChildren().pop()],
['conditional', map.get('conditional')!.getChildren()[0].getChildren()[0]],
['ampersand', map.get('ampersand')!.getChildren()[0].getChildren()[0]],
['barbar', map.get('barbar')!.getChildren()[0].getChildren()[0]],
['label', map.get('label')!.getChildren()[1]],
['match', map.get('match')!.getChildren()[0].getChildren()[0].getChildren()[1]],
['nullishCoalescingOperator', map.get('nullishCoalescingOperator')!.getChildren()[0].getChildren()[0]],
['optionalChaining', map.get('optionalChaining')!.getChildren()[1].getChildren()[0]],
])('should %s is increment.', (_, astNode) => {
const actual = new CyclomaticComplexityCountableNode(astNode);

expect(actual.isIncrement()).toBe(true);
});
});
});

0 comments on commit 99de01f

Please sign in to comment.