From a6920de6c76e1a8a1b394d8ff5a2a34484531c59 Mon Sep 17 00:00:00 2001 From: dfadler Date: Thu, 24 Apr 2014 10:21:18 -0700 Subject: [PATCH 1/3] Fixes issues that caused IE7/8 to fail --- index.js | 8 +- test/browser/qs.js | 68 ++++++++- test/parse.js | 44 +++--- test/stringify.js | 374 ++++++++++++++++++++++----------------------- 4 files changed, 280 insertions(+), 214 deletions(-) diff --git a/index.js b/index.js index fba2fb2..27d0969 100644 --- a/index.js +++ b/index.js @@ -17,6 +17,9 @@ var hasOwnProperty = Object.prototype.hasOwnProperty; var indexOf = typeof Array.prototype.indexOf === 'function' ? function(arr, el) { return arr.indexOf(el); } : function(arr, el) { + if (!isArray(arr)) { + arr = arr.split(''); + } for (var i = 0; i < arr.length; i++) { if (arr[i] === el) return i; } @@ -341,6 +344,9 @@ function lastBraceInKey(str) { var len = str.length , brace , c; + if (!isArray(str)) { + str = str.split(''); + } for (var i = 0; i < len; ++i) { c = str[i]; if (']' == c) brace = false; @@ -363,4 +369,4 @@ function decode(str) { } catch (err) { return str; } -} +} \ No newline at end of file diff --git a/test/browser/qs.js b/test/browser/qs.js index ccd9a9c..5ed0f5d 100644 --- a/test/browser/qs.js +++ b/test/browser/qs.js @@ -102,6 +102,12 @@ require.register("querystring", function(module, exports, require){ var toString = Object.prototype.toString; +/** + * Object#hasOwnProperty ref + */ + +var hasOwnProperty = Object.prototype.hasOwnProperty; + /** * Array#indexOf shim. */ @@ -109,6 +115,9 @@ var toString = Object.prototype.toString; var indexOf = typeof Array.prototype.indexOf === 'function' ? function(arr, el) { return arr.indexOf(el); } : function(arr, el) { + if (!isArray(arr)) { + arr = arr.split(''); + } for (var i = 0; i < arr.length; i++) { if (arr[i] === el) return i; } @@ -129,7 +138,11 @@ var isArray = Array.isArray || function(arr) { var objectKeys = Object.keys || function(obj) { var ret = []; - for (var key in obj) ret.push(key); + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + ret.push(key); + } + } return ret; }; @@ -161,15 +174,23 @@ var reduce = function(arr, fn, initial) { var isint = /^[0-9]+$/; function promote(parent, key) { - if (parent[key].length == 0) return parent[key] = {}; + if (parent[key].length == 0) return parent[key] = {} var t = {}; - for (var i in parent[key]) t[i] = parent[key][i]; + for (var i in parent[key]) { + if (hasOwnProperty.call(parent[key], i)) { + t[i] = parent[key][i]; + } + } parent[key] = t; return t; } function parse(parts, parent, key, val) { var part = parts.shift(); + + // illegal + if (hasOwnProperty.call(Object.prototype, key)) return; + // end if (!part) { if (isArray(parent[key])) { @@ -228,16 +249,44 @@ function merge(parent, key, val){ return parent; } +/** + * Compact sparse arrays. + */ + +function compact(obj) { + if ('object' != typeof obj) return obj; + + if (isArray(obj)) { + var ret = []; + + for (var i in obj) { + if (hasOwnProperty.call(obj, i)) { + ret.push(obj[i]); + } + } + + return ret; + } + + for (var key in obj) { + obj[key] = compact(obj[key]); + } + + return obj; +} + /** * Parse the given obj. */ function parseObject(obj){ var ret = { base: {} }; + forEach(objectKeys(obj), function(name){ merge(ret, name, obj[name]); }); - return ret.base; + + return compact(ret.base); } /** @@ -245,7 +294,7 @@ function parseObject(obj){ */ function parseString(str){ - return reduce(String(str).split('&'), function(ret, pair){ + var ret = reduce(String(str).split('&'), function(ret, pair){ var eql = indexOf(pair, '=') , brace = lastBraceInKey(pair) , key = pair.substr(0, brace || eql) @@ -258,6 +307,8 @@ function parseString(str){ return merge(ret, decode(key), decode(val)); }, { base: {} }).base; + + return compact(ret); } /** @@ -343,6 +394,7 @@ function stringifyObject(obj, prefix) { for (var i = 0, len = keys.length; i < len; ++i) { key = keys[i]; + if ('' == key) continue; if (null == obj[key]) { ret.push(encodeURIComponent(key) + '='); } else { @@ -368,6 +420,7 @@ function stringifyObject(obj, prefix) { function set(obj, key, val) { var v = obj[key]; + if (hasOwnProperty.call(Object.prototype, key)) return; if (undefined === v) { obj[key] = val; } else if (isArray(v)) { @@ -389,6 +442,9 @@ function lastBraceInKey(str) { var len = str.length , brace , c; + if (!isArray(str)) { + str = str.split(''); + } for (var i = 0; i < len; ++i) { c = str[i]; if (']' == c) brace = false; @@ -413,4 +469,4 @@ function decode(str) { } } })(); -}); +}); \ No newline at end of file diff --git a/test/parse.js b/test/parse.js index acc816f..ebfba68 100644 --- a/test/parse.js +++ b/test/parse.js @@ -51,12 +51,12 @@ describe('qs.parse()', function(){ , chs: '250x100' , chl: 'Hello|World' }); - }) + }); it('should support encoded = signs', function(){ expect(qs.parse('he%3Dllo=th%3Dere')) .to.eql({ 'he=llo': 'th=ere' }); - }) + }); it('should support nesting', function(){ expect(qs.parse('ops[>=]=25')) @@ -67,7 +67,7 @@ describe('qs.parse()', function(){ expect(qs.parse('user[name][first]=tj&user[name][last]=holowaychuk')) .to.eql({ user: { name: { first: 'tj', last: 'holowaychuk' }}}); - }) + }); it('should support array notation', function(){ expect(qs.parse('images[]')) @@ -94,22 +94,26 @@ describe('qs.parse()', function(){ expect(qs.parse('user[name][first]=tj&user[name][first]=TJ')) .to.eql({ user: { name: { first: ['tj', 'TJ'] }}}); - var o = qs.parse('existing[fcbaebfecc][name][last]=tj') - expect(o).to.eql({ existing: { 'fcbaebfecc': { name: { last: 'tj' }}}}) - expect(Array.isArray(o.existing)).to.equal(false); - }) + var o = qs.parse('existing[fcbaebfecc][name][last]=tj'); + expect(o).to.eql({ existing: { 'fcbaebfecc': { name: { last: 'tj' }}}}); + + if(Array.isArray) { + expect(Array.isArray(o.existing)).to.equal(false); + } + + }); it('should support arrays with indexes', function(){ expect(qs.parse('foo[0]=bar&foo[1]=baz')).to.eql({ foo: ['bar', 'baz'] }); expect(qs.parse('foo[1]=bar&foo[0]=baz')).to.eql({ foo: ['baz', 'bar'] }); expect(qs.parse('foo[base64]=RAWR')).to.eql({ foo: { base64: 'RAWR' }}); expect(qs.parse('foo[64base]=RAWR')).to.eql({ foo: { '64base': 'RAWR' }}); - }) + }); it('should expand to an array when dupliate keys are present', function(){ expect(qs.parse('items=bar&items=baz&items=raz')) .to.eql({ items: ['bar', 'baz', 'raz'] }); - }) + }); it('should support right-hand side brackets', function(){ expect(qs.parse('pets=["tobi"]')) @@ -123,23 +127,23 @@ describe('qs.parse()', function(){ expect(qs.parse('op[>=]=[1,2,3]&op[=]=[[[[1]]]]')) .to.eql({ op: { '>=': '[1,2,3]', '=': '[[[[1]]]]' }}); - }) + }); it('should support empty values', function(){ expect(qs.parse('')).to.eql({}); expect(qs.parse(undefined)).to.eql({}); expect(qs.parse(null)).to.eql({}); - }) + }); it('should transform arrays to objects', function(){ expect(qs.parse('foo[0]=bar&foo[bad]=baz')).to.eql({ foo: { 0: "bar", bad: "baz" }}); expect(qs.parse('foo[bad]=baz&foo[0]=bar')).to.eql({ foo: { 0: "bar", bad: "baz" }}); - }) + }); it('should support malformed uri chars', function(){ expect(qs.parse('{%:%}')).to.eql({ '{%:%}': '' }); expect(qs.parse('foo=%:%}')).to.eql({ 'foo': '%:%}' }); - }) + }); it('should support semi-parsed strings', function(){ expect(qs.parse({ 'user[name]': 'tobi' })) @@ -147,25 +151,25 @@ describe('qs.parse()', function(){ expect(qs.parse({ 'user[name]': 'tobi', 'user[email][main]': 'tobi@lb.com' })) .to.eql({ user: { name: 'tobi', email: { main: 'tobi@lb.com' } }}); - }) + }); it('should not produce empty keys', function(){ expect(qs.parse('_r=1&')) - .to.eql({ _r: '1' }) - }) + .to.eql({ _r: '1' }); + }); it('should not create big arrays of null objects', function(){ var q = qs.parse('a[999999999]=1&a[2]=2'); expect(q['a'].length).to.eql(2); expect(q).to.eql({ a: ['2', '1'] }); - }) + }); it('should not be able to override prototypes', function(){ var obj = qs.parse('toString=bad&bad[toString]=bad&constructor=bad'); expect(obj.toString).to.be.a(Function); expect(obj.bad.toString).to.be.a(Function); expect(obj.constructor).to.be.a(Function); - }) + }); it('should not be possible to access Object prototype', function() { qs.parse('constructor[prototype][bad]=bad'); @@ -176,5 +180,5 @@ describe('qs.parse()', function(){ it('should not throw when a native prototype has an enumerable property', function() { Object.prototype.crash = ''; expect(qs.parse.bind(null, 'test')).to.not.throwException(); - }) -}) + }); +}); diff --git a/test/stringify.js b/test/stringify.js index c1c28ac..86285db 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -12,229 +12,229 @@ describe('qs.stringify', function(){ expect(qs.stringify({ 'foo': 'bar' })).to.eql('foo=bar'); }); - it('should stringify a pair of string parameters delimited by &', function() { - expect(qs.stringify({'foo' : 'bar', 'bar' : 'baz'})).to.eql('foo=bar&bar=baz'); - }); - - it('should stringify and excaped char', function(){ - expect(qs.stringify({'foo' : '\"bar\"'})).to.eql('foo=%22bar%22'); - }); - - it('should stringify to empty string if a value is missing', function() { - expect(qs.stringify({foo:''})).to.eql('foo='); - }); - - it('should stringify numeric values to strings', function() { - expect(qs.stringify({'foo' : '1', 'bar' : '2'})).to.eql('foo=1&bar=2'); - }); + it('should stringify a pair of string parameters delimited by &', function() { + expect(qs.stringify({'foo' : 'bar', 'bar' : 'baz'})).to.eql('foo=bar&bar=baz'); + }); + + it('should stringify and excaped char', function(){ + expect(qs.stringify({'foo' : '\"bar\"'})).to.eql('foo=%22bar%22'); + }); + + it('should stringify to empty string if a value is missing', function() { + expect(qs.stringify({foo:''})).to.eql('foo='); + }); + + it('should stringify numeric values to strings', function() { + expect(qs.stringify({'foo' : '1', 'bar' : '2'})).to.eql('foo=1&bar=2'); + }); - it('should stringify that weird field', function(){ - expect(qs.stringify({'my weird field': "q1!2\"'w$5&7/z8)?"})).to.eql('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F'); - }); + it('should stringify that weird field', function(){ + expect(qs.stringify({'my weird field': "q1!2\"'w$5&7/z8)?"})).to.eql('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F'); + }); - it('should strigify a key name=name', function() { - expect(qs.stringify({'foo=baz': 'bar'})).to.eql('foo%3Dbaz=bar'); - }); + it('should strigify a key name=name', function() { + expect(qs.stringify({'foo=baz': 'bar'})).to.eql('foo%3Dbaz=bar'); + }); - it('should stringify a object with 2 properties', function() { - expect(qs.stringify({foo: 'bar', bar: 'baz'})).to.eql('foo=bar&bar=baz'); - }); + it('should stringify a object with 2 properties', function() { + expect(qs.stringify({foo: 'bar', bar: 'baz'})).to.eql('foo=bar&bar=baz'); + }); - it('should strigify two empty values to not undefined', function() { - expect(qs.stringify({ foo: 'bar', baz: '', raz: '' })).to.eql('foo=bar&baz=&raz='); - }); + it('should strigify two empty values to not undefined', function() { + expect(qs.stringify({ foo: 'bar', baz: '', raz: '' })).to.eql('foo=bar&baz=&raz='); + }); }); describe('escaping', function(){ - it('should work with escaping html entities in the value', function(){ - expect(qs.stringify({foo: 'foo bar'})).to.eql('foo=foo%20bar'); - }); - - it('should work with different forms of escaping html entities', function(){ - expect(qs.stringify({ - cht: 'p3' - , chd: 't:60,40' - , chs: '250x100' - , chl: 'Hello|World' - })).to.eql('cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld'); - }); - }); - - describe('nested', function(){ - - it('should work with a simple array with one value', function(){ - var str = 'foo[0]=bar'; - var obj = {'foo' : ['bar']}; - expect(qs.stringify(obj)).to.eql(str); - }); + it('should work with escaping html entities in the value', function(){ + expect(qs.stringify({foo: 'foo bar'})).to.eql('foo=foo%20bar'); + }); + + it('should work with different forms of escaping html entities', function(){ + expect(qs.stringify({ + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + })).to.eql('cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld'); + }); + }); + + describe('nested', function(){ + + it('should work with a simple array with one value', function(){ + var str = 'foo[0]=bar'; + var obj = {'foo' : ['bar']}; + expect(qs.stringify(obj)).to.eql(str); + }); - it('should work with a simple array with two values', function(){ - var str = 'foo[0]=bar&foo[1]=quux'; - var obj = {'foo' : ['bar', 'quux']}; - expect(qs.stringify(obj)).to.eql(str); - }); + it('should work with a simple array with two values', function(){ + var str = 'foo[0]=bar&foo[1]=quux'; + var obj = {'foo' : ['bar', 'quux']}; + expect(qs.stringify(obj)).to.eql(str); + }); - it('should work with a simple array with two numeric values', function(){ - var str = 'foo[0]=0&foo[1]=1'; - var obj = {'foo' : ['0', '1']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array and a object', function(){ - var str = 'foo=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : 'bar', 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array containing string values and a array containing numeric values', function(){ - var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array containing string values and a array containing numeric values', function(){ - var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a double nested array with string keys and a third level with a numeric key', function(){ - var str = 'x[y][z][0]=1'; - var obj = {'x' : {'y' : {'z' : ['1']}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a nested array in string with string keys and a numeric value of 1', function(){ - var str = 'x[y][z]=1'; - var obj = {'x' : {'y' : {'z' : '1'}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a nested array in string with string keys and a numeric value of 2', function(){ - var str = 'x[y][z]=2'; - var obj = {'x' : {'y' : {'z' : '2'}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with array in double nesting', function(){ - var str = 'x[y][z][0]=1&x[y][z][1]=2'; - var obj = {'x' : {'y' : {'z' : ['1', '2']}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object nesting', function(){ - var str = 'x[y][0][z]=1'; - var obj = {'x' : {'y' : [{'z' : '1'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for 2 objects nested with an array', function(){ - var str = 'x[y][0][z]=1&x[y][0][w]=2'; - var obj = {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - - it('should work for object, array, object nesting', function(){ + it('should work with a simple array with two numeric values', function(){ + var str = 'foo[0]=0&foo[1]=1'; + var obj = {'foo' : ['0', '1']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array and a object', function(){ + var str = 'foo=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : 'bar', 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array containing string values and a array containing numeric values', function(){ + var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array containing string values and a array containing numeric values', function(){ + var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a double nested array with string keys and a third level with a numeric key', function(){ + var str = 'x[y][z][0]=1'; + var obj = {'x' : {'y' : {'z' : ['1']}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a nested array in string with string keys and a numeric value of 1', function(){ + var str = 'x[y][z]=1'; + var obj = {'x' : {'y' : {'z' : '1'}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a nested array in string with string keys and a numeric value of 2', function(){ + var str = 'x[y][z]=2'; + var obj = {'x' : {'y' : {'z' : '2'}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with array in double nesting', function(){ + var str = 'x[y][z][0]=1&x[y][z][1]=2'; + var obj = {'x' : {'y' : {'z' : ['1', '2']}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object nesting', function(){ + var str = 'x[y][0][z]=1'; + var obj = {'x' : {'y' : [{'z' : '1'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for 2 objects nested with an array', function(){ + var str = 'x[y][0][z]=1&x[y][0][w]=2'; + var obj = {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + + it('should work for object, array, object nesting', function(){ var str = 'x[y][0][v][w]=1'; var obj = {'x' : {'y' : [{'v' : {'w' : '1'}}]}}; expect(qs.stringify(obj)).to.eql(str); }); - - it('should work for --', function(){ - var str = 'x[y][0][z]=1&x[y][0][v][w]=2'; - var obj = {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for ---', function(){ - var str = 'x[y][0][z]=1&x[y][1][z]=2'; - var obj = {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for ----', function(){ - var str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3'; - var obj = {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - + + it('should work for --', function(){ + var str = 'x[y][0][z]=1&x[y][0][v][w]=2'; + var obj = {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for ---', function(){ + var str = 'x[y][0][z]=1&x[y][1][z]=2'; + var obj = {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for ----', function(){ + var str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3'; + var obj = {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + it('should work for first and lastname of a user', function(){ var str = 'user[name][first]=tj&user[name][last]=holowaychuk'; var obj = { user: { name: { first: 'tj', last: 'holowaychuk' }}}; expect(qs.stringify(obj)).to.eql(str); }); - }); - - describe('errors', function(){ + }); + + describe('errors', function(){ it('should get a error for string', function(){ var input = 'foo=bar'; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - it('should get a error for array', function(){ + }); + + it('should get a error for array', function(){ var input = ['foo', 'bar']; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - it('should get a error for null', function(){ + }); + + it('should get a error for null', function(){ var input = null; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - }); - - describe('numbers', function(){ + }); + + }); + + describe('numbers', function(){ it('should use numbers in arrays', function() { - var str = 'limit[0]=1&limit[1]=2&limit[2]=3'; - var obj = { limit: [1, 2, 3] }; - expect(qs.stringify(obj)).to.eql(str); + var str = 'limit[0]=1&limit[1]=2&limit[2]=3'; + var obj = { limit: [1, 2, 3] }; + expect(qs.stringify(obj)).to.eql(str); }); it('should use numbers in objects', function() { - var str = 'limit=1'; - var obj = { limit: 1 }; - expect(qs.stringify(obj)).to.eql(str); + var str = 'limit=1'; + var obj = { limit: 1 }; + expect(qs.stringify(obj)).to.eql(str); }); - }); + }); - describe('others', function(){ - it('should work with a date', function() { - var date = new Date(0); - var str = 'at=' + encodeURIComponent(date) - var obj = { at: date }; - expect(qs.stringify(obj)).to.eql(str); - }); - }); + describe('others', function(){ + it('should work with a date', function() { + var date = new Date(0); + var str = 'at=' + encodeURIComponent(date); + var obj = { at: date }; + expect(qs.stringify(obj)).to.eql(str); + }); + }); }); From d4d252528cedbdd60b8c7b701dea512002fd27b7 Mon Sep 17 00:00:00 2001 From: dfadler Date: Mon, 28 Apr 2014 09:28:04 -0700 Subject: [PATCH 2/3] Pastes old source over tests --- test/parse.js | 44 ++++++++++++++++++++------------------------ test/stringify.js | 5 ++--- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/test/parse.js b/test/parse.js index ebfba68..a638a2e 100644 --- a/test/parse.js +++ b/test/parse.js @@ -51,12 +51,12 @@ describe('qs.parse()', function(){ , chs: '250x100' , chl: 'Hello|World' }); - }); + }) it('should support encoded = signs', function(){ expect(qs.parse('he%3Dllo=th%3Dere')) .to.eql({ 'he=llo': 'th=ere' }); - }); + }) it('should support nesting', function(){ expect(qs.parse('ops[>=]=25')) @@ -67,7 +67,7 @@ describe('qs.parse()', function(){ expect(qs.parse('user[name][first]=tj&user[name][last]=holowaychuk')) .to.eql({ user: { name: { first: 'tj', last: 'holowaychuk' }}}); - }); + }) it('should support array notation', function(){ expect(qs.parse('images[]')) @@ -94,26 +94,22 @@ describe('qs.parse()', function(){ expect(qs.parse('user[name][first]=tj&user[name][first]=TJ')) .to.eql({ user: { name: { first: ['tj', 'TJ'] }}}); - var o = qs.parse('existing[fcbaebfecc][name][last]=tj'); - expect(o).to.eql({ existing: { 'fcbaebfecc': { name: { last: 'tj' }}}}); - - if(Array.isArray) { - expect(Array.isArray(o.existing)).to.equal(false); - } - - }); + var o = qs.parse('existing[fcbaebfecc][name][last]=tj') + expect(o).to.eql({ existing: { 'fcbaebfecc': { name: { last: 'tj' }}}}) + expect(Array.isArray(o.existing)).to.equal(false); + }) it('should support arrays with indexes', function(){ expect(qs.parse('foo[0]=bar&foo[1]=baz')).to.eql({ foo: ['bar', 'baz'] }); expect(qs.parse('foo[1]=bar&foo[0]=baz')).to.eql({ foo: ['baz', 'bar'] }); expect(qs.parse('foo[base64]=RAWR')).to.eql({ foo: { base64: 'RAWR' }}); expect(qs.parse('foo[64base]=RAWR')).to.eql({ foo: { '64base': 'RAWR' }}); - }); + }) it('should expand to an array when dupliate keys are present', function(){ expect(qs.parse('items=bar&items=baz&items=raz')) .to.eql({ items: ['bar', 'baz', 'raz'] }); - }); + }) it('should support right-hand side brackets', function(){ expect(qs.parse('pets=["tobi"]')) @@ -127,23 +123,23 @@ describe('qs.parse()', function(){ expect(qs.parse('op[>=]=[1,2,3]&op[=]=[[[[1]]]]')) .to.eql({ op: { '>=': '[1,2,3]', '=': '[[[[1]]]]' }}); - }); + }) it('should support empty values', function(){ expect(qs.parse('')).to.eql({}); expect(qs.parse(undefined)).to.eql({}); expect(qs.parse(null)).to.eql({}); - }); + }) it('should transform arrays to objects', function(){ expect(qs.parse('foo[0]=bar&foo[bad]=baz')).to.eql({ foo: { 0: "bar", bad: "baz" }}); expect(qs.parse('foo[bad]=baz&foo[0]=bar')).to.eql({ foo: { 0: "bar", bad: "baz" }}); - }); + }) it('should support malformed uri chars', function(){ expect(qs.parse('{%:%}')).to.eql({ '{%:%}': '' }); expect(qs.parse('foo=%:%}')).to.eql({ 'foo': '%:%}' }); - }); + }) it('should support semi-parsed strings', function(){ expect(qs.parse({ 'user[name]': 'tobi' })) @@ -151,25 +147,25 @@ describe('qs.parse()', function(){ expect(qs.parse({ 'user[name]': 'tobi', 'user[email][main]': 'tobi@lb.com' })) .to.eql({ user: { name: 'tobi', email: { main: 'tobi@lb.com' } }}); - }); + }) it('should not produce empty keys', function(){ expect(qs.parse('_r=1&')) - .to.eql({ _r: '1' }); - }); + .to.eql({ _r: '1' }) + }) it('should not create big arrays of null objects', function(){ var q = qs.parse('a[999999999]=1&a[2]=2'); expect(q['a'].length).to.eql(2); expect(q).to.eql({ a: ['2', '1'] }); - }); + }) it('should not be able to override prototypes', function(){ var obj = qs.parse('toString=bad&bad[toString]=bad&constructor=bad'); expect(obj.toString).to.be.a(Function); expect(obj.bad.toString).to.be.a(Function); expect(obj.constructor).to.be.a(Function); - }); + }) it('should not be possible to access Object prototype', function() { qs.parse('constructor[prototype][bad]=bad'); @@ -180,5 +176,5 @@ describe('qs.parse()', function(){ it('should not throw when a native prototype has an enumerable property', function() { Object.prototype.crash = ''; expect(qs.parse.bind(null, 'test')).to.not.throwException(); - }); -}); + }) +}) \ No newline at end of file diff --git a/test/stringify.js b/test/stringify.js index 86285db..c21c3d7 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -231,10 +231,9 @@ describe('qs.stringify', function(){ describe('others', function(){ it('should work with a date', function() { var date = new Date(0); - var str = 'at=' + encodeURIComponent(date); + var str = 'at=' + encodeURIComponent(date) var obj = { at: date }; expect(qs.stringify(obj)).to.eql(str); }); }); -}); - +}); \ No newline at end of file From 47e64bd1047bd0ad7f2f05fc8d11c90773c1bcf6 Mon Sep 17 00:00:00 2001 From: dfadler Date: Mon, 28 Apr 2014 09:33:15 -0700 Subject: [PATCH 3/3] Pastes old source over tests --- test/stringify.js | 374 +++++++++++++++++++++++----------------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/test/stringify.js b/test/stringify.js index c21c3d7..ac95056 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -12,228 +12,228 @@ describe('qs.stringify', function(){ expect(qs.stringify({ 'foo': 'bar' })).to.eql('foo=bar'); }); - it('should stringify a pair of string parameters delimited by &', function() { - expect(qs.stringify({'foo' : 'bar', 'bar' : 'baz'})).to.eql('foo=bar&bar=baz'); - }); - - it('should stringify and excaped char', function(){ - expect(qs.stringify({'foo' : '\"bar\"'})).to.eql('foo=%22bar%22'); - }); - - it('should stringify to empty string if a value is missing', function() { - expect(qs.stringify({foo:''})).to.eql('foo='); - }); - - it('should stringify numeric values to strings', function() { - expect(qs.stringify({'foo' : '1', 'bar' : '2'})).to.eql('foo=1&bar=2'); - }); + it('should stringify a pair of string parameters delimited by &', function() { + expect(qs.stringify({'foo' : 'bar', 'bar' : 'baz'})).to.eql('foo=bar&bar=baz'); + }); + + it('should stringify and excaped char', function(){ + expect(qs.stringify({'foo' : '\"bar\"'})).to.eql('foo=%22bar%22'); + }); + + it('should stringify to empty string if a value is missing', function() { + expect(qs.stringify({foo:''})).to.eql('foo='); + }); + + it('should stringify numeric values to strings', function() { + expect(qs.stringify({'foo' : '1', 'bar' : '2'})).to.eql('foo=1&bar=2'); + }); - it('should stringify that weird field', function(){ - expect(qs.stringify({'my weird field': "q1!2\"'w$5&7/z8)?"})).to.eql('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F'); - }); + it('should stringify that weird field', function(){ + expect(qs.stringify({'my weird field': "q1!2\"'w$5&7/z8)?"})).to.eql('my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F'); + }); - it('should strigify a key name=name', function() { - expect(qs.stringify({'foo=baz': 'bar'})).to.eql('foo%3Dbaz=bar'); - }); + it('should strigify a key name=name', function() { + expect(qs.stringify({'foo=baz': 'bar'})).to.eql('foo%3Dbaz=bar'); + }); - it('should stringify a object with 2 properties', function() { - expect(qs.stringify({foo: 'bar', bar: 'baz'})).to.eql('foo=bar&bar=baz'); - }); + it('should stringify a object with 2 properties', function() { + expect(qs.stringify({foo: 'bar', bar: 'baz'})).to.eql('foo=bar&bar=baz'); + }); - it('should strigify two empty values to not undefined', function() { - expect(qs.stringify({ foo: 'bar', baz: '', raz: '' })).to.eql('foo=bar&baz=&raz='); - }); + it('should strigify two empty values to not undefined', function() { + expect(qs.stringify({ foo: 'bar', baz: '', raz: '' })).to.eql('foo=bar&baz=&raz='); + }); }); describe('escaping', function(){ - it('should work with escaping html entities in the value', function(){ - expect(qs.stringify({foo: 'foo bar'})).to.eql('foo=foo%20bar'); - }); - - it('should work with different forms of escaping html entities', function(){ - expect(qs.stringify({ - cht: 'p3' - , chd: 't:60,40' - , chs: '250x100' - , chl: 'Hello|World' - })).to.eql('cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld'); - }); - }); - - describe('nested', function(){ - - it('should work with a simple array with one value', function(){ - var str = 'foo[0]=bar'; - var obj = {'foo' : ['bar']}; - expect(qs.stringify(obj)).to.eql(str); - }); + it('should work with escaping html entities in the value', function(){ + expect(qs.stringify({foo: 'foo bar'})).to.eql('foo=foo%20bar'); + }); + + it('should work with different forms of escaping html entities', function(){ + expect(qs.stringify({ + cht: 'p3' + , chd: 't:60,40' + , chs: '250x100' + , chl: 'Hello|World' + })).to.eql('cht=p3&chd=t%3A60%2C40&chs=250x100&chl=Hello%7CWorld'); + }); + }); + + describe('nested', function(){ + + it('should work with a simple array with one value', function(){ + var str = 'foo[0]=bar'; + var obj = {'foo' : ['bar']}; + expect(qs.stringify(obj)).to.eql(str); + }); - it('should work with a simple array with two values', function(){ - var str = 'foo[0]=bar&foo[1]=quux'; - var obj = {'foo' : ['bar', 'quux']}; - expect(qs.stringify(obj)).to.eql(str); - }); + it('should work with a simple array with two values', function(){ + var str = 'foo[0]=bar&foo[1]=quux'; + var obj = {'foo' : ['bar', 'quux']}; + expect(qs.stringify(obj)).to.eql(str); + }); - it('should work with a simple array with two numeric values', function(){ - var str = 'foo[0]=0&foo[1]=1'; - var obj = {'foo' : ['0', '1']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array and a object', function(){ - var str = 'foo=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : 'bar', 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array containing string values and a array containing numeric values', function(){ - var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a array containing string values and a array containing numeric values', function(){ - var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; - var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a double nested array with string keys and a third level with a numeric key', function(){ - var str = 'x[y][z][0]=1'; - var obj = {'x' : {'y' : {'z' : ['1']}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a nested array in string with string keys and a numeric value of 1', function(){ - var str = 'x[y][z]=1'; - var obj = {'x' : {'y' : {'z' : '1'}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with a nested array in string with string keys and a numeric value of 2', function(){ - var str = 'x[y][z]=2'; - var obj = {'x' : {'y' : {'z' : '2'}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with array in double nesting', function(){ - var str = 'x[y][z][0]=1&x[y][z][1]=2'; - var obj = {'x' : {'y' : {'z' : ['1', '2']}}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object nesting', function(){ - var str = 'x[y][0][z]=1'; - var obj = {'x' : {'y' : [{'z' : '1'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work with object, array, object, array nesting', function(){ - var str = 'x[y][0][z][0]=1'; - var obj = {'x' : {'y' : [{'z' : ['1']}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for 2 objects nested with an array', function(){ - var str = 'x[y][0][z]=1&x[y][0][w]=2'; - var obj = {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - - it('should work for object, array, object nesting', function(){ + it('should work with a simple array with two numeric values', function(){ + var str = 'foo[0]=0&foo[1]=1'; + var obj = {'foo' : ['0', '1']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array and a object', function(){ + var str = 'foo=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : 'bar', 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array containing string values and a array containing numeric values', function(){ + var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a array containing string values and a array containing numeric values', function(){ + var str = 'foo[0]=bar&baz[0]=1&baz[1]=2&baz[2]=3'; + var obj = {'foo' : ['bar'], 'baz' : ['1', '2', '3']}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a double nested array with string keys and a third level with a numeric key', function(){ + var str = 'x[y][z][0]=1'; + var obj = {'x' : {'y' : {'z' : ['1']}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a nested array in string with string keys and a numeric value of 1', function(){ + var str = 'x[y][z]=1'; + var obj = {'x' : {'y' : {'z' : '1'}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with a nested array in string with string keys and a numeric value of 2', function(){ + var str = 'x[y][z]=2'; + var obj = {'x' : {'y' : {'z' : '2'}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with array in double nesting', function(){ + var str = 'x[y][z][0]=1&x[y][z][1]=2'; + var obj = {'x' : {'y' : {'z' : ['1', '2']}}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object nesting', function(){ + var str = 'x[y][0][z]=1'; + var obj = {'x' : {'y' : [{'z' : '1'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work with object, array, object, array nesting', function(){ + var str = 'x[y][0][z][0]=1'; + var obj = {'x' : {'y' : [{'z' : ['1']}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for 2 objects nested with an array', function(){ + var str = 'x[y][0][z]=1&x[y][0][w]=2'; + var obj = {'x' : {'y' : [{'z' : '1', 'w' : '2'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + + it('should work for object, array, object nesting', function(){ var str = 'x[y][0][v][w]=1'; var obj = {'x' : {'y' : [{'v' : {'w' : '1'}}]}}; expect(qs.stringify(obj)).to.eql(str); }); - - it('should work for --', function(){ - var str = 'x[y][0][z]=1&x[y][0][v][w]=2'; - var obj = {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for ---', function(){ - var str = 'x[y][0][z]=1&x[y][1][z]=2'; - var obj = {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - - it('should work for ----', function(){ - var str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3'; - var obj = {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}; - expect(qs.stringify(obj)).to.eql(str); - }); - + + it('should work for --', function(){ + var str = 'x[y][0][z]=1&x[y][0][v][w]=2'; + var obj = {'x' : {'y' : [{'z' : '1', 'v' : {'w' : '2'}}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for ---', function(){ + var str = 'x[y][0][z]=1&x[y][1][z]=2'; + var obj = {'x' : {'y' : [{'z' : '1'}, {'z' : '2'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + + it('should work for ----', function(){ + var str = 'x[y][0][z]=1&x[y][0][w]=a&x[y][1][z]=2&x[y][1][w]=3'; + var obj = {'x' : {'y' : [{'z' : '1', 'w' : 'a'}, {'z' : '2', 'w' : '3'}]}}; + expect(qs.stringify(obj)).to.eql(str); + }); + it('should work for first and lastname of a user', function(){ var str = 'user[name][first]=tj&user[name][last]=holowaychuk'; var obj = { user: { name: { first: 'tj', last: 'holowaychuk' }}}; expect(qs.stringify(obj)).to.eql(str); }); - }); - - describe('errors', function(){ + }); + + describe('errors', function(){ it('should get a error for string', function(){ var input = 'foo=bar'; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - it('should get a error for array', function(){ + }); + + it('should get a error for array', function(){ var input = ['foo', 'bar']; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - it('should get a error for null', function(){ + }); + + it('should get a error for null', function(){ var input = null; try { - qs.stringify(input); + qs.stringify(input); } catch (e) { - expect(e.message).to.eql('stringify expects an object'); + expect(e.message).to.eql('stringify expects an object'); } - }); - - }); - - describe('numbers', function(){ + }); + + }); + + describe('numbers', function(){ it('should use numbers in arrays', function() { - var str = 'limit[0]=1&limit[1]=2&limit[2]=3'; - var obj = { limit: [1, 2, 3] }; - expect(qs.stringify(obj)).to.eql(str); + var str = 'limit[0]=1&limit[1]=2&limit[2]=3'; + var obj = { limit: [1, 2, 3] }; + expect(qs.stringify(obj)).to.eql(str); }); it('should use numbers in objects', function() { - var str = 'limit=1'; - var obj = { limit: 1 }; - expect(qs.stringify(obj)).to.eql(str); + var str = 'limit=1'; + var obj = { limit: 1 }; + expect(qs.stringify(obj)).to.eql(str); }); - }); + }); - describe('others', function(){ - it('should work with a date', function() { - var date = new Date(0); - var str = 'at=' + encodeURIComponent(date) - var obj = { at: date }; - expect(qs.stringify(obj)).to.eql(str); - }); - }); + describe('others', function(){ + it('should work with a date', function() { + var date = new Date(0); + var str = 'at=' + encodeURIComponent(date) + var obj = { at: date }; + expect(qs.stringify(obj)).to.eql(str); + }); + }); }); \ No newline at end of file