qs 2.3.1 → 2.4.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.
package/.travis.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  language: node_js
2
2
 
3
3
  node_js:
4
- - 0.10
4
+ - 0.10
5
+ - 0.12
6
+ - iojs
package/CHANGELOG.md CHANGED
@@ -1,10 +1,20 @@
1
1
 
2
- ## [**2.3.0**](https://github.com/hapijs/qs/issues?milestone=15&state=open)
2
+ ## [**2.3.3**](https://github.com/hapijs/qs/issues?milestone=18&state=open)
3
+ - [**#59**](https://github.com/hapijs/qs/issues/59) make sure array indexes are >= 0, closes #57
4
+ - [**#58**](https://github.com/hapijs/qs/issues/58) make qs usable for browser loader
5
+
6
+ ## [**2.3.2**](https://github.com/hapijs/qs/issues?milestone=17&state=closed)
7
+ - [**#55**](https://github.com/hapijs/qs/issues/55) allow merging a string into an object
8
+
9
+ ## [**2.3.1**](https://github.com/hapijs/qs/issues?milestone=16&state=closed)
10
+ - [**#52**](https://github.com/hapijs/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
11
+
12
+ ## [**2.3.0**](https://github.com/hapijs/qs/issues?milestone=15&state=closed)
3
13
  - [**#50**](https://github.com/hapijs/qs/issues/50) add option to omit array indices, closes #46
4
14
 
5
15
  ## [**2.2.5**](https://github.com/hapijs/qs/issues?milestone=14&state=closed)
6
- - [**#49**](https://github.com/hapijs/qs/issues/49) refactor utils.merge, fixes #45
7
16
  - [**#39**](https://github.com/hapijs/qs/issues/39) Is there an alternative to Buffer.isBuffer?
17
+ - [**#49**](https://github.com/hapijs/qs/issues/49) refactor utils.merge, fixes #45
8
18
  - [**#41**](https://github.com/hapijs/qs/issues/41) avoid browserifying Buffer, for #39
9
19
 
10
20
  ## [**2.2.4**](https://github.com/hapijs/qs/issues?milestone=13&state=closed)
package/Makefile CHANGED
@@ -1,8 +1,8 @@
1
1
  test:
2
- @node node_modules/lab/bin/lab
2
+ @node node_modules/lab/bin/lab -a code -L
3
3
  test-cov:
4
- @node node_modules/lab/bin/lab -t 100
4
+ @node node_modules/lab/bin/lab -a code -t 100 -L
5
5
  test-cov-html:
6
- @node node_modules/lab/bin/lab -r html -o coverage.html
6
+ @node node_modules/lab/bin/lab -a code -L -r html -o coverage.html
7
7
 
8
- .PHONY: test test-cov test-cov-html
8
+ .PHONY: test test-cov test-cov-html
package/README.md CHANGED
@@ -153,6 +153,8 @@ Qs.parse('a[1]=b', { arrayLimit: 0 });
153
153
  // { a: { '1': 'b' } }
154
154
  ```
155
155
 
156
+ To disable array parsing entirely, set `arrayLimit` to `-1`.
157
+
156
158
  If you mix notations, **qs** will merge the two items into an object:
157
159
 
158
160
  ```javascript
@@ -198,6 +200,17 @@ Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
198
200
  // 'a=b&a=c&a=d'
199
201
  ```
200
202
 
203
+ You may use the `arrayFormat` option to specify the format of the output array
204
+
205
+ ```javascript
206
+ Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
207
+ // 'a[0]=b&a[1]=c'
208
+ Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
209
+ // 'a[]=b&a[]=c'
210
+ Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
211
+ // 'a=b&a=c'
212
+ ```
213
+
201
214
  Empty strings and null values will omit the value, but the equals sign (=) remains in place:
202
215
 
203
216
  ```javascript
package/index.js CHANGED
@@ -1 +1 @@
1
- module.exports = require('./lib');
1
+ module.exports = require('./lib/');
package/lib/parse.js CHANGED
@@ -29,6 +29,10 @@ internals.parseValues = function (str, options) {
29
29
  var key = Utils.decode(part.slice(0, pos));
30
30
  var val = Utils.decode(part.slice(pos + 1));
31
31
 
32
+ if (Object.prototype.hasOwnProperty(key)) {
33
+ continue;
34
+ }
35
+
32
36
  if (!obj.hasOwnProperty(key)) {
33
37
  obj[key] = val;
34
38
  }
@@ -62,6 +66,7 @@ internals.parseObject = function (chain, val, options) {
62
66
  if (!isNaN(index) &&
63
67
  root !== cleanRoot &&
64
68
  indexString === cleanRoot &&
69
+ index >= 0 &&
65
70
  index <= options.arrayLimit) {
66
71
 
67
72
  obj = [];
package/lib/stringify.js CHANGED
@@ -7,11 +7,21 @@ var Utils = require('./utils');
7
7
 
8
8
  var internals = {
9
9
  delimiter: '&',
10
- indices: true
10
+ arrayPrefixGenerators: {
11
+ brackets: function (prefix, key) {
12
+ return prefix + '[]';
13
+ },
14
+ indices: function (prefix, key) {
15
+ return prefix + '[' + key + ']';
16
+ },
17
+ repeat: function (prefix, key) {
18
+ return prefix;
19
+ }
20
+ }
11
21
  };
12
22
 
13
23
 
14
- internals.stringify = function (obj, prefix, options) {
24
+ internals.stringify = function (obj, prefix, generateArrayPrefix) {
15
25
 
16
26
  if (Utils.isBuffer(obj)) {
17
27
  obj = obj.toString();
@@ -39,13 +49,11 @@ internals.stringify = function (obj, prefix, options) {
39
49
  var objKeys = Object.keys(obj);
40
50
  for (var i = 0, il = objKeys.length; i < il; ++i) {
41
51
  var key = objKeys[i];
42
- if (!options.indices &&
43
- Array.isArray(obj)) {
44
-
45
- values = values.concat(internals.stringify(obj[key], prefix, options));
52
+ if (Array.isArray(obj)) {
53
+ values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix));
46
54
  }
47
55
  else {
48
- values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', options));
56
+ values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix));
49
57
  }
50
58
  }
51
59
 
@@ -57,7 +65,6 @@ module.exports = function (obj, options) {
57
65
 
58
66
  options = options || {};
59
67
  var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
60
- options.indices = typeof options.indices === 'boolean' ? options.indices : internals.indices;
61
68
 
62
69
  var keys = [];
63
70
 
@@ -67,10 +74,23 @@ module.exports = function (obj, options) {
67
74
  return '';
68
75
  }
69
76
 
77
+ var arrayFormat;
78
+ if (options.arrayFormat in internals.arrayPrefixGenerators) {
79
+ arrayFormat = options.arrayFormat;
80
+ }
81
+ else if ('indices' in options) {
82
+ arrayFormat = options.indices ? 'indices' : 'repeat';
83
+ }
84
+ else {
85
+ arrayFormat = 'indices';
86
+ }
87
+
88
+ var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat];
89
+
70
90
  var objKeys = Object.keys(obj);
71
91
  for (var i = 0, il = objKeys.length; i < il; ++i) {
72
92
  var key = objKeys[i];
73
- keys = keys.concat(internals.stringify(obj[key], key, options));
93
+ keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix));
74
94
  }
75
95
 
76
96
  return keys.join(delimiter);
package/lib/utils.js CHANGED
@@ -27,7 +27,13 @@ exports.merge = function (target, source) {
27
27
  }
28
28
 
29
29
  if (typeof source !== 'object') {
30
- target.push(source);
30
+ if (Array.isArray(target)) {
31
+ target.push(source);
32
+ }
33
+ else {
34
+ target[source] = true;
35
+ }
36
+
31
37
  return target;
32
38
  }
33
39
 
@@ -88,7 +94,7 @@ exports.compact = function (obj, refs) {
88
94
  if (Array.isArray(obj)) {
89
95
  var compacted = [];
90
96
 
91
- for (var i = 0, l = obj.length; i < l; ++i) {
97
+ for (var i = 0, il = obj.length; i < il; ++i) {
92
98
  if (typeof obj[i] !== 'undefined') {
93
99
  compacted.push(obj[i]);
94
100
  }
@@ -98,7 +104,7 @@ exports.compact = function (obj, refs) {
98
104
  }
99
105
 
100
106
  var keys = Object.keys(obj);
101
- for (var i = 0, il = keys.length; i < il; ++i) {
107
+ for (i = 0, il = keys.length; i < il; ++i) {
102
108
  var key = keys[i];
103
109
  obj[key] = exports.compact(obj[key], refs);
104
110
  }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "qs",
3
- "version": "2.3.1",
3
+ "version": "2.4.1",
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",
7
7
  "dependencies": {},
8
8
  "devDependencies": {
9
- "lab": "4.x.x"
9
+ "code": "1.x.x",
10
+ "lab": "5.x.x"
10
11
  },
11
12
  "scripts": {
12
13
  "test": "make test-cov"
package/test/parse.js CHANGED
@@ -1,5 +1,7 @@
1
+ /* eslint no-extend-native:0 */
1
2
  // Load modules
2
3
 
4
+ var Code = require('code');
3
5
  var Lab = require('lab');
4
6
  var Qs = require('../');
5
7
 
@@ -12,7 +14,7 @@ var internals = {};
12
14
  // Test shortcuts
13
15
 
14
16
  var lab = exports.lab = Lab.script();
15
- var expect = Lab.expect;
17
+ var expect = Code.expect;
16
18
  var describe = lab.experiment;
17
19
  var it = lab.test;
18
20
 
@@ -158,6 +160,12 @@ describe('parse()', function () {
158
160
  done();
159
161
  });
160
162
 
163
+ it('can add keys to objects', function (done) {
164
+
165
+ expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } });
166
+ done();
167
+ });
168
+
161
169
  it('correctly prunes undefined values when converting an array to an object', function (done) {
162
170
 
163
171
  expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
@@ -179,7 +187,7 @@ describe('parse()', function () {
179
187
 
180
188
  it('cannot override prototypes', function (done) {
181
189
 
182
- var obj = Qs.parse('toString=bad&bad[toString]=bad&constructor=bad');
190
+ var obj = Qs.parse('hasOwnProperty=bad&toString=bad&bad[toString]=bad&constructor=bad');
183
191
  expect(typeof obj.toString).to.equal('function');
184
192
  expect(typeof obj.bad.toString).to.equal('function');
185
193
  expect(typeof obj.constructor).to.equal('function');
@@ -296,6 +304,8 @@ describe('parse()', function () {
296
304
 
297
305
  it('allows overriding array limit', function (done) {
298
306
 
307
+ expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } });
308
+ expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } });
299
309
  expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
300
310
  done();
301
311
  });
@@ -303,14 +313,14 @@ describe('parse()', function () {
303
313
  it('parses an object', function (done) {
304
314
 
305
315
  var input = {
306
- "user[name]": {"pop[bob]": 3},
307
- "user[email]": null
316
+ 'user[name]': {'pop[bob]': 3},
317
+ 'user[email]': null
308
318
  };
309
319
 
310
320
  var expected = {
311
- "user": {
312
- "name": {"pop[bob]": 3},
313
- "email": null
321
+ 'user': {
322
+ 'name': {'pop[bob]': 3},
323
+ 'email': null
314
324
  }
315
325
  };
316
326
 
@@ -323,14 +333,14 @@ describe('parse()', function () {
323
333
  it('parses an object and not child values', function (done) {
324
334
 
325
335
  var input = {
326
- "user[name]": {"pop[bob]": { "test": 3 }},
327
- "user[email]": null
336
+ 'user[name]': {'pop[bob]': { 'test': 3 }},
337
+ 'user[email]': null
328
338
  };
329
339
 
330
340
  var expected = {
331
- "user": {
332
- "name": {"pop[bob]": { "test": 3 }},
333
- "email": null
341
+ 'user': {
342
+ 'name': {'pop[bob]': { 'test': 3 }},
343
+ 'email': null
334
344
  }
335
345
  };
336
346
 
@@ -344,8 +354,9 @@ describe('parse()', function () {
344
354
 
345
355
  var tempBuffer = global.Buffer;
346
356
  delete global.Buffer;
347
- expect(Qs.parse('a=b&c=d')).to.deep.equal({ a: 'b', c: 'd' });
357
+ var result = Qs.parse('a=b&c=d');
348
358
  global.Buffer = tempBuffer;
359
+ expect(result).to.deep.equal({ a: 'b', c: 'd' });
349
360
  done();
350
361
  });
351
362
 
@@ -365,10 +376,10 @@ describe('parse()', function () {
365
376
  expect(function () {
366
377
 
367
378
  parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
368
- }).to.not.throw(Error);
379
+ }).to.not.throw();
369
380
 
370
- expect(parsed).to.have.key('foo');
371
- expect(parsed.foo).to.have.keys('bar', 'baz');
381
+ expect(parsed).to.contain('foo');
382
+ expect(parsed.foo).to.contain('bar', 'baz');
372
383
  expect(parsed.foo.bar).to.equal('baz');
373
384
  expect(parsed.foo.baz).to.deep.equal(a);
374
385
  done();
@@ -378,9 +389,11 @@ describe('parse()', function () {
378
389
 
379
390
  var a = Object.create(null);
380
391
  a.b = 'c';
381
-
392
+
382
393
  expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
383
- expect(Qs.parse({ a: a })).to.deep.equal({ a: { b: 'c' } });
394
+ var result = Qs.parse({ a: a });
395
+ expect(result).to.contain('a');
396
+ expect(result.a).to.deep.equal(a);
384
397
  done();
385
398
  });
386
399
 
package/test/stringify.js CHANGED
@@ -1,5 +1,7 @@
1
+ /* eslint no-extend-native:0 */
1
2
  // Load modules
2
3
 
4
+ var Code = require('code');
3
5
  var Lab = require('lab');
4
6
  var Qs = require('../');
5
7
 
@@ -12,7 +14,7 @@ var internals = {};
12
14
  // Test shortcuts
13
15
 
14
16
  var lab = exports.lab = Lab.script();
15
- var expect = Lab.expect;
17
+ var expect = Code.expect;
16
18
  var describe = lab.experiment;
17
19
  var it = lab.test;
18
20
 
@@ -65,6 +67,36 @@ describe('stringify()', function () {
65
67
  done();
66
68
  });
67
69
 
70
+ it('uses indices notation for arrays when indices=true', function (done) {
71
+
72
+ expect(Qs.stringify({ a: ['b', 'c'] }, { indices: true })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
73
+ done();
74
+ });
75
+
76
+ it('uses indices notation for arrays when no arrayFormat is specified', function (done) {
77
+
78
+ expect(Qs.stringify({ a: ['b', 'c'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
79
+ done();
80
+ });
81
+
82
+ it('uses indices notation for arrays when no arrayFormat=indices', function (done) {
83
+
84
+ expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).to.equal('a%5B0%5D=b&a%5B1%5D=c');
85
+ done();
86
+ });
87
+
88
+ it('uses repeat notation for arrays when no arrayFormat=repeat', function (done) {
89
+
90
+ expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).to.equal('a=b&a=c');
91
+ done();
92
+ });
93
+
94
+ it('uses brackets notation for arrays when no arrayFormat=brackets', function (done) {
95
+
96
+ expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).to.equal('a%5B%5D=b&a%5B%5D=c');
97
+ done();
98
+ });
99
+
68
100
  it('stringifies a complicated object', function (done) {
69
101
 
70
102
  expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e');