qs 2.1.0 → 2.2.3

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 ADDED
@@ -0,0 +1,78 @@
1
+
2
+ ## [**2.2.3**](https://github.com/hapijs/qs/issues?milestone=12&state=open)
3
+ - [**#37**](https://github.com/hapijs/qs/issues/37) parser discards first empty value in array
4
+ - [**#36**](https://github.com/hapijs/qs/issues/36) Update to lab 4.x
5
+
6
+ ## [**2.2.2**](https://github.com/hapijs/qs/issues?milestone=11&state=closed)
7
+ - [**#33**](https://github.com/hapijs/qs/issues/33) Error when plain object in a value
8
+ - [**#34**](https://github.com/hapijs/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
9
+ - [**#24**](https://github.com/hapijs/qs/issues/24) Changelog? Semver?
10
+
11
+ ---
12
+
13
+
14
+
15
+ ## [**2.2.2**](https://github.com/hapijs/qs/issues?milestone=11&state=closed)
16
+ - [**#33**](https://github.com/hapijs/qs/issues/33) Error when plain object in a value
17
+ - [**#34**](https://github.com/hapijs/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
18
+ - [**#24**](https://github.com/hapijs/qs/issues/24) Changelog? Semver?
19
+
20
+ ---
21
+
22
+
23
+
24
+ ## [**2.2.2**](https://github.com/hapijs/qs/issues?milestone=11&state=open)
25
+ - [**#34**](https://github.com/hapijs/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
26
+ - [**#24**](https://github.com/hapijs/qs/issues/24) Changelog? Semver?
27
+
28
+ ---
29
+
30
+
31
+ # 2014-08-28
32
+ 95 commits against 24 issues, over a month [`32edf33`](https://github.com/hapijs/qs/commit/32edf33)⎆[`b1e7b53`](https://github.com/hapijs/qs/commit/b1e7b53)
33
+
34
+ ## [**2.2.1**](https://github.com/hapijs/qs/issues?milestone=10&state=closed)
35
+ - [**#32**](https://github.com/hapijs/qs/issues/32) account for circular references properly, closes #31
36
+ - [**#31**](https://github.com/hapijs/qs/issues/31) qs.parse stackoverflow on circular objects
37
+
38
+ ## [**2.2.0**](https://github.com/hapijs/qs/issues?milestone=9&state=closed)
39
+ - [**#30**](https://github.com/hapijs/qs/issues/30) Bug when merging non-object values into arrays
40
+ - [**#29**](https://github.com/hapijs/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
41
+ - [**#26**](https://github.com/hapijs/qs/issues/26) Don't use Buffer global if it's not present
42
+ - [**#23**](https://github.com/hapijs/qs/issues/23) Ability to not limit parameters?
43
+
44
+ ## [**2.1.0**](https://github.com/hapijs/qs/issues?milestone=8&state=closed)
45
+ - [**#22**](https://github.com/hapijs/qs/issues/22) Enable using a RegExp as delimiter
46
+
47
+ ## [**2.0.0**](https://github.com/hapijs/qs/issues?milestone=7&state=closed)
48
+ - [**#20**](https://github.com/hapijs/qs/issues/20) Configurable parametersLimit
49
+ - [**#18**](https://github.com/hapijs/qs/issues/18) Why is there arrayLimit?
50
+ - [**#21**](https://github.com/hapijs/qs/issues/21) make all limits optional, for #18, for #20
51
+
52
+ ## [**1.2.2**](https://github.com/hapijs/qs/issues?milestone=6&state=closed)
53
+ - [**#19**](https://github.com/hapijs/qs/issues/19) Don't overwrite null values
54
+
55
+ ## [**1.2.1**](https://github.com/hapijs/qs/issues?milestone=5&state=closed)
56
+ - [**#16**](https://github.com/hapijs/qs/issues/16) ignore non-string delimiters
57
+ - [**#15**](https://github.com/hapijs/qs/issues/15) Close code block
58
+
59
+ ## [**1.2.0**](https://github.com/hapijs/qs/issues?milestone=4&state=closed)
60
+ - [**#12**](https://github.com/hapijs/qs/issues/12) Add optional delim argument
61
+ - [**#13**](https://github.com/hapijs/qs/issues/13) fix #11: flattened keys in array are now correctly parsed
62
+
63
+ ## [**1.1.0**](https://github.com/hapijs/qs/issues?milestone=3&state=closed)
64
+ - [**#7**](https://github.com/hapijs/qs/issues/7) Empty values of a POST array disappear after being submitted
65
+ - [**#9**](https://github.com/hapijs/qs/issues/9) Should not omit equals signs (=) when value is null
66
+ - [**#6**](https://github.com/hapijs/qs/issues/6) Minor grammar fix in README
67
+
68
+ ## [**1.0.2**](https://github.com/hapijs/qs/issues?milestone=2&state=closed)
69
+ - [**#5**](https://github.com/hapijs/qs/issues/5) array holes incorrectly copied into object on large index
70
+
71
+
72
+ ## Issues
73
+ - [**#25**](https://github.com/hapijs/qs/issues/25) Remove references to Buffer
74
+ - [**#11**](https://github.com/hapijs/qs/issues/11) Flattened keys in array does not parse correctly
75
+ - [**#8**](https://github.com/hapijs/qs/issues/8) Square brackets should be URI encoded
76
+ - [**#3**](https://github.com/hapijs/qs/issues/3) Update README.md
77
+ - [**#2**](https://github.com/hapijs/qs/issues/2) Add travis and rework package
78
+
package/lib/parse.js CHANGED
@@ -16,7 +16,7 @@ var internals = {
16
16
  internals.parseValues = function (str, options) {
17
17
 
18
18
  var obj = {};
19
- var parts = str.split(options.delimiter, options.parameterLimit);
19
+ var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
20
20
 
21
21
  for (var i = 0, il = parts.length; i < il; ++i) {
22
22
  var part = parts[i];
@@ -29,7 +29,7 @@ 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 (!obj[key]) {
32
+ if (!obj.hasOwnProperty(key)) {
33
33
  obj[key] = val;
34
34
  }
35
35
  else {
@@ -138,16 +138,16 @@ module.exports = function (str, options) {
138
138
  options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
139
139
  options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
140
140
 
141
- var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : Utils.clone(str);
141
+ var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
142
142
  var obj = {};
143
143
 
144
144
  // Iterate over the keys and setup the new object
145
- //
146
- for (var key in tempObj) {
147
- if (tempObj.hasOwnProperty(key)) {
148
- var newObj = internals.parseKeys(key, tempObj[key], options);
149
- obj = Utils.merge(obj, newObj);
150
- }
145
+
146
+ var keys = Object.keys(tempObj);
147
+ for (var i = 0, il = keys.length; i < il; ++i) {
148
+ var key = keys[i];
149
+ var newObj = internals.parseKeys(key, tempObj[key], options);
150
+ obj = Utils.merge(obj, newObj);
151
151
  }
152
152
 
153
153
  return Utils.compact(obj);
package/lib/stringify.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // Load modules
2
2
 
3
+ var Utils = require('./utils');
4
+
3
5
 
4
6
  // Declare internals
5
7
 
@@ -10,7 +12,7 @@ var internals = {
10
12
 
11
13
  internals.stringify = function (obj, prefix) {
12
14
 
13
- if (Buffer.isBuffer(obj)) {
15
+ if (Utils.isBuffer(obj)) {
14
16
  obj = obj.toString();
15
17
  }
16
18
  else if (obj instanceof Date) {
package/lib/utils.js CHANGED
@@ -20,54 +20,35 @@ exports.arrayToObject = function (source) {
20
20
  };
21
21
 
22
22
 
23
- exports.clone = function (source) {
24
-
25
- if (typeof source !== 'object' ||
26
- source === null) {
27
-
28
- return source;
29
- }
30
-
31
- if (Buffer.isBuffer(source)) {
32
- return source.toString();
33
- }
34
-
35
- var obj = Array.isArray(source) ? [] : {};
36
- for (var i in source) {
37
- if (source.hasOwnProperty(i)) {
38
- obj[i] = exports.clone(source[i]);
39
- }
40
- }
41
-
42
- return obj;
43
- };
44
-
45
-
46
23
  exports.merge = function (target, source) {
47
24
 
48
25
  if (!source) {
49
26
  return target;
50
27
  }
51
28
 
52
- var obj = exports.clone(target);
53
-
54
29
  if (Array.isArray(source)) {
55
30
  for (var i = 0, il = source.length; i < il; ++i) {
56
31
  if (typeof source[i] !== 'undefined') {
57
- if (typeof obj[i] === 'object') {
58
- obj[i] = exports.merge(obj[i], source[i]);
32
+ if (typeof target[i] === 'object') {
33
+ target[i] = exports.merge(target[i], source[i]);
59
34
  }
60
35
  else {
61
- obj[i] = source[i];
36
+ target[i] = source[i];
62
37
  }
63
38
  }
64
39
  }
65
40
 
66
- return obj;
41
+ return target;
67
42
  }
68
43
 
69
- if (Array.isArray(obj)) {
70
- obj = exports.arrayToObject(obj);
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
+ }
71
52
  }
72
53
 
73
54
  var keys = Object.keys(source);
@@ -78,19 +59,19 @@ exports.merge = function (target, source) {
78
59
  if (value &&
79
60
  typeof value === 'object') {
80
61
 
81
- if (!obj[key]) {
82
- obj[key] = exports.clone(value);
62
+ if (!target[key]) {
63
+ target[key] = value;
83
64
  }
84
65
  else {
85
- obj[key] = exports.merge(obj[key], value);
66
+ target[key] = exports.merge(target[key], value);
86
67
  }
87
68
  }
88
69
  else {
89
- obj[key] = value;
70
+ target[key] = value;
90
71
  }
91
72
  }
92
73
 
93
- return obj;
74
+ return target;
94
75
  };
95
76
 
96
77
 
@@ -104,34 +85,55 @@ exports.decode = function (str) {
104
85
  };
105
86
 
106
87
 
107
- exports.compact = function (obj) {
88
+ exports.compact = function (obj, refs) {
89
+
90
+ if (typeof obj !== 'object' ||
91
+ obj === null) {
108
92
 
109
- if (typeof obj !== 'object' || obj === null) {
110
93
  return obj;
111
94
  }
112
95
 
113
- var compacted = {};
96
+ refs = refs || [];
97
+ var lookup = refs.indexOf(obj);
98
+ if (lookup !== -1) {
99
+ return refs[lookup];
100
+ }
114
101
 
115
- for (var key in obj) {
116
- if (obj.hasOwnProperty(key)) {
117
- if (Array.isArray(obj[key])) {
118
- compacted[key] = [];
102
+ refs.push(obj);
119
103
 
120
- for (var i = 0, l = obj[key].length; i < l; i++) {
121
- if (typeof obj[key][i] !== 'undefined') {
122
- compacted[key].push(obj[key][i]);
123
- }
124
- }
125
- }
126
- else {
127
- compacted[key] = exports.compact(obj[key]);
104
+ if (Array.isArray(obj)) {
105
+ var compacted = [];
106
+
107
+ for (var i = 0, l = obj.length; i < l; ++i) {
108
+ if (typeof obj[i] !== 'undefined') {
109
+ compacted.push(obj[i]);
128
110
  }
129
111
  }
112
+
113
+ return compacted;
130
114
  }
131
115
 
132
- return compacted;
116
+ var keys = Object.keys(obj);
117
+ for (var i = 0, il = keys.length; i < il; ++i) {
118
+ var key = keys[i];
119
+ obj[key] = exports.compact(obj[key], refs);
120
+ }
121
+
122
+ return obj;
133
123
  };
134
124
 
125
+
135
126
  exports.isRegExp = function (obj) {
136
127
  return Object.prototype.toString.call(obj) === '[object RegExp]';
137
128
  };
129
+
130
+
131
+ exports.isBuffer = function (obj) {
132
+
133
+ if (typeof Buffer !== 'undefined') {
134
+ return Buffer.isBuffer(obj);
135
+ }
136
+ else {
137
+ return false;
138
+ }
139
+ };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "qs",
3
- "version": "2.1.0",
3
+ "version": "2.2.3",
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": "3.x.x"
9
+ "lab": "4.x.x"
10
10
  },
11
11
  "scripts": {
12
12
  "test": "make test-cov"
package/test/parse.js CHANGED
@@ -11,11 +11,12 @@ var internals = {};
11
11
 
12
12
  // Test shortcuts
13
13
 
14
+ var lab = exports.lab = Lab.script();
14
15
  var expect = Lab.expect;
15
- var before = Lab.before;
16
- var after = Lab.after;
17
- var describe = Lab.experiment;
18
- var it = Lab.test;
16
+ var before = lab.before;
17
+ var after = lab.after;
18
+ var describe = lab.experiment;
19
+ var it = lab.test;
19
20
 
20
21
 
21
22
  describe('#parse', function () {
@@ -189,6 +190,7 @@ describe('#parse', function () {
189
190
 
190
191
  expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] });
191
192
  expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]=')).to.deep.equal({ a: ['b', '', 'c', ''] });
193
+ expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] });
192
194
  done();
193
195
  });
194
196
 
@@ -205,10 +207,10 @@ describe('#parse', function () {
205
207
  done();
206
208
  });
207
209
 
208
- it('parses buffers to strings', function (done) {
210
+ it('parses buffers correctly', function (done) {
209
211
 
210
212
  var b = new Buffer('test');
211
- expect(Qs.parse({ a: b })).to.deep.equal({ a: b.toString() });
213
+ expect(Qs.parse({ a: b })).to.deep.equal({ a: b });
212
214
  done();
213
215
  });
214
216
 
@@ -271,6 +273,12 @@ describe('#parse', function () {
271
273
  done();
272
274
  });
273
275
 
276
+ it('allows setting the parameter limit to Infinity', function (done) {
277
+
278
+ expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' });
279
+ done();
280
+ });
281
+
274
282
  it('allows overriding array limit', function (done) {
275
283
 
276
284
  expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
@@ -316,4 +324,62 @@ describe('#parse', function () {
316
324
  expect(result).to.deep.equal(expected);
317
325
  done();
318
326
  });
327
+
328
+ it('does not blow up when Buffer global is missing', function (done) {
329
+
330
+ var tempBuffer = global.Buffer;
331
+ delete global.Buffer;
332
+ expect(Qs.parse('a=b&c=d')).to.deep.equal({ a: 'b', c: 'd' });
333
+ global.Buffer = tempBuffer;
334
+ done();
335
+ });
336
+
337
+ it('does not crash when using invalid dot notation', function (done) {
338
+
339
+ expect(Qs.parse('roomInfoList[0].childrenAges[0]=15&roomInfoList[0].numberOfAdults=2')).to.deep.equal({ roomInfoList: [['15', '2']] });
340
+ done();
341
+ });
342
+
343
+ it('does not crash when parsing circular references', function (done) {
344
+
345
+ var a = {};
346
+ a.b = a;
347
+
348
+ var parsed;
349
+
350
+ expect(function () {
351
+
352
+ parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
353
+ }).to.not.throw(Error);
354
+
355
+ expect(parsed).to.have.key('foo');
356
+ expect(parsed.foo).to.have.keys('bar', 'baz');
357
+ expect(parsed.foo.bar).to.equal('baz');
358
+ expect(parsed.foo.baz).to.deep.equal(a);
359
+ done();
360
+ });
361
+
362
+ it('parses plain objects correctly', function (done) {
363
+
364
+ var a = Object.create(null);
365
+ a.b = 'c';
366
+
367
+ expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
368
+ expect(Qs.parse({ a: a })).to.deep.equal({ a: { b: 'c' } });
369
+ done();
370
+ });
371
+
372
+ it('parses dates correctly', function (done) {
373
+
374
+ var now = new Date();
375
+ expect(Qs.parse({ a: now })).to.deep.equal({ a: now });
376
+ done();
377
+ });
378
+
379
+ it('parses regular expressions correctly', function (done) {
380
+
381
+ var re = /^test$/;
382
+ expect(Qs.parse({ a: re })).to.deep.equal({ a: re });
383
+ done();
384
+ });
319
385
  });
package/test/stringify.js CHANGED
@@ -11,11 +11,12 @@ var internals = {};
11
11
 
12
12
  // Test shortcuts
13
13
 
14
+ var lab = exports.lab = Lab.script();
14
15
  var expect = Lab.expect;
15
- var before = Lab.before;
16
- var after = Lab.after;
17
- var describe = Lab.experiment;
18
- var it = Lab.test;
16
+ var before = lab.before;
17
+ var after = lab.after;
18
+ var describe = lab.experiment;
19
+ var it = lab.test;
19
20
 
20
21
 
21
22
  describe('#stringify', function () {
@@ -126,4 +127,13 @@ describe('#stringify', function () {
126
127
  expect(Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).to.equal('a=b;c=d');
127
128
  done();
128
129
  });
130
+
131
+ it('doesn\'t blow up when Buffer global is missing', function (done) {
132
+
133
+ var tempBuffer = global.Buffer;
134
+ delete global.Buffer;
135
+ expect(Qs.stringify({ a: 'b', c: 'd' })).to.equal('a=b&c=d');
136
+ global.Buffer = tempBuffer;
137
+ done();
138
+ });
129
139
  });