diff --git a/packages/router-core/src/qss.ts b/packages/router-core/src/qss.ts index 5b1b733324..f6ba5f990b 100644 --- a/packages/router-core/src/qss.ts +++ b/packages/router-core/src/qss.ts @@ -39,23 +39,6 @@ export function encode( return result.toString() } -/** - * Converts a string value to its appropriate type (string, number, boolean). - * @param mix - The string value to convert. - * @returns The converted value. - * @example - * // Example input: toValue("123") - * // Expected output: 123 - */ -/** Convert a string into a primitive boolean/number when possible. */ -function toValue(str: unknown) { - if (!str) return '' - - if (str === 'false') return false - if (str === 'true') return true - return +str * 0 === 0 && +str + '' === str ? +str : str -} - /** * Decodes a query string into an object. * @param str - The query string to decode. @@ -73,11 +56,11 @@ export function decode(str: any): any { for (const [key, value] of searchParams.entries()) { const previousValue = result[key] if (previousValue == null) { - result[key] = toValue(value) + result[key] = value } else if (Array.isArray(previousValue)) { - previousValue.push(toValue(value)) + previousValue.push(value) } else { - result[key] = [previousValue, toValue(value)] + result[key] = [previousValue, value] } } diff --git a/packages/router-core/src/searchParams.ts b/packages/router-core/src/searchParams.ts index ad9957aed9..ee5c29e886 100644 --- a/packages/router-core/src/searchParams.ts +++ b/packages/router-core/src/searchParams.ts @@ -35,7 +35,10 @@ export function parseSearchWith(parser: (str: string) => any) { const value = query[key] if (typeof value === 'string') { try { - query[key] = parser(value) + const parsed = parser(value) + if (parsed && typeof parsed === 'object') { + query[key] = parsed + } } catch (_err) { // silent } @@ -75,8 +78,10 @@ export function stringifySearchWith( try { // Check if it's a valid parseable string. // If it is, then stringify it again. - parser(val) - return stringify(val) + const parsed = parser(val) + if (parsed && typeof parsed === 'object') { + return stringify(val) + } } catch (_err) { // silent } diff --git a/packages/router-core/tests/qss.test.ts b/packages/router-core/tests/qss.test.ts index ce92857ab5..fc228c779a 100644 --- a/packages/router-core/tests/qss.test.ts +++ b/packages/router-core/tests/qss.test.ts @@ -61,7 +61,7 @@ describe('decode function', () => { it('should handle decoding a top-level key with a special character', () => { const queryString = 'foo%3Dbar=1' const decodedObj = decode(queryString) - expect(decodedObj).toEqual({ 'foo=bar': 1 }) + expect(decodedObj).toEqual({ 'foo=bar': '1' }) }) it('should handle decoding a top-level key with a special character and without a value', () => { diff --git a/packages/router-core/tests/searchParams.test.ts b/packages/router-core/tests/searchParams.test.ts index 006e119be5..c8dc204a6e 100644 --- a/packages/router-core/tests/searchParams.test.ts +++ b/packages/router-core/tests/searchParams.test.ts @@ -2,43 +2,43 @@ import { describe, expect, test } from 'vitest' import { defaultParseSearch, defaultStringifySearch } from '../src' describe('Search Params serialization and deserialization', () => { - /* - * JSON-compatible objects can be serialized into a string, - * and then deserialized back into the original object. - */ test.each([ - [{}, ''], - [{ foo: '' }, '?foo='], - [{ foo: 'bar' }, '?foo=bar'], - [{ foo: 'bar baz' }, '?foo=bar+baz'], - [{ foo: 123 }, '?foo=123'], - [{ foo: '123' }, '?foo=%22123%22'], - [{ foo: true }, '?foo=true'], - [{ foo: 'true' }, '?foo=%22true%22'], - [{ foo: null }, '?foo=null'], - [{ foo: 'null' }, '?foo=%22null%22'], - [{ foo: 'undefined' }, '?foo=undefined'], - [{ foo: {} }, '?foo=%7B%7D'], - [{ foo: '{}' }, '?foo=%22%7B%7D%22'], - [{ foo: [] }, '?foo=%5B%5D'], - [{ foo: '[]' }, '?foo=%22%5B%5D%22'], - [{ foo: [1, 2, 3] }, '?foo=%5B1%2C2%2C3%5D'], - [{ foo: '1,2,3' }, '?foo=1%2C2%2C3'], - [{ foo: { bar: 'baz' } }, '?foo=%7B%22bar%22%3A%22baz%22%7D'], - [{ 0: 1 }, '?0=1'], - [{ 'foo=bar': 1 }, '?foo%3Dbar=1'], - [{ '{}': 1 }, '?%7B%7D=1'], - [{ '': 1 }, '?=1'], - [{ '=': '=' }, '?%3D=%3D'], - [{ '=': '', '': '=' }, '?%3D=&=%3D'], - [{ 'foo=2&bar': 3 }, '?foo%3D2%26bar=3'], - [{ 'foo?': 1 }, '?foo%3F=1'], - [{ foo: 'bar=' }, '?foo=bar%3D'], - [{ foo: '2&bar=3' }, '?foo=2%26bar%3D3'], - ])('isomorphism %j', (input, expected) => { - const str = defaultStringifySearch(input) - expect(str).toEqual(expected) - expect(defaultParseSearch(str)).toEqual(input) + ['', {}], + ['?foo=', { foo: '' }], + ['?foo=bar', { foo: 'bar' }], + ['?foo=%22bar%22', { foo: '"bar"' }], + ['?foo=bar+baz', { foo: 'bar baz' }], + ['?foo=%22bar+baz%22', { foo: '"bar baz"' }], + ['?foo=123', { foo: '123' }], + ['?foo=%22123%22', { foo: '"123"' }], + ['?foo=true', { foo: 'true' }], + ['?foo=%22true%22', { foo: '"true"' }], + ['?foo=null', { foo: 'null' }], + ['?foo=%22null%22', { foo: '"null"' }], + ['?foo=undefined', { foo: 'undefined' }], + ['?foo=%22undefined%22', { foo: '"undefined"' }], + ['?foo=%7B%7D', { foo: {} }], + ['?foo=%22%7B%7D%22', { foo: '"{}"' }], + ['?foo=%5B%5D', { foo: [] }], + ['?foo=%22%5B%5D%22', { foo: '"[]"' }], + ['?foo=%5B1%2C2%2C3%5D', { foo: [1, 2, 3] }], + ['?foo=1%2C2%2C3', { foo: '1,2,3' }], + ['?foo=%7B%22bar%22%3A%22baz%22%7D', { foo: { bar: 'baz' } }], + ['?0=1', { 0: '1' }], + ['?foo%3Dbar=1', { 'foo=bar': '1' }], + ['?%7B%7D=1', { '{}': '1' }], + ['?=1', { '': '1' }], + ['?%3D=%3D', { '=': '=' }], + ['?%3D=&=%3D', { '=': '', '': '=' }], + ['?foo%3D2%26bar=3', { 'foo=2&bar': '3' }], + ['?foo%3F=1', { 'foo?': '1' }], + ['?foo=bar%3D', { foo: 'bar=' }], + ['?foo=2%26bar%3D3', { foo: '2&bar=3' }], + ])('isomorphism %j', (input, expectedObj) => { + const parsed = defaultParseSearch(input) + expect(parsed).toEqual(expectedObj) + const str = defaultStringifySearch(parsed) + expect(str).toEqual(input) }) test('undefined values are removed during stringification', () => { @@ -67,8 +67,8 @@ describe('Search Params serialization and deserialization', () => { ['?foo=[]', { foo: [] }], ['?foo=1,2,3', { foo: '1,2,3' }], ['?foo={"bar":"baz"}', { foo: { bar: 'baz' } }], - ['?foo=1&foo=2', { foo: [1, 2] }], - ['?foo=""', { foo: '' }], + ['?foo=1&foo=2', { foo: ['1', '2'] }], + ['?foo=""', { foo: '""' }], ['?foo=""""', { foo: '""""' }], ['?foo=()', { foo: '()' }], ['?foo=[{}]', { foo: [{}] }],