qs
Advanced tools
Comparing version 2.4.2 to 3.0.0
@@ -12,3 +12,4 @@ // Load modules | ||
arrayLimit: 20, | ||
parameterLimit: 1000 | ||
parameterLimit: 1000, | ||
strictNullHandling: false | ||
}; | ||
@@ -28,2 +29,6 @@ | ||
obj[Utils.decode(part)] = ''; | ||
if (options.strictNullHandling) { | ||
obj[Utils.decode(part)] = null; | ||
} | ||
} | ||
@@ -55,3 +60,3 @@ else { | ||
var obj = {}; | ||
var obj; | ||
if (root === '[]') { | ||
@@ -62,2 +67,3 @@ obj = []; | ||
else { | ||
obj = Object.create(null); | ||
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root; | ||
@@ -70,3 +76,4 @@ var index = parseInt(cleanRoot, 10); | ||
index >= 0 && | ||
index <= options.arrayLimit) { | ||
(options.parseArrays && | ||
index <= options.arrayLimit)) { | ||
@@ -91,2 +98,6 @@ obj = []; | ||
// Transform dot notation to bracket notation | ||
key = key.replace(/\.([^\.\[]+)/g, '[$1]'); | ||
// The regex chunks | ||
@@ -101,8 +112,2 @@ | ||
// Don't allow them to overwrite object prototype properties | ||
if (Object.prototype.hasOwnProperty(segment[1])) { | ||
return; | ||
} | ||
// Stash the parent if it exists | ||
@@ -121,5 +126,3 @@ | ||
++i; | ||
if (!Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { | ||
keys.push(segment[1]); | ||
} | ||
keys.push(segment[1]); | ||
} | ||
@@ -143,3 +146,3 @@ | ||
return {}; | ||
return Object.create(null); | ||
} | ||
@@ -151,6 +154,9 @@ | ||
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit; | ||
options.parseArrays = options.parseArrays !== false; | ||
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit; | ||
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling; | ||
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str; | ||
var obj = {}; | ||
var obj = Object.create(null); | ||
@@ -157,0 +163,0 @@ // Iterate over the keys and setup the new object |
@@ -12,17 +12,24 @@ // Load modules | ||
brackets: function (prefix, key) { | ||
return prefix + '[]'; | ||
}, | ||
indices: function (prefix, key) { | ||
return prefix + '[' + key + ']'; | ||
}, | ||
repeat: function (prefix, key) { | ||
return prefix; | ||
} | ||
} | ||
}, | ||
strictNullHandling: false | ||
}; | ||
internals.stringify = function (obj, prefix, generateArrayPrefix) { | ||
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, filter) { | ||
if (Utils.isBuffer(obj)) { | ||
if (typeof filter === 'function') { | ||
obj = filter(prefix, obj); | ||
} | ||
else if (Utils.isBuffer(obj)) { | ||
obj = obj.toString(); | ||
@@ -34,2 +41,6 @@ } | ||
else if (obj === null) { | ||
if (strictNullHandling) { | ||
return Utils.encode(prefix); | ||
} | ||
obj = ''; | ||
@@ -42,3 +53,3 @@ } | ||
return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)]; | ||
return [Utils.encode(prefix) + '=' + Utils.encode(obj)]; | ||
} | ||
@@ -52,10 +63,11 @@ | ||
var objKeys = Object.keys(obj); | ||
var objKeys = Array.isArray(filter) ? filter : Object.keys(obj); | ||
for (var i = 0, il = objKeys.length; i < il; ++i) { | ||
var key = objKeys[i]; | ||
if (Array.isArray(obj)) { | ||
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix)); | ||
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, filter)); | ||
} | ||
else { | ||
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix)); | ||
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, filter)); | ||
} | ||
@@ -72,2 +84,12 @@ } | ||
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter; | ||
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling; | ||
var objKeys; | ||
var filter; | ||
if (typeof options.filter === 'function') { | ||
filter = options.filter; | ||
obj = filter('', obj); | ||
} | ||
else if (Array.isArray(options.filter)) { | ||
objKeys = filter = options.filter; | ||
} | ||
@@ -95,6 +117,8 @@ var keys = []; | ||
var objKeys = Object.keys(obj); | ||
if (!objKeys) { | ||
objKeys = Object.keys(obj); | ||
} | ||
for (var i = 0, il = objKeys.length; i < il; ++i) { | ||
var key = objKeys[i]; | ||
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix)); | ||
keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix, strictNullHandling, filter)); | ||
} | ||
@@ -101,0 +125,0 @@ |
@@ -7,2 +7,6 @@ // Load modules | ||
var internals = {}; | ||
internals.hexTable = new Array(256); | ||
for (var i = 0; i < 256; ++i) { | ||
internals.hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); | ||
} | ||
@@ -12,3 +16,3 @@ | ||
var obj = {}; | ||
var obj = Object.create(null); | ||
for (var i = 0, il = source.length; i < il; ++i) { | ||
@@ -35,5 +39,8 @@ if (typeof source[i] !== 'undefined') { | ||
} | ||
else { | ||
else if (typeof target === 'object') { | ||
target[source] = true; | ||
} | ||
else { | ||
target = [target, source]; | ||
} | ||
@@ -80,3 +87,53 @@ return target; | ||
exports.encode = function (str) { | ||
// This code was originally written by Brian White (mscdex) for the io.js core querystring library. | ||
// It has been adapted here for stricter adherence to RFC 3986 | ||
if (str.length === 0) { | ||
return str; | ||
} | ||
if (typeof str !== 'string') { | ||
str = '' + str; | ||
} | ||
var out = ''; | ||
for (var i = 0, il = str.length; i < il; ++i) { | ||
var c = str.charCodeAt(i); | ||
if (c === 0x2D || // - | ||
c === 0x2E || // . | ||
c === 0x5F || // _ | ||
c === 0x7E || // ~ | ||
(c >= 0x30 && c <= 0x39) || // 0-9 | ||
(c >= 0x41 && c <= 0x5A) || // a-z | ||
(c >= 0x61 && c <= 0x7A)) { // A-Z | ||
out += str[i]; | ||
continue; | ||
} | ||
if (c < 0x80) { | ||
out += internals.hexTable[c]; | ||
continue; | ||
} | ||
if (c < 0x800) { | ||
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
continue; | ||
} | ||
if (c < 0xD800 || c >= 0xE000) { | ||
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
continue; | ||
} | ||
++i; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF)); | ||
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
} | ||
return out; | ||
}; | ||
exports.compact = function (obj, refs) { | ||
@@ -121,2 +178,3 @@ | ||
exports.isRegExp = function (obj) { | ||
return Object.prototype.toString.call(obj) === '[object RegExp]'; | ||
@@ -135,4 +193,4 @@ }; | ||
return !!(obj.constructor && | ||
obj.constructor.isBuffer && | ||
obj.constructor.isBuffer(obj)); | ||
obj.constructor.isBuffer && | ||
obj.constructor.isBuffer(obj)); | ||
}; |
{ | ||
"name": "qs", | ||
"version": "2.4.2", | ||
"version": "3.0.0", | ||
"description": "A querystring parser that supports nesting and arrays, with a depth limit", | ||
@@ -9,2 +9,3 @@ "homepage": "https://github.com/hapijs/qs", | ||
"devDependencies": { | ||
"browserify": "^10.2.1", | ||
"code": "1.x.x", | ||
@@ -14,3 +15,4 @@ "lab": "5.x.x" | ||
"scripts": { | ||
"test": "make test-cov" | ||
"test": "make test-cov", | ||
"dist": "browserify --standalone Qs index.js > dist/qs.js" | ||
}, | ||
@@ -25,8 +27,3 @@ "repository": { | ||
], | ||
"licenses": [ | ||
{ | ||
"type": "BSD", | ||
"url": "http://github.com/hapijs/qs/raw/master/LICENSE" | ||
} | ||
] | ||
"license": "BSD-3-Clause" | ||
} |
@@ -26,3 +26,3 @@ # qs | ||
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`. | ||
**qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`, or prefixing the sub-key with a dot `.`. | ||
For example, the string `'foo[bar]=baz'` converts to: | ||
@@ -38,2 +38,9 @@ | ||
The parsed value is returned as a plain object, created via `Object.create(null)` and as such you should be aware that prototype methods do not exist on it and a user may set those names to whatever value they like: | ||
```javascript | ||
Qs.parse('a.hasOwnProperty=b'); | ||
// { a: { hasOwnProperty: 'b' } } | ||
``` | ||
URI encoded strings work too: | ||
@@ -158,4 +165,9 @@ | ||
To disable array parsing entirely, set `arrayLimit` to `-1`. | ||
To disable array parsing entirely, set `parseArrays` to `false`. | ||
```javascript | ||
Qs.parse('a[]=b', { parseArrays: false }); | ||
// { a: { '0': 'b' } } | ||
``` | ||
If you mix notations, **qs** will merge the two items into an object: | ||
@@ -237,1 +249,59 @@ | ||
``` | ||
Finally, you can use the `filter` option to restrict which keys will be included in the stringified output. | ||
If you pass a function, it will be called for each key to obtain the replacement value. Otherwise, if you | ||
pass an array, it will be used to select properties and array indices for stringification: | ||
```javascript | ||
function filterFunc(prefix, value) { | ||
if (prefix == 'b') { | ||
// Return an `undefined` value to omit a property. | ||
return; | ||
} | ||
if (prefix == 'e[f]') { | ||
return value.getTime(); | ||
} | ||
if (prefix == 'e[g][0]') { | ||
return value * 2; | ||
} | ||
return value; | ||
} | ||
Qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc }) | ||
// 'a=b&c=d&e[f]=123&e[g][0]=4' | ||
Qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] }) | ||
// 'a=b&e=f' | ||
Qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] }) | ||
// 'a[0]=b&a[2]=d' | ||
``` | ||
### Handling of `null` values | ||
By default, `null` values are treated like empty strings: | ||
```javascript | ||
Qs.stringify({ a: null, b: '' }); | ||
// 'a=&b=' | ||
``` | ||
Parsing does not distinguish between parameters with and without equal signs. Both are converted to empty strings. | ||
```javascript | ||
Qs.parse('a&b=') | ||
// { a: '', b: '' } | ||
``` | ||
To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null` | ||
values have no `=` sign: | ||
```javascript | ||
Qs.stringify({ a: null, b: '' }, { strictNullHandling: true }); | ||
// 'a&b=' | ||
``` | ||
To parse values without `=` back to `null` use the `strictNullHandling` flag: | ||
```javascript | ||
Qs.parse('a&b=', { strictNullHandling: true }); | ||
// { a: null, b: '' } | ||
``` |
@@ -26,13 +26,17 @@ /* eslint no-extend-native:0 */ | ||
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' }); | ||
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' }); | ||
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } }); | ||
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } }); | ||
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } }); | ||
expect(Qs.parse('foo')).to.deep.equal({ foo: '' }); | ||
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' }); | ||
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' }); | ||
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' }); | ||
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' }); | ||
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' }); | ||
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' }, { prototype: false }); | ||
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' }, { prototype: false }); | ||
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } }, { prototype: false }); | ||
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } }, { prototype: false }); | ||
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } }, { prototype: false }); | ||
expect(Qs.parse('foo', {strictNullHandling: true})).to.deep.equal({ foo: null }, { prototype: false }); | ||
expect(Qs.parse('foo' )).to.deep.equal({ foo: '' }, { prototype: false }); | ||
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' }, { prototype: false }); | ||
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' }, { prototype: false }); | ||
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' }, { prototype: false }); | ||
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' }, { prototype: false }); | ||
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' }, { prototype: false }); | ||
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' }, { prototype: false }); | ||
expect(Qs.parse('foo=bar&baz', {strictNullHandling: true})).to.deep.equal({ foo: 'bar', baz: null }, { prototype: false }); | ||
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' }, { prototype: false }); | ||
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({ | ||
@@ -43,3 +47,3 @@ cht: 'p3', | ||
chl: 'Hello|World' | ||
}); | ||
}, { prototype: false }); | ||
done(); | ||
@@ -50,3 +54,3 @@ }); | ||
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } }); | ||
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } }, { prototype: false }); | ||
done(); | ||
@@ -57,3 +61,3 @@ }); | ||
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } }); | ||
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } }, { prototype: false }); | ||
done(); | ||
@@ -64,3 +68,3 @@ }); | ||
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }); | ||
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }, { prototype: false }); | ||
done(); | ||
@@ -71,4 +75,4 @@ }); | ||
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } }); | ||
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } }); | ||
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } }, { prototype: false }); | ||
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } }, { prototype: false }); | ||
done(); | ||
@@ -79,3 +83,3 @@ }); | ||
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
done(); | ||
@@ -86,5 +90,5 @@ }); | ||
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] }); | ||
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }); | ||
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] }, { prototype: false }); | ||
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }, { prototype: false }); | ||
done(); | ||
@@ -95,8 +99,8 @@ }); | ||
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
done(); | ||
@@ -107,4 +111,4 @@ }); | ||
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } }); | ||
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } }); | ||
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } }, { prototype: false }); | ||
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } }, { prototype: false }); | ||
done(); | ||
@@ -115,5 +119,5 @@ }); | ||
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }); | ||
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] }); | ||
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }, { prototype: false }); | ||
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] }, { prototype: false }); | ||
done(); | ||
@@ -124,4 +128,4 @@ }); | ||
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] }); | ||
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } }); | ||
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] }, { prototype: false }); | ||
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } }, { prototype: false }); | ||
done(); | ||
@@ -132,3 +136,3 @@ }); | ||
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } }); | ||
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } }, { prototype: false }); | ||
done(); | ||
@@ -139,3 +143,3 @@ }); | ||
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' }); | ||
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' }, { prototype: false }); | ||
done(); | ||
@@ -146,4 +150,4 @@ }); | ||
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } }); | ||
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } }); | ||
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } }, { prototype: false }); | ||
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } }, { prototype: false }); | ||
done(); | ||
@@ -154,4 +158,4 @@ }); | ||
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' }); | ||
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' }); | ||
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' }, { prototype: false }); | ||
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' }, { prototype: false }); | ||
done(); | ||
@@ -162,5 +166,5 @@ }); | ||
expect(Qs.parse('')).to.deep.equal({}); | ||
expect(Qs.parse(null)).to.deep.equal({}); | ||
expect(Qs.parse(undefined)).to.deep.equal({}); | ||
expect(Qs.parse('')).to.deep.equal({}, { prototype: false }); | ||
expect(Qs.parse(null)).to.deep.equal({}, { prototype: false }); | ||
expect(Qs.parse(undefined)).to.deep.equal({}, { prototype: false }); | ||
done(); | ||
@@ -171,14 +175,31 @@ }); | ||
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }); | ||
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]}); | ||
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false }); | ||
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false }); | ||
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }, { prototype: false }); | ||
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]}, { prototype: false }); | ||
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', hasOwnProperty: 'c' } }, { prototype: false }); | ||
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', hasOwnProperty: 'c', x: 'y' } }, { prototype: false }); | ||
done(); | ||
}); | ||
it('transforms arrays to objects (dot notation)', function (done) { | ||
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [ { baz: 'bar'} ], fool: { bad: 'baz' } }, { prototype: false }); | ||
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz')).to.deep.equal({ foo: [ { baz: 'bar'} ], fool: { bad: { boo: 'baz' } } }, { prototype: false }); | ||
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz')).to.deep.equal({ foo: [[ { baz: 'bar'} ]], fool: { bad: 'baz' } }, { prototype: false }); | ||
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] }, { prototype: false }); | ||
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2')).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] }, { prototype: false }); | ||
expect(Qs.parse('foo.bad=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false }); | ||
expect(Qs.parse('foo.bad=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }, { prototype: false }); | ||
expect(Qs.parse('foo[]=bar&foo.bad=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }, { prototype: false }); | ||
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }, { prototype: false }); | ||
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]}, { prototype: false }); | ||
done(); | ||
}); | ||
it('can add keys to objects', function (done) { | ||
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } }); | ||
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } }, { prototype: false }); | ||
done(); | ||
@@ -189,3 +210,3 @@ }); | ||
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } }); | ||
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } }, { prototype: false }); | ||
done(); | ||
@@ -196,4 +217,5 @@ }); | ||
expect(Qs.parse('{%:%}')).to.deep.equal({ '{%:%}': '' }); | ||
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' }); | ||
expect(Qs.parse('{%:%}', {strictNullHandling: true})).to.deep.equal({ '{%:%}': null }, { prototype: false }); | ||
expect(Qs.parse('{%:%}=')).to.deep.equal({ '{%:%}': '' }, { prototype: false }); | ||
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' }, { prototype: false }); | ||
done(); | ||
@@ -204,16 +226,6 @@ }); | ||
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' }); | ||
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' }, { prototype: false }); | ||
done(); | ||
}); | ||
it('cannot override prototypes', function (done) { | ||
var obj = Qs.parse('hasOwnProperty=bad&toString=bad&bad[toString]=bad&constructor=bad'); | ||
expect(typeof obj.toString).to.equal('function'); | ||
expect(typeof obj.bad.toString).to.equal('function'); | ||
expect(typeof obj.constructor).to.equal('function'); | ||
expect(typeof obj.hasOwnProperty).to.equal('function'); | ||
done(); | ||
}); | ||
it('cannot access Object prototype', function (done) { | ||
@@ -229,4 +241,4 @@ | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false }); | ||
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false }); | ||
done(); | ||
@@ -237,5 +249,6 @@ }); | ||
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] }); | ||
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]=')).to.deep.equal({ a: ['b', '', 'c', ''] }); | ||
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] }); | ||
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] }, { prototype: false }); | ||
expect(Qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', {strictNullHandling: true})).to.deep.equal({ a: ['b', null, 'c', ''] }, { prototype: false }); | ||
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', {strictNullHandling: true})).to.deep.equal({ a: ['b', '', 'c', null] }, { prototype: false }); | ||
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] }, { prototype: false }); | ||
done(); | ||
@@ -246,3 +259,3 @@ }); | ||
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] }); | ||
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] }, { prototype: false }); | ||
done(); | ||
@@ -253,4 +266,4 @@ }); | ||
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } }); | ||
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } }); | ||
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } }, { prototype: false }); | ||
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } }, { prototype: false }); | ||
done(); | ||
@@ -262,3 +275,3 @@ }); | ||
var b = new Buffer('test'); | ||
expect(Qs.parse({ a: b })).to.deep.equal({ a: b }); | ||
expect(Qs.parse({ a: b })).to.deep.equal({ a: b }, { prototype: false }); | ||
done(); | ||
@@ -269,4 +282,5 @@ }); | ||
expect(Qs.parse('[]&a=b')).to.deep.equal({ '0': '', a: 'b' }); | ||
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' }); | ||
expect(Qs.parse('[]=&a=b')).to.deep.equal({ '0': '', a: 'b' }, { prototype: false }); | ||
expect(Qs.parse('[]&a=b', {strictNullHandling: true})).to.deep.equal({ '0': null, a: 'b' }, { prototype: false }); | ||
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' }, { prototype: false }); | ||
done(); | ||
@@ -295,5 +309,5 @@ }); | ||
expect(Qs.parse.bind(null, 'a=b')).to.not.throw(); | ||
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' }); | ||
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' }, { prototype: false }); | ||
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw(); | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }, { prototype: false }); | ||
delete Object.prototype.crash; | ||
@@ -306,3 +320,3 @@ delete Array.prototype.crash; | ||
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' }); | ||
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false }); | ||
done(); | ||
@@ -313,3 +327,3 @@ }); | ||
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' }); | ||
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false }); | ||
done(); | ||
@@ -320,3 +334,3 @@ }); | ||
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' }); | ||
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false }); | ||
done(); | ||
@@ -327,3 +341,3 @@ }); | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' }); | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' }, { prototype: false }); | ||
done(); | ||
@@ -334,3 +348,3 @@ }); | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' }); | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false }); | ||
done(); | ||
@@ -341,8 +355,14 @@ }); | ||
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } }); | ||
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } }); | ||
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }); | ||
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } }, { prototype: false }); | ||
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } }, { prototype: false }); | ||
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }, { prototype: false }); | ||
done(); | ||
}); | ||
it('allows disabling array parsing', function (done) { | ||
expect(Qs.parse('a[0]=b&a[1]=c', { parseArrays: false })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }, { prototype: false }); | ||
done(); | ||
}); | ||
it('parses an object', function (done) { | ||
@@ -364,6 +384,26 @@ | ||
expect(result).to.deep.equal(expected); | ||
expect(result).to.deep.equal(expected, { prototype: false }); | ||
done(); | ||
}); | ||
it('parses an object in dot notation', function (done) { | ||
var input = { | ||
'user.name': {'pop[bob]': 3}, | ||
'user.email.': null | ||
}; | ||
var expected = { | ||
'user': { | ||
'name': {'pop[bob]': 3}, | ||
'email': null | ||
} | ||
}; | ||
var result = Qs.parse(input); | ||
expect(result).to.deep.equal(expected, { prototype: false }); | ||
done(); | ||
}); | ||
it('parses an object and not child values', function (done) { | ||
@@ -385,3 +425,3 @@ | ||
expect(result).to.deep.equal(expected); | ||
expect(result).to.deep.equal(expected, { prototype: false }); | ||
done(); | ||
@@ -396,12 +436,6 @@ }); | ||
global.Buffer = tempBuffer; | ||
expect(result).to.deep.equal({ a: 'b', c: 'd' }); | ||
expect(result).to.deep.equal({ a: 'b', c: 'd' }, { prototype: false }); | ||
done(); | ||
}); | ||
it('does not crash when using invalid dot notation', function (done) { | ||
expect(Qs.parse('roomInfoList[0].childrenAges[0]=15&roomInfoList[0].numberOfAdults=2')).to.deep.equal({ roomInfoList: [['15', '2']] }); | ||
done(); | ||
}); | ||
it('does not crash when parsing circular references', function (done) { | ||
@@ -422,3 +456,3 @@ | ||
expect(parsed.foo.bar).to.equal('baz'); | ||
expect(parsed.foo.baz).to.deep.equal(a); | ||
expect(parsed.foo.baz).to.deep.equal(a, { prototype: false }); | ||
done(); | ||
@@ -432,6 +466,6 @@ }); | ||
expect(Qs.parse(a)).to.deep.equal({ b: 'c' }); | ||
expect(Qs.parse(a)).to.deep.equal({ b: 'c' }, { prototype: false }); | ||
var result = Qs.parse({ a: a }); | ||
expect(result).to.contain('a'); | ||
expect(result.a).to.deep.equal(a); | ||
expect(result.a).to.deep.equal(a, { prototype: false }); | ||
done(); | ||
@@ -443,3 +477,3 @@ }); | ||
var now = new Date(); | ||
expect(Qs.parse({ a: now })).to.deep.equal({ a: now }); | ||
expect(Qs.parse({ a: now })).to.deep.equal({ a: now }, { prototype: false }); | ||
done(); | ||
@@ -451,5 +485,5 @@ }); | ||
var re = /^test$/; | ||
expect(Qs.parse({ a: re })).to.deep.equal({ a: re }); | ||
expect(Qs.parse({ a: re })).to.deep.equal({ a: re }, { prototype: false }); | ||
done(); | ||
}); | ||
}); |
@@ -29,2 +29,7 @@ /* eslint no-extend-native:0 */ | ||
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2'); | ||
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z'); | ||
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC'); | ||
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80'); | ||
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90'); | ||
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7'); | ||
done(); | ||
@@ -110,5 +115,11 @@ }); | ||
expect(Qs.stringify({ a: '' })).to.equal('a='); | ||
expect(Qs.stringify({ a: null }, {strictNullHandling: true})).to.equal('a'); | ||
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b='); | ||
expect(Qs.stringify({ a: null })).to.equal('a='); | ||
expect(Qs.stringify({ a: { b: null } })).to.equal('a%5Bb%5D='); | ||
expect(Qs.stringify({ a: null, b: '' }, {strictNullHandling: true})).to.equal('a&b='); | ||
expect(Qs.stringify({ a: { b: '' } })).to.equal('a%5Bb%5D='); | ||
expect(Qs.stringify({ a: { b: null } }, {strictNullHandling: true})).to.equal('a%5Bb%5D'); | ||
expect(Qs.stringify({ a: { b: null } }, {strictNullHandling: false})).to.equal('a%5Bb%5D='); | ||
done(); | ||
@@ -148,3 +159,6 @@ }); | ||
expect(Qs.stringify({ a: undefined })).to.equal(''); | ||
expect(Qs.stringify({ a: { b: undefined, c: null } })).to.equal('a%5Bc%5D='); | ||
expect(Qs.stringify({ a: { b: undefined, c: null } }, {strictNullHandling: true})).to.equal('a%5Bc%5D'); | ||
expect(Qs.stringify({ a: { b: undefined, c: null } }, {strictNullHandling: false})).to.equal('a%5Bc%5D='); | ||
expect(Qs.stringify({ a: { b: undefined, c: '' } })).to.equal('a%5Bc%5D='); | ||
done(); | ||
@@ -169,3 +183,3 @@ }); | ||
expect(Qs.stringify({ 'my weird field': 'q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F'); | ||
expect(Qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F'); | ||
done(); | ||
@@ -213,2 +227,38 @@ }); | ||
}); | ||
it('selects properties when filter=array', function (done) { | ||
expect(Qs.stringify({ a: 'b' }, { filter: ['a'] })).to.equal('a=b'); | ||
expect(Qs.stringify({ a: 1}, { filter: [] })).to.equal(''); | ||
expect(Qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2]})).to.equal('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3'); | ||
done(); | ||
}); | ||
it('supports custom representations when filter=function', function (done) { | ||
var calls = 0; | ||
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } }; | ||
var filterFunc = function (prefix, value) { | ||
calls++; | ||
if (calls === 1) { | ||
expect(prefix).to.be.empty(); | ||
expect(value).to.equal(obj); | ||
} | ||
else if (prefix === 'c') { | ||
return; | ||
} | ||
else if (value instanceof Date) { | ||
expect(prefix).to.equal('e[f]'); | ||
return value.getTime(); | ||
} | ||
return value; | ||
}; | ||
expect(Qs.stringify(obj, { filter: filterFunc })).to.equal('a=b&e%5Bf%5D=1257894000000'); | ||
expect(calls).to.equal(5); | ||
done(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
54302
19
913
304
3