qs 1.1.0 → 1.2.0

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/README.md CHANGED
@@ -19,6 +19,10 @@ var str = Qs.stringify(obj); // 'a=c'
19
19
 
20
20
  ### Parsing Objects
21
21
 
22
+ ```javascript
23
+ Qs.parse(string, [depth], [delimiter]);
24
+ ```
25
+
22
26
  **qs** allows you to create nested objects within your query strings, by surrounding the name of sub-keys with square brackets `[]`.
23
27
  For example, the string `'foo[bar]=baz'` converts to:
24
28
 
@@ -79,6 +83,13 @@ Qs.parse('a[b][c][d][e][f][g][h][i]=j', 1);
79
83
 
80
84
  The depth limit mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number.
81
85
 
86
+ An optional delimiter can also be passed:
87
+
88
+ ```javascript
89
+ Qs.parse('a=b;c=d', ';');
90
+ // { a: 'b', c: 'd' }
91
+ ```
92
+
82
93
  ### Parsing Arrays
83
94
 
84
95
  **qs** can also parse arrays using a similar `[]` notation:
@@ -137,6 +148,10 @@ Qs.parse('a[][b]=c');
137
148
 
138
149
  ### Stringifying
139
150
 
151
+ ```javascript
152
+ Qs.stringify(object, [delimiter]);
153
+ ```
154
+
140
155
  When stringifying, **qs** always URI encodes output. Objects are stringified as you would expect:
141
156
 
142
157
  ```javascript
@@ -168,3 +183,9 @@ Properties that are set to `undefined` will be omitted entirely:
168
183
  Qs.stringify({ a: null, b: undefined });
169
184
  // 'a='
170
185
  ```
