mauss
Version:
lightweight, modular, type-safe utilities
66 lines (65 loc) • 2.58 kB
JavaScript
/**
* Query string decoder (`qsd`) decodes a query string into an object. It accepts a query string with or without the leading `?` and returns a mapped object of decoded query string
*
* @param qs query string of a URL with or without the leading `?`
* @returns mapped object of decoded query string
*/
export function qsd(qs) {
if (qs[0] === '?')
qs = qs.slice(1);
if (!qs)
return {};
const dec = (s) => {
if (!s.trim())
return '';
s = decodeURIComponent(s);
if (['true', 'false'].includes(s))
return s[0] === 't';
return Number.isNaN(Number(s)) ? s : Number(s);
};
const dqs = {};
const qar = qs.split('&');
for (let i = 0; i < qar.length; i++) {
const [k, v] = qar[i].split('=');
if (v === undefined)
continue;
const item = dqs[k]; // satisfy TS
if (!dqs[k] && (dqs[k] = dec(v)))
continue;
if (!Array.isArray(item))
dqs[k] = [item];
dqs[k].push(dec(v));
}
return dqs;
}
/**
* Query string encoder (`qse`) encodes key-value pairs from an object into a query string. It optionally accepts a second argument for a transformer function that will be applied to the final value if it exists, else an empty string will be returned
*
* @param bound object with key-value pair to be updated in the URL, only accepts an object with nullish and primitive literals or an array of those values
* @param transformer function that is applied to the final string if it exists, useful in cases where we want to add a leading `?` when the query exists but not when it's empty, or when we would like to append another existing query string after only if the output of `qse` exists
* @returns final query string
*/
export function qse(bound, transformer = (final) => `?${final}`) {
const enc = encodeURIComponent;
let final = '';
for (let [k, v] of Object.entries(bound)) {
if (v == null || (typeof v === 'string' && !(v = v.trim())))
continue;
if ((k = enc(k)) && final)
final += '&';
if (Array.isArray(v)) {
let pointer = 0;
while (pointer < v.length) {
if (pointer)
final += '&';
const item = v[pointer++];
if (item == null)
continue;
final += `${k}=${enc(item)}`;
}
continue;
}
final += `${k}=${enc(v)}`;
}
return final ? transformer(final) : final;
}