Comparing version 0.5.2 to 0.5.3
{ | ||
"name": "querystring", | ||
"description": "Querystring parser / stringifier with nesting support", | ||
"repo": "visionmedia/node-querystring", | ||
"description": "query-string parser / stringifier with nesting support", | ||
"version": "0.5.3", | ||
"keywords": ["querystring", "query", "parser"], | ||
"main": "lib/querystring.js" | ||
"scripts": ["index.js"], | ||
"license": "MIT" | ||
} |
0.5.3 2012-12-09 | ||
================== | ||
* add info to component.json | ||
* remove regular client-side ./querystring.js, fix component.json support | ||
0.5.2 / 2012-11-14 | ||
@@ -88,2 +94,2 @@ ================== | ||
* Initial release | ||
* Initial release |
262
index.js
module.exports = require('./lib/querystring'); | ||
/** | ||
* Object#toString() ref for stringify(). | ||
*/ | ||
var toString = Object.prototype.toString; | ||
/** | ||
* Cache non-integer test regexp. | ||
*/ | ||
var isint = /^[0-9]+$/; | ||
function promote(parent, key) { | ||
if (parent[key].length == 0) return parent[key] = {}; | ||
var t = {}; | ||
for (var i in parent[key]) t[i] = parent[key][i]; | ||
parent[key] = t; | ||
return t; | ||
} | ||
function parse(parts, parent, key, val) { | ||
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 if ('undefined' == typeof parent[key]) { | ||
parent[key] = val; | ||
} else { | ||
parent[key] = [parent[key], val]; | ||
} | ||
// array | ||
} else { | ||
var obj = parent[key] = parent[key] || []; | ||
if (']' == part) { | ||
if (Array.isArray(obj)) { | ||
if ('' != val) obj.push(val); | ||
} else if ('object' == typeof obj) { | ||
obj[Object.keys(obj).length] = val; | ||
} else { | ||
obj = parent[key] = [parent[key], val]; | ||
} | ||
// prop | ||
} else if (~part.indexOf(']')) { | ||
part = part.substr(0, part.length - 1); | ||
if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); | ||
parse(parts, obj, part, val); | ||
// key | ||
} else { | ||
if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key); | ||
parse(parts, obj, part, val); | ||
} | ||
} | ||
} | ||
/** | ||
* Merge parent key/val pair. | ||
*/ | ||
function merge(parent, key, val){ | ||
if (~key.indexOf(']')) { | ||
var parts = key.split('[') | ||
, len = parts.length | ||
, last = len - 1; | ||
parse(parts, parent, 'base', val); | ||
// optimize | ||
} else { | ||
if (!isint.test(key) && Array.isArray(parent.base)) { | ||
var t = {}; | ||
for (var k in parent.base) t[k] = parent.base[k]; | ||
parent.base = t; | ||
} | ||
set(parent.base, key, val); | ||
} | ||
return parent; | ||
} | ||
/** | ||
* Parse the given obj. | ||
*/ | ||
function parseObject(obj){ | ||
var ret = { base: {} }; | ||
Object.keys(obj).forEach(function(name){ | ||
merge(ret, name, obj[name]); | ||
}); | ||
return ret.base; | ||
} | ||
/** | ||
* Parse the given str. | ||
*/ | ||
function parseString(str){ | ||
return String(str) | ||
.split('&') | ||
.reduce(function(ret, pair){ | ||
var 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); | ||
// ?foo | ||
if ('' == key) key = pair, val = ''; | ||
return merge(ret, decode(key), decode(val)); | ||
}, { base: {} }).base; | ||
} | ||
/** | ||
* Parse the given query `str` or `obj`, returning an object. | ||
* | ||
* @param {String} str | {Object} obj | ||
* @return {Object} | ||
* @api public | ||
*/ | ||
exports.parse = function(str){ | ||
if (null == str || '' == str) return {}; | ||
return 'object' == typeof str | ||
? parseObject(str) | ||
: parseString(str); | ||
}; | ||
/** | ||
* Turn the given `obj` into a query string | ||
* | ||
* @param {Object} obj | ||
* @return {String} | ||
* @api public | ||
*/ | ||
var stringify = exports.stringify = function(obj, prefix) { | ||
if (Array.isArray(obj)) { | ||
return stringifyArray(obj, prefix); | ||
} else if ('[object Object]' == toString.call(obj)) { | ||
return stringifyObject(obj, prefix); | ||
} else if ('string' == typeof obj) { | ||
return stringifyString(obj, prefix); | ||
} else { | ||
return prefix + '=' + encodeURIComponent(String(obj)); | ||
} | ||
}; | ||
/** | ||
* Stringify the given `str`. | ||
* | ||
* @param {String} str | ||
* @param {String} prefix | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function stringifyString(str, prefix) { | ||
if (!prefix) throw new TypeError('stringify expects an object'); | ||
return prefix + '=' + encodeURIComponent(str); | ||
} | ||
/** | ||
* Stringify the given `arr`. | ||
* | ||
* @param {Array} arr | ||
* @param {String} prefix | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function stringifyArray(arr, prefix) { | ||
var ret = []; | ||
if (!prefix) throw new TypeError('stringify expects an object'); | ||
for (var i = 0; i < arr.length; i++) { | ||
ret.push(stringify(arr[i], prefix + '[' + i + ']')); | ||
} | ||
return ret.join('&'); | ||
} | ||
/** | ||
* Stringify the given `obj`. | ||
* | ||
* @param {Object} obj | ||
* @param {String} prefix | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function stringifyObject(obj, prefix) { | ||
var ret = [] | ||
, keys = Object.keys(obj) | ||
, key; | ||
for (var i = 0, len = keys.length; i < len; ++i) { | ||
key = keys[i]; | ||
ret.push(stringify(obj[key], prefix | ||
? prefix + '[' + encodeURIComponent(key) + ']' | ||
: encodeURIComponent(key))); | ||
} | ||
return ret.join('&'); | ||
} | ||
/** | ||
* 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; | ||
} | ||
} | ||
/** | ||
* Decode `str`. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function decode(str) { | ||
try { | ||
return decodeURIComponent(str.replace(/\+/g, ' ')); | ||
} catch (err) { | ||
return str; | ||
} | ||
} |
{ | ||
"name": "qs", | ||
"description": "querystring parser", | ||
"version": "0.5.2", | ||
"version": "0.5.3", | ||
"keywords": ["query string", "parser", "component"], | ||
@@ -6,0 +6,0 @@ "repository": { |
Sorry, the diff of this file is not supported yet
382227
20
12597