diff --git a/.eslintrc b/.eslintrc index 98560175..21c65e20 100644 --- a/.eslintrc +++ b/.eslintrc @@ -4,12 +4,12 @@ "extends": "@ljharb", "rules": { - "complexity": [2, 25], + "complexity": [2, 26], "consistent-return": 1, "id-length": [2, { "min": 1, "max": 25, "properties": "never" }], "indent": [2, 4], - "max-params": [2, 11], - "max-statements": [2, 42], + "max-params": [2, 12], + "max-statements": [2, 43], "no-extra-parens": 1, "no-continue": 1, "no-magic-numbers": 0, diff --git a/README.md b/README.md index 1ec74627..32fc3123 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,15 @@ var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false }); assert.equal(unencoded, 'a[b]=c'); ``` +Encoding can be disabled for keys by setting the `encodeValuesOnly` option to `true`: +```javascript +var encodedValues = qs.stringify( + { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + { encodeValuesOnly: true } +) +assert.equal(encodedValues,'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'); +``` + This encoding can also be replaced by a custom encoding method set as `encoder` option: ```javascript @@ -400,7 +409,7 @@ assert.equal(nullsSkipped, 'a=b'); ### Dealing with special character sets -By default the encoding and decoding of characters is done in `utf-8`. If you +By default the encoding and decoding of characters is done in `utf-8`. If you wish to encode querystrings to a different character set (i.e. [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library: diff --git a/lib/stringify.js b/lib/stringify.js index 8b5c8484..28bdeece 100755 --- a/lib/stringify.js +++ b/lib/stringify.js @@ -21,6 +21,7 @@ var defaults = { delimiter: '&', encode: true, encoder: utils.encode, + encodeValuesOnly: false, serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching return toISO.call(date); }, @@ -39,7 +40,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching sort, allowDots, serializeDate, - formatter + formatter, + encodeValuesOnly ) { var obj = object; if (typeof filter === 'function') { @@ -48,7 +50,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching obj = serializeDate(obj); } else if (obj === null) { if (strictNullHandling) { - return encoder ? encoder(prefix) : prefix; + return encoder && !encodeValuesOnly ? encoder(prefix) : prefix; } obj = ''; @@ -56,7 +58,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) { if (encoder) { - return [formatter(encoder(prefix)) + '=' + formatter(encoder(obj))]; + var keyValue = encodeValuesOnly ? prefix : encoder(prefix); + return [formatter(keyValue) + '=' + formatter(encoder(obj))]; } return [formatter(prefix) + '=' + formatter(String(obj))]; } @@ -94,7 +97,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching sort, allowDots, serializeDate, - formatter + formatter, + encodeValuesOnly )); } else { values = values.concat(stringify( @@ -108,7 +112,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching sort, allowDots, serializeDate, - formatter + formatter, + encodeValuesOnly )); } } @@ -132,6 +137,7 @@ module.exports = function (object, opts) { var sort = typeof options.sort === 'function' ? options.sort : null; var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots; var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate; + var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly; if (typeof options.format === 'undefined') { options.format = formats.default; } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) { @@ -192,7 +198,8 @@ module.exports = function (object, opts) { sort, allowDots, serializeDate, - formatter + formatter, + encodeValuesOnly )); } diff --git a/test/stringify.js b/test/stringify.js index c3dd095c..711dae50 100755 --- a/test/stringify.js +++ b/test/stringify.js @@ -535,4 +535,33 @@ test('stringify()', function (t) { ); st.end(); }); + + t.test('encodeValuesOnly', function (st) { + st.equal( + qs.stringify( + { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + { encodeValuesOnly: true } + ), + 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h' + ); + st.equal( + qs.stringify( + { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] } + ), + 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h' + ); + st.end(); + }); + + t.test('encodeValuesOnly - strictNullHandling', function (st) { + st.equal( + qs.stringify( + { a: { b: null } }, + { encodeValuesOnly: true, strictNullHandling: true } + ), + 'a[b]' + ); + st.end(); + }); + });