Skip to content

Commit

Permalink
Add comma format to the arrayFormat option (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
zepod authored and sindresorhus committed Mar 14, 2019
1 parent 49d2203 commit b22c2af
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 38 deletions.
4 changes: 2 additions & 2 deletions index.d.ts
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down
94 changes: 58 additions & 36 deletions index.js
Expand Up @@ -5,37 +5,59 @@ 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('')];
};

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, 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('')];
};
}
}
Expand Down Expand Up @@ -80,6 +102,13 @@ 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) {
Expand Down Expand Up @@ -205,17 +234,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);
Expand Down
7 changes: 7 additions & 0 deletions index.test-d.ts
Expand Up @@ -20,6 +20,7 @@ expectType<string>(
);
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'index'}));
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'none'}));
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'comma'}));
expectType<string>(queryString.stringify({foo: 'bar'}, {sort: false}));
const order = ['c', 'a', 'b'];
expectType<string>(
Expand Down Expand Up @@ -47,6 +48,9 @@ expectType<queryString.ParsedQuery>(
expectType<queryString.ParsedQuery>(
queryString.parse('?foo=bar', {arrayFormat: 'none'})
);
expectType<queryString.ParsedQuery>(
queryString.parse('?foo=bar', {arrayFormat: 'comma'})
);

// Parse URL
expectType<queryString.ParsedUrl>(queryString.parseUrl('?foo=bar'));
Expand All @@ -63,6 +67,9 @@ expectType<queryString.ParsedUrl>(
expectType<queryString.ParsedUrl>(
queryString.parseUrl('?foo=bar', {arrayFormat: 'none'})
);
expectType<queryString.ParsedUrl>(
queryString.parseUrl('?foo=bar', {arrayFormat: 'comma'})
);

// Extract
expectType<string>(queryString.extract('http://foo.bar/?abc=def&hij=klm'));
15 changes: 15 additions & 0 deletions readme.md
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions test/parse.js
Expand Up @@ -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'
Expand All @@ -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'
Expand Down
18 changes: 18 additions & 0 deletions test/stringify.js
Expand Up @@ -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,
Expand Down

0 comments on commit b22c2af

Please sign in to comment.