forked from tj/node-querystring
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added client-side support. Closes tj#33
- Loading branch information
Showing
12 changed files
with
14,205 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
|
||
querystring.js: lib/head.js lib/querystring.js lib/tail.js | ||
cat $^ > $@ | ||
|
||
test: | ||
@./node_modules/.bin/mocha \ | ||
--require should \ | ||
--ui bdd | ||
|
||
.PHONY: test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
(function(exports){ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
})('undefined' == typeof exports ? qs = {} : exports); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
(function(exports){ | ||
/*! | ||
* querystring | ||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca> | ||
* MIT Licensed | ||
*/ | ||
|
||
/** | ||
* Library version. | ||
*/ | ||
|
||
exports.version = '0.4.2'; | ||
|
||
/** | ||
* 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){ | ||
try{ | ||
pair = decodeURIComponent(pair.replace(/\+/g, ' ')); | ||
} catch(e) { | ||
// ignore | ||
} | ||
|
||
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, key, 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 + '=' + 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; | ||
} | ||
} | ||
})('undefined' == typeof exports ? qs = {} : exports); |
Oops, something went wrong.