Skip to content

Commit d165003

Browse files
committed
feat: add boolean param parser
1 parent 568bd40 commit d165003

File tree

2 files changed

+152
-9
lines changed

2 files changed

+152
-9
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { describe, expect, it } from 'vitest'
2+
import {
3+
PARAM_BOOLEAN_SINGLE,
4+
PARAM_BOOLEAN_OPTIONAL,
5+
PARAM_BOOLEAN_REPEATABLE,
6+
PARAM_BOOLEAN_REPEATABLE_OPTIONAL,
7+
PARAM_PARSER_BOOL,
8+
} from './booleans'
9+
10+
describe('PARAM_BOOLEAN_SINGLE', () => {
11+
describe('get()', () => {
12+
it('parses true values', () => {
13+
expect(PARAM_BOOLEAN_SINGLE.get('true')).toBe(true)
14+
expect(PARAM_BOOLEAN_SINGLE.get('TRUE')).toBe(true)
15+
expect(PARAM_BOOLEAN_SINGLE.get('True')).toBe(true)
16+
})
17+
18+
it('parses false values', () => {
19+
expect(PARAM_BOOLEAN_SINGLE.get('false')).toBe(false)
20+
expect(PARAM_BOOLEAN_SINGLE.get('FALSE')).toBe(false)
21+
expect(PARAM_BOOLEAN_SINGLE.get('False')).toBe(false)
22+
})
23+
24+
it('throws for invalid values', () => {
25+
expect(() => PARAM_BOOLEAN_SINGLE.get('yes')).toThrow()
26+
expect(() => PARAM_BOOLEAN_SINGLE.get('no')).toThrow()
27+
expect(() => PARAM_BOOLEAN_SINGLE.get('1')).toThrow()
28+
expect(() => PARAM_BOOLEAN_SINGLE.get('0')).toThrow()
29+
expect(() => PARAM_BOOLEAN_SINGLE.get('on')).toThrow()
30+
expect(() => PARAM_BOOLEAN_SINGLE.get('off')).toThrow()
31+
expect(() => PARAM_BOOLEAN_SINGLE.get('maybe')).toThrow()
32+
expect(() => PARAM_BOOLEAN_SINGLE.get('invalid')).toThrow()
33+
expect(() => PARAM_BOOLEAN_SINGLE.get('true1')).toThrow()
34+
expect(() => PARAM_BOOLEAN_SINGLE.get('falsy')).toThrow()
35+
})
36+
37+
it('returns false for null or empty values', () => {
38+
expect(PARAM_BOOLEAN_SINGLE.get(null)).toBe(false)
39+
expect(PARAM_BOOLEAN_SINGLE.get('')).toBe(false)
40+
})
41+
})
42+
43+
describe('set()', () => {
44+
it('converts boolean to string', () => {
45+
expect(PARAM_BOOLEAN_SINGLE.set(true)).toBe('true')
46+
expect(PARAM_BOOLEAN_SINGLE.set(false)).toBe('false')
47+
})
48+
49+
it('converts null to false string', () => {
50+
expect(PARAM_BOOLEAN_SINGLE.set(null)).toBe('false')
51+
})
52+
})
53+
})
54+
55+
describe('PARAM_BOOLEAN_OPTIONAL', () => {
56+
describe('get()', () => {
57+
it('returns null for null input', () => {
58+
expect(PARAM_BOOLEAN_OPTIONAL.get(null)).toBe(null)
59+
})
60+
61+
it('parses valid values', () => {
62+
expect(PARAM_BOOLEAN_OPTIONAL.get('true')).toBe(true)
63+
expect(PARAM_BOOLEAN_OPTIONAL.get('false')).toBe(false)
64+
})
65+
66+
it('throws for invalid values', () => {
67+
expect(() => PARAM_BOOLEAN_OPTIONAL.get('invalid')).toThrow()
68+
})
69+
})
70+
71+
describe('set()', () => {
72+
it('returns null for null input', () => {
73+
expect(PARAM_BOOLEAN_OPTIONAL.set(null)).toBe(null)
74+
})
75+
76+
it('converts boolean to string', () => {
77+
expect(PARAM_BOOLEAN_OPTIONAL.set(true)).toBe('true')
78+
expect(PARAM_BOOLEAN_OPTIONAL.set(false)).toBe('false')
79+
})
80+
})
81+
})
82+
83+
describe('PARAM_BOOLEAN_REPEATABLE', () => {
84+
describe('get()', () => {
85+
it('parses array of boolean values', () => {
86+
expect(
87+
PARAM_BOOLEAN_REPEATABLE.get(['true', 'false', 'TRUE', 'FALSE'])
88+
).toEqual([true, false, true, false])
89+
})
90+
91+
it('throws for invalid values in array', () => {
92+
expect(() => PARAM_BOOLEAN_REPEATABLE.get(['true', 'invalid'])).toThrow()
93+
})
94+
})
95+
96+
describe('set()', () => {
97+
it('converts array of booleans to strings', () => {
98+
expect(PARAM_BOOLEAN_REPEATABLE.set([true, false, true])).toEqual([
99+
'true',
100+
'false',
101+
'true',
102+
])
103+
})
104+
})
105+
})
106+
107+
describe('PARAM_PARSER_BOOL', () => {
108+
describe('get()', () => {
109+
it('handles single values', () => {
110+
expect(PARAM_PARSER_BOOL.get('true')).toBe(true)
111+
expect(PARAM_PARSER_BOOL.get('false')).toBe(false)
112+
})
113+
114+
it('handles null values', () => {
115+
expect(PARAM_PARSER_BOOL.get(null)).toBe(false)
116+
})
117+
118+
it('handles array values', () => {
119+
expect(PARAM_PARSER_BOOL.get(['true', 'false'])).toEqual([true, false])
120+
})
121+
})
122+
123+
describe('set()', () => {
124+
it('handles single values', () => {
125+
expect(PARAM_PARSER_BOOL.set(true)).toBe('true')
126+
expect(PARAM_PARSER_BOOL.set(false)).toBe('false')
127+
})
128+
129+
it('handles null values', () => {
130+
expect(PARAM_PARSER_BOOL.set(null)).toBe('false')
131+
})
132+
133+
it('handles array values', () => {
134+
expect(PARAM_PARSER_BOOL.set([true, false])).toEqual(['true', 'false'])
135+
})
136+
})
137+
})