186
+
187
+ The delimiter may be overridden with stringify as well:
188
+
189
+ ```javascript
190
+ Qs.stringify({ a: 'b', c: 'd' }, ';');
191
+ // 'a=b;c=d'
package/lib/parse.js CHANGED
@@ -6,16 +6,19 @@ var Utils = require('./utils');
6
6
  // Declare internals
7
7
 
8
8
  var internals = {
9
+ delimiter: '&',
9
10
  depth: 5,
10
11
  arrayLimit: 20,
11
12
  parametersLimit: 1000
12
13
  };
13
14
 
14
15
 
15
- internals.parseValues = function (str) {
16
+ internals.parseValues = function (str, delimiter) {
17
+
18
+ delimiter = typeof delimiter === 'undefined' ? internals.delimiter : delimiter;
16
19
 
17
20
  var obj = {};
18
- var parts = str.split('&').slice(0, internals.parametersLimit);
21
+ var parts = str.split(delimiter, internals.parametersLimit);
19
22
 
20
23
  for (var i = 0, il = parts.length; i < il; ++i) {
21
24
  var part = parts[i];
@@ -79,8 +82,6 @@ internals.parseKeys = function (key, val, depth) {
79
82
  return;
80
83
  }
81
84
 
82
- depth = typeof depth === 'undefined' ? internals.depth : depth;
83
-
84
85
  // The regex chunks
85
86
 
86
87
  var parent = /^([^\[\]]*)/;
@@ -124,7 +125,7 @@ internals.parseKeys = function (key, val, depth) {
124
125
  };
125
126
 
126
127
 
127
- module.exports = function (str, depth) {
128
+ module.exports = function (str, depth, delimiter) {
128
129
 
129
130
  if (str === '' ||
130
131
  str === null ||
@@ -133,11 +134,16 @@ module.exports = function (str, depth) {
133
134
  return {};
134
135
  }
135
136
 
136
- var tempObj = typeof str === 'string' ? internals.parseValues(str) : Utils.clone(str);
137
+ if (typeof depth !== 'number') {
138
+ delimiter = depth;
139
+ depth = internals.depth;
140
+ }
141
+
142
+ var tempObj = typeof str === 'string' ? internals.parseValues(str, delimiter) : Utils.clone(str);
137
143
  var obj = {};
138
144
 
139
145
  // Iterate over the keys and setup the new object
140
-
146
+ //
141
147
  for (var key in tempObj) {
142
148
  if (tempObj.hasOwnProperty(key)) {
143
149
  var newObj = internals.parseKeys(key, tempObj[key], depth);
package/lib/stringify.js CHANGED
@@ -3,7 +3,9 @@
3
3
 
4
4
  // Declare internals
5
5
 
6
- var internals = {};
6
+ var internals = {
7
+ delimiter: '&'
8
+ };
7
9
 
8
10
 
9
11
  internals.stringify = function (obj, prefix) {
@@ -37,7 +39,9 @@ internals.stringify = function (obj, prefix) {
37
39
  };
38
40
 
39
41
 
40
- module.exports = function (obj) {
42
+ module.exports = function (obj, delimiter) {
43
+
44
+ delimiter = typeof delimiter === 'undefined' ? internals.delimiter : delimiter;
41
45
 
42
46
  var keys = [];
43
47
 
@@ -47,5 +51,5 @@ module.exports = function (obj) {
47
51
  }
48
52
  }
49
53
 
50
- return keys.join('&');
54
+ return keys.join(delimiter);
51
55
  };
package/lib/utils.js CHANGED
@@ -10,8 +10,7 @@ exports.arrayToObject = function (source) {
10
10
 
11
11
  var obj = {};
12
12
  for (var i = 0, il = source.length; i < il; ++i) {
13
- if (source[i] !== undefined &&
14
- source[i] !== null) {
13
+ if (typeof source[i] !== 'undefined') {
15
14
 
16
15
  obj[i] = source[i];
17
16
  }
@@ -54,8 +53,13 @@ exports.merge = function (target, source) {
54
53
 
55
54
  if (Array.isArray(source)) {
56
55
  for (var i = 0, il = source.length; i < il; ++i) {
57
- if (source[i] !== undefined) {
58
- obj[i] = source[i];
56
+ if (typeof source[i] !== 'undefined') {
57
+ if (typeof obj[i] === 'object') {
58
+ obj[i] = exports.merge(obj[i], source[i]);
59
+ }
60
+ else {
61
+ obj[i] = source[i];
62
+ }
59
63
  }
60
64
  }
61
65
 
@@ -114,9 +118,7 @@ exports.compact = function (obj) {
114
118
  compacted[key] = [];
115
119
 
116
120
  for (var i = 0, l = obj[key].length; i < l; i++) {
117
- if (obj[key].hasOwnProperty(i) &&
118
- obj[key][i] !== null) {
119
-
121
+ if (typeof obj[key][i] !== 'undefined') {
120
122
  compacted[key].push(obj[key][i]);
121
123
  }
122
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qs",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A querystring parser that supports nesting and arrays, with a depth limit",
5
5
  "homepage": "https://github.com/hapijs/qs",
6
6
  "main": "index.js",
package/test/parse.js CHANGED
@@ -138,6 +138,7 @@ describe('#parse', function () {
138
138
  expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } });
139
139
  expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } });
140
140
  expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
141
+ expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({foo: [ {a: 'a', b: 'b'}, {a: 'aa', b: 'bb'} ]});
141
142
  done();
142
143
  });
143
144
 
@@ -236,8 +237,19 @@ describe('#parse', function () {
236
237
  it('should not throw when a native prototype has an enumerable property', { parallel: false }, function (done) {
237
238
 
238
239
  Object.prototype.crash = '';
239
- expect(Qs.parse.bind(null, 'test')).to.not.throw();
240
+ Array.prototype.crash = '';
241
+ expect(Qs.parse.bind(null, 'a=b')).to.not.throw();
242
+ expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' });
243
+ expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw();
244
+ expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] });
240
245
  delete Object.prototype.crash;
246
+ delete Array.prototype.crash;
247
+ done();
248
+ });
249
+
250
+ it('parses a string with an alternative delimiter', function (done) {
251
+
252
+ expect(Qs.parse('a=b;c=d', ';')).to.deep.equal({ a: 'b', c: 'd' });
241
253
  done();
242
254
  });
243
255
  });
package/test/stringify.js CHANGED
@@ -120,4 +120,10 @@ describe('#stringify', function () {
120
120
  expect(Qs.stringify({ a: { b: new Buffer('test') } })).to.equal('a%5Bb%5D=test');
121
121
  done();
122
122
  });
123
+
124
+ it('stringifies an object using an alternative delimiter', function (done) {
125
+
126
+ expect(Qs.stringify({ a: 'b', c: 'd' }, ';')).to.equal('a=b;c=d');
127
+ done();
128
+ });
123
129
  });