From 17146063de34121658b68743acf29951f209dec5 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sun, 27 Oct 2024 16:57:04 +0900 Subject: [PATCH] refactor(request): use `URLSearchParams` for parsing query params --- src/utils/url.test.ts | 1 + src/utils/url.ts | 98 ++++++++----------------------------------- 2 files changed, 18 insertions(+), 81 deletions(-) diff --git a/src/utils/url.test.ts b/src/utils/url.test.ts index bae253b7..0c5b3971 100644 --- a/src/utils/url.test.ts +++ b/src/utils/url.test.ts @@ -174,6 +174,7 @@ describe('url', () => { expect(getQueryParam('http://example.com/?Hono+is=a+web+framework', 'Hono is')).toBe( 'a web framework' ) + expect(getQueryParam('http://example.com/?q=%h', 'q')).toBe('%h') expect(getQueryParam('http://example.com/?name0=sam&name1=tom', 'name0')).toBe('sam') expect(getQueryParam('http://example.com/?name0=sam&name1=tom', 'name1')).toBe('tom') diff --git a/src/utils/url.ts b/src/utils/url.ts index 47db1c69..2791c411 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -199,95 +199,31 @@ export const checkOptionalParameter = (path: string): string[] | null => { return results.filter((v, i, a) => a.indexOf(v) === i) } -// Optimized -const _decodeURI = (value: string) => { - if (!/[%+]/.test(value)) { - return value - } - if (value.indexOf('+') !== -1) { - value = value.replace(/\+/g, ' ') - } - return /%/.test(value) ? decodeURIComponent_(value) : value -} - const _getQueryParam = ( url: string, key?: string, multiple?: boolean -): string | undefined | Record | string[] | Record => { - let encoded +): + | string + | undefined + | string[] + | Record + | Record => { + const searchParams = new URLSearchParams(getQueryStrings(url)) - if (!multiple && key && !/[%+]/.test(key)) { - // optimized for unencoded key - - let keyIndex = url.indexOf(`?${key}`, 8) - if (keyIndex === -1) { - keyIndex = url.indexOf(`&${key}`, 8) - } - while (keyIndex !== -1) { - const trailingKeyCode = url.charCodeAt(keyIndex + key.length + 1) - if (trailingKeyCode === 61) { - const valueIndex = keyIndex + key.length + 2 - const endIndex = url.indexOf('&', valueIndex) - return _decodeURI(url.slice(valueIndex, endIndex === -1 ? undefined : endIndex)) - } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) { - return '' - } - keyIndex = url.indexOf(`&${key}`, keyIndex + 1) - } - - encoded = /[%+]/.test(url) - if (!encoded) { - return undefined - } - // fallback to default routine + if (key) { + const params = multiple ? searchParams.getAll(key) : searchParams.get(key) + return multiple ? (params?.length ? params : undefined) : params ?? undefined } - const results: Record | Record = {} - encoded ??= /[%+]/.test(url) + const result = Array.from(searchParams.keys()).reduce< + Record | Record + >((acc, key) => { + acc[key] = multiple ? searchParams.getAll(key) : searchParams.get(key) ?? undefined + return acc + }, {}) - let keyIndex = url.indexOf('?', 8) - while (keyIndex !== -1) { - const nextKeyIndex = url.indexOf('&', keyIndex + 1) - let valueIndex = url.indexOf('=', keyIndex) - if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) { - valueIndex = -1 - } - let name = url.slice( - keyIndex + 1, - valueIndex === -1 ? (nextKeyIndex === -1 ? undefined : nextKeyIndex) : valueIndex - ) - if (encoded) { - name = _decodeURI(name) - } - - keyIndex = nextKeyIndex - - if (name === '') { - continue - } - - let value - if (valueIndex === -1) { - value = '' - } else { - value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? undefined : nextKeyIndex) - if (encoded) { - value = _decodeURI(value) - } - } - - if (multiple) { - if (!(results[name] && Array.isArray(results[name]))) { - results[name] = [] - } - ;(results[name] as string[]).push(value) - } else { - results[name] ??= value - } - } - - return key ? results[key] : results + return result } export const getQueryParam: (