Skip to content

Commit c257cf2

Browse files
committed
Test whitespace for number
1 parent c25f13f commit c257cf2

File tree

3 files changed

+56
-29
lines changed

3 files changed

+56
-29
lines changed

src/lib/parse.test.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,6 @@ test('parseUrlSearchParams: with URLSearchParams input', (t) => {
2424
)
2525
})
2626

27-
test.todo(
28-
'parseUrlSearchParams: parse empty or whitespace number params as null',
29-
)
30-
test.todo('parse empty or whitespace boolean params as null')
31-
test.todo('parse empty or whitespace date params as null')
32-
test.todo('parse empty or whitespace object params as null')
33-
test.todo('parse empty or whitespace record params as null')
34-
35-
test.todo('parse empty or whitespace array params as empty')
36-
test.todo(
37-
'cannot parse multiple empty or whitespace array params like foo=&foo=',
38-
)
39-
test.todo(
40-
'cannot parse mixed empty or whitespace array params like foo=&foo=bar',
41-
)
42-
43-
test.todo('parse addtional strings as true and false')
44-
45-
test.todo('parse repeated array params like foo=bar&foo=baz')
46-
test.todo('parse bracket array params like foo[]=bar&foo[]=baz')
47-
test.todo('parse comma array params like foo=bar,baz')
48-
49-
test.todo('cannot parse mixed array params like foo=bar,baz&foo=bar&foo[]=baz')
50-
test.todo('cannot parse array values containing a comma like foo=a,b&foo=b,c')
51-
test.todo(
52-
'cannot parse array values containing a comma like foo[]=a,b&foo[]=b,c',
53-
)
54-
5527
// e.g., foo.bar= would conflict with foo.bar.a= or foo.bar.b=2
5628
// since this would be a null object containing values (null is still a value).
5729
test.todo('cannot parse conflicting object keys')

src/lib/parse.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,24 @@ const parseFromParamSchema = (
5151
const parse = (k: string, values: string[], type: ValueType): unknown => {
5252
// TODO: Add better errors with coercion. If coercion fails, passthough?
5353
if (values.length === 0) return undefined
54-
if (type === 'number') return Number(values[0])
54+
55+
if (values[0] == null) {
56+
throw new Error(`Unexpected nil value when parsing ${k}`)
57+
}
58+
59+
if (type === 'number') return parseNumber(values[0])
5560
if (type === 'boolean') return values[0] === 'true'
5661
if (type === 'string') return String(values[0])
5762
if (type === 'string_array') return values
5863
if (type === 'number_array') return values.map((v) => Number(v))
5964
throw new UnparseableSearchParamError(k, 'unsupported type')
6065
}
6166

67+
const parseNumber = (v: string): number | null => {
68+
if (v.trim().length === 0) return null
69+
return Number(v)
70+
}
71+
6272
export class UnparseableSearchParamError extends Error {
6373
constructor(name: string, message: string) {
6474
super(`Could not parse parameter: '${name}' ${message}`)

test/generous-parsing.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import test from 'ava'
2+
import { z, type ZodSchema } from 'zod'
3+
4+
import { parseUrlSearchParams } from '@seamapi/url-search-params-parser'
5+
6+
const parseEmptyOrWhitespace = test.macro({
7+
title(providedTitle) {
8+
return `parses empty or whitespace ${providedTitle} params as null`
9+
},
10+
exec(t, type: ZodSchema) {
11+
const schema = z.object({ foo: type })
12+
const expected = { foo: null }
13+
t.deepEqual(parseUrlSearchParams('foo=', schema), expected)
14+
t.deepEqual(parseUrlSearchParams('foo=%20', schema), expected)
15+
t.deepEqual(parseUrlSearchParams('foo= %20 ++ + ', schema), expected)
16+
t.deepEqual(parseUrlSearchParams('foo=+', schema), expected)
17+
},
18+
})
19+
20+
test('number', parseEmptyOrWhitespace, z.number())
21+
22+
test.todo('parse empty or whitespace boolean params as null')
23+
test.todo('parse empty or whitespace date params as null')
24+
test.todo('parse empty or whitespace object params as null')
25+
test.todo('parse empty or whitespace record params as null')
26+
27+
test.todo('parse empty or whitespace array params as empty')
28+
test.todo(
29+
'cannot parse multiple empty or whitespace array params like foo=&foo=',
30+
)
31+
test.todo(
32+
'cannot parse mixed empty or whitespace array params like foo=&foo=bar',
33+
)
34+
35+
test.todo('parse additional strings as true and false')
36+
37+
test.todo('parse repeated array params like foo=bar&foo=baz')
38+
test.todo('parse bracket array params like foo[]=bar&foo[]=baz')
39+
test.todo('parse comma array params like foo=bar,baz')
40+
41+
test.todo('cannot parse mixed array params like foo=bar,baz&foo=bar&foo[]=baz')
42+
test.todo('cannot parse array values containing a comma like foo=a,b&foo=b,c')
43+
test.todo(
44+
'cannot parse array values containing a comma like foo[]=a,b&foo[]=b,c',
45+
)

0 commit comments

Comments
 (0)