Skip to content

Commit 8f427f3

Browse files
committed
chore: release version 5.5.2 with new sign feature for number and percentage formatting
1 parent 40b3906 commit 8f427f3

7 files changed

Lines changed: 146 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# deverything
22

3+
## 5.5.2
4+
5+
### Patch Changes
6+
7+
- sign
8+
39
## 5.5.1
410

511
### Patch Changes
@@ -10,7 +16,7 @@
1016

1117
### Minor Changes
1218

13-
- sortBySortdedKeys
19+
- sortBySortedKeys
1420

1521
## 5.4.0
1622

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "deverything",
3-
"version": "5.5.1",
3+
"version": "5.5.2",
44
"description": "Everything you need for Dev",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",

src/formatters/formatNumber.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,32 @@ describe("formatNumber", () => {
3636
expect(formattedValue).toEqual("123,456.123");
3737
});
3838

39+
describe("sign", () => {
40+
test("prefixes positive number with +", () => {
41+
expect(formatNumber(1234, { sign: true })).toBe("+1,234");
42+
});
43+
44+
test("no prefix for zero", () => {
45+
expect(formatNumber(0, { sign: true })).toBe("0");
46+
});
47+
48+
test("no prefix for negative", () => {
49+
expect(formatNumber(-50, { sign: true })).toBe("-50");
50+
});
51+
52+
test("prefixes positive compact value with +", () => {
53+
expect(formatNumber(1500, { sign: true, compact: true })).toBe("+1.5K");
54+
});
55+
56+
test("prefixes positive percentage with +", () => {
57+
expect(formatNumber(0.25, { sign: true, percentage: true })).toBe("+25%");
58+
});
59+
60+
test("no prefix for zero percentage", () => {
61+
expect(formatNumber(0, { sign: true, percentage: true })).toBe("0%");
62+
});
63+
});
64+
3965
describe("Percentage", () => {
4066
test("no digits", () => {
4167
const formattedValue = formatNumber(0.123456, { percentage: true });

src/formatters/formatNumber.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,25 @@ export const formatNumber = (
2424
maxDigits,
2525
percentage,
2626
unit = "",
27+
sign = false,
2728
}: {
2829
compact?: boolean;
2930
maxDigits?: number;
3031
percentage?: boolean;
3132
unit?: string;
33+
sign?: boolean;
3234
} = {}
3335
): string => {
36+
let prefix = "";
37+
38+
if (sign) {
39+
prefix = value > 0 ? "+" : "";
40+
}
41+
3442
if (percentage) {
3543
const useValue = isNumber(value) ? value : 0;
3644
const number = (useValue * 100).toFixed(maxDigits || 0);
37-
return `${number}%`;
45+
return `${prefix}${number}%`;
3846
}
3947

4048
// < 1 case
@@ -51,7 +59,7 @@ export const formatNumber = (
5159
const formatter = Intl.NumberFormat("en", {
5260
maximumSignificantDigits: maxDigits ?? 3,
5361
});
54-
return `${formatter.format(scaled)}${tier.suffix}${unit}`;
62+
return `${prefix}${formatter.format(scaled)}${tier.suffix}${unit}`;
5563
}
5664

5765
// > 1 case
@@ -60,5 +68,5 @@ export const formatNumber = (
6068
maximumSignificantDigits: maxDigits,
6169
});
6270

63-
return `${formatter.format(value)}${unit}`;
71+
return `${prefix}${formatter.format(value)}${unit}`;
6472
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { describe, expect, test } from "vitest";
2+
import { formatPercentage, formatPercentageNumber } from "./formatPercentage";
3+
4+
describe("formatPercentageNumber", () => {
5+
test("converts ratio to percentage string", () => {
6+
expect(formatPercentageNumber(0.5)).toBe("50");
7+
});
8+
9+
test("respects digits option", () => {
10+
expect(formatPercentageNumber(0.123456, { digits: 2 })).toBe("12.35");
11+
});
12+
13+
test("clamps to -100 at minimum", () => {
14+
expect(formatPercentageNumber(-0.5)).toBe("-50");
15+
expect(formatPercentageNumber(-2)).toBe("-100");
16+
});
17+
18+
test("clamps to 100 at maximum", () => {
19+
expect(formatPercentageNumber(1.5)).toBe("100");
20+
});
21+
22+
describe("sign", () => {
23+
test("prefixes positive values with +", () => {
24+
expect(formatPercentageNumber(0.25, { sign: true })).toBe("+25");
25+
});
26+
27+
test("no prefix for zero", () => {
28+
expect(formatPercentageNumber(0, { sign: true })).toBe("0");
29+
});
30+
31+
test("negative value shows minus sign from the number", () => {
32+
expect(formatPercentageNumber(-0.1, { sign: true })).toBe("-10");
33+
});
34+
35+
test("respects digits alongside sign", () => {
36+
expect(formatPercentageNumber(0.1234, { sign: true, digits: 2 })).toBe(
37+
"+12.34"
38+
);
39+
});
40+
});
41+
});
42+
43+
describe("formatPercentage", () => {
44+
test("appends % symbol", () => {
45+
expect(formatPercentage(1)).toBe("100%");
46+
expect(formatPercentage(0, { digits: 2 })).toBe("0.00%");
47+
});
48+
49+
describe("sign", () => {
50+
test("prefixes positive values with +", () => {
51+
expect(formatPercentage(0.25, { sign: true })).toBe("+25%");
52+
});
53+
54+
test("prefixes negative values with -", () => {
55+
expect(formatPercentage(-0.25, { sign: true })).toBe("-25%");
56+
});
57+
58+
test("no prefix for zero", () => {
59+
expect(formatPercentage(0, { sign: true })).toBe("0%");
60+
});
61+
62+
test("respects digits alongside sign", () => {
63+
expect(formatPercentage(0.1234, { sign: true, digits: 2 })).toBe(
64+
"+12.34%"
65+
);
66+
});
67+
});
68+
});

src/formatters/formatPercentage.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,21 @@ export const formatPercentageNumber = (
88
value: number,
99
{
1010
digits,
11+
sign,
1112
}: {
1213
digits?: number;
14+
sign?: boolean;
1315
} = {}
1416
): string => {
15-
return `${clamp({
17+
let prefix = "";
18+
19+
if (sign) {
20+
prefix = value > 0 ? "+" : "";
21+
}
22+
23+
return `${prefix}${clamp({
1624
number: value * 100,
17-
min: 0,
25+
min: -100,
1826
max: 100,
1927
}).toFixed(digits || 0)}`;
2028
};
@@ -28,9 +36,11 @@ export const formatPercentage = (
2836
value: number,
2937
{
3038
digits,
39+
sign,
3140
}: {
3241
digits?: number;
42+
sign?: boolean;
3343
} = {}
3444
): string => {
35-
return `${formatPercentageNumber(value, { digits })}%`;
45+
return `${formatPercentageNumber(value, { digits, sign })}%`;
3646
};

src/formatters/formatProgress.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,26 @@ const calculateRemainingTime = (
8080
return formatRemainingTime(remainingSeconds);
8181
};
8282

83+
/**
84+
* Formats a progress indicator showing the current index, total, and completion percentage.
85+
*
86+
* When a `progressId` is provided, also estimates and appends the remaining time based on
87+
* the rate of progress since the first call with that ID. Tracking state is automatically
88+
* cleaned up once the final item is reached.
89+
*
90+
* @param index - Zero-based index of the current item being processed.
91+
* @param total - Total number of items.
92+
* @param options - Optional configuration.
93+
* @param options.progressId - Stable identifier used to track throughput across calls and
94+
* compute a remaining-time estimate. Omit to skip time estimation.
95+
* @returns A formatted string such as `"42/100 42.00%"` or `"42/100 42.00% (~3m 20s remaining)"`.
96+
*
97+
* @example
98+
* for (const [i, item] of items.entries()) {
99+
* console.log(formatProgress(i, items.length, { progressId: "my-job" }));
100+
* await process(item);
101+
* }
102+
*/
83103
export const formatProgress = (
84104
index: number,
85105
total: number,

0 commit comments

Comments
 (0)