Skip to content

Commit

Permalink
[New] [Fix] stringify: revert 0e903c0; add commaRoundTrip option
Browse files Browse the repository at this point in the history
Fixes #442. See #441, #434.
  • Loading branch information
ljharb committed Jun 27, 2022
1 parent 95bc018 commit c313472
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Expand Up @@ -14,7 +14,7 @@
"id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
"indent": [2, 4],
"max-lines-per-function": [2, { "max": 150 }],
"max-params": [2, 15],
"max-params": [2, 16],
"max-statements": [2, 53],
"multiline-comment-style": 0,
"no-continue": 1,
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -402,6 +402,8 @@ qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
// 'a=b,c'
```

Note: when using `arrayFormat` set to `'comma'`, you can also pass the `commaRoundTrip` option set to `true` or `false`, to append `[]` on single-item arrays, so that they can round trip through a parse.

When objects are stringified, by default they use bracket notation:

```javascript
Expand Down
11 changes: 9 additions & 2 deletions lib/stringify.js
Expand Up @@ -62,6 +62,7 @@ var stringify = function stringify(
object,
prefix,
generateArrayPrefix,
commaRoundTrip,
strictNullHandling,
skipNulls,
encoder,
Expand Down Expand Up @@ -126,7 +127,7 @@ var stringify = function stringify(
for (var i = 0; i < valuesArray.length; ++i) {
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
}
return [formatter(keyValue) + (isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];
return [formatter(keyValue) + (commaRoundTrip && isArray(obj) && valuesArray.length === 1 ? '[]' : '') + '=' + valuesJoined];
}
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
}
Expand All @@ -150,7 +151,7 @@ var stringify = function stringify(
objKeys = sort ? keys.sort(sort) : keys;
}

var adjustedPrefix = generateArrayPrefix === 'comma' && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix;
var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix;

for (var j = 0; j < objKeys.length; ++j) {
var key = objKeys[j];
Expand All @@ -171,6 +172,7 @@ var stringify = function stringify(
value,
keyPrefix,
generateArrayPrefix,
commaRoundTrip,
strictNullHandling,
skipNulls,
encoder,
Expand Down Expand Up @@ -267,6 +269,10 @@ module.exports = function (object, opts) {
}

var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') {
throw new TypeError('`commaRoundTrip` must be a boolean, or absent');
}
var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip;

if (!objKeys) {
objKeys = Object.keys(obj);
Expand All @@ -287,6 +293,7 @@ module.exports = function (object, opts) {
obj[key],
key,
generateArrayPrefix,
commaRoundTrip,
options.strictNullHandling,
options.skipNulls,
options.encode ? options.encoder : null,
Expand Down
21 changes: 18 additions & 3 deletions test/stringify.js
Expand Up @@ -144,7 +144,8 @@ test('stringify()', function (t) {
st.test('array with a single item', function (s2t) {
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c');
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c');
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a[]=c'); // so it parses back as an array
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c');
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a[]=c'); // so it parses back as an array
s2t.equal(qs.stringify({ a: ['c'] }, { encodeValuesOnly: true }), 'a[0]=c');

s2t.end();
Expand Down Expand Up @@ -379,12 +380,14 @@ test('stringify()', function (t) {
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' }), 'b[0]=&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }), 'b[]=&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }), 'b=&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }), 'b[]=&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }), 'b=&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', commaRoundTrip: true }), 'b[]=&c=c');
// with strictNullHandling
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', strictNullHandling: true }), 'b[0]&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', strictNullHandling: true }), 'b[]&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', strictNullHandling: true }), 'b&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true }), 'b[]&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true }), 'b&c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true }), 'b[]&c=c');
// with skipNulls
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }), 'c=c');
st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }), 'c=c');
Expand Down Expand Up @@ -712,6 +715,18 @@ test('stringify()', function (t) {
arrayFormat: 'comma'
}
),
'a=' + date.getTime(),
'works with arrayFormat comma'
);
st.equal(
qs.stringify(
{ a: [date] },
{
serializeDate: function (d) { return d.getTime(); },
arrayFormat: 'comma',
commaRoundTrip: true
}
),
'a%5B%5D=' + date.getTime(),
'works with arrayFormat comma'
);
Expand Down

0 comments on commit c313472

Please sign in to comment.