From 5bbf768c48a915f69d37237cb35c552f67e836d1 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Tue, 2 Sep 2025 23:06:06 +0200 Subject: [PATCH] refactor(router-core): defaultParseSearch,defaultStringifySearch better performance w/ early json exit --- packages/router-core/src/searchParams.ts | 33 ++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/router-core/src/searchParams.ts b/packages/router-core/src/searchParams.ts index b121f773e5b..c4af534f287 100644 --- a/packages/router-core/src/searchParams.ts +++ b/packages/router-core/src/searchParams.ts @@ -8,6 +8,7 @@ export const defaultStringifySearch = stringifySearchWith( ) export function parseSearchWith(parser: (str: string) => any) { + const isJsonParser = parser === JSON.parse return (searchStr: string): AnySchema => { if (searchStr[0] === '?') { searchStr = searchStr.substring(1) @@ -18,7 +19,10 @@ export function parseSearchWith(parser: (str: string) => any) { // Try to parse any query params that might be json for (const key in query) { const value = query[key] - if (typeof value === 'string') { + if ( + typeof value === 'string' && + (!isJsonParser || looksLikeJson(value)) + ) { try { query[key] = parser(value) } catch (_err) { @@ -36,6 +40,7 @@ export function stringifySearchWith( parser?: (str: string) => any, ) { const hasParser = typeof parser === 'function' + const isJsonParser = parser === JSON.parse function stringifyValue(val: any) { if (typeof val === 'object' && val !== null) { try { @@ -43,7 +48,11 @@ export function stringifySearchWith( } catch (_err) { // silent } - } else if (hasParser && typeof val === 'string') { + } else if ( + hasParser && + typeof val === 'string' && + (!isJsonParser || looksLikeJson(val)) + ) { try { // Check if it's a valid parseable string. // If it is, then stringify it again. @@ -64,3 +73,23 @@ export function stringifySearchWith( export type SearchSerializer = (searchObj: Record) => string export type SearchParser = (searchStr: string) => Record + +/** + * Fast check to see if the string is a likely to be a JSON value. + * It could return false positives (returned true but wasn't actually a json), + * but not false negatives (returned false but was actually a json). + */ +function looksLikeJson(str: string): boolean { + if (!str) return false + const c = str.charCodeAt(0) + return ( + c === 34 || // " + c === 123 || // { + c === 91 || // [ + c === 45 || // - + (c >= 48 && c <= 57) || // 0-9 + c === 116 || // t (true) + c === 102 || // f (false) + c === 110 // n (null) + ) +}