From 61598bc5457150be912c5cbd988e519965b60fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99drzy=C5=84ski?= Date: Fri, 25 Aug 2023 15:44:47 +0200 Subject: [PATCH] feat(utils): added util to parse query --- packages/utils/src/index.ts | 5 +- packages/utils/src/url/parseQuery.ts | 56 +++++++++++++++++++ packages/utils/src/url/queryTypes.ts | 4 ++ .../utils/src/{ => url}/stringifyQuery.ts | 4 +- 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 packages/utils/src/url/parseQuery.ts create mode 100644 packages/utils/src/url/queryTypes.ts rename packages/utils/src/{ => url}/stringifyQuery.ts (81%) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 4524566..be17fc4 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -14,6 +14,10 @@ export * from './array/forEachParalell.js'; export * from './string/formatWith.js'; export * from './string/isDigit.js'; +export * from './url/stringifyQuery.js'; +export * from './url/parseQuery.js'; +export * from './url/queryTypes.js'; + export * from './assert.js'; export * from './cachedGetter.js'; export * from './cachedProp.js'; @@ -40,4 +44,3 @@ export * from './timeout.js'; export * from './writable.js'; export * from './promiseAll.js'; export * from './getTopLevelDomain.js'; -export * from './stringifyQuery.js'; diff --git a/packages/utils/src/url/parseQuery.ts b/packages/utils/src/url/parseQuery.ts new file mode 100644 index 0000000..14bc47a --- /dev/null +++ b/packages/utils/src/url/parseQuery.ts @@ -0,0 +1,56 @@ +import { QueryParams, QueryParamsSimple } from './queryTypes.js'; + +export function parseQuery(querystring: string | null | undefined): QueryParamsSimple; +export function parseQuery( + querystring: string | null | undefined, + options: { multiple: false }, +): QueryParamsSimple; +export function parseQuery( + querystring: string | null | undefined, + options: { multiple: true }, +): QueryParams; +export function parseQuery( + querystring: string | null | undefined, + options?: { multiple: boolean }, +): QueryParams { + const query: QueryParams = {}; + const multiple = options?.multiple || false; + + if (!querystring) { + return query; + } + + if (querystring.startsWith('?')) { + querystring = querystring.slice(1); + } + + for (const item of querystring.split('&')) { + const [rawKey, rawValue] = item.split('='); + const key = decodeURIComponent(rawKey); + const value = decodeURIComponent(rawValue); + + // Sometimes a query string can have multiple values + // for the same key, so to factor that case in, you + // could collect an array of values for the same key + let entry = query[key]; + + if (entry === undefined) { + query[key] = value; + continue; + } + + if (!multiple) { + // Allows only for a single value per key + continue; + } + + // If the value for this key was not previously an array, update it + if (!Array.isArray(entry)) { + query[key] = entry = [entry]; + } + + entry.push(value); + } + + return query; +} diff --git a/packages/utils/src/url/queryTypes.ts b/packages/utils/src/url/queryTypes.ts new file mode 100644 index 0000000..c51456b --- /dev/null +++ b/packages/utils/src/url/queryTypes.ts @@ -0,0 +1,4 @@ +type QueryParamValue = string | null; +export type QueryParam = QueryParamValue | QueryParamValue[]; +export type QueryParams = Record; +export type QueryParamsSimple = Record; diff --git a/packages/utils/src/stringifyQuery.ts b/packages/utils/src/url/stringifyQuery.ts similarity index 81% rename from packages/utils/src/stringifyQuery.ts rename to packages/utils/src/url/stringifyQuery.ts index 7804130..b874a5c 100644 --- a/packages/utils/src/stringifyQuery.ts +++ b/packages/utils/src/url/stringifyQuery.ts @@ -1,6 +1,4 @@ -type QueryParamValue = string | null; -export type QueryParam = QueryParamValue | QueryParamValue[]; -export type QueryParams = Record; +import { QueryParams } from './queryTypes.js'; export function stringifyQuery(params: QueryParams) { let qs = '';