From e14468ef9d3dc5bb37d8e2019250ab1d4079355c Mon Sep 17 00:00:00 2001 From: eleith Date: Fri, 15 Apr 2011 14:15:49 -0700 Subject: [PATCH 01/11] added support for deeply nested objects in arrays and deeply nested arrays in objects --- lib/querystring.js | 40 ++++++++++++++++++++++-- test/querystring.test.js | 66 ++++++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 5fb3441..1c4a93a 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -38,6 +38,7 @@ exports.parse = function(str) { // nested if (~key.indexOf(']')) { + var parts = key.split('[') , len = parts.length , last = len - 1; @@ -47,6 +48,7 @@ exports.parse = function(str) { // end if (!part) { + if (Array.isArray(parent[key])) { parent[key].push(val); } else if ('object' == typeof parent[key]) { @@ -59,11 +61,45 @@ exports.parse = function(str) { obj = parent[key] = Array.isArray(parent[key]) ? parent[key] : []; - if ('' != val) obj.push(val); + + // if there are more parts + if(parts.length) + { + // and if obj is an array with items in it, continue parsing from the end of the object + if(obj.length) + { + parse(obj[obj.length - 1], parts, obj, part); + } + // otherwise, obj is an empty array, push a new object into it and continue parsing + else + { + var newobj = {}; + obj.push(newobj); + parse(newobj, parts, obj, part); + } + } + else + if ('' != val) obj.push(val); + // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - parse(obj[part] = obj[part] || {}, parts, obj, part); + + // if part already exists on object and it is NOT specified as an array AND + // if there are no more parts OR the last part is specified as an array AND the next part DOES exist in the object + // then we are pushing a new object into the earlier specified array + if(obj[part] && !Array.isArray(obj[part]) && Array.isArray(parent) && + (!parts.length || (parts[parts.length - 1] != ']' && obj[part][parts[0].substring(0, parts[0].length - 1)]))) + { + var newobj = {}; + parent.push(newobj); + parse(newobj[part] = {}, parts, newobj, part); + } + else + { + parse(obj[part] = obj[part] || {}, parts, obj, part); + } + // key } else { parse(obj[part] = obj[part] || {}, parts, obj, part); diff --git a/test/querystring.test.js b/test/querystring.test.js index a4ca6db..ee5901f 100644 --- a/test/querystring.test.js +++ b/test/querystring.test.js @@ -117,17 +117,59 @@ module.exports = { qs.parse('').should.eql({}); qs.parse(undefined).should.eql({}); qs.parse(null).should.eql({}); + }, + + 'test complex': function(){ + + // if no arrays are EVER specified, parser will create arrays for you + qs.parse('users[name][first]=tj&users[name][first]=tobi') + .should.eql({ + users: { name: { first: [ 'tj', 'tobi' ] } } + }); + + // once an array is specified, objects that are parsed are PUSHED onto the array + qs.parse('users[][name][first]=tj&users[][name][first]=tobi') + .should.eql({ + users: [ { name: { first: 'tj' } }, { name: { first: 'tobi' } } ] + }); + + // arrays can be specified within objects + qs.parse('users[name][][first]=tj&users[name][][first]=tobi') + .should.eql({ + users: { name: [ { first: 'tj' }, { first: 'tobi' } ] } + }); + + // if you specify an array but want a deeper object to be pushed into a deeper array, you can specify that with [] + qs.parse('users[][name][first][]=tj&users[][name][first][]=tobi') + .should.eql({ + users: [ { name: { first: [ 'tj', 'tobi' ] } } ] + }); + + // you can continue adding to a deep object object + qs.parse('users[][name][first]=tj&users[][name][last]=holowaychuk') + .should.eql({ + users: [ { name: { first: 'tj', last: 'holowaychuk' } } ] + }); + + // order matters, once a new object is pushed, you can't add anything back into the youngest object + qs.parse('users[][name][first]=tobi&users[][name][first]=tj&users[][name][last]=holowaychuk') + .should.eql({ + users: [ { name: { first: 'tobi' } }, { name: { first: 'tj', last: 'holowaychuk' } } ] + }); + }, + + 'test deep': function(){ + + // deep objects should work + qs.parse('users[][name][first][nickname]=tj&users[][name][first][nickname]=tobi') + .should.eql({ + users: [ { name: { first: { nickname: 'tj' } } }, { name: { first: { nickname: 'tobi' } } } ] + }); + + // deep objects should work + qs.parse('users[][name][first][nickname][]=tj&users[][name][first][nickname][]=tobi') + .should.eql({ + users: [ { name: { first: { nickname: [ 'tj', 'tobi' ] } } } ] + }); } - - // 'test complex': function(){ - // qs.parse('users[][name][first]=tj&users[foo]=bar') - // .should.eql({ - // users: [ { name: 'tj' }, { name: 'tobi' }, { foo: 'bar' }] - // }); - // - // qs.parse('users[][name][first]=tj&users[][name][first]=tobi') - // .should.eql({ - // users: [ { name: 'tj' }, { name: 'tobi' }] - // }); - // } }; From ca8fa2bdabc658ffc76612695c1a78e38c57ebe2 Mon Sep 17 00:00:00 2001 From: eleith Date: Fri, 15 Apr 2011 16:05:15 -0700 Subject: [PATCH 02/11] unmessifying + styling the visionmedia way --- lib/querystring.js | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 1c4a93a..a0ec33b 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -62,44 +62,33 @@ exports.parse = function(str) { ? parent[key] : []; - // if there are more parts - if(parts.length) - { - // and if obj is an array with items in it, continue parsing from the end of the object - if(obj.length) - { - parse(obj[obj.length - 1], parts, obj, part); - } - // otherwise, obj is an empty array, push a new object into it and continue parsing - else - { - var newobj = {}; - obj.push(newobj); - parse(newobj, parts, obj, part); - } + // if there are more parts, we need to continue parsing + if(parts.length) { + // if obj is an empty array, push a new object into in + if(!obj.length) obj.push({}); + + // the new obj is the last one in this array + parse(obj[obj.length - 1], parts, obj, part); } - else - if ('' != val) obj.push(val); + else if ('' != val) obj.push(val); // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - // if part already exists on object and it is NOT specified as an array AND - // if there are no more parts OR the last part is specified as an array AND the next part DOES exist in the object - // then we are pushing a new object into the earlier specified array - if(obj[part] && !Array.isArray(obj[part]) && Array.isArray(parent) && - (!parts.length || (parts[parts.length - 1] != ']' && obj[part][parts[0].substring(0, parts[0].length - 1)]))) - { - var newobj = {}; - parent.push(newobj); - parse(newobj[part] = {}, parts, newobj, part); - } - else - { - parse(obj[part] = obj[part] || {}, parts, obj, part); + // does object already have property AND parent is a nested array + if(obj[part] && Array.isArray(parent)) { + var left = parts.length; + + // are there no more parts OR + // is the last part not a '[]' AND the next part already exists as a previously parsed property + if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { + parent.push(obj = {}); + } } + parse(obj[part] = obj[part] || {}, parts, obj, part); + // key } else { parse(obj[part] = obj[part] || {}, parts, obj, part); From 9453ab8a1e571aa219951a5471e29c510a88dcf0 Mon Sep 17 00:00:00 2001 From: eleith Date: Fri, 15 Apr 2011 14:15:49 -0700 Subject: [PATCH 03/11] added support for deeply nested objects in arrays and deeply nested arrays in objects Signed-off-by: Tj Holowaychuk --- lib/querystring.js | 40 ++++++++++++++++++++++-- test/querystring.test.js | 66 ++++++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 5fb3441..1c4a93a 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -38,6 +38,7 @@ exports.parse = function(str) { // nested if (~key.indexOf(']')) { + var parts = key.split('[') , len = parts.length , last = len - 1; @@ -47,6 +48,7 @@ exports.parse = function(str) { // end if (!part) { + if (Array.isArray(parent[key])) { parent[key].push(val); } else if ('object' == typeof parent[key]) { @@ -59,11 +61,45 @@ exports.parse = function(str) { obj = parent[key] = Array.isArray(parent[key]) ? parent[key] : []; - if ('' != val) obj.push(val); + + // if there are more parts + if(parts.length) + { + // and if obj is an array with items in it, continue parsing from the end of the object + if(obj.length) + { + parse(obj[obj.length - 1], parts, obj, part); + } + // otherwise, obj is an empty array, push a new object into it and continue parsing + else + { + var newobj = {}; + obj.push(newobj); + parse(newobj, parts, obj, part); + } + } + else + if ('' != val) obj.push(val); + // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - parse(obj[part] = obj[part] || {}, parts, obj, part); + + // if part already exists on object and it is NOT specified as an array AND + // if there are no more parts OR the last part is specified as an array AND the next part DOES exist in the object + // then we are pushing a new object into the earlier specified array + if(obj[part] && !Array.isArray(obj[part]) && Array.isArray(parent) && + (!parts.length || (parts[parts.length - 1] != ']' && obj[part][parts[0].substring(0, parts[0].length - 1)]))) + { + var newobj = {}; + parent.push(newobj); + parse(newobj[part] = {}, parts, newobj, part); + } + else + { + parse(obj[part] = obj[part] || {}, parts, obj, part); + } + // key } else { parse(obj[part] = obj[part] || {}, parts, obj, part); diff --git a/test/querystring.test.js b/test/querystring.test.js index a4ca6db..ee5901f 100644 --- a/test/querystring.test.js +++ b/test/querystring.test.js @@ -117,17 +117,59 @@ module.exports = { qs.parse('').should.eql({}); qs.parse(undefined).should.eql({}); qs.parse(null).should.eql({}); + }, + + 'test complex': function(){ + + // if no arrays are EVER specified, parser will create arrays for you + qs.parse('users[name][first]=tj&users[name][first]=tobi') + .should.eql({ + users: { name: { first: [ 'tj', 'tobi' ] } } + }); + + // once an array is specified, objects that are parsed are PUSHED onto the array + qs.parse('users[][name][first]=tj&users[][name][first]=tobi') + .should.eql({ + users: [ { name: { first: 'tj' } }, { name: { first: 'tobi' } } ] + }); + + // arrays can be specified within objects + qs.parse('users[name][][first]=tj&users[name][][first]=tobi') + .should.eql({ + users: { name: [ { first: 'tj' }, { first: 'tobi' } ] } + }); + + // if you specify an array but want a deeper object to be pushed into a deeper array, you can specify that with [] + qs.parse('users[][name][first][]=tj&users[][name][first][]=tobi') + .should.eql({ + users: [ { name: { first: [ 'tj', 'tobi' ] } } ] + }); + + // you can continue adding to a deep object object + qs.parse('users[][name][first]=tj&users[][name][last]=holowaychuk') + .should.eql({ + users: [ { name: { first: 'tj', last: 'holowaychuk' } } ] + }); + + // order matters, once a new object is pushed, you can't add anything back into the youngest object + qs.parse('users[][name][first]=tobi&users[][name][first]=tj&users[][name][last]=holowaychuk') + .should.eql({ + users: [ { name: { first: 'tobi' } }, { name: { first: 'tj', last: 'holowaychuk' } } ] + }); + }, + + 'test deep': function(){ + + // deep objects should work + qs.parse('users[][name][first][nickname]=tj&users[][name][first][nickname]=tobi') + .should.eql({ + users: [ { name: { first: { nickname: 'tj' } } }, { name: { first: { nickname: 'tobi' } } } ] + }); + + // deep objects should work + qs.parse('users[][name][first][nickname][]=tj&users[][name][first][nickname][]=tobi') + .should.eql({ + users: [ { name: { first: { nickname: [ 'tj', 'tobi' ] } } } ] + }); } - - // 'test complex': function(){ - // qs.parse('users[][name][first]=tj&users[foo]=bar') - // .should.eql({ - // users: [ { name: 'tj' }, { name: 'tobi' }, { foo: 'bar' }] - // }); - // - // qs.parse('users[][name][first]=tj&users[][name][first]=tobi') - // .should.eql({ - // users: [ { name: 'tj' }, { name: 'tobi' }] - // }); - // } }; From e510209933ad79ddee4585365db87331bd3cd1b3 Mon Sep 17 00:00:00 2001 From: eleith Date: Fri, 15 Apr 2011 16:05:15 -0700 Subject: [PATCH 04/11] unmessifying + styling the visionmedia way Signed-off-by: Tj Holowaychuk --- lib/querystring.js | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 1c4a93a..a0ec33b 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -62,44 +62,33 @@ exports.parse = function(str) { ? parent[key] : []; - // if there are more parts - if(parts.length) - { - // and if obj is an array with items in it, continue parsing from the end of the object - if(obj.length) - { - parse(obj[obj.length - 1], parts, obj, part); - } - // otherwise, obj is an empty array, push a new object into it and continue parsing - else - { - var newobj = {}; - obj.push(newobj); - parse(newobj, parts, obj, part); - } + // if there are more parts, we need to continue parsing + if(parts.length) { + // if obj is an empty array, push a new object into in + if(!obj.length) obj.push({}); + + // the new obj is the last one in this array + parse(obj[obj.length - 1], parts, obj, part); } - else - if ('' != val) obj.push(val); + else if ('' != val) obj.push(val); // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - // if part already exists on object and it is NOT specified as an array AND - // if there are no more parts OR the last part is specified as an array AND the next part DOES exist in the object - // then we are pushing a new object into the earlier specified array - if(obj[part] && !Array.isArray(obj[part]) && Array.isArray(parent) && - (!parts.length || (parts[parts.length - 1] != ']' && obj[part][parts[0].substring(0, parts[0].length - 1)]))) - { - var newobj = {}; - parent.push(newobj); - parse(newobj[part] = {}, parts, newobj, part); - } - else - { - parse(obj[part] = obj[part] || {}, parts, obj, part); + // does object already have property AND parent is a nested array + if(obj[part] && Array.isArray(parent)) { + var left = parts.length; + + // are there no more parts OR + // is the last part not a '[]' AND the next part already exists as a previously parsed property + if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { + parent.push(obj = {}); + } } + parse(obj[part] = obj[part] || {}, parts, obj, part); + // key } else { parse(obj[part] = obj[part] || {}, parts, obj, part); From 37b27c3257fbea06ff17c4c62d2c62c767bb9900 Mon Sep 17 00:00:00 2001 From: eleith Date: Sat, 30 Apr 2011 15:20:19 -0700 Subject: [PATCH 05/11] added a new test and update lib to support it updated examples to use util module instead of inspect module --- examples.js | 22 +++++++++++----------- lib/querystring.js | 4 +++- test/querystring.test.js | 8 ++++++++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/examples.js b/examples.js index 6fe9f47..42baa15 100644 --- a/examples.js +++ b/examples.js @@ -6,34 +6,34 @@ var qs = require('./'); var obj = qs.parse('foo'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('foo=bar=baz'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('users[]'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('name=tj&email=tj@vision-media.ca'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('users[]=tj&users[]=tobi&users[]=jane'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('user[name][first]=tj&user[name][last]=holowaychuk'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('users[][name][first]=tj&users[][name][last]=holowaychuk'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('a=a&a=b&a=c'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('user[tj]=tj&user[tj]=TJ'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('user[names]=tj&user[names]=TJ&user[names]=Tyler'); -require('inspect')(obj) +require('util').inspect(obj) var obj = qs.parse('user[name][first]=tj&user[name][first]=TJ'); -require('inspect')(obj) \ No newline at end of file +require('util').inspect(obj) diff --git a/lib/querystring.js b/lib/querystring.js index a0ec33b..087540e 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -46,6 +46,8 @@ exports.parse = function(str) { function parse(obj, parts, parent, key) { var part = parts.shift(); + debugger + // end if (!part) { @@ -65,7 +67,7 @@ exports.parse = function(str) { // if there are more parts, we need to continue parsing if(parts.length) { // if obj is an empty array, push a new object into in - if(!obj.length) obj.push({}); + if(!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); // the new obj is the last one in this array parse(obj[obj.length - 1], parts, obj, part); diff --git a/test/querystring.test.js b/test/querystring.test.js index ee5901f..00d8e14 100644 --- a/test/querystring.test.js +++ b/test/querystring.test.js @@ -171,5 +171,13 @@ module.exports = { .should.eql({ users: [ { name: { first: { nickname: [ 'tj', 'tobi' ] } } } ] }); + }, + + 'test deep complex': function() { + // deep objects should work + qs.parse('a[b][][c]=1&a[b][]=2&a[b][]=3&a[b][][d]=4') + .should.eql({ + a: { b : [ { c: 1 }, 2, 3, { d: 4 } ] } + }); } }; From 6b1f55568d800681e455ebe233b37664baef3237 Mon Sep 17 00:00:00 2001 From: eleith Date: Sat, 30 Apr 2011 16:15:10 -0700 Subject: [PATCH 06/11] oh noes! (de) bugger --- lib/querystring.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 087540e..099d8b2 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -46,8 +46,6 @@ exports.parse = function(str) { function parse(obj, parts, parent, key) { var part = parts.shift(); - debugger - // end if (!part) { From 405ddbcb96f598ceb958e7831d5f93c1d0b805ac Mon Sep 17 00:00:00 2001 From: eleith Date: Mon, 2 May 2011 02:50:51 -0700 Subject: [PATCH 07/11] support numerical indices, mixed indices (named and numerical) and all such combinations there of --- lib/querystring.js | 23 ++++++++++++++++++----- test/querystring.test.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 099d8b2..9c452c9 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -57,10 +57,23 @@ exports.parse = function(str) { parent[key] = [parent[key], val]; } // array - } else if (']' == part) { - obj = parent[key] = Array.isArray(parent[key]) - ? parent[key] - : []; + } else if (']' == part || ('0]' == part && JSON.stringify(obj) == '{}')) { + // existing array, append to it + if(Array.isArray(parent[key])) { + obj = parent[key]; + } else { + obj = []; + + // was an object, but parser found out it was actually an array! + // preserve any named indices if we can + if(parent[key]) { + for(var field in parent[key]) { + obj[field] = parent[key][field]; + } + } + } + + parent[key] = obj; // if there are more parts, we need to continue parsing if(parts.length) { @@ -86,7 +99,7 @@ exports.parse = function(str) { parent.push(obj = {}); } } - + parse(obj[part] = obj[part] || {}, parts, obj, part); // key diff --git a/test/querystring.test.js b/test/querystring.test.js index 00d8e14..b2a0bbd 100644 --- a/test/querystring.test.js +++ b/test/querystring.test.js @@ -179,5 +179,38 @@ module.exports = { .should.eql({ a: { b : [ { c: 1 }, 2, 3, { d: 4 } ] } }); + }, + + 'indice types': function() { + + // numbered indice starting with 0 or [] means we want an array + qs.parse('a[0]=1') + .should.eql({ + a: [1] + }).obj.a.should.be.an.instanceof(Array); + + // without [0] or [], means we want an object + qs.parse('a[1]=2') + .should.eql({ + a: { 1: 2 } + }).obj.a.should.be.a('object'); + + // [] triggers the array creation, no matter what, it will push from last indice that it can + qs.parse('a[8]=1&a[]=2&a[2]=3&a[500]=4') + .should.eql({ + a: {2:3, 8:1, 9:2, 500:4} + }).obj.a.should.be.an.instanceof(Array); + + // arrays can have named indices!? + qs.parse('a[foo]=bar&a[]=2') + .should.eql({ + a: { foo: 'bar', 0: 2} + }).obj.a.should.be.an.instanceof(Array); + + // no [] or [0], then we have an object, no matter what + qs.parse('a[foo]=bar&a[1]=2') + .should.eql({ + a: { foo: 'bar', 1: 2} + }).obj.a.should.be.a('object'); } }; From 6c4c2c95ca1a5ed9633062882a37f7f491b0c892 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Mon, 16 May 2011 10:27:22 -0700 Subject: [PATCH 08/11] misc --- test/querystring.test.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/querystring.test.js b/test/querystring.test.js index 525725c..61c570a 100644 --- a/test/querystring.test.js +++ b/test/querystring.test.js @@ -120,8 +120,7 @@ module.exports = { }, 'test complex': function(){ - - // if no arrays are EVER specified, parser will create arrays for you + // if no arrays are EVER specified, parser will create arrays for you qs.parse('users[name][first]=tj&users[name][first]=tobi') .should.eql({ users: { name: { first: [ 'tj', 'tobi' ] } } @@ -181,13 +180,13 @@ module.exports = { }, 'indice types': function() { - // numbered indice starting with 0 or [] means we want an array + // numbered indice starting with 0 or [] means we want an array qs.parse('a[0]=1') .should.eql({ a: [1] }).obj.a.should.be.an.instanceof(Array); - // without [0] or [], means we want an object + // without [0] or [], means we want an object qs.parse('a[1]=2') .should.eql({ a: { 1: 2 } From e698499dbb5d2b5969747bfe824a1647b2a92943 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Mon, 16 May 2011 10:27:56 -0700 Subject: [PATCH 09/11] tabs -> spaces --- lib/querystring.js | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 9c452c9..a5ee3da 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -58,49 +58,49 @@ exports.parse = function(str) { } // array } else if (']' == part || ('0]' == part && JSON.stringify(obj) == '{}')) { - // existing array, append to it - if(Array.isArray(parent[key])) { - obj = parent[key]; - } else { - obj = []; - - // was an object, but parser found out it was actually an array! - // preserve any named indices if we can - if(parent[key]) { - for(var field in parent[key]) { - obj[field] = parent[key][field]; - } - } - } - - parent[key] = obj; - - // if there are more parts, we need to continue parsing - if(parts.length) { - // if obj is an empty array, push a new object into in - if(!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); - - // the new obj is the last one in this array - parse(obj[obj.length - 1], parts, obj, part); - } - else if ('' != val) obj.push(val); + // existing array, append to it + if(Array.isArray(parent[key])) { + obj = parent[key]; + } else { + obj = []; + + // was an object, but parser found out it was actually an array! + // preserve any named indices if we can + if(parent[key]) { + for(var field in parent[key]) { + obj[field] = parent[key][field]; + } + } + } + + parent[key] = obj; + + // if there are more parts, we need to continue parsing + if(parts.length) { + // if obj is an empty array, push a new object into in + if(!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); + + // the new obj is the last one in this array + parse(obj[obj.length - 1], parts, obj, part); + } + else if ('' != val) obj.push(val); // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - // does object already have property AND parent is a nested array - if(obj[part] && Array.isArray(parent)) { - var left = parts.length; - - // are there no more parts OR - // is the last part not a '[]' AND the next part already exists as a previously parsed property - if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { - parent.push(obj = {}); - } - } - - parse(obj[part] = obj[part] || {}, parts, obj, part); + // does object already have property AND parent is a nested array + if(obj[part] && Array.isArray(parent)) { + var left = parts.length; + + // are there no more parts OR + // is the last part not a '[]' AND the next part already exists as a previously parsed property + if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { + parent.push(obj = {}); + } + } + + parse(obj[part] = obj[part] || {}, parts, obj, part); // key } else { From 94c0f3676d333c0edcb5636a43817149eb879eb4 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Mon, 16 May 2011 10:30:32 -0700 Subject: [PATCH 10/11] fix crazy indentation --- lib/querystring.js | 65 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index a5ee3da..bf0a06c 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -48,7 +48,6 @@ exports.parse = function(str) { // end if (!part) { - if (Array.isArray(parent[key])) { parent[key].push(val); } else if ('object' == typeof parent[key]) { @@ -58,49 +57,49 @@ exports.parse = function(str) { } // array } else if (']' == part || ('0]' == part && JSON.stringify(obj) == '{}')) { - // existing array, append to it - if(Array.isArray(parent[key])) { - obj = parent[key]; - } else { - obj = []; - - // was an object, but parser found out it was actually an array! - // preserve any named indices if we can - if(parent[key]) { - for(var field in parent[key]) { - obj[field] = parent[key][field]; + // existing array, append to it + if (Array.isArray(parent[key])) { + obj = parent[key]; + } else { + obj = []; + // was an object, but parser found out it was actually an array! + // preserve any named indices if we can + if (parent[key]) { + for(var field in parent[key]) { + obj[field] = parent[key][field]; + } + } } - } - } - parent[key] = obj; + parent[key] = obj; - // if there are more parts, we need to continue parsing - if(parts.length) { - // if obj is an empty array, push a new object into in - if(!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); + // if there are more parts, we need to continue parsing + if (parts.length) { + // if obj is an empty array, push a new object into in + if (!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); - // the new obj is the last one in this array - parse(obj[obj.length - 1], parts, obj, part); - } - else if ('' != val) obj.push(val); + // the new obj is the last one in this array + parse(obj[obj.length - 1], parts, obj, part); + } else if ('' != val) { + obj.push(val); + } // prop } else if (~part.indexOf(']')) { part = part.substr(0, part.length - 1); - // does object already have property AND parent is a nested array - if(obj[part] && Array.isArray(parent)) { - var left = parts.length; + // does object already have property AND parent is a nested array + if (obj[part] && Array.isArray(parent)) { + var left = parts.length; - // are there no more parts OR - // is the last part not a '[]' AND the next part already exists as a previously parsed property - if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { - parent.push(obj = {}); - } - } + // are there no more parts OR + // is the last part not a '[]' AND the next part already exists as a previously parsed property + if (!left || (parts[left - 1] != ']' && obj[part][parts[0].slice(0, -1)] !== undefined)) { + parent.push(obj = {}); + } + } - parse(obj[part] = obj[part] || {}, parts, obj, part); + parse(obj[part] = obj[part] || {}, parts, obj, part); // key } else { From 0eb5401a242798faa131588d592106ddfd7e66a9 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Mon, 16 May 2011 10:30:51 -0700 Subject: [PATCH 11/11] misc --- lib/querystring.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/querystring.js b/lib/querystring.js index bf0a06c..836e643 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -76,7 +76,7 @@ exports.parse = function(str) { // if there are more parts, we need to continue parsing if (parts.length) { // if obj is an empty array, push a new object into in - if (!obj.length || typeof(obj[obj.length - 1]) != 'object') obj.push({}); + if (!obj.length || 'object' != typeof(obj[obj.length - 1])) obj.push({}); // the new obj is the last one in this array parse(obj[obj.length - 1], parts, obj, part);