qs 2.0.0 → 2.2.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 ADDED
@@ -0,0 +1,56 @@
1
+
2
+ ## [**2.2.2**](https://github.com/hapijs/qs/issues?milestone=11&state=open)
3
+ - [**#34**](https://github.com/hapijs/qs/issues/34) use Object.prototype.hasOwnProperty.call instead of obj.hasOwnProperty
4
+ - [**#24**](https://github.com/hapijs/qs/issues/24) Changelog? Semver?
5
+
6
+ ---
7
+
8
+
9
+ # 2014-08-28
10
+ 95 commits against 24 issues, over a month [`32edf33`](https://github.com/hapijs/qs/commit/32edf33)⎆[`b1e7b53`](https://github.com/hapijs/qs/commit/b1e7b53)
11
+
12
+ ## [**2.2.1**](https://github.com/hapijs/qs/issues?milestone=10&state=closed)
13
+ - [**#32**](https://github.com/hapijs/qs/issues/32) account for circular references properly, closes #31
14
+ - [**#31**](https://github.com/hapijs/qs/issues/31) qs.parse stackoverflow on circular objects
15
+
16
+ ## [**2.2.0**](https://github.com/hapijs/qs/issues?milestone=9&state=closed)
17
+ - [**#30**](https://github.com/hapijs/qs/issues/30) Bug when merging non-object values into arrays
18
+ - [**#29**](https://github.com/hapijs/qs/issues/29) Don't call Utils.clone at the top of Utils.merge
19
+ - [**#26**](https://github.com/hapijs/qs/issues/26) Don't use Buffer global if it's not present
20
+ - [**#23**](https://github.com/hapijs/qs/issues/23) Ability to not limit parameters?
21
+
22
+ ## [**2.1.0**](https://github.com/hapijs/qs/issues?milestone=8&state=closed)
23
+ - [**#22**](https://github.com/hapijs/qs/issues/22) Enable using a RegExp as delimiter
24
+
25
+ ## [**2.0.0**](https://github.com/hapijs/qs/issues?milestone=7&state=closed)
26
+ - [**#20**](https://github.com/hapijs/qs/issues/20) Configurable parametersLimit
27
+ - [**#18**](https://github.com/hapijs/qs/issues/18) Why is there arrayLimit?
28
+ - [**#21**](https://github.com/hapijs/qs/issues/21) make all limits optional, for #18, for #20
29
+
30
+ ## [**1.2.2**](https://github.com/hapijs/qs/issues?milestone=6&state=closed)
31
+ - [**#19**](https://github.com/hapijs/qs/issues/19) Don't overwrite null values
32
+
33
+ ## [**1.2.1**](https://github.com/hapijs/qs/issues?milestone=5&state=closed)
34
+ - [**#16**](https://github.com/hapijs/qs/issues/16) ignore non-string delimiters
35
+ - [**#15**](https://github.com/hapijs/qs/issues/15) Close code block
36
+
37
+ ## [**1.2.0**](https://github.com/hapijs/qs/issues?milestone=4&state=closed)
38
+ - [**#12**](https://github.com/hapijs/qs/issues/12) Add optional delim argument
39
+ - [**#13**](https://github.com/hapijs/qs/issues/13) fix #11: flattened keys in array are now correctly parsed
40
+
41
+ ## [**1.1.0**](https://github.com/hapijs/qs/issues?milestone=3&state=closed)
42
+ - [**#7**](https://github.com/hapijs/qs/issues/7) Empty values of a POST array disappear after being submitted
43
+ - [**#9**](https://github.com/hapijs/qs/issues/9) Should not omit equals signs (=) when value is null
44
+ - [**#6**](https://github.com/hapijs/qs/issues/6) Minor grammar fix in README
45
+
46
+ ## [**1.0.2**](https://github.com/hapijs/qs/issues?milestone=2&state=closed)
47
+ - [**#5**](https://github.com/hapijs/qs/issues/5) array holes incorrectly copied into object on large index
48
+
49
+
50
+ ## Issues
51
+ - [**#25**](https://github.com/hapijs/qs/issues/25) Remove references to Buffer
52
+ - [**#11**](https://github.com/hapijs/qs/issues/11) Flattened keys in array does not parse correctly
53
+ - [**#8**](https://github.com/hapijs/qs/issues/8) Square brackets should be URI encoded
54
+ - [**#3**](https://github.com/hapijs/qs/issues/3) Update README.md
55
+ - [**#2**](https://github.com/hapijs/qs/issues/2) Add travis and rework package
56
+
package/README.md CHANGED
@@ -97,6 +97,13 @@ Qs.parse('a=b;c=d', { delimiter: ';' });
97
97
  // { a: 'b', c: 'd' }
98
98
  ```
99
99
 
100
+ Delimiters can be a regular expression too:
101
+
102
+ ```javascript
103
+ Qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ });
104
+ // { a: 'b', c: 'd', e: 'f' }
105
+ ```
106
+
100
107
  ### Parsing Arrays
101
108
 
102
109
  **qs** can also parse arrays using a similar `[]` notation:
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];
@@ -133,21 +133,21 @@ module.exports = function (str, options) {
133
133
  }
134
134
 
135
135
  options = options || {};
136
- options.delimiter = typeof options.delimiter === 'string' ? options.delimiter : internals.delimiter;
136
+ options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
137
137
  options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
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,30 +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;
114
+ }
115
+
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);
130
120
  }
131
121
 
132
- return compacted;
122
+ return obj;
123
+ };
124
+
125
+
126
+ exports.isRegExp = function (obj) {
127
+ return Object.prototype.toString.call(obj) === '[object RegExp]';
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
+ }
133
139
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qs",
3
- "version": "2.0.0",
3
+ "version": "2.2.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",
package/test/parse.js CHANGED
@@ -205,10 +205,10 @@ describe('#parse', function () {
205
205
  done();
206
206
  });
207
207
 
208
- it('parses buffers to strings', function (done) {
208
+ it('parses buffers correctly', function (done) {
209
209
 
210
210
  var b = new Buffer('test');
211
- expect(Qs.parse({ a: b })).to.deep.equal({ a: b.toString() });
211
+ expect(Qs.parse({ a: b })).to.deep.equal({ a: b });
212
212
  done();
213
213
  });
214
214
 
@@ -247,13 +247,19 @@ describe('#parse', function () {
247
247
  done();
248
248
  });
249
249
 
250
- it('parses a string with an alternative delimiter', function (done) {
250
+ it('parses a string with an alternative string delimiter', function (done) {
251
251
 
252
252
  expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' });
253
253
  done();
254
254
  });
255
255
 
256
- it('does not use non-string objects as delimiters', function (done) {
256
+ it('parses a string with an alternative RegExp delimiter', function (done) {
257
+
258
+ expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' });
259
+ done();
260
+ });
261
+
262
+ it('does not use non-splittable objects as delimiters', function (done) {
257
263
 
258
264
  expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' });
259
265
  done();
@@ -265,6 +271,12 @@ describe('#parse', function () {
265
271
  done();
266
272
  });
267
273
 
274
+ it('allows setting the parameter limit to Infinity', function (done) {
275
+
276
+ expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' });
277
+ done();
278
+ });
279
+
268
280
  it('allows overriding array limit', function (done) {
269
281
 
270
282
  expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } });
@@ -310,4 +322,62 @@ describe('#parse', function () {
310
322
  expect(result).to.deep.equal(expected);
311
323
  done();
312
324
  });
325
+
326
+ it('does not blow up when Buffer global is missing', function (done) {
327
+
328
+ var tempBuffer = global.Buffer;
329
+ delete global.Buffer;
330
+ expect(Qs.parse('a=b&c=d')).to.deep.equal({ a: 'b', c: 'd' });
331
+ global.Buffer = tempBuffer;
332
+ done();
333
+ });
334
+
335
+ it('does not crash when using invalid dot notation', function (done) {
336
+
337
+ expect(Qs.parse('roomInfoList[0].childrenAges[0]=15&roomInfoList[0].numberOfAdults=2')).to.deep.equal({ roomInfoList: [['15', '2']] });
338
+ done();
339
+ });
340
+
341
+ it('does not crash when parsing circular references', function (done) {
342
+
343
+ var a = {};
344
+ a.b = a;
345
+
346
+ var parsed;
347
+
348
+ expect(function () {
349
+
350
+ parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a });
351
+ }).to.not.throw(Error);
352
+
353
+ expect(parsed).to.have.key('foo');
354
+ expect(parsed.foo).to.have.keys('bar', 'baz');
355
+ expect(parsed.foo.bar).to.equal('baz');
356
+ expect(parsed.foo.baz).to.deep.equal(a);
357
+ done();
358
+ });
359
+
360
+ it('parses plain objects correctly', function (done) {
361
+
362
+ var a = Object.create(null);
363
+ a.b = 'c';
364
+
365
+ expect(Qs.parse(a)).to.deep.equal({ b: 'c' });
366
+ expect(Qs.parse({ a: a })).to.deep.equal({ a: { b: 'c' } });
367
+ done();
368
+ });
369
+
370
+ it('parses dates correctly', function (done) {
371
+
372
+ var now = new Date();
373
+ expect(Qs.parse({ a: now })).to.deep.equal({ a: now });
374
+ done();
375
+ });
376
+
377
+ it('parses regular expressions correctly', function (done) {
378
+
379
+ var re = /^test$/;
380
+ expect(Qs.parse({ a: re })).to.deep.equal({ a: re });
381
+ done();
382
+ });
313
383
  });
package/test/stringify.js CHANGED
@@ -126,4 +126,13 @@ describe('#stringify', function () {
126
126
  expect(Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).to.equal('a=b;c=d');
127
127
  done();
128
128
  });
129
+
130
+ it('doesn\'t blow up when Buffer global is missing', function (done) {
131
+
132
+ var tempBuffer = global.Buffer;
133
+ delete global.Buffer;
134
+ expect(Qs.stringify({ a: 'b', c: 'd' })).to.equal('a=b&c=d');
135
+ global.Buffer = tempBuffer;
136
+ done();
137
+ });
129
138
  });