qs 6.5.0 → 6.5.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/.eslintrc CHANGED
@@ -6,6 +6,7 @@
6
6
  "rules": {
7
7
  "complexity": [2, 28],
8
8
  "consistent-return": 1,
9
+ "func-name-matching": 0,
9
10
  "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
10
11
  "indent": [2, 4],
11
12
  "max-params": [2, 12],
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## **6.5.1**
2
+ - [Fix] Fix parsing & compacting very deep objects (#224)
3
+ - [Refactor] name utils functions
4
+ - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`
5
+ - [Tests] up to `node` `v8.4`; use `nvm install-latest-npm` so newer npm doesn’t break older node
6
+ - [Tests] Use precise dist for Node.js 0.6 runtime (#225)
7
+ - [Tests] make 0.6 required, now that it’s passing
8
+ - [Tests] on `node` `v8.2`; fix npm on node 0.6
9
+
1
10
  ## **6.5.0**
2
11
  - [New] add `utils.assign`
3
12
  - [New] pass default encoder/decoder to custom encoder/decoder functions (#206)
package/dist/qs.js CHANGED
@@ -80,36 +80,38 @@ var parseValues = function parseQueryStringValues(str, options) {
80
80
  return obj;
81
81
  };
82
82
 
83
- var parseObject = function parseObjectRecursive(chain, val, options) {
84
- if (!chain.length) {
85
- return val;
86
- }
83
+ var parseObject = function (chain, val, options) {
84
+ var leaf = val;
87
85
 
88
- var root = chain.shift();
86
+ for (var i = chain.length - 1; i >= 0; --i) {
87
+ var obj;
88
+ var root = chain[i];
89
89
 
90
- var obj;
91
- if (root === '[]') {
92
- obj = [];
93
- obj = obj.concat(parseObject(chain, val, options));
94
- } else {
95
- obj = options.plainObjects ? Object.create(null) : {};
96
- var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
97
- var index = parseInt(cleanRoot, 10);
98
- if (
99
- !isNaN(index)
100
- && root !== cleanRoot
101
- && String(index) === cleanRoot
102
- && index >= 0
103
- && (options.parseArrays && index <= options.arrayLimit)
104
- ) {
90
+ if (root === '[]') {
105
91
  obj = [];
106
- obj[index] = parseObject(chain, val, options);
92
+ obj = obj.concat(leaf);
107
93
  } else {
108
- obj[cleanRoot] = parseObject(chain, val, options);
94
+ obj = options.plainObjects ? Object.create(null) : {};
95
+ var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
96
+ var index = parseInt(cleanRoot, 10);
97
+ if (
98
+ !isNaN(index)
99
+ && root !== cleanRoot
100
+ && String(index) === cleanRoot
101
+ && index >= 0
102
+ && (options.parseArrays && index <= options.arrayLimit)
103
+ ) {
104
+ obj = [];
105
+ obj[index] = leaf;
106
+ } else {
107
+ obj[cleanRoot] = leaf;
108
+ }
109
109
  }
110
+
111
+ leaf = obj;
110
112
  }
111
113
 
112
- return obj;
114
+ return leaf;
113
115
  };
114
116
 
115
117
  var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
@@ -347,7 +349,7 @@ module.exports = function (object, opts) {
347
349
  var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
348
350
  var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
349
351
  if (typeof options.format === 'undefined') {
350
- options.format = formats.default;
352
+ options.format = formats['default'];
351
353
  } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
352
354
  throw new TypeError('Unknown format option provided.');
353
355
  }
@@ -431,7 +433,30 @@ var hexTable = (function () {
431
433
  return array;
432
434
  }());
433
435
 
434
- exports.arrayToObject = function (source, options) {
436
+ var compactQueue = function compactQueue(queue) {
437
+ var obj;
438
+
439
+ while (queue.length) {
440
+ var item = queue.pop();
441
+ obj = item.obj[item.prop];
442
+
443
+ if (Array.isArray(obj)) {
444
+ var compacted = [];
445
+
446
+ for (var j = 0; j < obj.length; ++j) {
447
+ if (typeof obj[j] !== 'undefined') {
448
+ compacted.push(obj[j]);
449
+ }
450
+ }
451
+
452
+ item.obj[item.prop] = compacted;
453
+ }
454
+ }
455
+
456
+ return obj;
457
+ };
458
+
459
+ exports.arrayToObject = function arrayToObject(source, options) {
435
460
  var obj = options && options.plainObjects ? Object.create(null) : {};
436
461
  for (var i = 0; i < source.length; ++i) {
437
462
  if (typeof source[i] !== 'undefined') {
@@ -442,7 +467,7 @@ exports.arrayToObject = function (source, options) {
442
467
  return obj;
443
468
  };
444
469
 
445
- exports.merge = function (target, source, options) {
470
+ exports.merge = function merge(target, source, options) {
446
471
  if (!source) {
447
472
  return target;
448
473
  }
@@ -512,7 +537,7 @@ exports.decode = function (str) {
512
537
  }
513
538
  };
514
539
 
515
- exports.encode = function (str) {
540
+ exports.encode = function encode(str) {
516
541
  // This code was originally written by Brian White (mscdex) for the io.js core querystring library.
517
542
  // It has been adapted here for stricter adherence to RFC 3986
518
543
  if (str.length === 0) {
@@ -526,7 +551,7 @@ exports.encode = function (str) {
526
551
  var c = string.charCodeAt(i);
527
552
 
528
553
  if (
529
- c === 0x2D // -
554
+ c === 0x2D // -
530
555
  || c === 0x2E // .
531
556
  || c === 0x5F // _
532
557
  || c === 0x7E // ~
@@ -564,46 +589,33 @@ exports.encode = function (str) {
564
589
  return out;
565
590
  };
566
591
 
567
- exports.compact = function (obj, references) {
568
- if (typeof obj !== 'object' || obj === null) {
569
- return obj;
570
- }
571
-
572
- var refs = references || [];
573
- var lookup = refs.indexOf(obj);
574
- if (lookup !== -1) {
575
- return refs[lookup];
576
- }
577
-
578
- refs.push(obj);
592
+ exports.compact = function compact(value) {
593
+ var queue = [{ obj: { o: value }, prop: 'o' }];
594
+ var refs = [];
579
595
 
580
- if (Array.isArray(obj)) {
581
- var compacted = [];
596
+ for (var i = 0; i < queue.length; ++i) {
597
+ var item = queue[i];
598
+ var obj = item.obj[item.prop];
582
599
 
583
- for (var i = 0; i < obj.length; ++i) {
584
- if (obj[i] && typeof obj[i] === 'object') {
585
- compacted.push(exports.compact(obj[i], refs));
586
- } else if (typeof obj[i] !== 'undefined') {
587
- compacted.push(obj[i]);
600
+ var keys = Object.keys(obj);
601
+ for (var j = 0; j < keys.length; ++j) {
602
+ var key = keys[j];
603
+ var val = obj[key];
604
+ if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
605
+ queue.push({ obj: obj, prop: key });
606
+ refs.push(val);
588
607
  }
589
608
  }
590
-
591
- return compacted;
592
609
  }
593
610
 
594
- var keys = Object.keys(obj);
595
- keys.forEach(function (key) {
596
- obj[key] = exports.compact(obj[key], refs);
597
- });
598
-
599
- return obj;
611
+ return compactQueue(queue);
600
612
  };
601
613
 
602
- exports.isRegExp = function (obj) {
614
+ exports.isRegExp = function isRegExp(obj) {
603
615
  return Object.prototype.toString.call(obj) === '[object RegExp]';
604
616
  };
605
617
 
606
- exports.isBuffer = function (obj) {
618
+ exports.isBuffer = function isBuffer(obj) {
607
619
  if (obj === null || typeof obj === 'undefined') {
608
620
  return false;
609
621
  }
package/lib/parse.js CHANGED
@@ -46,36 +46,38 @@ var parseValues = function parseQueryStringValues(str, options) {
46
46
  return obj;
47
47
  };
48
48
 
49
- var parseObject = function parseObjectRecursive(chain, val, options) {
50
- if (!chain.length) {
51
- return val;
52
- }
49
+ var parseObject = function (chain, val, options) {
50
+ var leaf = val;
51
+
52
+ for (var i = chain.length - 1; i >= 0; --i) {
53
+ var obj;
54
+ var root = chain[i];
53
55
 
54
- var root = chain.shift();
55
-
56
- var obj;
57
- if (root === '[]') {
58
- obj = [];
59
- obj = obj.concat(parseObject(chain, val, options));
60
- } else {
61
- obj = options.plainObjects ? Object.create(null) : {};
62
- var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
63
- var index = parseInt(cleanRoot, 10);
64
- if (
65
- !isNaN(index)
66
- && root !== cleanRoot
67
- && String(index) === cleanRoot
68
- && index >= 0
69
- && (options.parseArrays && index <= options.arrayLimit)
70
- ) {
56
+ if (root === '[]') {
71
57
  obj = [];
72
- obj[index] = parseObject(chain, val, options);
58
+ obj = obj.concat(leaf);
73
59
  } else {
74
- obj[cleanRoot] = parseObject(chain, val, options);
60
+ obj = options.plainObjects ? Object.create(null) : {};
61
+ var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
62
+ var index = parseInt(cleanRoot, 10);
63
+ if (
64
+ !isNaN(index)
65
+ && root !== cleanRoot
66
+ && String(index) === cleanRoot
67
+ && index >= 0
68
+ && (options.parseArrays && index <= options.arrayLimit)
69
+ ) {
70
+ obj = [];
71
+ obj[index] = leaf;
72
+ } else {
73
+ obj[cleanRoot] = leaf;
74
+ }
75
75
  }
76
+
77
+ leaf = obj;
76
78
  }
77
79
 
78
- return obj;
80
+ return leaf;
79
81
  };
80
82
 
81
83
  var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
package/lib/stringify.js CHANGED
@@ -139,7 +139,7 @@ module.exports = function (object, opts) {
139
139
  var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
140
140
  var encodeValuesOnly = typeof options.encodeValuesOnly === 'boolean' ? options.encodeValuesOnly : defaults.encodeValuesOnly;
141
141
  if (typeof options.format === 'undefined') {
142
- options.format = formats.default;
142
+ options.format = formats['default'];
143
143
  } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
144
144
  throw new TypeError('Unknown format option provided.');
145
145
  }
package/lib/utils.js CHANGED
@@ -11,7 +11,30 @@ var hexTable = (function () {
11
11
  return array;
12
12
  }());
13
13
 
14
- exports.arrayToObject = function (source, options) {
14
+ var compactQueue = function compactQueue(queue) {
15
+ var obj;
16
+
17
+ while (queue.length) {
18
+ var item = queue.pop();
19
+ obj = item.obj[item.prop];
20
+
21
+ if (Array.isArray(obj)) {
22
+ var compacted = [];
23
+
24
+ for (var j = 0; j < obj.length; ++j) {
25
+ if (typeof obj[j] !== 'undefined') {
26
+ compacted.push(obj[j]);
27
+ }
28
+ }
29
+
30
+ item.obj[item.prop] = compacted;
31
+ }
32
+ }
33
+
34
+ return obj;
35
+ };
36
+
37
+ exports.arrayToObject = function arrayToObject(source, options) {
15
38
  var obj = options && options.plainObjects ? Object.create(null) : {};
16
39
  for (var i = 0; i < source.length; ++i) {
17
40
  if (typeof source[i] !== 'undefined') {
@@ -22,7 +45,7 @@ exports.arrayToObject = function (source, options) {
22
45
  return obj;
23
46
  };
24
47
 
25
- exports.merge = function (target, source, options) {
48
+ exports.merge = function merge(target, source, options) {
26
49
  if (!source) {
27
50
  return target;
28
51
  }
@@ -92,7 +115,7 @@ exports.decode = function (str) {
92
115
  }
93
116
  };
94
117
 
95
- exports.encode = function (str) {
118
+ exports.encode = function encode(str) {
96
119
  // This code was originally written by Brian White (mscdex) for the io.js core querystring library.
97
120
  // It has been adapted here for stricter adherence to RFC 3986
98
121
  if (str.length === 0) {
@@ -106,7 +129,7 @@ exports.encode = function (str) {
106
129
  var c = string.charCodeAt(i);
107
130
 
108
131
  if (
109
- c === 0x2D // -
132
+ c === 0x2D // -
110
133
  || c === 0x2E // .
111
134
  || c === 0x5F // _
112
135
  || c === 0x7E // ~
@@ -144,46 +167,33 @@ exports.encode = function (str) {
144
167
  return out;
145
168
  };
146
169
 
147
- exports.compact = function (obj, references) {
148
- if (typeof obj !== 'object' || obj === null) {
149
- return obj;
150
- }
151
-
152
- var refs = references || [];
153
- var lookup = refs.indexOf(obj);
154
- if (lookup !== -1) {
155
- return refs[lookup];
156
- }
157
-
158
- refs.push(obj);
159
-
160
- if (Array.isArray(obj)) {
161
- var compacted = [];
162
-
163
- for (var i = 0; i < obj.length; ++i) {
164
- if (obj[i] && typeof obj[i] === 'object') {
165
- compacted.push(exports.compact(obj[i], refs));
166
- } else if (typeof obj[i] !== 'undefined') {
167
- compacted.push(obj[i]);
170
+ exports.compact = function compact(value) {
171
+ var queue = [{ obj: { o: value }, prop: 'o' }];
172
+ var refs = [];
173
+
174
+ for (var i = 0; i < queue.length; ++i) {
175
+ var item = queue[i];
176
+ var obj = item.obj[item.prop];
177
+
178
+ var keys = Object.keys(obj);
179
+ for (var j = 0; j < keys.length; ++j) {
180
+ var key = keys[j];
181
+ var val = obj[key];
182
+ if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
183
+ queue.push({ obj: obj, prop: key });
184
+ refs.push(val);
168
185
  }
169
186
  }
170
-
171
- return compacted;
172
187
  }
173
188
 
174
- var keys = Object.keys(obj);
175
- keys.forEach(function (key) {
176
- obj[key] = exports.compact(obj[key], refs);
177
- });
178
-
179
- return obj;
189
+ return compactQueue(queue);
180
190
  };
181
191
 
182
- exports.isRegExp = function (obj) {
192
+ exports.isRegExp = function isRegExp(obj) {
183
193
  return Object.prototype.toString.call(obj) === '[object RegExp]';
184
194
  };
185
195
 
186
- exports.isBuffer = function (obj) {
196
+ exports.isBuffer = function isBuffer(obj) {
187
197
  if (obj === null || typeof obj === 'undefined') {
188
198
  return false;
189
199
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qs",
3
3
  "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
4
  "homepage": "https://github.com/ljharb/qs",
5
- "version": "6.5.0",
5
+ "version": "6.5.1",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
@@ -24,17 +24,17 @@
24
24
  },
25
25
  "dependencies": {},
26
26
  "devDependencies": {
27
- "@ljharb/eslint-config": "^11.0.0",
27
+ "@ljharb/eslint-config": "^12.2.1",
28
28
  "browserify": "^14.4.0",
29
29
  "covert": "^1.1.0",
30
30
  "editorconfig-tools": "^0.1.1",
31
- "eslint": "^3.19.0",
31
+ "eslint": "^4.6.1",
32
32
  "evalmd": "^0.0.17",
33
33
  "iconv-lite": "^0.4.18",
34
34
  "mkdirp": "^0.5.1",
35
35
  "qs-iconv": "^1.0.4",
36
36
  "safe-publish-latest": "^1.1.1",
37
- "tape": "^4.7.0"
37
+ "tape": "^4.8.0"
38
38
  },
39
39
  "scripts": {
40
40
  "prepublish": "safe-publish-latest && npm run dist",
package/test/.eslintrc CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "rules": {
3
+ "array-bracket-newline": 0,
4
+ "array-element-newline": 0,
3
5
  "consistent-return": 2,
4
6
  "max-lines": 0,
5
7
  "max-nested-callbacks": [2, 3],
6
8
  "max-statements": 0,
9
+ "no-buffer-constructor": 0,
7
10
  "no-extend-native": 0,
8
11
  "no-magic-numbers": 0,
12
+ "object-curly-newline": 0,
9
13
  "sort-keys": 0
10
14
  }
11
15
  }
package/test/parse.js CHANGED
@@ -396,6 +396,33 @@ test('parse()', function (t) {
396
396
  st.end();
397
397
  });
398
398
 
399
+ t.test('does not crash when parsing deep objects', function (st) {
400
+ var parsed;
401
+ var str = 'foo';
402
+
403
+ for (var i = 0; i < 5000; i++) {
404
+ str += '[p]';
405
+ }
406
+
407
+ str += '=bar';
408
+
409
+ st.doesNotThrow(function () {
410
+ parsed = qs.parse(str, { depth: 5000 });
411
+ });
412
+
413
+ st.equal('foo' in parsed, true, 'parsed has "foo" property');
414
+
415
+ var depth = 0;
416
+ var ref = parsed.foo;
417
+ while ((ref = ref.p)) {
418
+ depth += 1;
419
+ }
420
+
421
+ st.equal(depth, 5000, 'parsed is 5000 properties deep');
422
+
423
+ st.end();
424
+ });
425
+
399
426
  t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
400
427
  var a = Object.create(null);
401
428
  a.b = 'c';
@@ -529,7 +556,7 @@ test('parse()', function (t) {
529
556
  });
530
557
 
531
558
  t.test('throws error with wrong decoder', function (st) {
532
- st.throws(function () {
559
+ st['throws'](function () {
533
560
  qs.parse({}, { decoder: 'string' });
534
561
  }, new TypeError('Decoder has to be a function.'));
535
562
  st.end();
package/test/stringify.js CHANGED
@@ -474,7 +474,7 @@ test('stringify()', function (t) {
474
474
  });
475
475
 
476
476
  t.test('throws error with wrong encoder', function (st) {
477
- st.throws(function () {
477
+ st['throws'](function () {
478
478
  qs.stringify({}, { encoder: 'string' });
479
479
  }, new TypeError('Encoder has to be a function.'));
480
480
  st.end();
@@ -504,7 +504,7 @@ test('stringify()', function (t) {
504
504
  mutatedDate.toISOString = function () {
505
505
  throw new SyntaxError();
506
506
  };
507
- st.throws(function () {
507
+ st['throws'](function () {
508
508
  mutatedDate.toISOString();
509
509
  }, SyntaxError);
510
510
  st.equal(
@@ -546,7 +546,7 @@ test('stringify()', function (t) {
546
546
  t.test('Edge cases and unknown formats', function (st) {
547
547
  ['UFO1234', false, 1234, null, {}, []].forEach(
548
548
  function (format) {
549
- st.throws(
549
+ st['throws'](
550
550
  function () {
551
551
  qs.stringify({ a: 'b c' }, { format: format });
552
552
  },