Skip to content

Commit 4c4b23d

Browse files
bakkerthehackerljharb
authored andcommitted
[Fix] stringify: encode comma values more consistently
1 parent 1778ed4 commit 4c4b23d

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"indent": [2, 4],
1616
"max-lines-per-function": [2, { "max": 150 }],
1717
"max-params": [2, 16],
18-
"max-statements": [2, 53],
18+
"max-statements": [2, 100],
1919
"multiline-comment-style": 0,
2020
"no-continue": 1,
2121
"no-magic-numbers": 0,

lib/stringify.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ var arrayPrefixGenerators = {
1919
};
2020

2121
var isArray = Array.isArray;
22-
var split = String.prototype.split;
2322
var push = Array.prototype.push;
2423
var pushToArray = function (arr, valueOrArray) {
2524
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -121,14 +120,6 @@ var stringify = function stringify(
121120
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
122121
if (encoder) {
123122
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
124-
if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
125-
var valuesArray = split.call(String(obj), ',');
126-
var valuesJoined = '';
127-
for (var i = 0; i < valuesArray.length; ++i) {
128-
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
129-
}
130-
return [formatter(keyValue) + (commaRoundTrip && isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];
131-
}
132123
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
133124
}
134125
return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -143,6 +134,9 @@ var stringify = function stringify(
143134
var objKeys;
144135
if (generateArrayPrefix === 'comma' && isArray(obj)) {
145136
// we need to join elements in
137+
if (encodeValuesOnly && encoder) {
138+
obj = utils.maybeMap(obj, encoder);
139+
}
146140
objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
147141
} else if (isArray(filter)) {
148142
objKeys = filter;
@@ -175,7 +169,7 @@ var stringify = function stringify(
175169
commaRoundTrip,
176170
strictNullHandling,
177171
skipNulls,
178-
encoder,
172+
generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
179173
filter,
180174
sort,
181175
allowDots,

test/stringify.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ test('stringify()', function (t) {
162162

163163
st.test('array with multiple items with a comma inside', function (s2t) {
164164
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c%2Cd,e');
165-
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%25%2Cd%2Ce');
165+
s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
166166

167167
s2t.end();
168168
});
@@ -178,6 +178,44 @@ test('stringify()', function (t) {
178178
st.end();
179179
});
180180

181+
t.test('stringifies comma and empty array values', function (st) {
182+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }), 'a[0]=,&a[1]=&a[2]=c,d%');
183+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }), 'a[]=,&a[]=&a[]=c,d%');
184+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }), 'a=,,,c,d%');
185+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }), 'a=,&a=&a=c,d%');
186+
187+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=%2C&a[1]=&a[2]=c%2Cd%25');
188+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=%2C&a[]=&a[]=c%2Cd%25');
189+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C,,c%2Cd%25');
190+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
191+
192+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
193+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25');
194+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C%2C%2Cc%2Cd%25');
195+
st.equal(qs.stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&a=&a=c%2Cd%25');
196+
197+
st.end();
198+
});
199+
200+
t.test('stringifies comma and empty non-array values', function (st) {
201+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }), 'a=,&b=&c=c,d%');
202+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }), 'a=,&b=&c=c,d%');
203+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }), 'a=,&b=&c=c,d%');
204+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }), 'a=,&b=&c=c,d%');
205+
206+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
207+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
208+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
209+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
210+
211+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), 'a=%2C&b=&c=c%2Cd%25');
212+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }), 'a=%2C&b=&c=c%2Cd%25');
213+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), 'a=%2C&b=&c=c%2Cd%25');
214+
st.equal(qs.stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), 'a=%2C&b=&c=c%2Cd%25');
215+
216+
st.end();
217+
});
218+
181219
t.test('stringifies a nested array value with dots notation', function (st) {
182220
st.equal(
183221
qs.stringify(

0 commit comments

Comments
 (0)