qs 0.5.2 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/History.md CHANGED
@@ -1,4 +1,25 @@
1
1
 
2
+ 0.5.6 / 2013-04-09
3
+ ==================
4
+
5
+ * fix empty key productions in parser
6
+
7
+ 0.5.5 / 2013-03-20
8
+ ==================
9
+
10
+ * output key= for null or undefined values. Closes #52
11
+
12
+ 0.5.4 / 2013-03-15
13
+ ==================
14
+
15
+ * fix ignoring of null / undefined. Closes #44
16
+
17
+ 0.5.3 2012-12-09
18
+ ==================
19
+
20
+ * add info to component.json
21
+ * remove regular client-side ./querystring.js, fix component.json support
22
+
2
23
  0.5.2 / 2012-11-14
3
24
  ==================
4
25
 
@@ -85,4 +106,4 @@
85
106
  0.0.1 / 2011-02-07
86
107
  ==================
87
108
 
88
- * Initial release
109
+ * Initial release
package/Makefile CHANGED
@@ -1,10 +1,4 @@
1
1
 
2
- test/browser/qs.js: querystring.js
3
- component build package.json test/browser/qs
4
-
5
- querystring.js: lib/head.js lib/querystring.js lib/tail.js
6
- cat $^ > $@
7
-
8
2
  test:
9
3
  @./node_modules/.bin/mocha \
10
4
  --ui bdd
package/component.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "querystring",
3
- "description": "Querystring parser / stringifier with nesting support",
3
+ "repo": "visionmedia/node-querystring",
4
+ "description": "query-string parser / stringifier with nesting support",
5
+ "version": "0.5.6",
4
6
  "keywords": ["querystring", "query", "parser"],
5
- "main": "lib/querystring.js"
6
- }
7
+ "scripts": ["index.js"],
8
+ "license": "MIT"
9
+ }
package/examples.js CHANGED
@@ -48,4 +48,4 @@ var obj = qs.parse('user[0]=tj&user[foo]=TJ');
48
48
  console.log(obj)
49
49
 
50
50
  var str = qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }});
51
- console.log(str);
51
+ console.log(str);
package/index.js CHANGED
@@ -1,2 +1,268 @@
1
1
 
