diff --git a/README.md b/README.md index cb47d60a..8b45caff 100644 --- a/README.md +++ b/README.md @@ -275,10 +275,15 @@ assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] }); Some people use comma to join array, **qs** can parse it: ```javascript +var arraysOfObjects = qs.parse('a[]=b,c', { comma: true }) +assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] }) +``` +or +```javascript var arraysOfObjects = qs.parse('a=b,c', { comma: true }) assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] }) ``` -(_this cannot convert nested objects, such as `a={b:1},{c:d}`_) +(_this cannot convert nested objects, such as `a[]={b:1},{c:d}`_) ### Stringifying @@ -356,7 +361,7 @@ qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) // 'a=b&a=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' }) -// 'a=b,c' +// 'a[]=b,c' ``` When objects are stringified, by default they use bracket notation: diff --git a/lib/stringify.js b/lib/stringify.js index b2e5f06e..22e66a30 100644 --- a/lib/stringify.js +++ b/lib/stringify.js @@ -8,7 +8,9 @@ var arrayPrefixGenerators = { brackets: function brackets(prefix) { // eslint-disable-line func-name-matching return prefix + '[]'; }, - comma: 'comma', + comma: function comma(prefix) { // eslint-disable-line func-name-matching + return prefix + '[]'; + }, indices: function indices(prefix, key) { // eslint-disable-line func-name-matching return prefix + '[' + key + ']'; }, @@ -57,6 +59,7 @@ var isNonNullishPrimitive = function isNonNullishPrimitive(v) { // eslint-disabl var stringify = function stringify( // eslint-disable-line func-name-matching object, prefix, + arrayFormat, generateArrayPrefix, strictNullHandling, skipNulls, @@ -74,8 +77,10 @@ var stringify = function stringify( // eslint-disable-line func-name-matching obj = filter(prefix, obj); } else if (obj instanceof Date) { obj = serializeDate(obj); - } else if (generateArrayPrefix === 'comma' && isArray(obj)) { + } else if (arrayFormat === 'comma' && isArray(obj)) { obj = obj.join(','); + // eslint-disable-next-line no-param-reassign + prefix = generateArrayPrefix(prefix); } if (obj === null) { @@ -119,6 +124,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching pushToArray(values, stringify( obj[key], typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix, + arrayFormat, generateArrayPrefix, strictNullHandling, skipNulls, @@ -135,6 +141,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching pushToArray(values, stringify( obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), + arrayFormat, generateArrayPrefix, strictNullHandling, skipNulls, @@ -248,6 +255,7 @@ module.exports = function (object, opts) { pushToArray(keys, stringify( obj[key], key, + arrayFormat, generateArrayPrefix, options.strictNullHandling, options.skipNulls, diff --git a/test/parse.js b/test/parse.js index 397b867d..7092a09a 100644 --- a/test/parse.js +++ b/test/parse.js @@ -361,6 +361,7 @@ test('parse()', function (t) { t.test('parses string with comma as array divider', function (st) { st.deepEqual(qs.parse('foo=bar,tee', { comma: true }), { foo: ['bar', 'tee'] }); + st.deepEqual(qs.parse('foo[]=bar,tee', { comma: true }), { foo: ['bar', 'tee'] }); st.deepEqual(qs.parse('foo[bar]=coffee,tee', { comma: true }), { foo: { bar: ['coffee', 'tee'] } }); st.deepEqual(qs.parse('foo=', { comma: true }), { foo: '' }); st.deepEqual(qs.parse('foo', { comma: true }), { foo: '' }); diff --git a/test/stringify.js b/test/stringify.js index 053fe1f2..bbb6af9f 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -105,7 +105,7 @@ test('stringify()', function (t) { ); st.equal( qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' }), - 'a=b%2Cc%2Cd', + 'a%5B%5D=b%2Cc%2Cd', 'comma => comma' ); st.equal( @@ -134,7 +134,7 @@ test('stringify()', function (t) { t.test('stringifies a nested array value', function (st) { st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d'); - st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D=c%2Cd'); // a[b]=c,d + st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D%5B%5D=c%2Cd'); // a[b][]=c,d st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); st.end(); }); @@ -161,7 +161,7 @@ test('stringify()', function (t) { { a: { b: ['c', 'd'] } }, { allowDots: true, encode: false, arrayFormat: 'comma' } ), - 'a.b=c,d', + 'a.b[]=c,d', 'comma: stringifies with dots + comma' ); st.equal( @@ -719,5 +719,15 @@ test('stringify()', function (t) { st.end(); }); + t.test('stringifies a comma array value with single element', function (st) { + st.equal( + qs.stringify({ a: ['b'] }, { arrayFormat: 'comma' }), + 'a%5B%5D=b', + 'comma => comma' + ); + + st.end(); + }); + t.end(); });