Skip to content

Commit 567c984

Browse files
committed
refactor: format fns
1 parent e7eaea9 commit 567c984

File tree

2 files changed

+119
-10
lines changed

2 files changed

+119
-10
lines changed

packages/utilities/i18n-utils/src/format-bytes.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,28 @@ export const formatBytes = (bytes: number, locale = "en-US", options: FormatByte
4040
const { unitSystem = "decimal", precision = 3, unit = "byte", unitDisplay = "short" } = options
4141

4242
const factor = unitSystem === "binary" ? 1024 : 1000
43-
4443
const prefix = unit === "bit" ? bitPrefixes : bytePrefixes
45-
const index = Math.max(0, Math.min(Math.floor(Math.log10(bytes) / 3), prefix.length - 1))
4644

47-
const v = parseFloat((bytes / Math.pow(factor, index)).toPrecision(precision))
45+
// Handle negative values
46+
const isNegative = bytes < 0
47+
const absoluteBytes = Math.abs(bytes)
48+
49+
// Find the appropriate unit using iterative division
50+
let value = absoluteBytes
51+
let index = 0
52+
53+
while (value >= factor && index < prefix.length - 1) {
54+
value /= factor
55+
index++
56+
}
57+
58+
// Apply precision
59+
const v = parseFloat(value.toPrecision(precision))
60+
61+
// Restore sign if negative
62+
const finalValue = isNegative ? -v : v
4863

49-
return formatNumber(v, locale, {
64+
return formatNumber(finalValue, locale, {
5065
style: "unit",
5166
unit: prefix[index] + unit,
5267
unitDisplay,

packages/utilities/i18n-utils/tests/format-byte.test.ts

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { formatBytes, type FormatBytesOptions } from "../src"
22

33
describe("formatBytes", () => {
4-
describe("decimal definition", () => {
4+
describe("edge cases", () => {
55
test("should return empty string for NaN", () => {
66
const result = formatBytes(NaN)
77
expect(result).toMatchInlineSnapshot(`""`)
@@ -12,6 +12,24 @@ describe("formatBytes", () => {
1212
expect(result).toMatchInlineSnapshot(`"0 B"`)
1313
})
1414

15+
test("should handle negative values", () => {
16+
expect(formatBytes(-1500)).toMatchInlineSnapshot(`"-1.5 kB"`)
17+
expect(formatBytes(-1048576, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"-1 MB"`)
18+
})
19+
20+
test("should handle very small values", () => {
21+
expect(formatBytes(1)).toMatchInlineSnapshot(`"1 byte"`)
22+
expect(formatBytes(0.5)).toMatchInlineSnapshot(`"0.5 byte"`)
23+
expect(formatBytes(100)).toMatchInlineSnapshot(`"100 byte"`)
24+
})
25+
26+
test("should handle Infinity", () => {
27+
expect(formatBytes(Infinity)).toMatchInlineSnapshot(`"∞ PB"`)
28+
expect(formatBytes(-Infinity)).toMatchInlineSnapshot(`"-∞ PB"`)
29+
})
30+
})
31+
32+
describe("decimal definition", () => {
1533
test("should format bytes correctly", () => {
1634
const options: FormatBytesOptions = { unit: "byte", unitDisplay: "short" }
1735
const result = formatBytes(1500, "en-US", options)
@@ -30,6 +48,19 @@ describe("formatBytes", () => {
3048
expect(result).toMatchInlineSnapshot(`"1.5 GB"`)
3149
})
3250

51+
test("should handle very large values (petabyte)", () => {
52+
expect(formatBytes(1e15)).toMatchInlineSnapshot(`"1 PB"`)
53+
expect(formatBytes(1.5e15)).toMatchInlineSnapshot(`"1.5 PB"`)
54+
expect(formatBytes(2.5e15)).toMatchInlineSnapshot(`"2.5 PB"`)
55+
})
56+
57+
test("should handle boundary values", () => {
58+
expect(formatBytes(999)).toMatchInlineSnapshot(`"999 byte"`)
59+
expect(formatBytes(1000)).toMatchInlineSnapshot(`"1 kB"`)
60+
expect(formatBytes(999999)).toMatchInlineSnapshot(`"1,000 kB"`)
61+
expect(formatBytes(1000000)).toMatchInlineSnapshot(`"1 MB"`)
62+
})
63+
3364
test("sink", () => {
3465
expect(formatBytes(1024)).toMatchInlineSnapshot(`"1.02 kB"`)
3566
expect(formatBytes(1048576)).toMatchInlineSnapshot(`"1.05 MB"`)
@@ -42,6 +73,47 @@ describe("formatBytes", () => {
4273
})
4374
})
4475

76+
describe("precision control", () => {
77+
test("should respect different precision values", () => {
78+
expect(formatBytes(1234567, "en-US", { precision: 1 })).toMatchInlineSnapshot(`"1 MB"`)
79+
expect(formatBytes(1234567, "en-US", { precision: 2 })).toMatchInlineSnapshot(`"1.2 MB"`)
80+
expect(formatBytes(1234567, "en-US", { precision: 3 })).toMatchInlineSnapshot(`"1.23 MB"`)
81+
// toPrecision gives 1.2346, but Intl.NumberFormat rounds it to 1.235
82+
expect(formatBytes(1234567, "en-US", { precision: 5 })).toMatchInlineSnapshot(`"1.235 MB"`)
83+
})
84+
85+
test("should handle precision with toPrecision rounding", () => {
86+
// toPrecision rounds, so 1.2345... becomes 1.235 with precision 4
87+
expect(formatBytes(1234567, "en-US", { precision: 4 })).toMatchInlineSnapshot(`"1.235 MB"`)
88+
})
89+
})
90+
91+
describe("unit display modes", () => {
92+
test("should format with long unit display", () => {
93+
expect(formatBytes(1500, "en-US", { unitDisplay: "long" })).toMatchInlineSnapshot(`"1.5 kilobytes"`)
94+
expect(formatBytes(1500000, "en-US", { unitDisplay: "long" })).toMatchInlineSnapshot(`"1.5 megabytes"`)
95+
})
96+
97+
test("should format with short unit display", () => {
98+
expect(formatBytes(1500, "en-US", { unitDisplay: "short" })).toMatchInlineSnapshot(`"1.5 kB"`)
99+
expect(formatBytes(1500000, "en-US", { unitDisplay: "short" })).toMatchInlineSnapshot(`"1.5 MB"`)
100+
})
101+
102+
test("should format with narrow unit display", () => {
103+
expect(formatBytes(1500, "en-US", { unitDisplay: "narrow" })).toMatchInlineSnapshot(`"1.5kB"`)
104+
expect(formatBytes(1500000, "en-US", { unitDisplay: "narrow" })).toMatchInlineSnapshot(`"1.5MB"`)
105+
})
106+
})
107+
108+
describe("bits vs bytes", () => {
109+
test("should format bits with different scales", () => {
110+
expect(formatBytes(1500, "en-US", { unit: "bit" })).toMatchInlineSnapshot(`"1.5 kb"`)
111+
expect(formatBytes(1500000, "en-US", { unit: "bit" })).toMatchInlineSnapshot(`"1.5 Mb"`)
112+
expect(formatBytes(1500000000, "en-US", { unit: "bit" })).toMatchInlineSnapshot(`"1.5 Gb"`)
113+
expect(formatBytes(1500000000000, "en-US", { unit: "bit" })).toMatchInlineSnapshot(`"1.5 Tb"`)
114+
})
115+
})
116+
45117
describe("binary definition", () => {
46118
test("should format bytes correctly", () => {
47119
const options: FormatBytesOptions = { unitSystem: "binary", unit: "byte", unitDisplay: "short" }
@@ -61,6 +133,20 @@ describe("formatBytes", () => {
61133
expect(result).toMatchInlineSnapshot(`"1.5 GB"`)
62134
})
63135

136+
test("should handle very large binary values (petabyte)", () => {
137+
const peta = Math.pow(1024, 5)
138+
139+
expect(formatBytes(peta, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 PB"`)
140+
expect(formatBytes(1.5 * peta, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1.5 PB"`)
141+
expect(formatBytes(2 * peta, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"2 PB"`)
142+
})
143+
144+
test("should handle boundary values", () => {
145+
expect(formatBytes(1023, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1,020 byte"`)
146+
expect(formatBytes(1024, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 kB"`)
147+
expect(formatBytes(1025, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 kB"`)
148+
})
149+
64150
test("sink", () => {
65151
expect(formatBytes(1024, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 kB"`)
66152
expect(formatBytes(1048576, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 MB"`)
@@ -69,11 +155,19 @@ describe("formatBytes", () => {
69155
expect(formatBytes(1148903751, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1.07 GB"`)
70156
expect(formatBytes(1099511627776, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 TB"`)
71157
expect(formatBytes(1209462790553, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1.1 TB"`)
72-
expect(formatBytes(1022, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"0.998 kB"`)
73-
expect(formatBytes(1018, "en-US", { unitSystem: "binary", precision: 2 })).toMatchInlineSnapshot(`"0.99 kB"`)
74-
expect(formatBytes(1048575, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 MB"`)
75-
expect(formatBytes(1073741823, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 GB"`)
76-
expect(formatBytes(1099511627775, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1 TB"`)
158+
expect(formatBytes(1022, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1,020 byte"`)
159+
expect(formatBytes(1018, "en-US", { unitSystem: "binary", precision: 2 })).toMatchInlineSnapshot(`"1,000 byte"`)
160+
expect(formatBytes(1048575, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1,020 kB"`)
161+
expect(formatBytes(1073741823, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1,020 MB"`)
162+
expect(formatBytes(1099511627775, "en-US", { unitSystem: "binary" })).toMatchInlineSnapshot(`"1,020 GB"`)
163+
})
164+
})
165+
166+
describe("locale variations", () => {
167+
test("should format with different locales", () => {
168+
expect(formatBytes(1500, "de-DE")).toMatchInlineSnapshot(`"1,5 kB"`)
169+
expect(formatBytes(1500, "fr-FR")).toMatchInlineSnapshot(`"1,5 ko"`)
170+
expect(formatBytes(1500000, "ja-JP")).toMatchInlineSnapshot(`"1.5 MB"`)
77171
})
78172
})
79173
})

0 commit comments

Comments
 (0)