diff --git a/lib/parse.js b/lib/parse.js index ba05d27c..93144343 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1,6 +1,7 @@ 'use strict'; var utils = require('./utils'); +var ValueError = require('./value-error'); var has = Object.prototype.hasOwnProperty; var isArray = Array.isArray; @@ -218,6 +219,10 @@ var normalizeParseOptions = function normalizeParseOptions(opts) { throw new TypeError('`decodeDotInKeys` option can only be `true` or `false`, when provided'); } + if (opts.allowDots === false && opts.decodeDotInKeys === true) { + throw new ValueError('Provided combination is not valid: allowDots=false & decodeDotInKeys=true'); + } + if (opts.decoder !== null && typeof opts.decoder !== 'undefined' && typeof opts.decoder !== 'function') { throw new TypeError('Decoder has to be a function.'); } diff --git a/lib/stringify.js b/lib/stringify.js index d4d7be65..34a78547 100644 --- a/lib/stringify.js +++ b/lib/stringify.js @@ -3,6 +3,7 @@ var getSideChannel = require('side-channel'); var utils = require('./utils'); var formats = require('./formats'); +var ValueError = require('./value-error'); var has = Object.prototype.hasOwnProperty; var arrayPrefixGenerators = { @@ -215,6 +216,10 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { throw new TypeError('Encoder has to be a function.'); } + if (opts.allowDots === true && opts.encodeDotInKeys === false) { + throw new ValueError('Provided combination is not valid: allowDots=true & encodeDotInKeys=false'); + } + var charset = opts.charset || defaults.charset; if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); diff --git a/lib/value-error.js b/lib/value-error.js new file mode 100644 index 00000000..26f1e5ed --- /dev/null +++ b/lib/value-error.js @@ -0,0 +1,9 @@ +'use strict'; + +var ValueError = function ValueError(message) { + var error = new Error(message); + error.name = 'ValueError'; + return error; +}; + +module.exports = ValueError; diff --git a/test/parse.js b/test/parse.js index 47cbc428..41ccffa3 100644 --- a/test/parse.js +++ b/test/parse.js @@ -82,11 +82,6 @@ test('parse()', function (t) { { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' }, 'with allowDots false and decodeDotInKeys false' ); - st.deepEqual( - qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: false, decodeDotInKeys: true }), - { 'name%2Eobj.first': 'John', 'name%2Eobj.last': 'Doe' }, - 'with allowDots false and decodeDotInKeys true' - ); st.deepEqual( qs.parse('name%252Eobj.first=John&name%252Eobj.last=Doe', { allowDots: true, decodeDotInKeys: false }), @@ -107,14 +102,6 @@ test('parse()', function (t) { { 'name%2Eobj%2Esubobject.first%2Egodly%2Ename': 'John', 'name%2Eobj%2Esubobject.last': 'Doe' }, 'with allowDots false and decodeDotInKeys false' ); - st.deepEqual( - qs.parse( - 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe', - { allowDots: false, decodeDotInKeys: true } - ), - { 'name%2Eobj%2Esubobject.first%2Egodly%2Ename': 'John', 'name%2Eobj%2Esubobject.last': 'Doe' }, - 'with allowDots false and decodeDotInKeys true' - ); st.deepEqual( qs.parse( 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe', @@ -135,7 +122,7 @@ test('parse()', function (t) { st.end(); }); - t.test('should throw when decodeDotKeys is not of type boolean', function (st) { + t.test('should throw when decodeDotInKeys is not of type boolean', function (st) { st['throws']( function () { qs.parse('foo[]&bar=baz', { decodeDotInKeys: 'foobar' }); }, TypeError @@ -158,6 +145,22 @@ test('parse()', function (t) { st.end(); }); + t.test('should throw when allowDots is false and decodeDotInKeys is true', function (st) { + st['throws']( + function () { + qs.parse( + 'name%252Eobj.first=John&name%252Eobj.last=Doe', + { allowDots: false, decodeDotInKeys: true } + ); + }, { + name: 'ValueError', + message: 'Provided combination is not valid: allowDots=false & decodeDotInKeys=true' + } + ); + + st.end(); + }); + t.test('allows empty arrays in obj values', function (st) { st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: true }), { foo: [], bar: 'baz' }); st.deepEqual(qs.parse('foo[]&bar=baz', { allowEmptyArrays: false }), { foo: [''], bar: 'baz' }); diff --git a/test/stringify.js b/test/stringify.js index 55eed2be..2ab9c3be 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -73,14 +73,6 @@ test('stringify()', function (t) { 'name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe', 'with allowDots false and encodeDotInKeys false' ); - st.equal( - qs.stringify( - { 'name.obj': { first: 'John', last: 'Doe' } }, - { allowDots: true, encodeDotInKeys: false } - ), - 'name.obj.first=John&name.obj.last=Doe', - 'with allowDots true and encodeDotInKeys false' - ); st.equal( qs.stringify( { 'name.obj': { first: 'John', last: 'Doe' } }, @@ -106,14 +98,6 @@ test('stringify()', function (t) { 'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe', 'with allowDots false and encodeDotInKeys false' ); - st.equal( - qs.stringify( - { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, - { allowDots: true, encodeDotInKeys: false } - ), - 'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe', - 'with allowDots true and encodeDotInKeys false' - ); st.equal( qs.stringify( { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, @@ -174,6 +158,22 @@ test('stringify()', function (t) { st.end(); }); + t.test('should throw when allowDots is true and encodeDotInKeys is false', function (st) { + st['throws']( + function () { + qs.stringify( + { 'name.obj': { first: 'John', last: 'Doe' } }, + { allowDots: true, encodeDotInKeys: false } + ); + }, { + message: 'Provided combination is not valid: allowDots=true & encodeDotInKeys=false', + name: 'ValueError' + } + ); + + st.end(); + }); + t.test('adds query prefix', function (st) { st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b'); st.end();