diff options
author | Peter Griess <pg@std.in> | 2010-09-13 13:54:30 -0500 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-09-13 12:39:30 -0700 |
commit | 422d3c93bc7391e105cfb4363011088c27ec86a6 (patch) | |
tree | 70a30ffb42ee712f08d8b9f28e4b02009a7dc56d /lib/querystring.js | |
parent | debf3894906e5b52f16c066e81679997538a55e2 (diff) | |
download | nodejs-422d3c93bc7391e105cfb4363011088c27ec86a6.tar.gz nodejs-422d3c93bc7391e105cfb4363011088c27ec86a6.tar.bz2 nodejs-422d3c93bc7391e105cfb4363011088c27ec86a6.zip |
Get rid of PHP/Rails style parameter munging.
- Handle only the most basic of query string parsing and construction.
Leave the rest (e.g. Rails/PHP behaviors) to modules higher up the
stack, like Express.
Diffstat (limited to 'lib/querystring.js')
-rw-r--r-- | lib/querystring.js | 129 |
1 files changed, 56 insertions, 73 deletions
diff --git a/lib/querystring.js b/lib/querystring.js index 69ea00854..f60ab1dc5 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -10,8 +10,22 @@ QueryString.escape = function (str) { return encodeURIComponent(str); }; +var stringifyPrimitive = function(v) { + switch (typeof v) { + case "string": + return v; + + case "boolean": + return v ? "true" : "false"; + + case "number": + return isFinite(v) ? v : ""; + + default: + return ""; + } +}; -var stack = []; /** * <p>Converts an arbitrary value to a Query String representation.</p> * @@ -21,92 +35,61 @@ var stack = []; * @param obj {Variant} any arbitrary value to convert to query string * @param sep {String} (optional) Character that should join param k=v pairs together. Default: "&" * @param eq {String} (optional) Character that should join keys to their values. Default: "=" - * @param munge {Boolean} (optional) Indicate whether array/object params should be munged, PHP/Rails-style. Default: true * @param name {String} (optional) Name of the current key, for handling children recursively. * @static */ -QueryString.stringify = QueryString.encode = function (obj, sep, eq, munge, name) { - munge = typeof munge == "undefined" || munge; +QueryString.stringify = QueryString.encode = function (obj, sep, eq, name) { sep = sep || "&"; eq = eq || "="; - var type = Object.prototype.toString.call(obj); - if (obj == null || type == "[object Function]" || type == "[object Number]" && !isFinite(obj)) { - return name ? QueryString.escape(name) + eq : ""; - } - - switch (type) { - case '[object Boolean]': - obj = +obj; // fall through - case '[object Number]': - case '[object String]': - return QueryString.escape(name) + eq + QueryString.escape(obj); - case '[object Array]': - name = name + (munge ? "[]" : ""); - return obj.map(function (item) { - return QueryString.stringify(item, sep, eq, munge, name); - }).join(sep); - } - // now we know it's an object. - - // Check for cyclical references in nested objects - for (var i = stack.length - 1; i >= 0; --i) if (stack[i] === obj) { - throw new Error("querystring.stringify. Cyclical reference"); - } - - stack.push(obj); + obj = (obj === null) ? undefined : obj; - var begin = name ? name + "[" : "", - end = name ? "]" : "", - keys = Object.keys(obj), - n, - s = Object.keys(obj).map(function (key) { - n = begin + key + end; - return QueryString.stringify(obj[key], sep, eq, munge, n); + switch (typeof obj) { + case "object": + return Object.keys(obj).map(function(k) { + if (Array.isArray(obj[k])) { + return obj[k].map(function(v) { + return QueryString.escape(stringifyPrimitive(k)) + + eq + + QueryString.escape(stringifyPrimitive(v)); + }).join(sep); + } else { + return QueryString.escape(stringifyPrimitive(k)) + + eq + + QueryString.escape(stringifyPrimitive(obj[k])); + } }).join(sep); - stack.pop(); - - if (!s && name) { - return name + "="; + default: + return (name) ? + QueryString.escape(stringifyPrimitive(name)) + eq + + QueryString.escape(stringifyPrimitive(obj)) : + ""; } - return s; }; -// matches .xxxxx or [xxxxx] or ['xxxxx'] or ["xxxxx"] with optional [] at the end -var chunks = /(?:(?:^|\.)([^\[\(\.]+)(?=\[|\.|$|\()|\[([^"'][^\]]*?)\]|\["([^\]"]*?)"\]|\['([^\]']*?)'\])(\[\])?/g; // Parse a key=val string. QueryString.parse = QueryString.decode = function (qs, sep, eq) { + sep = sep || "&"; + eq = eq || "="; var obj = {}; - if (qs === undefined) { return {} } - String(qs).split(sep || "&").map(function (keyValue) { - var res = obj, - next, - kv = keyValue.split(eq || "="), - key = QueryString.unescape(kv.shift(), true), - value = QueryString.unescape(kv.join(eq || "="), true); - key.replace(chunks, function (all, name, nameInBrackets, nameIn2Quotes, nameIn1Quotes, isArray, offset) { - var end = offset + all.length == key.length; - name = name || nameInBrackets || nameIn2Quotes || nameIn1Quotes; - next = end ? value : {}; - if (Array.isArray(res[name])) { - res[name].push(next); - res = next; - } else { - if (name in res) { - if (isArray || end) { - res = (res[name] = [res[name], next])[1]; - } else { - res = res[name]; - } - } else { - if (isArray) { - res = (res[name] = [next])[0]; - } else { - res = res[name] = next; - } - } - } - }); + + if (typeof qs !== 'string') { + return obj; + } + + qs.split(sep).forEach(function(kvp) { + var x = kvp.split(eq); + var k = QueryString.unescape(x[0], true); + var v = QueryString.unescape(x.slice(1).join(eq), true); + + if (!(k in obj)) { + obj[k] = v; + } else if (!Array.isArray(obj[k])) { + obj[k] = [obj[k], v]; + } else { + obj[k].push(v); + } }); + return obj; }; |