2
- module.exports = require('./lib/querystring');
2
+ /**
3
+ * Object#toString() ref for stringify().
4
+ */
5
+
6
+ var toString = Object.prototype.toString;
7
+
8
+ /**
9
+ * Cache non-integer test regexp.
10
+ */
11
+
12
+ var isint = /^[0-9]+$/;
13
+
14
+ function promote(parent, key) {
15
+ if (parent[key].length == 0) return parent[key] = {};
16
+ var t = {};
17
+ for (var i in parent[key]) t[i] = parent[key][i];
18
+ parent[key] = t;
19
+ return t;
20
+ }
21
+
22
+ function parse(parts, parent, key, val) {
23
+ var part = parts.shift();
24
+ // end
25
+ if (!part) {
26
+ if (Array.isArray(parent[key])) {
27
+ parent[key].push(val);
28
+ } else if ('object' == typeof parent[key]) {
29
+ parent[key] = val;
30
+ } else if ('undefined' == typeof parent[key]) {
31
+ parent[key] = val;
32
+ } else {
33
+ parent[key] = [parent[key], val];
34
+ }
35
+ // array
36
+ } else {
37
+ var obj = parent[key] = parent[key] || [];
38
+ if (']' == part) {
39
+ if (Array.isArray(obj)) {
40
+ if ('' != val) obj.push(val);
41
+ } else if ('object' == typeof obj) {
42
+ obj[Object.keys(obj).length] = val;
43
+ } else {
44
+ obj = parent[key] = [parent[key], val];
45
+ }
46
+ // prop
47
+ } else if (~part.indexOf(']')) {
48
+ part = part.substr(0, part.length - 1);
49
+ if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
50
+ parse(parts, obj, part, val);
51
+ // key
52
+ } else {
53
+ if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
54
+ parse(parts, obj, part, val);
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Merge parent key/val pair.
61
+ */
62
+
63
+ function merge(parent, key, val){
64
+ if (~key.indexOf(']')) {
65
+ var parts = key.split('[')
66
+ , len = parts.length
67
+ , last = len - 1;
68
+ parse(parts, parent, 'base', val);
69
+ // optimize
70
+ } else {
71
+ if (!isint.test(key) && Array.isArray(parent.base)) {
72
+ var t = {};
73
+ for (var k in parent.base) t[k] = parent.base[k];
74
+ parent.base = t;
75
+ }
76
+ set(parent.base, key, val);
77
+ }
78
+
79
+ return parent;
80
+ }
81
+
82
+ /**
83
+ * Parse the given obj.
84
+ */
85
+
86
+ function parseObject(obj){
87
+ var ret = { base: {} };
88
+ Object.keys(obj).forEach(function(name){
89
+ merge(ret, name, obj[name]);
90
+ });
91
+ return ret.base;
92
+ }
93
+
94
+ /**
95
+ * Parse the given str.
96
+ */
97
+
98
+ function parseString(str){
99
+ return String(str)
100
+ .split('&')
101
+ .reduce(function(ret, pair){
102
+ var eql = pair.indexOf('=')
103
+ , brace = lastBraceInKey(pair)
104
+ , key = pair.substr(0, brace || eql)
105
+ , val = pair.substr(brace || eql, pair.length)
106
+ , val = val.substr(val.indexOf('=') + 1, val.length);
107
+
108
+ // ?foo
109
+ if ('' == key) key = pair, val = '';
110
+ if ('' == key) return ret;
111
+
112
+ return merge(ret, decode(key), decode(val));
113
+ }, { base: {} }).base;
114
+ }
115
+
116
+ /**
117
+ * Parse the given query `str` or `obj`, returning an object.
118
+ *
119
+ * @param {String} str | {Object} obj
120
+ * @return {Object}
121
+ * @api public
122
+ */
123
+
124
+ exports.parse = function(str){
125
+ if (null == str || '' == str) return {};
126
+ return 'object' == typeof str
127
+ ? parseObject(str)
128
+ : parseString(str);
129
+ };
130
+
131
+ /**
132
+ * Turn the given `obj` into a query string
133
+ *
134
+ * @param {Object} obj
135
+ * @return {String}
136
+ * @api public
137
+ */
138
+
139
+ var stringify = exports.stringify = function(obj, prefix) {
140
+ if (Array.isArray(obj)) {
141
+ return stringifyArray(obj, prefix);
142
+ } else if ('[object Object]' == toString.call(obj)) {
143
+ return stringifyObject(obj, prefix);
144
+ } else if ('string' == typeof obj) {
145
+ return stringifyString(obj, prefix);
146
+ } else {
147
+ return prefix + '=' + encodeURIComponent(String(obj));
148
+ }
149
+ };
150
+
151
+ /**
152
+ * Stringify the given `str`.
153
+ *
154
+ * @param {String} str
155
+ * @param {String} prefix
156
+ * @return {String}
157
+ * @api private
158
+ */
159
+
160
+ function stringifyString(str, prefix) {
161
+ if (!prefix) throw new TypeError('stringify expects an object');
162
+ return prefix + '=' + encodeURIComponent(str);
163
+ }
164
+
165
+ /**
166
+ * Stringify the given `arr`.
167
+ *
168
+ * @param {Array} arr
169
+ * @param {String} prefix
170
+ * @return {String}
171
+ * @api private
172
+ */
173
+
174
+ function stringifyArray(arr, prefix) {
175
+ var ret = [];
176
+ if (!prefix) throw new TypeError('stringify expects an object');
177
+ for (var i = 0; i < arr.length; i++) {
178
+ ret.push(stringify(arr[i], prefix + '[' + i + ']'));
179
+ }
180
+ return ret.join('&');
181
+ }
182
+
183
+ /**
184
+ * Stringify the given `obj`.
185
+ *
186
+ * @param {Object} obj
187
+ * @param {String} prefix
188
+ * @return {String}
189
+ * @api private
190
+ */
191
+
192
+ function stringifyObject(obj, prefix) {
193
+ var ret = []
194
+ , keys = Object.keys(obj)
195
+ , key;
196
+
197
+ for (var i = 0, len = keys.length; i < len; ++i) {
198
+ key = keys[i];
199
+ if ('' == key) continue;
200
+ if (null == obj[key]) {
201
+ ret.push(encodeURIComponent(key) + '=');
202
+ } else {
203
+ ret.push(stringify(obj[key], prefix
204
+ ? prefix + '[' + encodeURIComponent(key) + ']'
205
+ : encodeURIComponent(key)));
206
+ }
207
+ }
208
+
209
+ return ret.join('&');
210
+ }
211
+
212
+ /**
213
+ * Set `obj`'s `key` to `val` respecting
214
+ * the weird and wonderful syntax of a qs,
215
+ * where "foo=bar&foo=baz" becomes an array.
216
+ *
217
+ * @param {Object} obj
218
+ * @param {String} key
219
+ * @param {String} val
220
+ * @api private
221
+ */
222
+
223
+ function set(obj, key, val) {
224
+ var v = obj[key];
225
+ if (undefined === v) {
226
+ obj[key] = val;
227
+ } else if (Array.isArray(v)) {
228
+ v.push(val);
229
+ } else {
230
+ obj[key] = [v, val];
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Locate last brace in `str` within the key.
236
+ *
237
+ * @param {String} str
238
+ * @return {Number}
239
+ * @api private
240
+ */
241
+
242
+ function lastBraceInKey(str) {
243
+ var len = str.length
244
+ , brace
245
+ , c;
246
+ for (var i = 0; i < len; ++i) {
247
+ c = str[i];
248
+ if (']' == c) brace = false;
249
+ if ('[' == c) brace = true;
250
+ if ('=' == c && !brace) return i;
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Decode `str`.
256
+ *
257
+ * @param {String} str
258
+ * @return {String}
259
+ * @api private
260
+ */
261
+
262
+ function decode(str) {
263
+ try {
264
+ return decodeURIComponent(str.replace(/\+/g, ' '));
265
+ } catch (err) {
266
+ return str;
267
+ }
268
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qs",
3
3
  "description": "querystring parser",
4
- "version": "0.5.2",
4
+ "version": "0.5.6",
5
5
  "keywords": ["query string", "parser", "component"],
6
6
  "repository": {
7
7
  "type" : "git",
@@ -19,4 +19,4 @@
19
19
  "author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
20
20
  "main": "index",
21
21
  "engines": { "node": "*" }
22
- }
22
+ }
package/test/parse.js CHANGED
@@ -144,4 +144,9 @@ describe('qs.parse()', function(){
144
144
  expect(qs.parse({ 'user[name]': 'tobi', 'user[email][main]': 'tobi@lb.com' }))
145
145
  .to.eql({ user: { name: 'tobi', email: { main: 'tobi@lb.com' } }});
146
146
  })
147
- })
147
+
148
+ it('should not produce empty keys', function(){
149
+ expect(qs.parse('_r=1&'))
150
+ .to.eql({ _r: '1' })
151
+ })
152
+ })
package/test/stringify.js CHANGED
@@ -16,7 +16,9 @@ var str_identities = {
16
16
  { str: 'foo=1&bar=2', obj: {'foo' : '1', 'bar' : '2'}},
17
17
  { str: 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F', obj: {'my weird field': "q1!2\"'w$5&7/z8)?"}},
18
18
  { str: 'foo%3Dbaz=bar', obj: {'foo=baz': 'bar'}},
19
- { str: 'foo=bar&bar=baz', obj: {foo: 'bar', bar: 'baz'}}
19
+ { str: 'foo=bar&bar=baz', obj: {foo: 'bar', bar: 'baz'}},
20
+ { str: 'foo=bar&baz=&raz=', obj: { foo: 'bar', baz: null, raz: undefined }},
21
+ { str: 'foo=bar', obj: { foo: 'bar', '':'' }}
20
22
  ],
21
23
  'escaping': [
22
24
  { str: 'foo=foo%20bar', obj: {foo: 'foo bar'}},
package/lib/head.js DELETED
@@ -1 +0,0 @@
1
- ;(function(){
@@ -1,262 +0,0 @@
1
-
2
- /**
3
- * Object#toString() ref for stringify().
4
- */
5
-
6
- var toString = Object.prototype.toString;
7
-
8
- /**
9
- * Cache non-integer test regexp.
10
- */
11
-
12
- var isint = /^[0-9]+$/;
13
-
14
- function promote(parent, key) {
15
- if (parent[key].length == 0) return parent[key] = {};
16
- var t = {};
17
- for (var i in parent[key]) t[i] = parent[key][i];
18
- parent[key] = t;
19
- return t;
20
- }
21
-
22
- function parse(parts, parent, key, val) {
23
- var part = parts.shift();
24
- // end
25
- if (!part) {
26
- if (Array.isArray(parent[key])) {
27
- parent[key].push(val);
28
- } else if ('object' == typeof parent[key]) {
29
- parent[key] = val;
30
- } else if ('undefined' == typeof parent[key]) {
31
- parent[key] = val;
32
- } else {
33
- parent[key] = [parent[key], val];
34
- }
35
- // array
36
- } else {
37
- var obj = parent[key] = parent[key] || [];
38
- if (']' == part) {
39
- if (Array.isArray(obj)) {
40
- if ('' != val) obj.push(val);
41
- } else if ('object' == typeof obj) {
42
- obj[Object.keys(obj).length] = val;
43
- } else {
44
- obj = parent[key] = [parent[key], val];
45
- }
46
- // prop
47
- } else if (~part.indexOf(']')) {
48
- part = part.substr(0, part.length - 1);
49
- if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
50
- parse(parts, obj, part, val);
51
- // key
52
- } else {
53
- if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
54
- parse(parts, obj, part, val);
55
- }
56
- }
57
- }
58
-
59
- /**
60
- * Merge parent key/val pair.
61
- */
62
-
63
- function merge(parent, key, val){
64
- if (~key.indexOf(']')) {
65
- var parts = key.split('[')
66
- , len = parts.length
67
- , last = len - 1;
68
- parse(parts, parent, 'base', val);
69
- // optimize
70
- } else {
71
- if (!isint.test(key) && Array.isArray(parent.base)) {
72
- var t = {};
73
- for (var k in parent.base) t[k] = parent.base[k];
74
- parent.base = t;
75
- }
76
- set(parent.base, key, val);
77
- }
78
-
79
- return parent;
80
- }
81
-
82
- /**
83
- * Parse the given obj.
84
- */
85
-
86
- function parseObject(obj){
87
- var ret = { base: {} };
88
- Object.keys(obj).forEach(function(name){
89
- merge(ret, name, obj[name]);
90
- });
91
- return ret.base;
92
- }
93
-
94
- /**
95
- * Parse the given str.
96
- */
97
-
98
- function parseString(str){
99
- return String(str)
100
- .split('&')
101
- .reduce(function(ret, pair){
102
- var eql = pair.indexOf('=')
103
- , brace = lastBraceInKey(pair)
104
- , key = pair.substr(0, brace || eql)
105
- , val = pair.substr(brace || eql, pair.length)
106
- , val = val.substr(val.indexOf('=') + 1, val.length);
107
-
108
- // ?foo
109
- if ('' == key) key = pair, val = '';
110
-
111
- return merge(ret, decode(key), decode(val));
112
- }, { base: {} }).base;
113
- }
114
-
115
- /**
116
- * Parse the given query `str` or `obj`, returning an object.
117
- *
118
- * @param {String} str | {Object} obj
119
- * @return {Object}
120
- * @api public
121
- */
122
-
123
- exports.parse = function(str){
124
- if (null == str || '' == str) return {};
125
- return 'object' == typeof str
126
- ? parseObject(str)
127
- : parseString(str);
128
- };
129
-
130
- /**
131
- * Turn the given `obj` into a query string
132
- *
133
- * @param {Object} obj
134
- * @return {String}
135
- * @api public
136
- */
137
-
138
- var stringify = exports.stringify = function(obj, prefix) {
139
- if (Array.isArray(obj)) {
140
- return stringifyArray(obj, prefix);
141
- } else if ('[object Object]' == toString.call(obj)) {
142
- return stringifyObject(obj, prefix);
143
- } else if ('string' == typeof obj) {
144
- return stringifyString(obj, prefix);
145
- } else {
146
- return prefix + '=' + encodeURIComponent(String(obj));
147
- }
148
- };
149
-
150
- /**
151
- * Stringify the given `str`.
152
- *
153
- * @param {String} str
154
- * @param {String} prefix
155
- * @return {String}
156
- * @api private
157
- */
158
-
159
- function stringifyString(str, prefix) {
160
- if (!prefix) throw new TypeError('stringify expects an object');
161
- return prefix + '=' + encodeURIComponent(str);
162
- }
163
-
164
- /**
165
- * Stringify the given `arr`.
166
- *
167
- * @param {Array} arr
168
- * @param {String} prefix
169
- * @return {String}
170
- * @api private
171
- */
172
-
173
- function stringifyArray(arr, prefix) {
174
- var ret = [];
175
- if (!prefix) throw new TypeError('stringify expects an object');
176
- for (var i = 0; i < arr.length; i++) {
177
- ret.push(stringify(arr[i], prefix + '[' + i + ']'));
178
- }
179
- return ret.join('&');
180
- }
181
-
182
- /**
183
- * Stringify the given `obj`.
184
- *
185
- * @param {Object} obj
186
- * @param {String} prefix
187
- * @return {String}
188
- * @api private
189
- */
190
-
191
- function stringifyObject(obj, prefix) {
192
- var ret = []
193
- , keys = Object.keys(obj)
194
- , key;
195
-
196
- for (var i = 0, len = keys.length; i < len; ++i) {
197
- key = keys[i];
198
- ret.push(stringify(obj[key], prefix
199
- ? prefix + '[' + encodeURIComponent(key) + ']'
200
- : encodeURIComponent(key)));
201
- }
202
-
203
- return ret.join('&');
204
- }
205
-
206
- /**
207
- * Set `obj`'s `key` to `val` respecting
208
- * the weird and wonderful syntax of a qs,
209
- * where "foo=bar&foo=baz" becomes an array.
210
- *
211
- * @param {Object} obj
212
- * @param {String} key
213
- * @param {String} val
214
- * @api private
215
- */
216
-
217
- function set(obj, key, val) {
218
- var v = obj[key];
219
- if (undefined === v) {
220
- obj[key] = val;
221
- } else if (Array.isArray(v)) {
222
- v.push(val);
223
- } else {
224
- obj[key] = [v, val];
225
- }
226
- }
227
-
228
- /**
229
- * Locate last brace in `str` within the key.
230
- *
231
- * @param {String} str
232
- * @return {Number}
233
- * @api private
234
- */
235
-
236
- function lastBraceInKey(str) {
237
- var len = str.length
238
- , brace
239
- , c;
240
- for (var i = 0; i < len; ++i) {
241
- c = str[i];
242
- if (']' == c) brace = false;
243
- if ('[' == c) brace = true;
244
- if ('=' == c && !brace) return i;
245
- }
246
- }
247
-
248
- /**
249
- * Decode `str`.
250
- *
251
- * @param {String} str
252
- * @return {String}
253
- * @api private
254
- */
255
-
256
- function decode(str) {
257
- try {
258
- return decodeURIComponent(str.replace(/\+/g, ' '));
259
- } catch (err) {
260
- return str;
261
- }
262
- }
package/lib/tail.js DELETED
@@ -1 +0,0 @@
1
- })();
package/querystring.js DELETED
@@ -1,254 +0,0 @@
1
- ;(function(){
2
-
3
- /**
4
- * Object#toString() ref for stringify().
5
- */
6
-
7
- var toString = Object.prototype.toString;
8
-
9
- /**
10
- * Cache non-integer test regexp.
11
- */
12
-
13
- var isint = /^[0-9]+$/;
14
-
15
- function promote(parent, key) {
16
- if (parent[key].length == 0) return parent[key] = {};
17
- var t = {};
18
- for (var i in parent[key]) t[i] = parent[key][i];
19
- parent[key] = t;
20
- return t;
21
- }
22
-
23
- function parse(parts, parent, key, val) {
24
- var part = parts.shift();
25
- // end
26
- if (!part) {
27
- if (Array.isArray(parent[key])) {
28
- parent[key].push(val);
29
- } else if ('object' == typeof parent[key]) {
30
- parent[key] = val;
31
- } else if ('undefined' == typeof parent[key]) {
32
- parent[key] = val;
33
- } else {
34
- parent[key] = [parent[key], val];
35
- }
36
- // array
37
- } else {
38
- var obj = parent[key] = parent[key] || [];
39
- if (']' == part) {
40
- if (Array.isArray(obj)) {
41
- if ('' != val) obj.push(val);
42
- } else if ('object' == typeof obj) {
43
- obj[Object.keys(obj).length] = val;
44
- } else {
45
- obj = parent[key] = [parent[key], val];
46
- }
47
- // prop
48
- } else if (~part.indexOf(']')) {
49
- part = part.substr(0, part.length - 1);
50
- if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
51
- parse(parts, obj, part, val);
52
- // key
53
- } else {
54
- if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
55
- parse(parts, obj, part, val);
56
- }
57
- }
58
- }
59
-
60
- /**
61
- * Merge parent key/val pair.
62
- */
63
-
64
- function merge(parent, key, val){
65
- if (~key.indexOf(']')) {
66
- var parts = key.split('[')
67
- , len = parts.length
68
- , last = len - 1;
69
- parse(parts, parent, 'base', val);
70
- // optimize
71
- } else {
72
- if (!isint.test(key) && Array.isArray(parent.base)) {
73
- var t = {};
74
- for (var k in parent.base) t[k] = parent.base[k];
75
- parent.base = t;
76
- }
77
- set(parent.base, key, val);
78
- }
79
-
80
- return parent;
81
- }
82
-
83
- /**
84
- * Parse the given obj.
85
- */
86
-
87
- function parseObject(obj){
88
- var ret = { base: {} };
89
- Object.keys(obj).forEach(function(name){
90
- merge(ret, name, obj[name]);
91
- });
92
- return ret.base;
93
- }
94
-
95
- /**
96
- * Parse the given str.
97
- */
98
-
99
- function parseString(str){
100
- return String(str)
101
- .split('&')
102
- .reduce(function(ret, pair){
103
- try{
104
- pair = decodeURIComponent(pair.replace(/\+/g, ' '));
105
- } catch(e) {
106
- // ignore
107
- }
108
-
109
- var eql = pair.indexOf('=')
110
- , brace = lastBraceInKey(pair)
111
- , key = pair.substr(0, brace || eql)
112
- , val = pair.substr(brace || eql, pair.length)
113
- , val = val.substr(val.indexOf('=') + 1, val.length);
114
-
115
- // ?foo
116
- if ('' == key) key = pair, val = '';
117
-
118
- return merge(ret, key, val);
119
- }, { base: {} }).base;
120
- }
121
-
122
- /**
123
- * Parse the given query `str` or `obj`, returning an object.
124
- *
125
- * @param {String} str | {Object} obj
126
- * @return {Object}
127
- * @api public
128
- */
129
-
130
- exports.parse = function(str){
131
- if (null == str || '' == str) return {};
132
- return 'object' == typeof str
133
- ? parseObject(str)
134
- : parseString(str);
135
- };
136
-
137
- /**
138
- * Turn the given `obj` into a query string
139
- *
140
- * @param {Object} obj
141
- * @return {String}
142
- * @api public
143
- */
144
-
145
- var stringify = exports.stringify = function(obj, prefix) {
146
- if (Array.isArray(obj)) {
147
- return stringifyArray(obj, prefix);
148
- } else if ('[object Object]' == toString.call(obj)) {
149
- return stringifyObject(obj, prefix);
150
- } else if ('string' == typeof obj) {
151
- return stringifyString(obj, prefix);
152
- } else {
153
- return prefix + '=' + obj;
154
- }
155
- };
156
-
157
- /**
158
- * Stringify the given `str`.
159
- *
160
- * @param {String} str
161
- * @param {String} prefix
162
- * @return {String}
163
- * @api private
164
- */
165
-
166
- function stringifyString(str, prefix) {
167
- if (!prefix) throw new TypeError('stringify expects an object');
168
- return prefix + '=' + encodeURIComponent(str);
169
- }
170
-
171
- /**
172
- * Stringify the given `arr`.
173
- *
174
- * @param {Array} arr
175
- * @param {String} prefix
176
- * @return {String}
177
- * @api private
178
- */
179
-
180
- function stringifyArray(arr, prefix) {
181
- var ret = [];
182
- if (!prefix) throw new TypeError('stringify expects an object');
183
- for (var i = 0; i < arr.length; i++) {
184
- ret.push(stringify(arr[i], prefix + '['+i+']'));
185
- }
186
- return ret.join('&');
187
- }
188
-
189
- /**
190
- * Stringify the given `obj`.
191
- *
192
- * @param {Object} obj
193
- * @param {String} prefix
194
- * @return {String}
195
- * @api private
196
- */
197
-
198
- function stringifyObject(obj, prefix) {
199
- var ret = []
200
- , keys = Object.keys(obj)
201
- , key;
202
-
203
- for (var i = 0, len = keys.length; i < len; ++i) {
204
- key = keys[i];
205
- ret.push(stringify(obj[key], prefix
206
- ? prefix + '[' + encodeURIComponent(key) + ']'
207
- : encodeURIComponent(key)));
208
- }
209
-
210
- return ret.join('&');
211
- }
212
-
213
- /**
214
- * Set `obj`'s `key` to `val` respecting
215
- * the weird and wonderful syntax of a qs,
216
- * where "foo=bar&foo=baz" becomes an array.
217
- *
218
- * @param {Object} obj
219
- * @param {String} key
220
- * @param {String} val
221
- * @api private
222
- */
223
-
224
- function set(obj, key, val) {
225
- var v = obj[key];
226
- if (undefined === v) {
227
- obj[key] = val;
228
- } else if (Array.isArray(v)) {
229
- v.push(val);
230
- } else {
231
- obj[key] = [v, val];
232
- }
233
- }
234
-
235
- /**
236
- * Locate last brace in `str` within the key.
237
- *
238
- * @param {String} str
239
- * @return {Number}
240
- * @api private
241
- */
242
-
243
- function lastBraceInKey(str) {
244
- var len = str.length
245
- , brace
246
- , c;
247
- for (var i = 0; i < len; ++i) {
248
- c = str[i];
249
- if (']' == c) brace = false;
250
- if ('[' == c) brace = true;
251
- if ('=' == c && !brace) return i;
252
- }
253
- }
254
- })();