qs 2.2.4 → 2.3.2

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/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
1
 
2
+ ## [**2.3.1**](https://github.com/hapijs/qs/issues?milestone=16&state=closed)
3
+ - [**#52**](https://github.com/hapijs/qs/issues/52) Return "undefined" and "false" instead of throwing "TypeError".
4
+
5
+ ## [**2.3.0**](https://github.com/hapijs/qs/issues?milestone=15&state=closed)
6
+ - [**#50**](https://github.com/hapijs/qs/issues/50) add option to omit array indices, closes #46
7
+
8
+ ## [**2.2.5**](https://github.com/hapijs/qs/issues?milestone=14&state=closed)
9
+ - [**#39**](https://github.com/hapijs/qs/issues/39) Is there an alternative to Buffer.isBuffer?
10
+ - [**#49**](https://github.com/hapijs/qs/issues/49) refactor utils.merge, fixes #45
11
+ - [**#41**](https://github.com/hapijs/qs/issues/41) avoid browserifying Buffer, for #39
12
+
13
+ ## [**2.2.4**](https://github.com/hapijs/qs/issues?milestone=13&state=closed)
14
+ - [**#38**](https://github.com/hapijs/qs/issues/38) how to handle object keys beginning with a number
15
+
2
16
  ## [**2.2.3**](https://github.com/hapijs/qs/issues?milestone=12&state=closed)
3
17
  - [**#37**](https://github.com/hapijs/qs/issues/37) parser discards first empty value in array
4
18
  - [**#36**](https://github.com/hapijs/qs/issues/36) Update to lab 4.x
package/README.md CHANGED
@@ -184,13 +184,20 @@ Qs.stringify({ a: { b: 'c' } });
184
184
 
185
185
  Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
186
186
 
187
- When arrays are stringified, they are always given explicit indices:
187
+ When arrays are stringified, by default they are given explicit indices:
188
188
 
189
189
  ```javascript
190
190
  Qs.stringify({ a: ['b', 'c', 'd'] });
191
191
  // 'a[0]=b&a[1]=c&a[2]=d'
192
192
  ```
193
193
 
194
+ You may override this by setting the `indices` option to `false`:
195
+
196
+ ```javascript
197
+ Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
198
+ // 'a=b&a=c&a=d'
199
+ ```
200
+
194
201
  Empty strings and null values will omit the value, but the equals sign (=) remains in place:
195
202
 
196
203
  ```javascript
package/lib/stringify.js CHANGED
@@ -6,11 +6,12 @@ var Utils = require('./utils');
6
6
  // Declare internals
7
7
 
8
8
  var internals = {
9
- delimiter: '&'
9
+ delimiter: '&',
10
+ indices: true
10
11
  };
11
12
 
12
13
 
13
- internals.stringify = function (obj, prefix) {
14
+ internals.stringify = function (obj, prefix, options) {
14
15
 
15
16
  if (Utils.isBuffer(obj)) {
16
17
  obj = obj.toString();
@@ -31,9 +32,20 @@ internals.stringify = function (obj, prefix) {
31
32
 
32
33
  var values = [];
33
34
 
34
- for (var key in obj) {
35
- if (obj.hasOwnProperty(key)) {
36
- values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']'));
35
+ if (typeof obj === 'undefined') {
36
+ return values;
37
+ }
38
+
39
+ var objKeys = Object.keys(obj);
40
+ for (var i = 0, il = objKeys.length; i < il; ++i) {
41
+ var key = objKeys[i];
42
+ if (!options.indices &&
43
+ Array.isArray(obj)) {
44
+
45
+ values = values.concat(internals.stringify(obj[key], prefix, options));
46
+ }
47
+ else {
48
+ values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', options));
37
49
  }
38
50
  }
39
51
 
@@ -45,13 +57,20 @@ module.exports = function (obj, options) {
45
57
 
46
58
  options = options || {};
47
59
  var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter;
60
+ options.indices = typeof options.indices === 'boolean' ? options.indices : internals.indices;
48
61
 
49
62
  var keys = [];
50
63
 
51
- for (var key in obj) {
52
- if (obj.hasOwnProperty(key)) {
53
- keys = keys.concat(internals.stringify(obj[key], key));
54
- }
64
+ if (typeof obj !== 'object' ||
65
+ obj === null) {
66
+
67
+ return '';
68
+ }
69
+
70
+ var objKeys = Object.keys(obj);
71
+ for (var i = 0, il = objKeys.length; i < il; ++i) {
72
+ var key = objKeys[i];
73
+ keys = keys.concat(internals.stringify(obj[key], key, options));
55
74
  }
56
75
 
57
76
  return keys.join(delimiter);
package/lib/utils.js CHANGED
@@ -26,29 +26,26 @@ exports.merge = function (target, source) {
26
26
  return target;
27
27
  }
28
28
 
29
- if (Array.isArray(source)) {
30
- for (var i = 0, il = source.length; i < il; ++i) {
31
- if (typeof source[i] !== 'undefined') {
32
- if (typeof target[i] === 'object') {
33
- target[i] = exports.merge(target[i], source[i]);
34
- }
35
- else {
36
- target[i] = source[i];
37
- }
38
- }
29
+ if (typeof source !== 'object') {
30
+ if (Array.isArray(target)) {
31
+ target.push(source);
32
+ }
33
+ else {
34
+ target[source] = true;
39
35
  }
40
36
 
41
37
  return target;
42
38
  }
43
39
 
44
- if (Array.isArray(target)) {
45
- if (typeof source !== 'object') {
46
- target.push(source);
47
- return target;
48
- }
49
- else {
50
- target = exports.arrayToObject(target);
51
- }
40
+ if (typeof target !== 'object') {
41
+ target = [target].concat(source);
42
+ return target;
43
+ }
44
+
45
+ if (Array.isArray(target) &&
46
+ !Array.isArray(source)) {
47
+
48
+ target = exports.arrayToObject(target);
52
49
  }
53
50
 
54
51
  var keys = Object.keys(source);
@@ -56,18 +53,11 @@ exports.merge = function (target, source) {
56
53
  var key = keys[k];
57
54
  var value = source[key];
58
55
 
59
- if (value &&
60
- typeof value === 'object') {
61
-
62
- if (!target[key]) {
63
- target[key] = value;
64
- }
65
- else {
66
- target[key] = exports.merge(target[key], value);
67
- }
56
+ if (!target[key]) {
57
+ target[key] = value;
68
58
  }
69
59
  else {
70
- target[key] = value;
60
+ target[key] = exports.merge(target[key], value);
71
61
  }
72
62
  }
73
63
 
@@ -130,10 +120,13 @@ exports.isRegExp = function (obj) {
130
120
 
131
121
  exports.isBuffer = function (obj) {
132
122
 
133
- if (typeof Buffer !== 'undefined') {
134
- return Buffer.isBuffer(obj);
135
- }
136
- else {
123
+ if (obj === null ||
124
+ typeof obj === 'undefined') {
125
+
137
126
  return false;
138
127
  }
128
+
129
+ return !!(obj.constructor &&
130
+ obj.constructor.isBuffer &&
131
+ obj.constructor.isBuffer(obj));
139
132
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qs",
3
- "version": "2.2.4",
3
+ "version": "2.3.2",
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",
@@ -19,7 +19,6 @@
19
19
  "querystring",
20
20
  "qs"
21
21
  ],
22
- "author": "Nathan LaFreniere <quitlahok@gmail.com>",
23
22
  "licenses": [
24
23
  {
25
24
  "type": "BSD",
package/test/parse.js CHANGED
@@ -13,13 +13,11 @@ var internals = {};
13
13
 
14
14
  var lab = exports.lab = Lab.script();
15
15
  var expect = Lab.expect;
16
- var before = lab.before;
17
- var after = lab.after;
18
16
  var describe = lab.experiment;
19
17
  var it = lab.test;
20
18
 
21
19
 
22
- describe('#parse', function () {
20
+ describe('parse()', function () {
23
21
 
24
22
  it('parses a simple string', function (done) {
25
23
 
@@ -82,6 +80,17 @@ describe('#parse', function () {
82
80
  done();
83
81
  });
84
82
 
83
+ it('parses a mix of simple and explicit arrays', function (done) {
84
+
85
+ expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] });
86
+ expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
87
+ expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
88
+ expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] });
89
+ expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] });
90
+ expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] });
91
+ done();
92
+ });
93
+
85
94
  it('parses a nested array', function (done) {
86
95
 
87
96
  expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } });
@@ -149,6 +158,12 @@ describe('#parse', function () {
149
158
  done();
150
159
  });
151
160
 
161
+ it('can add keys to objects', function (done) {
162
+
163
+ expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } });
164
+ done();
165
+ });
166
+
152
167
  it('correctly prunes undefined values when converting an array to an object', function (done) {
153
168
 
154
169
  expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } });
@@ -369,7 +384,7 @@ describe('#parse', function () {
369
384
 
370
385
  var a = Object.create(null);
371
386
  a.b = 'c';
372
-
387
+
373
388
  expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
374
389
  expect(Qs.parse({ a: a })).to.deep.equal({ a: { b: 'c' } });
375
390
  done();
package/test/stringify.js CHANGED
@@ -13,13 +13,11 @@ var internals = {};
13
13
 
14
14
  var lab = exports.lab = Lab.script();
15
15
  var expect = Lab.expect;
16
- var before = lab.before;
17
- var after = lab.after;
18
16
  var describe = lab.experiment;
19
17
  var it = lab.test;
20
18
 
21
19
 
22
- describe('#stringify', function () {
20
+ describe('stringify()', function () {
23
21
 
24
22
  it('stringifies a querystring object', function (done) {
25
23
 
@@ -42,6 +40,12 @@ describe('#stringify', function () {
42
40
  done();
43
41
  });
44
42
 
43
+ it('omits array indices when asked', function (done) {
44
+
45
+ expect(Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false })).to.equal('a=b&a=c&a=d');
46
+ done();
47
+ });
48
+
45
49
  it('stringifies a nested array value', function (done) {
46
50
 
47
51
  expect(Qs.stringify({ a: { b: ['c', 'd'] } })).to.equal('a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
@@ -55,6 +59,12 @@ describe('#stringify', function () {
55
59
  done();
56
60
  });
57
61
 
62
+ it('does not omit object keys when indices = false', function (done) {
63
+
64
+ expect(Qs.stringify({ a: [{ b: 'c' }] }, { indices: false })).to.equal('a%5Bb%5D=c');
65
+ done();
66
+ });
67
+
58
68
  it('stringifies a complicated object', function (done) {
59
69
 
60
70
  expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e');
@@ -70,6 +80,34 @@ describe('#stringify', function () {
70
80
  done();
71
81
  });
72
82
 
83
+ it('stringifies an empty object', function (done) {
84
+
85
+ var obj = Object.create(null);
86
+ obj.a = 'b';
87
+ expect(Qs.stringify(obj)).to.equal('a=b');
88
+ done();
89
+ });
90
+
91
+ it('returns an empty string for invalid input', function (done) {
92
+
93
+ expect(Qs.stringify(undefined)).to.equal('');
94
+ expect(Qs.stringify(false)).to.equal('');
95
+ expect(Qs.stringify(null)).to.equal('');
96
+ expect(Qs.stringify('')).to.equal('');
97
+ done();
98
+ });
99
+
100
+ it('stringifies an object with an empty object as a child', function (done) {
101
+
102
+ var obj = {
103
+ a: Object.create(null)
104
+ };
105
+
106
+ obj.a.b = 'c';
107
+ expect(Qs.stringify(obj)).to.equal('a%5Bb%5D=c');
108
+ done();
109
+ });
110
+
73
111
  it('drops keys with a value of undefined', function (done) {
74
112
 
75
113
  expect(Qs.stringify({ a: undefined })).to.equal('');