Skip to content

Commit 9096643

Browse files
committed
fix: return null deltaPercentage when previous month has zero contributions
- Hardcoded +100% was misleading regardless of current month total - deltaPercentage is now number | null in MonthlyStats type - calculateMonthlyStats returns null when previousMonthTotal === 0 - generateMonthlySVG and generateAutoThemeMonthlySVG render 'N/A' for null - Updated test to expect null instead of 100
1 parent 9b64cab commit 9096643

4 files changed

Lines changed: 41 additions & 33 deletions

File tree

lib/calculate.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ describe('calculateMonthlyStats', () => {
348348

349349
expect(result.previousMonthTotal).toBe(0);
350350
expect(result.currentMonthTotal).toBe(10);
351-
expect(result.deltaPercentage).toBe(100);
351+
expect(result.deltaPercentage).toBeNull();
352352
});
353353

354354
it('handles zero current month contributions', () => {

lib/calculate.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,16 @@ export function calculateMonthlyStats(
207207
}).format(now);
208208

209209
const deltaAbsolute = currentMonthTotal - previousMonthTotal;
210-
let deltaPercentage = 0;
211-
212-
if (previousMonthTotal === 0) {
213-
if (currentMonthTotal > 0) {
214-
deltaPercentage = 100;
215-
}
216-
} else {
217-
deltaPercentage = Math.round((deltaAbsolute / previousMonthTotal) * 100);
218-
if (deltaPercentage === -0) deltaPercentage = 0;
219-
}
210+
// When there is no baseline (previous month = 0), the percentage change is
211+
// mathematically undefined. Return null so the renderer can display 'N/A'
212+
// instead of the misleading hardcoded +100%.
213+
const deltaPercentage: number | null =
214+
previousMonthTotal === 0
215+
? null
216+
: (() => {
217+
const pct = Math.round((deltaAbsolute / previousMonthTotal) * 100);
218+
return pct === -0 ? 0 : pct;
219+
})();
220220

221221
return {
222222
currentMonthTotal,

lib/svg/generator.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -434,18 +434,22 @@ export function generateMonthlySVG(stats: MonthlyStats, params: BadgeParams): st
434434
: `${stats.deltaAbsolute} commits`;
435435
} else if (params.delta_format === 'both') {
436436
deltaText =
437-
stats.deltaPercentage > 0
438-
? `+${stats.deltaPercentage}% (+${stats.deltaAbsolute})`
439-
: stats.deltaPercentage < 0
440-
? `${stats.deltaPercentage}% (${stats.deltaAbsolute})`
441-
: `0% (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`;
437+
stats.deltaPercentage === null
438+
? `N/A (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`
439+
: stats.deltaPercentage > 0
440+
? `+${stats.deltaPercentage}% (+${stats.deltaAbsolute})`
441+
: stats.deltaPercentage < 0
442+
? `${stats.deltaPercentage}% (${stats.deltaAbsolute})`
443+
: `0% (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`;
442444
} else {
443445
deltaText =
444-
stats.deltaPercentage > 0
445-
? `+${stats.deltaPercentage}%`
446-
: stats.deltaPercentage < 0
447-
? `${stats.deltaPercentage}%`
448-
: `0%`;
446+
stats.deltaPercentage === null
447+
? 'N/A'
448+
: stats.deltaPercentage > 0
449+
? `+${stats.deltaPercentage}%`
450+
: stats.deltaPercentage < 0
451+
? `${stats.deltaPercentage}%`
452+
: `0%`;
449453
}
450454
const deltaColor = stats.deltaAbsolute >= 0 ? accent : '#ff4444';
451455

@@ -514,18 +518,22 @@ function generateAutoThemeMonthlySVG(stats: MonthlyStats, params: BadgeParams):
514518
: `${stats.deltaAbsolute} commits`;
515519
} else if (params.delta_format === 'both') {
516520
deltaText =
517-
stats.deltaPercentage > 0
518-
? `+${stats.deltaPercentage}% (+${stats.deltaAbsolute})`
519-
: stats.deltaPercentage < 0
520-
? `${stats.deltaPercentage}% (${stats.deltaAbsolute})`
521-
: `0% (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`;
521+
stats.deltaPercentage === null
522+
? `N/A (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`
523+
: stats.deltaPercentage > 0
524+
? `+${stats.deltaPercentage}% (+${stats.deltaAbsolute})`
525+
: stats.deltaPercentage < 0
526+
? `${stats.deltaPercentage}% (${stats.deltaAbsolute})`
527+
: `0% (${stats.deltaAbsolute > 0 ? '+' : ''}${stats.deltaAbsolute})`;
522528
} else {
523529
deltaText =
524-
stats.deltaPercentage > 0
525-
? `+${stats.deltaPercentage}%`
526-
: stats.deltaPercentage < 0
527-
? `${stats.deltaPercentage}%`
528-
: `0%`;
530+
stats.deltaPercentage === null
531+
? 'N/A'
532+
: stats.deltaPercentage > 0
533+
? `+${stats.deltaPercentage}%`
534+
: stats.deltaPercentage < 0
535+
? `${stats.deltaPercentage}%`
536+
: `0%`;
529537
}
530538

531539
return `

types/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ export interface MonthlyStats {
7777
/** Total number of contributions in the previous calendar month. */
7878
previousMonthTotal: number;
7979

80-
/** Percentage change in contributions compared to the previous month (can be negative). */
81-
deltaPercentage: number;
80+
/** Percentage change in contributions compared to the previous month (can be negative). Null when previous month has zero contributions (undefined baseline). */
81+
deltaPercentage: number | null;
8282

8383
/** Absolute change in contribution count compared to the previous month (can be negative). */
8484
deltaAbsolute: number;

0 commit comments

Comments
 (0)