From 9850a54500441b38e88bfbf135844451fc54e49e Mon Sep 17 00:00:00 2001 From: zepod Date: Fri, 1 Mar 2019 14:21:40 +0100 Subject: [PATCH 1/5] Use reduce for encoderForArrayFormat --- index.js | 68 ++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index 6a1b3c2a..bffc3071 100644 --- a/index.js +++ b/index.js @@ -5,35 +5,38 @@ const decodeComponent = require('decode-uri-component'); function encoderForArrayFormat(options) { switch (options.arrayFormat) { case 'index': - return (key, value, index) => { - return value === null ? [ - encode(key, options), - '[', - index, - ']' - ].join('') : [ - encode(key, options), - '[', - encode(index, options), - ']=', - encode(value, options) - ].join(''); + return key => (result, value) => { + const index = result.length; + if (value === undefined) { + return result; + } + if (value === null) { + return [...result, [encode(key, options), '[', index, ']'].join('')]; + } + return [ + ...result, + [encode(key, options), '[', encode(index, options), ']=', encode(value, options)].join('') + ]; }; case 'bracket': - return (key, value) => { - return value === null ? [encode(key, options), '[]'].join('') : [ - encode(key, options), - '[]=', - encode(value, options) - ].join(''); + return key => (result, value) => { + if (value === undefined) { + return result; + } + if (value === null) { + return [...result, [encode(key, options), '[]'].join('')]; + } + return [...result, [encode(key, options), '[]=', encode(value, options)].join('')]; }; default: - return (key, value) => { - return value === null ? encode(key, options) : [ - encode(key, options), - '=', - encode(value, options) - ].join(''); + return key => (result, value) => { + if (value === undefined) { + return result; + } + if (value === null) { + return [...result, encode(key, options)]; + } + return [...result, [encode(key, options), '=', encode(value, options)].join('')]; }; } } @@ -201,17 +204,10 @@ exports.stringify = (obj, options) => { } if (Array.isArray(value)) { - const result = []; - - for (const value2 of value.slice()) { - if (value2 === undefined) { - continue; - } - - result.push(formatter(key, value2, result.length)); - } - - return result.join('&'); + return value + .slice() + .reduce(formatter(key), []) + .join('&'); } return encode(key, options) + '=' + encode(value, options); From ed4e1fdb0f29440d1cac57cf6ebfde58f389bea0 Mon Sep 17 00:00:00 2001 From: zepod Date: Fri, 1 Mar 2019 14:36:51 +0100 Subject: [PATCH 2/5] Add comma option for encoder --- index.js | 10 ++++++++++ test/stringify.js | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/index.js b/index.js index bffc3071..dae2464c 100644 --- a/index.js +++ b/index.js @@ -28,6 +28,16 @@ function encoderForArrayFormat(options) { } return [...result, [encode(key, options), '[]=', encode(value, options)].join('')]; }; + case 'comma': + return key => (result, value, index) => { + if (!value) { + return result; + } + if (index === 0) { + return [[encode(key, options), '=', encode(value, options)].join('')]; + } + return [[result, encode(value, options)].join(',')]; + }; default: return key => (result, value) => { if (value === undefined) { diff --git a/test/stringify.js b/test/stringify.js index 0302b507..497e969c 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -117,6 +117,24 @@ test('array stringify representation with array brackets and null value', t => { }), 'bar[]&foo[]=a&foo[]&foo[]='); }); +test('array stringify representation with array commas', t => { + t.is(m.stringify({ + foo: null, + bar: ['one', 'two'] + }, { + arrayFormat: 'comma' + }), 'bar=one,two&foo'); +}); + +test('array stringify representation with array commas and null value', t => { + t.is(m.stringify({ + foo: ['a', null, ''], + bar: [null] + }, { + arrayFormat: 'comma' + }), 'foo=a'); +}); + test('array stringify representation with a bad array format', t => { t.is(m.stringify({ foo: null, From de17d5d4f62d27fb6f74800a5655667c69ed39c3 Mon Sep 17 00:00:00 2001 From: zepod Date: Fri, 1 Mar 2019 14:58:36 +0100 Subject: [PATCH 3/5] Add coma option for decoder --- index.js | 6 ++++++ test/parse.js | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/index.js b/index.js index dae2464c..1896d421 100644 --- a/index.js +++ b/index.js @@ -89,6 +89,12 @@ function parserForArrayFormat(options) { accumulator[key] = [].concat(accumulator[key], value); }; + case 'comma': + return (key, value, accumulator) => { + const isArray = typeof value === 'string' && value.split('').indexOf(',') > -1; + const newValue = isArray ? value.split(',') : value; + accumulator[key] = newValue; + }; default: return (key, value, accumulator) => { if (accumulator[key] === undefined) { diff --git a/test/parse.js b/test/parse.js index 999cff83..93717cf8 100644 --- a/test/parse.js +++ b/test/parse.js @@ -107,6 +107,12 @@ test('query strings having brackets arrays and format option as `bracket`', t => }), {foo: ['bar', 'baz']}); }); +test('query strings having comma separated arrays and format option as `comma`', t => { + t.deepEqual(m.parse('foo=bar,baz', { + arrayFormat: 'comma' + }), {foo: ['bar', 'baz']}); +}); + test('query strings having brackets arrays with null and format option as `bracket`', t => { t.deepEqual(m.parse('bar[]&foo[]=a&foo[]&foo[]=', { arrayFormat: 'bracket' @@ -116,6 +122,15 @@ test('query strings having brackets arrays with null and format option as `brack }); }); +test('query strings having comma separated arrays with null and format option as `comma`', t => { + t.deepEqual(m.parse('bar&foo=a,', { + arrayFormat: 'comma' + }), { + foo: ['a', ''], + bar: null + }); +}); + test('query strings having indexed arrays and format option as `index`', t => { t.deepEqual(m.parse('foo[0]=bar&foo[1]=baz', { arrayFormat: 'index' From 5ba6d27220acae48e551036fa47e717f71bdfa4f Mon Sep 17 00:00:00 2001 From: zepod Date: Fri, 1 Mar 2019 15:01:50 +0100 Subject: [PATCH 4/5] Update readme.md with comma option --- readme.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/readme.md b/readme.md index f4640ccb..24f810d2 100644 --- a/readme.md +++ b/readme.md @@ -90,6 +90,13 @@ queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'}); //=> foo: [1,2,3] ``` +- `comma`: stands for parsing separating array elements with comma, such as: + +```js +queryString.parse('foo=1,2,3', {arrayFormat: 'comma'}); +//=> foo: [1,2,3] +``` + - `none`: is the **default** option and removes any bracket representation, such as: ```js @@ -137,6 +144,14 @@ queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'index'}); // => foo[0]=1&foo[1]=2&foo[3]=3 ``` +- `comma`: stands for parsing separating array elements with comma, such as: + +```js +queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'comma'}); +// => foo=1,2,3 +``` + + - `none`: is the __default__ option and removes any bracket representation, such as: ```js From 9db8133f52f62f306fa7948276bafefdc466de0a Mon Sep 17 00:00:00 2001 From: zepod Date: Tue, 5 Mar 2019 09:56:24 +0100 Subject: [PATCH 5/5] Add Typescript definitions for comma arrayformat --- index.d.ts | 4 ++-- index.test-d.ts | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 8d34e213..73735059 100644 --- a/index.d.ts +++ b/index.d.ts @@ -29,7 +29,7 @@ export interface ParseOptions { * queryString.parse('foo=1&foo=2&foo=3'); * //=> foo: [1,2,3] */ - readonly arrayFormat?: 'bracket' | 'index' | 'none'; + readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none'; } export interface ParsedQuery { @@ -100,7 +100,7 @@ export interface StringifyOptions { * queryString.stringify({foo: [1,2,3]}); * // => foo=1&foo=2&foo=3 */ - readonly arrayFormat?: 'bracket' | 'index' | 'none'; + readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none'; /** * Supports both `Function` as a custom sorting function or `false` to disable sorting. diff --git a/index.test-d.ts b/index.test-d.ts index 243c241d..2226bfcd 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -20,6 +20,7 @@ expectType( ); expectType(queryString.stringify({foo: 'bar'}, {arrayFormat: 'index'})); expectType(queryString.stringify({foo: 'bar'}, {arrayFormat: 'none'})); +expectType(queryString.stringify({foo: 'bar'}, {arrayFormat: 'comma'})); expectType(queryString.stringify({foo: 'bar'}, {sort: false})); const order = ['c', 'a', 'b']; expectType( @@ -47,6 +48,9 @@ expectType( expectType( queryString.parse('?foo=bar', {arrayFormat: 'none'}) ); +expectType( + queryString.parse('?foo=bar', {arrayFormat: 'comma'}) +); // Parse URL expectType(queryString.parseUrl('?foo=bar')); @@ -63,6 +67,9 @@ expectType( expectType( queryString.parseUrl('?foo=bar', {arrayFormat: 'none'}) ); +expectType( + queryString.parseUrl('?foo=bar', {arrayFormat: 'comma'}) +); // Extract expectType(queryString.extract('http://foo.bar/?abc=def&hij=klm'));