From d2619a0b20878d40062acf80a2a6397fd8761542 Mon Sep 17 00:00:00 2001 From: Tetsuro Yoshikawa Date: Sun, 31 Jul 2022 00:27:09 +0900 Subject: [PATCH] feat: can show CyclomaticComplexity for HTML. --- .../Parts/FileMetricsTable/FileMetricsTable.ts | 1 + .../Component/Parts/FileMetricsTable/index.ts | 11 ++++++++--- .../HTML/FrontEnd/Component/Parts/Summary.ts | 9 +++++++-- .../HTML/FrontEnd/Component/Parts/TableRow.ts | 3 ++- src/Reporter/HTML/FrontEnd/Entity/FileMetrics.ts | 12 ++++++++++-- src/Reporter/HTML/FrontEnd/Entity/MetricsType.ts | 1 + src/Reporter/HTML/FrontEnd/Entity/Summary.ts | 6 +++++- .../FrontEnd/Entity/__tests__/FileMetrics.test.ts | 6 ++++-- .../HTML/FrontEnd/Entity/__tests__/Summary.test.ts | 4 +++- .../FrontEnd/Infrastructure/Event/GetDashboard.ts | 2 +- .../FrontEnd/Infrastructure/Repository/Analyzed.ts | 13 +++++++++---- .../Repository/__tests__/Analyzed.test.ts | 2 +- 12 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/FileMetricsTable.ts b/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/FileMetricsTable.ts index ee471b9..45bfb76 100644 --- a/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/FileMetricsTable.ts +++ b/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/FileMetricsTable.ts @@ -47,6 +47,7 @@ export class FileMetricsTable implements m.Component> m('tr', [ m('th', 'FilePath'), m('th', 'CognitiveComplexity(Max/Avg)'), + m('th', 'CyclomaticComplexity(Max/Avg)'), m('th', 'BugsDelivered(Sum/Max)'), m('th', 'Maintainability(Min/Avg)'), m('th', 'LineOfCode'), diff --git a/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/index.ts b/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/index.ts index 3ac37ce..5e03cf9 100644 --- a/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/index.ts +++ b/src/Reporter/HTML/FrontEnd/Component/Parts/FileMetricsTable/index.ts @@ -5,11 +5,16 @@ import { GetDashboard } from '../../../Infrastructure/Event/GetDashboard'; import { FileMetricsTable as Presentational } from './FileMetricsTable'; type Param = { list: FileMetrics[] }; -type SortableMetrics = 'Complexity' | 'BugsDelivered' | 'Maintainability'; +type SortableMetrics = 'CyclomaticComplexity' | 'CognitiveComplexity' | 'BugsDelivered' | 'Maintainability'; export class FileMetricsTable implements m.Component { - private currentSelect: SortableMetrics = 'Complexity'; - private selectableMetrics: SortableMetrics[] = ['Complexity', 'BugsDelivered', 'Maintainability']; + private currentSelect: SortableMetrics = 'CognitiveComplexity'; + private selectableMetrics: SortableMetrics[] = [ + 'CognitiveComplexity', + 'CyclomaticComplexity', + 'BugsDelivered', + 'Maintainability', + ]; oninit() { EventStore.get(GetDashboard).dispatch(this.currentSelect); diff --git a/src/Reporter/HTML/FrontEnd/Component/Parts/Summary.ts b/src/Reporter/HTML/FrontEnd/Component/Parts/Summary.ts index 8802720..cb1fdd6 100644 --- a/src/Reporter/HTML/FrontEnd/Component/Parts/Summary.ts +++ b/src/Reporter/HTML/FrontEnd/Component/Parts/Summary.ts @@ -3,7 +3,8 @@ import { MetricsValue } from '../../Entity/MetricsValue'; import { SummaryColumn } from './SummaryColumn'; interface SummarySource { - getAverageComplexity(): MetricsValue; + getAverageCognitiveComplexity(): MetricsValue; + getAverageCyclomaticComplexity(): MetricsValue; getAverageMaintainability(): MetricsValue; getSumBugsDelivered(): MetricsValue; getTotalLineOfCode(): number; @@ -14,7 +15,11 @@ export class Summary implements m.Component<{ summary: SummarySource }> { return m('.level', [ m(SummaryColumn, { title: 'Cognitive Complexity', - metrics: vnode.attrs.summary.getAverageComplexity(), + metrics: vnode.attrs.summary.getAverageCognitiveComplexity(), + }), + m(SummaryColumn, { + title: 'Cyclomatic Complexity', + metrics: vnode.attrs.summary.getAverageCyclomaticComplexity(), }), m(SummaryColumn, { title: 'Maintainability', diff --git a/src/Reporter/HTML/FrontEnd/Component/Parts/TableRow.ts b/src/Reporter/HTML/FrontEnd/Component/Parts/TableRow.ts index c8cbc6e..44c9001 100644 --- a/src/Reporter/HTML/FrontEnd/Component/Parts/TableRow.ts +++ b/src/Reporter/HTML/FrontEnd/Component/Parts/TableRow.ts @@ -17,7 +17,8 @@ export class TableRow implements m.Component { vnode.attrs.fileName ) ), - m('td', `${vnode.attrs.getMaximumComplexity()}/${vnode.attrs.getAverageComplexity()}`), + m('td', `${vnode.attrs.getMaximumCognitiveComplexity()}/${vnode.attrs.getAverageCognitiveComplexity()}`), + m('td', `${vnode.attrs.getMaximumCyclomaticComplexity()}/${vnode.attrs.getAverageCyclomaticComplexity()}`), m('td', `${vnode.attrs.getSumBugsDelivered()}/${vnode.attrs.getMaximumBugsDelivered()}`), m('td', `${vnode.attrs.getMinimumMaintainability()}/${vnode.attrs.getAverageMaintainability()}`), m('td', vnode.attrs.logicalLineOfCode), diff --git a/src/Reporter/HTML/FrontEnd/Entity/FileMetrics.ts b/src/Reporter/HTML/FrontEnd/Entity/FileMetrics.ts index d7f3a8f..9613b25 100644 --- a/src/Reporter/HTML/FrontEnd/Entity/FileMetrics.ts +++ b/src/Reporter/HTML/FrontEnd/Entity/FileMetrics.ts @@ -29,14 +29,22 @@ export class FileMetrics { return this.metricsCalculator.getLength(); } - getMaximumComplexity() { + getMaximumCognitiveComplexity() { return this.metricsCalculator.max(MetricsType.CognitiveComplexity); } - getAverageComplexity() { + getAverageCognitiveComplexity() { return this.metricsCalculator.average(MetricsType.CognitiveComplexity); } + getMaximumCyclomaticComplexity() { + return this.metricsCalculator.max(MetricsType.CyclomaticComplexity); + } + + getAverageCyclomaticComplexity() { + return this.metricsCalculator.average(MetricsType.CyclomaticComplexity); + } + getMaximumBugsDelivered() { return this.metricsCalculator.max(MetricsType.HalsteadBugsDelivered); } diff --git a/src/Reporter/HTML/FrontEnd/Entity/MetricsType.ts b/src/Reporter/HTML/FrontEnd/Entity/MetricsType.ts index e3486ef..9d1b229 100644 --- a/src/Reporter/HTML/FrontEnd/Entity/MetricsType.ts +++ b/src/Reporter/HTML/FrontEnd/Entity/MetricsType.ts @@ -31,6 +31,7 @@ export class MetricsType { [60, 0], ]) ); + public static readonly CyclomaticComplexity = new MetricsType(11, 'CyclomaticComplexity', new Map([[8, 2]])); private constructor( private readonly scaler: number, diff --git a/src/Reporter/HTML/FrontEnd/Entity/Summary.ts b/src/Reporter/HTML/FrontEnd/Entity/Summary.ts index 52ea3c3..4199a79 100644 --- a/src/Reporter/HTML/FrontEnd/Entity/Summary.ts +++ b/src/Reporter/HTML/FrontEnd/Entity/Summary.ts @@ -9,10 +9,14 @@ export class Summary { this.metricsCalculator = new MetricsCalculator(fileSummaries.flatMap((fileSummary) => fileSummary.childrenMetrics)); } - getAverageComplexity() { + getAverageCognitiveComplexity() { return this.metricsCalculator.average(MetricsType.CognitiveComplexity); } + getAverageCyclomaticComplexity() { + return this.metricsCalculator.average(MetricsType.CyclomaticComplexity); + } + getAverageMaintainability() { return this.metricsCalculator.average(MetricsType.Maintainability); } diff --git a/src/Reporter/HTML/FrontEnd/Entity/__tests__/FileMetrics.test.ts b/src/Reporter/HTML/FrontEnd/Entity/__tests__/FileMetrics.test.ts index 90fca98..510e445 100644 --- a/src/Reporter/HTML/FrontEnd/Entity/__tests__/FileMetrics.test.ts +++ b/src/Reporter/HTML/FrontEnd/Entity/__tests__/FileMetrics.test.ts @@ -36,7 +36,7 @@ describe('FileMetrics', () => { ] ); - expect(metrics.getMaximumComplexity()).toStrictEqual(expected); + expect(metrics.getMaximumCognitiveComplexity()).toStrictEqual(expected); }); }); @@ -55,7 +55,9 @@ describe('FileMetrics', () => { ] ); - expect(metrics.getAverageComplexity()).toStrictEqual(new MetricsValue(MetricsType.CognitiveComplexity, 3.5)); + expect(metrics.getAverageCognitiveComplexity()).toStrictEqual( + new MetricsValue(MetricsType.CognitiveComplexity, 3.5) + ); }); }); diff --git a/src/Reporter/HTML/FrontEnd/Entity/__tests__/Summary.test.ts b/src/Reporter/HTML/FrontEnd/Entity/__tests__/Summary.test.ts index 7ff852c..4b77afa 100644 --- a/src/Reporter/HTML/FrontEnd/Entity/__tests__/Summary.test.ts +++ b/src/Reporter/HTML/FrontEnd/Entity/__tests__/Summary.test.ts @@ -31,7 +31,9 @@ describe('Summary', () => { ), ]); - expect(summary.getAverageComplexity()).toStrictEqual(new MetricsValue(MetricsType.CognitiveComplexity, 4)); + expect(summary.getAverageCognitiveComplexity()).toStrictEqual( + new MetricsValue(MetricsType.CognitiveComplexity, 4) + ); }); }); diff --git a/src/Reporter/HTML/FrontEnd/Infrastructure/Event/GetDashboard.ts b/src/Reporter/HTML/FrontEnd/Infrastructure/Event/GetDashboard.ts index d463bef..4c7e6fc 100644 --- a/src/Reporter/HTML/FrontEnd/Infrastructure/Event/GetDashboard.ts +++ b/src/Reporter/HTML/FrontEnd/Infrastructure/Event/GetDashboard.ts @@ -3,7 +3,7 @@ import { FileMetrics } from '../../Entity/FileMetrics'; import { Analyzed } from '../Repository/Analyzed'; import { Event } from './Event'; -type SortKey = 'Complexity' | 'BugsDelivered' | 'Maintainability'; +type SortKey = 'CognitiveComplexity' | 'CyclomaticComplexity' | 'BugsDelivered' | 'Maintainability'; export class GetDashboard extends Event { constructor(private readonly repository: Analyzed) { diff --git a/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/Analyzed.ts b/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/Analyzed.ts index 106cfeb..c96db20 100644 --- a/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/Analyzed.ts +++ b/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/Analyzed.ts @@ -3,7 +3,7 @@ import { FileMetrics as Converter } from '../Converter/FileMetrics'; import { FileMetrics as DataModel } from '../DataModel/FileMetrics'; import { ResourceLoader } from '../ResourceLoader'; -type SortKey = 'Complexity' | 'BugsDelivered' | 'Maintainability'; +type SortKey = 'CyclomaticComplexity' | 'CognitiveComplexity' | 'BugsDelivered' | 'Maintainability'; export class Analyzed { private fileMetrics: Map = new Map(); @@ -11,7 +11,8 @@ export class Analyzed { private readonly sortLogics = new Map([ ['BugsDelivered', this.getDiffBugDelivered], - ['Complexity', this.getDiffMaximumComplexity], + ['CyclomaticComplexity', this.getDiffMaximumCyclomaticComplexity], + ['CognitiveComplexity', this.getDiffMaximumCognitiveComplexity], ['Maintainability', this.getDiffMinimumMaintainability], ]); @@ -36,8 +37,12 @@ export class Analyzed { return Number(second.getSumBugsDelivered()) - Number(first.getSumBugsDelivered()); } - private getDiffMaximumComplexity(first: FileMetrics, second: FileMetrics) { - return Number(second.getMaximumComplexity()) - Number(first.getMaximumComplexity()); + private getDiffMaximumCognitiveComplexity(first: FileMetrics, second: FileMetrics) { + return Number(second.getMaximumCognitiveComplexity()) - Number(first.getMaximumCognitiveComplexity()); + } + + private getDiffMaximumCyclomaticComplexity(first: FileMetrics, second: FileMetrics) { + return Number(second.getMaximumCyclomaticComplexity()) - Number(first.getMaximumCyclomaticComplexity()); } private getDiffMinimumMaintainability(first: FileMetrics, second: FileMetrics) { diff --git a/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/__tests__/Analyzed.test.ts b/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/__tests__/Analyzed.test.ts index 0522890..7ed491f 100644 --- a/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/__tests__/Analyzed.test.ts +++ b/src/Reporter/HTML/FrontEnd/Infrastructure/Repository/__tests__/Analyzed.test.ts @@ -47,7 +47,7 @@ describe('Analyzed', () => { describe('.getSortedList()', () => { it('should get complexity sorted list.', async () => { - const list = await repository.getSortedList('Complexity'); + const list = await repository.getSortedList('CognitiveComplexity'); expect(list.map((row) => row.fileName)).toStrictEqual([ 'maxComplexity.ts',