diff --git a/src/Utils/__tests__/parseQuery.test.ts b/src/Utils/__tests__/parseQuery.test.ts new file mode 100644 index 0000000..9c4924e --- /dev/null +++ b/src/Utils/__tests__/parseQuery.test.ts @@ -0,0 +1,49 @@ +import { assertEquals } from 'https://deno.land/std/assert/mod.ts'; +import { parseQuery } from '../parseQuery.ts'; + +Deno.test('parseQuery: single-value parameters are parsed as strings', () => { + const url = new URL('http://localhost?foo=bar&limit=10'); + const result = parseQuery(url.searchParams); + + assertEquals(result, { + foo: 'bar', + limit: '10', + }); +}); + +Deno.test('parseQuery: multi-value parameters are parsed as string arrays', () => { + const url = new URL('http://localhost?tag=ts&tag=deno&tag=web'); + const result = parseQuery(url.searchParams); + + assertEquals(result, { + tag: ['ts', 'deno', 'web'], + }); +}); + +Deno.test('parseQuery: mixed single and multi-value parameters', () => { + const url = new URL( + 'http://localhost?sort=asc&filter=active&filter=pending', + ); + const result = parseQuery(url.searchParams); + + assertEquals(result, { + sort: 'asc', + filter: ['active', 'pending'], + }); +}); + +Deno.test('parseQuery: empty query string returns empty object', () => { + const url = new URL('http://localhost'); + const result = parseQuery(url.searchParams); + + assertEquals(result, {}); +}); + +Deno.test('parseQuery: repeated single-value keys are grouped', () => { + const url = new URL('http://localhost?a=1&a=2&a=3'); + const result = parseQuery(url.searchParams); + + assertEquals(result, { + a: ['1', '2', '3'], + }); +}); diff --git a/src/Utils/parseQuery.ts b/src/Utils/parseQuery.ts new file mode 100644 index 0000000..5125f52 --- /dev/null +++ b/src/Utils/parseQuery.ts @@ -0,0 +1,30 @@ +import { Query } from '../Types/Query.ts'; + +/** + * Parses a `URLSearchParams` object into an `IQuery` structure + * that preserves both single and multi-value semantics. + * + * For each query parameter key, this function checks how often the key appears: + * - If the key occurs once, the value is stored as a string. + * - If the key occurs multiple times, the values are stored as a string array. + * + * This ensures compatibility with the `IQuery` type definition, + * which allows both `string` and `string[]` as value types. + * + * Example: + * - ?tag=deno&tag=ts → { tag: ["deno", "ts"] } + * - ?page=2 → { page: "2" } + * + * @param searchParams - The `URLSearchParams` instance from a parsed URL. + * @returns An object conforming to `IQuery`, with normalized parameter values. + */ +export function parseQuery(searchParams: URLSearchParams): Query { + const query: Query = {}; + + for (const key of new Set(searchParams.keys())) { + const values = searchParams.getAll(key); + query[key] = values.length > 1 ? values : values[0]; + } + + return query; +}