qs 0.4.0 → 0.5.1

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.
File without changes
package/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: node_js
2
+ node_js:
3
+ - 0.6
4
+ - 0.4
package/History.md CHANGED
@@ -1,4 +1,24 @@
1
1
 
2
+ 0.5.1 / 2012-09-18
3
+ ==================
4
+
5
+ * fix encoded `=`. Closes #43
6
+
7
+ 0.5.0 / 2012-05-04
8
+ ==================
9
+
10
+ * Added component support
11
+
12
+ 0.4.2 / 2012-02-08
13
+ ==================
14
+
15
+ * Fixed: ensure objects are created when appropriate not arrays [aheckmann]
16
+
17
+ 0.4.1 / 2012-01-26
18
+ ==================
19
+
20
+ * Fixed stringify()ing numbers. Closes #23
21
+
2
22
  0.4.0 / 2011-11-21
3
23
  ==================
4
24
 
package/Makefile CHANGED
@@ -1,5 +1,12 @@
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
+
2
8
  test:
3
- @./node_modules/.bin/mocha
9
+ @./node_modules/.bin/mocha \
10
+ --ui bdd
4
11
 
5
12
  .PHONY: test
package/Readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # node-querystring
2
2
 
3
- query string parser for node supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others.
3
+ query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,8 +8,15 @@
8
8
 
9
9
  ## Examples
10
10
 
11
- require('qs').parse('user[name][first]=tj&user[email]=tj');
12
- // => { user: { name: { first: 'tj' }, email: 'tj' } }
11
+ ```js
12
+ var qs = require('qs');
13
+
14
+ qs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com');
15
+ // => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } }
16
+
17
+ qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }})
18
+ // => user[name]=Tobi&user[email]=tobi%40learnboost.com
19
+ ```
13
20
 
14
21
  ## Testing
15
22
 
@@ -21,6 +28,10 @@ and execute:
21
28
 
22
29
  $ make test
23
30
 
31
+ browser:
32
+
33
+ $ open test/browser/index.html
34
+
24
35
  ## License
25
36
 
26
37
  (The MIT License)
package/component.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "querystring",
3
+ "description": "Querystring parser / stringifier with nesting support",
4
+ "keywords": ["querystring", "query", "parser"],
5
+ "main": "lib/querystring.js"
6
+ }
package/examples.js CHANGED
@@ -46,3 +46,6 @@ console.log(obj)
46
46
 
47
47
  var obj = qs.parse('user[0]=tj&user[foo]=TJ');
48
48
  console.log(obj)
49
+
50
+ var str = qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }});
51
+ console.log(str);
package/lib/head.js ADDED
@@ -0,0 +1 @@
1
+ ;(function(){
@@ -1,16 +1,4 @@
1
1
 
2
- /*!
3
- * querystring
4
- * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
5
- * MIT Licensed
6
- */
7
-
8
- /**
9
- * Library version.
10
- */
11
-
12
- exports.version = '0.4.0';
13
-
14
2
  /**
15
3
  * Object#toString() ref for stringify().
16
4
  */
@@ -21,7 +9,7 @@ var toString = Object.prototype.toString;
21
9
  * Cache non-integer test regexp.
22
10
  */
23
11
 
24
- var notint = /[^0-9]/;
12
+ var isint = /^[0-9]+$/;
25
13
 
26
14
  function promote(parent, key) {
27
15
  if (parent[key].length == 0) return parent[key] = {};
@@ -58,11 +46,11 @@ function parse(parts, parent, key, val) {
58
46
  // prop
59
47
  } else if (~part.indexOf(']')) {
60
48
  part = part.substr(0, part.length - 1);
61
- if(notint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
49
+ if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
62
50
  parse(parts, obj, part, val);
63
51
  // key
64
52
  } else {
65
- if(notint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
53
+ if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
66
54
  parse(parts, obj, part, val);
67
55
  }
68
56
  }
@@ -80,7 +68,7 @@ function merge(parent, key, val){
80
68
  parse(parts, parent, 'base', val);
81
69
  // optimize
82
70
  } else {
83
- if (notint.test(key) && Array.isArray(parent.base)) {
71
+ if (!isint.test(key) && Array.isArray(parent.base)) {
84
72
  var t = {};
85
73
  for (var k in parent.base) t[k] = parent.base[k];
86
74
  parent.base = t;
@@ -111,12 +99,6 @@ function parseString(str){
111
99
  return String(str)
112
100
  .split('&')
113
101
  .reduce(function(ret, pair){
114
- try{
115
- pair = decodeURIComponent(pair.replace(/\+/g, ' '));
116
- } catch(e) {
117
- // ignore
118
- }
119
-
120
102
  var eql = pair.indexOf('=')
121
103
  , brace = lastBraceInKey(pair)
122
104
  , key = pair.substr(0, brace || eql)
@@ -126,7 +108,7 @@ function parseString(str){
126
108
  // ?foo
127
109
  if ('' == key) key = pair, val = '';
128
110
 
129
- return merge(ret, key, val);
111
+ return merge(ret, decode(key), decode(val));
130
112
  }, { base: {} }).base;
131
113
  }
132
114
 
@@ -161,7 +143,7 @@ var stringify = exports.stringify = function(obj, prefix) {
161
143
  } else if ('string' == typeof obj) {
162
144
  return stringifyString(obj, prefix);
163
145
  } else {
164
- return prefix;
146
+ return prefix + '=' + obj;
165
147
  }
166
148
  };
167
149
 
@@ -192,7 +174,7 @@ function stringifyArray(arr, prefix) {
192
174
  var ret = [];
193
175
  if (!prefix) throw new TypeError('stringify expects an object');
194
176
  for (var i = 0; i < arr.length; i++) {
195
- ret.push(stringify(arr[i], prefix + '[]'));
177
+ ret.push(stringify(arr[i], prefix + '['+i+']'));
196
178
  }
197
179
  return ret.join('&');
198
180
  }
@@ -210,12 +192,14 @@ function stringifyObject(obj, prefix) {
210
192
  var ret = []
211
193
  , keys = Object.keys(obj)
212
194
  , key;
195
+
213
196
  for (var i = 0, len = keys.length; i < len; ++i) {
214
197
  key = keys[i];
215
198
  ret.push(stringify(obj[key], prefix
216
199
  ? prefix + '[' + encodeURIComponent(key) + ']'
217
200
  : encodeURIComponent(key)));
218
201
  }
202
+
219
203
  return ret.join('&');
220
204
  }
221
205
 
@@ -260,3 +244,19 @@ function lastBraceInKey(str) {
260
244
  if ('=' == c && !brace) return i;
261
245
  }
262
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 ADDED
@@ -0,0 +1 @@
1
+ })();
package/package.json CHANGED
@@ -1,14 +1,20 @@
1
1
  {
2
2
  "name": "qs",
3
3
  "description": "querystring parser",
4
- "version": "0.4.0",
4
+ "version": "0.5.1",
5
+ "keywords": ["query string", "parser", "component"],
5
6
  "repository": {
6
7
  "type" : "git",
7
8
  "url" : "git://github.com/visionmedia/node-querystring.git"
8
9
  },
9
10
  "devDependencies": {
10
11
  "mocha": "*"
11
- , "should": "*"
12
+ , "expect.js": "*"
13
+ },
14
+ "component": {
15
+ "scripts": {
16
+ "querystring": "querystring.js"
17
+ }
12
18
  },
13
19
  "author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
14
20
  "main": "index",
package/querystring.js ADDED
@@ -0,0 +1,254 @@
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
+ })();