Skip to content

motss/tyqs

Repository files navigation

tyqs

Tiny and type-safe querystring library for the web


Buy me a coffee Follow me

npm-latest MIT License

Downloads Total downloads

Dependencies ci publish codecov

Code of Conduct

Querystring decoder and encoder using URLSearchParams.

Table of contents

Pre-requisite

Install

# Install via NPM
$ npm i tyqs

Features

Support Feature Description Example
parse Decodes URL search params into an object. parse('a=a&b=1') returns { a: 'a', b: '1' }.
stringify Encodes an object into URL search params. stringify({ a: 'a', b: 1 }) gives a=a&b=1.
Parse multiple values Parses comma-separated param into an array of values. parse('a=a,b') returns { a: ['a', 'b'] }.
Parse single value Parses single-value param into a string. parse('a=a') returns { a: 'a' }.
Parse multiple params of the same name Parses multiple params of the same name into an array of values. parse('a=a,b&a=c') returns { a: ['a', 'b', 'c'] }.
Parse nested params Parses nested params with dot or bracket notation. parse('a.a=a&b[a]=b&c[a].b=c&d.a[b].c=d') returns { a: { a: 'a' }, b: { a: 'b' }, c: { a: { b: 'c' } }, d: { a: { b: { c: 'd' } } } }.
Stringify nested params Stringifies nested params with dot or bracket notation. stringify({ a: { a: 'a' } } ) gives a.a=a.
Optional replacer function for parsing Optionally alters final parsed value. See Optional replacer function.
Optional replacer function for stringify Optionally alters final stringified value. See Optional replacer function.
Omit nullish value in stringify By default, all nullish values are omitted when stringify-ing an object. stringify({ a: 'a', b: undefined, c: null }) gives a=a.
Parse a[0]=a&a[1]=b into array Not supported but it should work. For arrays, use comma-separated value. parse('a[0]=a&a[1]=b') returns { a: { 0: 'a', 1: 'b' } }.
🚧 Stringify non-JavaScript primitives Stringifies all non-JavaScript primitives with its best effort. stringify({ a() {return;} }) gives a=a%28%29+%7Breturn%3B%7D.

Usage

TypeScript or ES Modules

import { parse, stringify } from 'tyqs';

parse('a=a'); // { a: 'a' }
parse('a=a&a=b'); // { a: ['a', 'b'] }
parse('a=a,b'); // { a: ['a', 'b'] }
parse('a.a=a'); // { a: { a: 'a' } }
parse('a[a]=a'); // { a: { a: 'a' } }
parse('a[a].b=a'); // { a: { a: { b: 'a' } } }
parse('a[a].b=a,b'); // { a: { a: { b: ['a', 'b'] } } }
parse('a=1'); // { a: '1' }
parse('a.a=1'); // { a: { a: '1' } }
parse('a.a[b]=1'); // { a: { a: { b: '1' } } }

stringify({ a: 'a' }); // a=a
stringify({ a: [1, 2] }); // a=1,2
stringify({ a: { a: [1, 2] } }); // a.a=1,2
stringify({ a: 'a', b: undefined, c: null }); // a=a

Optional replacer function

All functions provided accepts an optional replacer function to alter the final output of each parameter.

// parse(searchParams, replacer)
const searchParams = new URLSearchParams('a=1,2,3&b=true&c=&a=4');
const parseOptions = {
  replacer({
    firstRawValue: [firstRawValue],
    key,
    rawValue,
    value,
  }) {
    switch (key) {
      case 'a': return rawValue.map(n => Number(n));
      case 'b': return firstRawValue === 'true';
      case 'c': return firstRawValue === '' ? undefined : firstRawValue;
      default: return value;
    }
  },
};

parse(searchParams);
/**
 * output:
 * {
 *   a: ['1', '2', '3', '4'],
 *   b: 'true',
 *   c: '',
 * }
 */

parse(searchParams, parseOptions.replacer);
/**
 * output:
 * {
 *   a: [1, 2, 3, 4],
 *   b: true,
 *   c: undefined,
 * }
 */



// stringify(input, replacer)
const input = {
  a: null,
  b: undefined,
  c: {
    a: null,
    d: {
      a: undefined,
    },
  },
  d() { return; }
};
const stringifyOptions = {
  replacer({
    rawValue,
    value,
    key,
    flattenedKey,
  }) {
    if (key === 'b' || flattenedKey === 'c.d.a') return '<nil>';
    if (rawValue == null) return '';

    /** Returning a nullish value to omit the current key-value pair in the output. */
    if (typeof(rawValue) === 'function') return;

    return value;
  },
};

stringify(input);
/** output: d=d%28%29+%7B+return%3B+%7D */

stringify(input, stringifyOptions.replacer);
/** output: a=&b=%3Cnil%3E&c.a=&c.d.a=%3Cnil%3E */

API Reference

parse(searchParams[, replacer])

  • searchParams <string | URLSearchParams> URL search parameters.
  • replacer <?Function> Optional replacer function that allows you to alter the final parsed value.
    • firstRawValue <Array<string>> This returns an array of values of the first key-value pair of a given key, e.g. a=a&a=b will return { a: ['a'] }.
    • key <string> Parameter name.
    • rawValue <Array<string>> This returns an array of values from all key-value pairs of the same key, e.g. a=a&a=b will return { a: ['a', 'b'] }.
    • value <string | Array<string>> This returns the best value of a given parameter key which is heuristically determined by the library, e.g. a=a,b&b=a&a=c will return { a: ['a', 'b', 'c'] } (an array of values) and b='a' (single value).
  • returns: <Object> An object of decoded URL search params from a given string.

This method decodes/ parses a string value into an object. By default, URLSearchParams.prototype.getAll is used to retrieve the values from all key-value pairs of the same name, e.g. a=a&a=b will return { a: ['a', 'b'] }. As you can see, this approach will be able to get all param values when you define multiple pairs of the same key. However, there is a downside which is when you have just 1 key-value pair and you expect it to be a single-value param, say a=a&b=b, will give { a: ['a'], b: ['b'] }. To avoid any confusion, the library automatically parses such single-value param into a single value instead, e.g. a=a&b=b will always give { a: 'a', b: 'b' }.

Under some circumstances, you might want it to behave differently. For that you can alter the outcome with an optional replacer function.

stringify(input[, replacer])

  • value <unknown> Any value of unknown type. It accepts any JavaScript primitives and objects.
  • replacer <?Function> Optional replacer function that allows you to alter the final stringified value.
    • flattenedKey <string> Flattened key, e.g. { a: { b: { c: 'a' } } }'s key will be flattened to a.b.c.
    • key <string> Parameter name.
    • rawValue <unknown> Raw value of a parameter.
    • value <string> Stringified value.
  • returns: <string> A string of encoded URL search params from a given object.

This method encodes/ stringifies an object into a string. When a raw value is nullish, it will be omitted in the stringified output, e.g. { a: 'a', b: null, c: undefined } will return a=a as null and undefined are nullish values.

If you want to include nullish values in the stringified output, you can override that with an optional replacer function.

Contributing

Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

License

MIT License © Rong Sen Ng (motss)