summaryrefslogtreecommitdiff
path: root/lib/querystring.js
diff options
context:
space:
mode:
authorPeter Griess <pg@std.in>2010-09-13 13:54:30 -0500
committerRyan Dahl <ry@tinyclouds.org>2010-09-13 12:39:30 -0700
commit422d3c93bc7391e105cfb4363011088c27ec86a6 (patch)
tree70a30ffb42ee712f08d8b9f28e4b02009a7dc56d /lib/querystring.js
parentdebf3894906e5b52f16c066e81679997538a55e2 (diff)
downloadnodejs-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.js129
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;
};