Skip to content

Commit 0a64499

Browse files
committed
fix: validate numeric options strictly
1 parent d6d5f7e commit 0a64499

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

‎src/parse.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,19 @@ export function readJsonBodyOption<T = unknown>(
2929
}
3030

3131
export function parseIntOption(value: string, name: string): number {
32-
const parsed = Number.parseInt(value, 10)
33-
if (Number.isNaN(parsed)) {
32+
const parsed = Number(value)
33+
if (!/^[+-]?\d+$/.test(value) || !Number.isFinite(parsed)) {
3434
throw new Error(`Invalid value for ${name}: "${value}" is not an integer`)
3535
}
3636
return parsed
3737
}
3838

3939
export function parseFloatOption(value: string, name: string): number {
40-
const parsed = Number.parseFloat(value)
41-
if (Number.isNaN(parsed)) {
40+
const parsed = Number(value)
41+
if (
42+
!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(value) ||
43+
!Number.isFinite(parsed)
44+
) {
4245
throw new Error(`Invalid value for ${name}: "${value}" is not a number`)
4346
}
4447
return parsed

‎test/parse.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,27 @@ describe("parseIntOption", () => {
2727
'Invalid value for --limit: "" is not an integer',
2828
)
2929
})
30+
31+
it.each([
32+
"10foo",
33+
"1.9",
34+
"1e2",
35+
"0x10",
36+
])('throws when "%s" is not entirely an integer', value => {
37+
expect(() => parseIntOption(value, "--limit")).toThrow(
38+
`Invalid value for --limit: "${value}" is not an integer`,
39+
)
40+
})
3041
})
3142

3243
describe("parseFloatOption", () => {
3344
it("parses valid floats", () => {
3445
expect(parseFloatOption("0.5", "--slippage")).toBe(0.5)
3546
expect(parseFloatOption("1", "--slippage")).toBe(1)
3647
expect(parseFloatOption("0.01", "--slippage")).toBe(0.01)
48+
expect(parseFloatOption(".5", "--slippage")).toBe(0.5)
49+
expect(parseFloatOption("1.", "--slippage")).toBe(1)
50+
expect(parseFloatOption("1e-2", "--slippage")).toBe(0.01)
3751
})
3852

3953
it("throws on non-numeric strings", () => {
@@ -47,6 +61,17 @@ describe("parseFloatOption", () => {
4761
'Invalid value for --slippage: "" is not a number',
4862
)
4963
})
64+
65+
it.each([
66+
"0.5oops",
67+
"0.01%",
68+
"Infinity",
69+
"1e309",
70+
])('throws when "%s" is not an entirely finite number', value => {
71+
expect(() => parseFloatOption(value, "--slippage")).toThrow(
72+
`Invalid value for --slippage: "${value}" is not a number`,
73+
)
74+
})
5075
})
5176

5277
describe("readJsonBodyOption", () => {

0 commit comments

Comments
 (0)