packages/router/src/experimental/route-resolver/matchers/param-parsers/booleans.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@ import { ParamParser } from './types'
33

44
export const PARAM_BOOLEAN_SINGLE = {
55
get: (value: string | null) => {
6-
if (value === 'true') return true
7-
if (value === 'false') return false
6+
if (!value) return false
7+
8+
const lowercaseValue = value.toLowerCase()
9+
10+
if (lowercaseValue === 'true') {
11+
return true
12+
}
13+
14+
if (lowercaseValue === 'false') {
15+
return false
16+
}
17+
818
throw miss()
919
},
10-
set: (value: boolean) => String(value),
20+
set: (value: boolean | null) => String(!!value),
1121
} satisfies ParamParser<boolean, string | null>
1222

1323
export const PARAM_BOOLEAN_OPTIONAL = {
@@ -38,13 +48,9 @@ export const PARAM_PARSER_BOOL: ParamParser<boolean | boolean[] | null> = {
3848
get: value =>
3949
Array.isArray(value)
4050
? PARAM_BOOLEAN_REPEATABLE.get(value)
41-
: value != null
42-
? PARAM_BOOLEAN_SINGLE.get(value)
43-
: null,
51+
: PARAM_BOOLEAN_SINGLE.get(value),
4452
set: value =>
4553
Array.isArray(value)
4654
? PARAM_BOOLEAN_REPEATABLE.set(value)
47-
: value != null
48-
? PARAM_BOOLEAN_SINGLE.set(value)
49-
: null,
55+
: PARAM_BOOLEAN_SINGLE.set(value),
5056
}

0 commit comments

Comments
 (0)