Skip to content

Commit b22c2af

Browse files
zepodsindresorhus
authored andcommitted
Add comma format to the arrayFormat option (#167)
1 parent 49d2203 commit b22c2af

File tree

6 files changed

+115
-38
lines changed

6 files changed

+115
-38
lines changed

index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface ParseOptions {
2929
* queryString.parse('foo=1&foo=2&foo=3');
3030
* //=> foo: [1,2,3]
3131
*/
32-
readonly arrayFormat?: 'bracket' | 'index' | 'none';
32+
readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none';
3333
}
3434

3535
export interface ParsedQuery {
@@ -100,7 +100,7 @@ export interface StringifyOptions {
100100
* queryString.stringify({foo: [1,2,3]});
101101
* // => foo=1&foo=2&foo=3
102102
*/
103-
readonly arrayFormat?: 'bracket' | 'index' | 'none';
103+
readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'none';
104104

105105
/**
106106
* Supports both `Function` as a custom sorting function or `false` to disable sorting.

index.js

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,59 @@ const decodeComponent = require('decode-uri-component');
55
function encoderForArrayFormat(options) {
66
switch (options.arrayFormat) {
77
case 'index':
8-
return (key, value, index) => {
9-
return value === null ? [
10-
encode(key, options),
11-
'[',
12-
index,
13-
']'
14-
].join('') : [
15-
encode(key, options),
16-
'[',
17-
encode(index, options),
18-
']=',
19-
encode(value, options)
20-
].join('');
8+
return key => (result, value) => {
9+
const index = result.length;
10+
if (value === undefined) {
11+
return result;
12+
}
13+
14+
if (value === null) {
15+
return [...result, [encode(key, options), '[', index, ']'].join('')];
16+
}
17+
18+
return [
19+
...result,
20+
[encode(key, options), '[', encode(index, options), ']=', encode(value, options)].join('')
21+
];
2122
};
2223

2324
case 'bracket':
24-
return (key, value) => {
25-
return value === null ? [encode(key, options), '[]'].join('') : [
26-
encode(key, options),
27-
'[]=',
28-
encode(value, options)
29-
].join('');
25+
return key => (result, value) => {
26+
if (value === undefined) {
27+
return result;
28+
}
29+
30+
if (value === null) {
31+
return [...result, [encode(key, options), '[]'].join('')];
32+
}
33+
34+
return [...result, [encode(key, options), '[]=', encode(value, options)].join('')];
35+
};
36+
37+
case 'comma':
38+
return key => (result, value, index) => {
39+
if (!value) {
40+
return result;
41+
}
42+
43+
if (index === 0) {
44+
return [[encode(key, options), '=', encode(value, options)].join('')];
45+
}
46+
47+
return [[result, encode(value, options)].join(',')];
3048
};
3149

3250
default:
33-
return (key, value) => {
34-
return value === null ? encode(key, options) : [
35-
encode(key, options),
36-
'=',
37-
encode(value, options)
38-
].join('');
51+
return key => (result, value) => {
52+
if (value === undefined) {
53+
return result;
54+
}
55+
56+
if (value === null) {
57+
return [...result, encode(key, options)];
58+
}
59+
60+
return [...result, [encode(key, options), '=', encode(value, options)].join('')];
3961
};
4062
}
4163
}
@@ -80,6 +102,13 @@ function parserForArrayFormat(options) {
80102
accumulator[key] = [].concat(accumulator[key], value);
81103
};
82104

105+
case 'comma':
106+
return (key, value, accumulator) => {
107+
const isArray = typeof value === 'string' && value.split('').indexOf(',') > -1;
108+
const newValue = isArray ? value.split(',') : value;
109+
accumulator[key] = newValue;
110+
};
111+
83112
default:
84113
return (key, value, accumulator) => {
85114
if (accumulator[key] === undefined) {
@@ -205,17 +234,10 @@ exports.stringify = (obj, options) => {
205234
}
206235

207236
if (Array.isArray(value)) {
208-
const result = [];
209-
210-
for (const value2 of value.slice()) {
211-
if (value2 === undefined) {
212-
continue;
213-
}
214-
215-
result.push(formatter(key, value2, result.length));
216-
}
217-
218-
return result.join('&');
237+
return value
238+
.slice()
239+
.reduce(formatter(key), [])
240+
.join('&');
219241
}
220242

221243
return encode(key, options) + '=' + encode(value, options);

index.test-d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ expectType<string>(
2020
);
2121
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'index'}));
2222
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'none'}));
23+
expectType<string>(queryString.stringify({foo: 'bar'}, {arrayFormat: 'comma'}));
2324
expectType<string>(queryString.stringify({foo: 'bar'}, {sort: false}));
2425
const order = ['c', 'a', 'b'];
2526
expectType<string>(
@@ -47,6 +48,9 @@ expectType<queryString.ParsedQuery>(
4748
expectType<queryString.ParsedQuery>(
4849
queryString.parse('?foo=bar', {arrayFormat: 'none'})
4950
);
51+
expectType<queryString.ParsedQuery>(
52+
queryString.parse('?foo=bar', {arrayFormat: 'comma'})
53+
);
5054

5155
// Parse URL
5256
expectType<queryString.ParsedUrl>(queryString.parseUrl('?foo=bar'));
@@ -63,6 +67,9 @@ expectType<queryString.ParsedUrl>(
6367
expectType<queryString.ParsedUrl>(
6468
queryString.parseUrl('?foo=bar', {arrayFormat: 'none'})
6569
);
70+
expectType<queryString.ParsedUrl>(
71+
queryString.parseUrl('?foo=bar', {arrayFormat: 'comma'})
72+
);
6673

6774
// Extract
6875
expectType<string>(queryString.extract('http://foo.bar/?abc=def&hij=klm'));

readme.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ queryString.parse('foo[0]=1&foo[1]=2&foo[3]=3', {arrayFormat: 'index'});
9090
//=> foo: [1,2,3]
9191
```
9292

93+
- `comma`: stands for parsing separating array elements with comma, such as:
94+
95+
```js
96+
queryString.parse('foo=1,2,3', {arrayFormat: 'comma'});
97+
//=> foo: [1,2,3]
98+
```
99+
93100
- `none`: is the **default** option and removes any bracket representation, such as:
94101

95102
```js
@@ -137,6 +144,14 @@ queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'index'});
137144
// => foo[0]=1&foo[1]=2&foo[3]=3
138145
```
139146

147+
- `comma`: stands for parsing separating array elements with comma, such as:
148+
149+
```js
150+
queryString.stringify({foo: [1,2,3]}, {arrayFormat: 'comma'});
151+
// => foo=1,2,3
152+
```
153+
154+
140155
- `none`: is the __default__ option and removes any bracket representation, such as:
141156

142157
```js

test/parse.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ test('query strings having brackets arrays and format option as `bracket`', t =>
107107
}), {foo: ['bar', 'baz']});
108108
});
109109

110+
test('query strings having comma separated arrays and format option as `comma`', t => {
111+
t.deepEqual(m.parse('foo=bar,baz', {
112+
arrayFormat: 'comma'
113+
}), {foo: ['bar', 'baz']});
114+
});
115+
110116
test('query strings having brackets arrays with null and format option as `bracket`', t => {
111117
t.deepEqual(m.parse('bar[]&foo[]=a&foo[]&foo[]=', {
112118
arrayFormat: 'bracket'
@@ -116,6 +122,15 @@ test('query strings having brackets arrays with null and format option as `brack
116122
});
117123
});
118124

125+
test('query strings having comma separated arrays with null and format option as `comma`', t => {
126+
t.deepEqual(m.parse('bar&foo=a,', {
127+
arrayFormat: 'comma'
128+
}), {
129+
foo: ['a', ''],
130+
bar: null
131+
});
132+
});
133+
119134
test('query strings having indexed arrays and format option as `index`', t => {
120135
t.deepEqual(m.parse('foo[0]=bar&foo[1]=baz', {
121136
arrayFormat: 'index'

test/stringify.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,24 @@ test('array stringify representation with array brackets and null value', t => {
117117
}), 'bar[]&foo[]=a&foo[]&foo[]=');
118118
});
119119

120+
test('array stringify representation with array commas', t => {
121+
t.is(m.stringify({
122+
foo: null,
123+
bar: ['one', 'two']
124+
}, {
125+
arrayFormat: 'comma'
126+
}), 'bar=one,two&foo');
127+
});
128+
129+
test('array stringify representation with array commas and null value', t => {
130+
t.is(m.stringify({
131+
foo: ['a', null, ''],
132+
bar: [null]
133+
}, {
134+
arrayFormat: 'comma'
135+
}), 'foo=a');
136+
});
137+
120138
test('array stringify representation with a bad array format', t => {
121139
t.is(m.stringify({
122140
foo: null,

0 commit comments

Comments
 (0)