/*!
* querystring
* Copyright(c) 2010 TJ Holowaychuk
* MIT Licensed
*/
/**
* Library version.
*/
exports.version = '0.1.0';
/**
* Parse the given query `str`, returning an object.
*
* @param {String} str
* @return {Object}
* @api public
*/
exports.parse = function(str) {
if (str == undefined || str == '') return {};
return String(str)
.split('&')
.reduce(function(ret, pair){
var pair = decodeURIComponent(pair.replace(/\+/g, ' '))
, eql = pair.indexOf('=')
, brace = lastBraceInKey(pair)
, key = pair.substr(0, brace || eql)
, val = pair.substr(brace || eql, pair.length)
, val = val.substr(val.indexOf('=') + 1, val.length)
, obj = ret;
// ?foo
if ('' == key) key = pair, val = '';
// nested
if (~key.indexOf(']')) {
var parts = key.split('[')
, len = parts.length
, last = len - 1;
function parse(obj, parts, parent, key) {
var part = parts.shift();
// end
if (!part) {
if (Array.isArray(parent[key])) {
parent[key].push(val);
} else if ('object' == typeof parent[key]) {
parent[key] = val;
} else {
parent[key] = [parent[key], val];
}
// array
} else if (']' == part) {
obj = parent[key] = Array.isArray(parent[key])
? parent[key]
: [];
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);
// key
} else {
parse(obj[part] = obj[part] || {}, parts, obj, part);
}
}
parse(obj, parts);
// optimize
} else {
set(obj, key, val);
}
return ret;
}, {});
};
/**
* Set `obj`'s `key` to `val` respecting
* the weird and wonderful syntax of a qs,
* where "foo=bar&foo=baz" becomes an array.
*
* @param {Object} obj
* @param {String} key
* @param {String} val
* @api private
*/
function set(obj, key, val) {
var v = obj[key];
if (undefined === v) {
obj[key] = val;
} else if (Array.isArray(v)) {
v.push(val);
} else {
obj[key] = [v, val];
}
}
/**
* Locate last brace in `str` within the key.
*
* @param {String} str
* @return {Number}
* @api private
*/
function lastBraceInKey(str) {
var len = str.length
, brace
, c;
for (var i = 0; i < len; ++i) {
c = str[i];
if (']' == c) brace = false;
if ('[' == c) brace = true;
if ('=' == c && !brace) return i;
}
}