From e225975bdf5a0d144aa9c64cc4408ba479a6be9e Mon Sep 17 00:00:00 2001 From: Francois Best Date: Mon, 11 Sep 2023 21:35:12 +0200 Subject: [PATCH] feat: Add server-side parser utility Thanks to @r1chm8 for the idea in #348. --- src/app/demos/server-side-parsing/page.tsx | 6 +-- src/lib/parsers.ts | 50 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/app/demos/server-side-parsing/page.tsx b/src/app/demos/server-side-parsing/page.tsx index 6154ec2e..4f4f7113 100644 --- a/src/app/demos/server-side-parsing/page.tsx +++ b/src/app/demos/server-side-parsing/page.tsx @@ -4,14 +4,12 @@ import { counterParser } from './parser' type PageProps = { searchParams: { - counter?: string + counter?: string | string[] } } export default function ServerSideParsingDemo({ searchParams }: PageProps) { - const counter = - counterParser.parse(searchParams.counter ?? '') ?? - counterParser.defaultValue + const counter = counterParser.parseServerSide(searchParams.counter) console.log('Server side counter: %d', counter) return ( <> diff --git a/src/lib/parsers.ts b/src/lib/parsers.ts index 958cb572..5804e2de 100644 --- a/src/lib/parsers.ts +++ b/src/lib/parsers.ts @@ -30,7 +30,39 @@ export type ParserBuilder = Parser & withDefault(defaultValue: NonNullable): Parser & Options & { readonly defaultValue: NonNullable + + /** + * Use the parser in Server Components + * + * `parse` is intended to be used only by the hook, but you can use this + * method to hydrate query values on server-side rendered pages. + * See the `server-side-parsing` demo for an example. + * + * Note that when multiple queries are presented to the parser + * (eg: `/?a=1&a=2`), only the **first** will be parsed, to mimic the + * behaviour of URLSearchParams: + * https://url.spec.whatwg.org/#dom-urlsearchparams-get + * + * @param value as coming from page props + */ + parseServerSide(value: string | string[] | undefined): NonNullable } + + /** + * Use the parser in Server Components + * + * `parse` is intended to be used only by the hook, but you can use this + * method to hydrate query values on server-side rendered pages. + * See the `server-side-parsing` demo for an example. + * + * Note that when multiple queries are presented to the parser + * (eg: `/?a=1&a=2`), only the **first** will be parsed, to mimic the + * behaviour of URLSearchParams: + * https://url.spec.whatwg.org/#dom-urlsearchparams-get + * + * @param value as coming from page props + */ + parseServerSide(value: string | string[] | undefined): T | null } /** @@ -40,10 +72,26 @@ export type ParserBuilder = Parser & export function createParser(parser: Parser): ParserBuilder { return { ...parser, + parseServerSide(value = '') { + let str = '' + if (Array.isArray(value)) { + // Follow the spec: + // https://url.spec.whatwg.org/#dom-urlsearchparams-get + str = value[0] + } + if (typeof value === 'string') { + str = value + } + return this.parse(str) + }, withDefault(defaultValue) { + const nullableParse = this.parseServerSide.bind(this) return { ...this, - defaultValue + defaultValue, + parseServerSide(value = '') { + return nullableParse(value) ?? defaultValue + } } }, withOptions(options: Options) {