Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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