diff --git a/README.md b/README.md index a3984bf..6c19b28 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,163 @@ parse('foo.bar=abc&baz=def'); */ ``` +Stringifying an object: + +```ts +import {stringify} from 'picoquery'; + +stringify({ + foo: { + bar: 123 + } +}); + +/* +foo.bar=123 +*/ +``` + +## API + +### `stringify(object[, options])` + +Converts the given object into a query string, optionally with configured +options. + +### `parse(str[, options])` + +Parses the given query string into an object, optionally with configured +options. + +### Options + +### Default options + +The default options are as follows: + +```ts +{ + nested: true, + nestingSyntax: 'dot', + arrayRepeat: false, + arrayRepeatSyntax: 'repeat', + delimiter: '&' +} +``` + +#### `nested` + +When true, nested objects are supported. + +For example, when parsing: + +```ts +parse('foo.bar=baz', {nested: true}); + +// {foo: {bar: 'baz'}} +``` + +When stringifying: + +```ts +stringify({foo: {bar: 'baz'}}, {nested: true}); + +// foo.bar=baz +``` + +This also results in arrays being supported: + +```ts +parse('foo.0=bar', {nested: true}); +// {foo: ['bar']} + +stringify({foo: ['bar']}, {nested: true}); +// foo.0=bar +``` + +### `nestingSyntax` + +Sets which style of nesting syntax should be used. The choices are: + +- `dot` (e.g. `foo.bar=baz`) +- `index` (e.g. `foo[bar]=baz`) + +### `arrayRepeat` + +If `true`, this will treat repeated keys as arrays. + +For example: + +```ts +parse('foo=x&foo=y', {arrayRepeat: true}); +// {foo: ['x', 'y']} + +stringify({foo: ['x', 'y']}, {arrayRepeat: true}); +// foo=x&foo=y +``` + +### `arrayRepeatSyntax` + +Sets which style of array repetition syntax should be used. The choices are: + +- `bracket` (e.g. `foo[]=x&foo[]=y`) +- `repeat` (e.g. `foo=x&foo=y`) + +### `delimiter` + +Sets the delimiter to be used instead of `&`. + +For example: + +```ts +parse('foo=x;bar=y', {delimiter: ';'}); +// {foo: 'x', bar: 'y'} + +stringify({foo: 'x', bar: 'y'}, {delimiter: ';'}); +// foo=x;bar=y +``` + +### `valueDeserializer` + +Can be set to a function which will be used to deserialize each value during +parsing. + +It will be called with the `value` and the `key` (i.e. `(value, key) => *`). + +For example: + +```ts +parse('foo=300', { + valueDeserializer: (value) => { + const asNum = Number(value); + return Number.isNaN(asNum) ? value : asNum; + } +}); + +// {foo: 300} +``` + +### `keyDeserializer` + +Can be set to a function which will be used to deserialize each key during +parsing. + +It will be called with the `key` from the query string +(i.e. `(key) => PropertyKey`). + +For example: + +```ts +parse('300=foo', { + keyDeserializer: (key) => { + const asNum = Number(key); + return Number.isNaN(asNum) ? key : asNum; + } +}); + +// {300: 'foo'} +``` + ## License MIT diff --git a/src/shared.ts b/src/shared.ts index c58d4a4..48f3db6 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -10,19 +10,14 @@ export type NestingSyntax = // `foo[bar]` | 'index'; -// This is a special return value for deserializers and serializers, to tell the library -// to fall back to using the default (de)serialize function. -// We can't just return `null` or `undefined` etc, because we may want to deserialize to that -export const CONTINUE = Symbol('continue'); - export type DeserializeValueFunction = ( value: string, key: string -) => unknown | typeof CONTINUE; +) => unknown; export type DeserializeKeyFunction = ( key: string -) => PropertyKey | typeof CONTINUE; +) => PropertyKey; export interface Options { // Enable parsing nested objects and arrays