Skip to content

Commit

Permalink
fix: Errors thrown in parsers count as null
Browse files Browse the repository at this point in the history
This allows using a Zod schema in custom parsers without
the overhead of using safeParse there.
  • Loading branch information
franky47 committed Nov 11, 2023
1 parent 82e292b commit 9ce0eae
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 4 deletions.
7 changes: 7 additions & 0 deletions packages/next-usequerystate/src/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ export function debug(message: string, ...args: any[]) {
console.debug(message, ...args)
}

export function warn(message: string, ...args: any[]) {
if (!enabled) {
return
}
console.warn(message, ...args)
}

export function sprintf(base: string, ...args: any[]) {
return base.replace(/%[sfdO]/g, match => {
const arg = args.shift()
Expand Down
8 changes: 6 additions & 2 deletions packages/next-usequerystate/src/parsers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Options } from './defs'
import { safeParse } from './utils'

export type Parser<T> = {
parse: (value: string) => T | null
Expand Down Expand Up @@ -86,7 +87,7 @@ export function createParser<T>(parser: Required<Parser<T>>): ParserBuilder<T> {
if (typeof value === 'string') {
str = value
}
return parser.parse(str)
return safeParse(parser.parse, str)
}

return {
Expand Down Expand Up @@ -278,7 +279,10 @@ export function parseAsArrayOf<ItemType>(
return query
.split(separator)
.map(item =>
itemParser.parse(item.replaceAll(encodedSeparator, separator))
safeParse(
itemParser.parse,
item.replaceAll(encodedSeparator, separator)
)
)
.filter(value => value !== null && value !== undefined) as ItemType[]
},
Expand Down
3 changes: 2 additions & 1 deletion packages/next-usequerystate/src/useQueryState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getQueuedValue,
scheduleFlushToURL
} from './update-queue'
import { safeParse } from './utils'

export interface UseQueryStateOptions<T> extends Parser<T>, Options {}

Expand Down Expand Up @@ -226,7 +227,7 @@ export function useQueryState<T = string>(
: // Components mounted after page load must use the current URL value
new URLSearchParams(location.search).get(key) ?? null
const value = queueValue ?? urlValue
return value === null ? null : parse(value)
return value === null ? null : safeParse(parse, value)
})
const stateRef = React.useRef(internalState)
debug(
Expand Down
3 changes: 2 additions & 1 deletion packages/next-usequerystate/src/useQueryStates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getQueuedValue,
scheduleFlushToURL
} from './update-queue'
import { safeParse } from './utils'

type KeyMapValue<Type> = Parser<Type> & {
defaultValue?: Type
Expand Down Expand Up @@ -172,7 +173,7 @@ function parseMap<KeyMap extends UseQueryStatesKeysMap>(
const urlQuery = searchParams?.get(key) ?? null
const queueQuery = getQueuedValue(key)
const query = queueQuery ?? urlQuery
const value = query === null ? null : parse(query)
const value = query === null ? null : safeParse(parse, query)
obj[key as keyof KeyMap] = value ?? defaultValue ?? null
return obj
}, {} as Values<KeyMap>)
Expand Down
11 changes: 11 additions & 0 deletions packages/next-usequerystate/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { warn } from './debug'
import type { Parser } from './parsers'

export function safeParse<T>(parser: Parser<T>['parse'], value: string) {
try {
return parser(value)
} catch (error) {
warn('[nuqs] Error while parsing value `%s`: %O', error)
return null
}
}

0 comments on commit 9ce0eae

Please sign in to comment.