2010-01-04 08:14:12 +01:00
|
|
|
// Query String Utilities
|
|
|
|
|
|
|
|
var QueryString = exports;
|
2010-06-29 10:24:43 +02:00
|
|
|
var urlDecode = process.binding("http_parser").urlDecode;
|
2010-01-04 08:14:12 +01:00
|
|
|
|
2010-06-15 06:13:09 +02:00
|
|
|
// a safe fast alternative to decodeURIComponent
|
|
|
|
QueryString.unescape = urlDecode;
|
2010-01-04 08:14:12 +01:00
|
|
|
|
|
|
|
QueryString.escape = function (str) {
|
|
|
|
return encodeURIComponent(str);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var stack = [];
|
|
|
|
/**
|
|
|
|
* <p>Converts an arbitrary value to a Query String representation.</p>
|
|
|
|
*
|
|
|
|
* <p>Objects with cyclical references will trigger an exception.</p>
|
|
|
|
*
|
|
|
|
* @method stringify
|
|
|
|
* @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: "="
|
2010-04-28 08:31:28 +02:00
|
|
|
* @param munge {Boolean} (optional) Indicate whether array/object params should be munged, PHP/Rails-style. Default: true
|
2010-01-04 08:14:12 +01:00
|
|
|
* @param name {String} (optional) Name of the current key, for handling children recursively.
|
|
|
|
* @static
|
|
|
|
*/
|
2010-06-15 06:13:09 +02:00
|
|
|
QueryString.stringify = QueryString.encode = function (obj, sep, eq, munge, name) {
|
2010-06-29 10:24:43 +02:00
|
|
|
munge = typeof munge == "undefined" || munge;
|
2010-01-04 08:14:12 +01:00
|
|
|
sep = sep || "&";
|
|
|
|
eq = eq || "=";
|
2010-07-18 22:16:43 +02:00
|
|
|
var type = Object.prototype.toString.call(obj);
|
|
|
|
if (obj == null || type == "[object Function]" || type == "[object Number]" && !isFinite(obj)) {
|
2010-06-29 10:24:43 +02:00
|
|
|
return name ? QueryString.escape(name) + eq : "";
|
2010-01-04 08:14:12 +01:00
|
|
|
}
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-07-18 22:16:43 +02:00
|
|
|
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);
|
2010-01-04 08:14:12 +01:00
|
|
|
}
|
|
|
|
// now we know it's an object.
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-01-04 08:14:12 +01:00
|
|
|
// 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");
|
|
|
|
}
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-01-04 08:14:12 +01:00
|
|
|
stack.push(obj);
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-06-29 10:24:43 +02:00
|
|
|
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);
|
|
|
|
}).join(sep);
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-01-04 08:14:12 +01:00
|
|
|
stack.pop();
|
2010-04-11 22:46:24 +02:00
|
|
|
|
2010-06-29 10:24:43 +02:00
|
|
|
if (!s && name) {
|
|
|
|
return name + "=";
|
|
|
|
}
|
2010-01-04 08:14:12 +01:00
|
|
|
return s;
|
|
|
|
};
|
|
|
|
|
2010-06-29 10:24:43 +02:00
|
|
|
// matches .xxxxx or [xxxxx] or ['xxxxx'] or ["xxxxx"] with optional [] at the end
|
|
|
|
var chunks = /(?:(?:^|\.)([^\[\(\.]+)(?=\[|\.|$|\()|\[([^"'][^\]]*?)\]|\["([^\]"]*?)"\]|\['([^\]']*?)'\])(\[\])?/g;
|
2010-01-04 08:14:12 +01:00
|
|
|
// Parse a key=val string.
|
2010-06-29 10:24:43 +02:00
|
|
|
QueryString.parse = QueryString.decode = function (qs, sep, eq) {
|
|
|
|
var obj = {};
|
2010-08-05 09:13:40 +02:00
|
|
|
if (qs === undefined) { return {} }
|
2010-06-29 10:24:43 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return obj;
|
2010-01-04 08:14:12 +01:00
|
|
|
};
|